├── .DS_Store ├── .gitignore ├── .idea ├── modules.xml └── vcs.xml ├── LICENSE ├── README.md ├── ThinkMap.iml ├── app ├── .gitignore ├── build.gradle ├── note │ └── 软件设计 ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── owant │ │ └── thinkmap │ │ ├── ExampleInstrumentedTest.java │ │ └── ui │ │ └── splash │ │ └── SplashActivityTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── owant │ │ │ └── thinkmap │ │ │ ├── App.java │ │ │ ├── AppConstants.java │ │ │ ├── AppPermissions.java │ │ │ ├── adapter │ │ │ └── CurrentWorkAdapter.java │ │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseAlertDialog.java │ │ │ ├── BaseFragment.java │ │ │ ├── BasePresenter.java │ │ │ └── BaseView.java │ │ │ ├── control │ │ │ └── MoveAndScaleHandler.java │ │ │ ├── drawable │ │ │ └── GravityCompoundDrawable.java │ │ │ ├── file │ │ │ ├── Conf.java │ │ │ ├── OwantFileCreate.java │ │ │ └── ZipTool.java │ │ │ ├── line │ │ │ ├── EaseCubicInterpolator.java │ │ │ └── ReboundInterpolator.java │ │ │ ├── manager │ │ │ └── ThreadPoolManager.java │ │ │ ├── model │ │ │ ├── CurrentFileModel.java │ │ │ ├── ForTreeItem.java │ │ │ ├── NodeModel.java │ │ │ └── TreeModel.java │ │ │ ├── net │ │ │ └── BaseResponse.java │ │ │ ├── test │ │ │ └── ExampleCreator.java │ │ │ ├── ui │ │ │ ├── EditAlertDialog.java │ │ │ ├── SplashActivity.java │ │ │ ├── about │ │ │ │ └── AboutUsActivity.java │ │ │ ├── codemode │ │ │ │ └── CodeModeActivity.java │ │ │ ├── editmap │ │ │ │ ├── EditMapActivity.java │ │ │ │ ├── EditMapContract.java │ │ │ │ └── EditMapPresenter.java │ │ │ ├── splash │ │ │ │ └── SplashActivity.java │ │ │ └── workspace │ │ │ │ ├── WorkSpaceActivity.java │ │ │ │ ├── WorkSpaceContract.java │ │ │ │ └── WorkSpacePresenter.java │ │ │ ├── util │ │ │ ├── AndroidUtil.java │ │ │ ├── DensityUtils.java │ │ │ ├── LOG.java │ │ │ ├── LooperFlag.java │ │ │ ├── MakeZipClient.java │ │ │ ├── SharePreUtil.java │ │ │ ├── StringTool.java │ │ │ └── code │ │ │ │ ├── BindView.jar │ │ │ │ └── BindViewTool.java │ │ │ └── view │ │ │ ├── NodeView.java │ │ │ ├── RecycleItemClickListener.java │ │ │ ├── RecycleItemLongClickListener.java │ │ │ ├── RightTreeLayoutManager.java │ │ │ ├── TreeLayoutManager.java │ │ │ ├── TreeView.java │ │ │ ├── TreeViewItemClick.java │ │ │ ├── TreeViewItemLongClick.java │ │ │ └── ViewBox.java │ └── res │ │ ├── anim │ │ ├── alpha_exit.xml │ │ ├── alpha_in.xml │ │ ├── big_enter.xml │ │ └── right_in.xml │ │ ├── color │ │ └── tab_color.xml │ │ ├── drawable │ │ ├── box.xml │ │ ├── btn_bg.xml │ │ ├── dialog_edit_input_bg.xml │ │ ├── edit_bg.xml │ │ ├── enter_bg.xml │ │ ├── node_view_bg.xml │ │ ├── selector_purple.xml │ │ └── tab_bg.xml │ │ ├── layout-v21 │ │ ├── div_edit_menu.xml │ │ └── item_current_file.xml │ │ ├── layout │ │ ├── activity_about_us.xml │ │ ├── activity_code_model.xml │ │ ├── activity_edit_think_map.xml │ │ ├── activity_main.xml │ │ ├── activity_splash.xml │ │ ├── activity_support.xml │ │ ├── activity_work_space_2.xml │ │ ├── dialog_edit_input.xml │ │ ├── div_action_bar.xml │ │ ├── div_edit_menu.xml │ │ ├── item_current_file.xml │ │ ├── scroll_item_menu.xml │ │ ├── test_3.xml │ │ └── test_gv.xml │ │ ├── menu │ │ └── work_space_menu.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_app.png │ │ └── support_code.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── clear_input.png │ │ ├── ic_back.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_app.png │ │ └── menu_moreoverflow.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_app.png │ │ ├── introduce.png │ │ ├── iv_add_node.png │ │ ├── iv_add_sub_node.png │ │ ├── iv_code_mode.png │ │ ├── iv_front_view.png │ │ ├── menu_delete.png │ │ └── search.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── raw │ │ └── examples.zip │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── owant │ └── thinkmap │ ├── ExampleUnitTest.java │ └── model │ └── TreeModelTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── info2.png └── settings.gradle /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owant/ThinkMap/80be866bb34fd4acb44204192e4a564f3de7e60f/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | .idea/gradle.xml 11 | .idea/misc.xml 12 | .idea/runConfigurations.xml 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Draw a tree in android,ThinkMap 2 | 3 | 4 | 5 | ### The Simple code 6 | 7 | following the simple code, you can build a tree. 8 | 9 | ``` 10 | final NodeModel nodeA = new NodeModel<>("A"); 11 | final NodeModel nodeB = new NodeModel<>("B"); 12 | final NodeModel nodeC = new NodeModel<>("C"); 13 | final NodeModel nodeD = new NodeModel<>("D"); 14 | final NodeModel nodeE = new NodeModel<>("E"); 15 | final NodeModel nodeF = new NodeModel<>("F"); 16 | final NodeModel nodeG = new NodeModel<>("G"); 17 | final NodeModel nodeH = new NodeModel<>("H"); 18 | final NodeModel nodeI = new NodeModel<>("I"); 19 | final NodeModel nodeJ = new NodeModel<>("J"); 20 | final NodeModel nodeK = new NodeModel<>("K"); 21 | final NodeModel nodeL = new NodeModel<>("L"); 22 | final NodeModel nodeM = new NodeModel<>("M"); 23 | final NodeModel nodeN = new NodeModel<>("N"); 24 | final NodeModel nodeO = new NodeModel<>("O"); 25 | final NodeModel nodeP = new NodeModel<>("P"); 26 | final NodeModel nodeQ = new NodeModel<>("Q"); 27 | final NodeModel nodeR = new NodeModel<>("R"); 28 | final NodeModel nodeS = new NodeModel<>("S"); 29 | final NodeModel nodeT = new NodeModel<>("T"); 30 | final NodeModel nodeU = new NodeModel<>("U"); 31 | final NodeModel nodeV = new NodeModel<>("V"); 32 | final NodeModel nodeW = new NodeModel<>("W"); 33 | final NodeModel nodeX = new NodeModel<>("X"); 34 | final NodeModel nodeY = new NodeModel<>("Y"); 35 | final NodeModel nodeZ = new NodeModel<>("Z"); 36 | 37 | 38 | final TreeModel tree = new TreeModel<>(nodeA); 39 | tree.addNode(nodeA, nodeB, nodeC, nodeD); 40 | tree.addNode(nodeC, nodeE, nodeF, nodeG, nodeH, nodeI); 41 | tree.addNode(nodeB, nodeJ, nodeK, nodeL); 42 | tree.addNode(nodeD, nodeM, nodeN, nodeO); 43 | tree.addNode(nodeF, nodeP, nodeQ, nodeR, nodeS); 44 | tree.addNode(nodeR, nodeT, nodeU, nodeV, nodeW, nodeX); 45 | tree.addNode(nodeT, nodeY, nodeZ); 46 | 47 | int dx = DensityUtils.dp2px(this, 20); 48 | int dy = DensityUtils.dp2px(this, 20); 49 | int mHeight = DensityUtils.dp2px(this, 720); 50 | 51 | testTreeView.setTreeLayoutManager(new RightTreeLayoutManager(dx, dy, mHeight)); 52 | testTreeView.setTreeModel(tree); 53 | 54 | ``` 55 | 56 | 57 | ### AppStore 58 | 59 | http://shouji.baidu.com/software/11238419.html 60 | 61 | 62 | ### Other 63 | 64 | https://blog.csdn.net/u012131702/article/details/54409193 65 | 66 | -------------------------------------------------------------------------------- /ThinkMap.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | signingConfigs { 5 | config { 6 | keyAlias 'OWANT' 7 | keyPassword 'owant123456' 8 | storeFile file('/Users/owant/Desktop/MyKey') 9 | storePassword 'owant123456' 10 | } 11 | } 12 | compileSdkVersion 26 13 | buildToolsVersion "26.0.1" 14 | defaultConfig { 15 | applicationId "com.owant.thinkmap" 16 | minSdkVersion 15 17 | targetSdkVersion 26 18 | versionCode 10 19 | versionName "1.0.4" 20 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 21 | } 22 | 23 | buildTypes { 24 | 25 | debug{ 26 | applicationIdSuffix ".debug" 27 | manifestPlaceholders = [app_name: "ThinkMap_Debug"] 28 | //示例版本,用于判断是否需要更新示例 29 | resValue("string", "examplesVersion", "v1.0.5") 30 | minifyEnabled false 31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 32 | 33 | 34 | } 35 | 36 | release { 37 | applicationIdSuffix ".debug" 38 | manifestPlaceholders = [app_name: "ThinkMap_Debug"] 39 | //示例版本,用于判断是否需要更新示例 40 | resValue("string", "examplesVersion", "v1.0.5") 41 | minifyEnabled false 42 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 43 | } 44 | } 45 | } 46 | 47 | 48 | ext { 49 | support_version = "25.3.1" 50 | } 51 | 52 | dependencies { 53 | compile fileTree(include: ['*.jar'], dir: 'libs') 54 | testCompile 'junit:junit:4.12' 55 | compile 'com.nineoldandroids:library:2.4.0' 56 | compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28' 57 | compile "com.android.support:appcompat-v7:${support_version}" 58 | compile "com.android.support:cardview-v7:${support_version}" 59 | compile "com.android.support:recyclerview-v7:${support_version}" 60 | //leak检测 61 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' 62 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 63 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 64 | androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2', { 65 | exclude group: 'com.android.support', module: 'support-annotations' 66 | exclude group: 'com.android.support', module: 'support-v4' 67 | exclude group: 'com.android.support', module: 'design' 68 | exclude group: 'com.android.support', module: 'recyclerview-v7' 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/note/软件设计: -------------------------------------------------------------------------------- 1 | 文件格式:.owant 2 | 文件目录为 3 | 文件名(my_play.owant) 4 | content 5 | conf.txt 6 | 7 | 流程: 8 | (要进行清理) 9 | 1.在owantmaps里创建一个create_file文件夹; 10 | 2.content文件进行写序列化的tree对象; 11 | 3.创建一个conf.txt文件进行保存文件基本信息,修改日期,文件名,系统的版本; 12 | 4.为file_name_temp和conf.txt进行压缩为owant文件; 13 | 5.删除create_file文件夹下的所有文件; 14 | 15 | 16 | 17 | TreeView的设计结构 18 | 19 | TreeView 20 | +setTreeModel(TreeModel model) 21 | +setTreeLayoutManager(TreeLayoutManager manager) //树形结构的位置管理器 22 | +onMeasure() 23 | +onLayout() 24 | 25 | 26 | TreeLayoutManager 27 | +onTreeLayout() //进行树形结构的位置确认 28 | +onTreeLayoutCallback(int left,int right,int top,int bottom) //位置确定后的回调 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/owant/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | #基本模型不能混淆 20 | -keep class com.owant.thinkmap.model.*{*;} 21 | -keep public class * extends com.owant.thinkmap.model.NodeModel 22 | -keep public class * extends com.owant.thinkmap.model.TreeModel 23 | 24 | #使用了fastJSON不能混淆泛型,注解 25 | -keepattributes Signature 26 | -keepattributes *Annotation* 27 | 28 | 29 | ##支付宝混淆 30 | #-libraryjars libs/alipaySDK-20150602.jar 31 | #-keep class com.alipay.android.app.IAlixPay{*;} 32 | #-keep class com.alipay.android.app.IAlixPay$Stub{*;} 33 | #-keep class com.alipay.android.app.IRemoteServiceCallback{*;} 34 | #-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;} 35 | #-keep class com.alipay.sdk.app.PayTask{ public *;} 36 | #-keep class com.alipay.sdk.app.AuthTask{ public *;} 37 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/owant/thinkmap/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.owant.thinkmap", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/owant/thinkmap/ui/splash/SplashActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.splash; 2 | 3 | 4 | import android.support.test.rule.ActivityTestRule; 5 | import android.support.test.runner.AndroidJUnit4; 6 | import android.test.suitebuilder.annotation.LargeTest; 7 | import android.view.View; 8 | import android.widget.ImageButton; 9 | import android.widget.Toolbar; 10 | 11 | import org.hamcrest.Matcher; 12 | import org.junit.Rule; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | 16 | import static android.support.test.espresso.Espresso.onView; 17 | import static android.support.test.espresso.action.ViewActions.click; 18 | import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; 19 | import static android.support.test.espresso.matcher.ViewMatchers.withParent; 20 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 21 | import static org.hamcrest.Matchers.allOf; 22 | 23 | @LargeTest 24 | @RunWith(AndroidJUnit4.class) 25 | public class SplashActivityTest { 26 | 27 | @Rule 28 | public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(SplashActivity.class); 29 | 30 | @Test 31 | public void splashActivityTest() throws InterruptedException { 32 | 33 | onView(navigationIconMatcher()).perform(click()); 34 | onView(withText("QQ")).perform(click()); 35 | 36 | } 37 | 38 | public static Matcher navigationIconMatcher() { 39 | return allOf( 40 | isAssignableFrom(ImageButton.class), 41 | withParent(isAssignableFrom(Toolbar.class))); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 88 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/App.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap; 2 | 3 | import android.app.Application; 4 | 5 | import com.owant.thinkmap.util.SharePreUtil; 6 | 7 | /** 8 | * Created by owant on 22/03/2017. 9 | */ 10 | 11 | public class App extends Application { 12 | 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | 17 | //初始化工具 18 | SharePreUtil.getInstance().init(getApplicationContext()); 19 | // LeakCanary.install(this); 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/AppConstants.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap; 2 | 3 | /** 4 | * Created by owant on 17/03/2017. 5 | */ 6 | 7 | public class AppConstants { 8 | 9 | //owant文件 10 | public final static String owant_maps = "/OwantMaps/"; 11 | public final static String temp_create_file = "temp_create_file/"; 12 | public final static String content = "content"; 13 | public final static String conf = "conf.txt"; 14 | 15 | //演示文件 16 | public final static String examples_names = "examples.zip"; 17 | public final static String sp_examples_version = "examples_version"; 18 | 19 | /** 20 | * 控制LOG 21 | */ 22 | public static final boolean CONFIG_DEBUG = true; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/AppPermissions.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap; 2 | 3 | import android.Manifest; 4 | import android.os.Build; 5 | import android.support.annotation.RequiresApi; 6 | 7 | /** 8 | * Created by owant on 23/03/2017. 9 | */ 10 | 11 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) 12 | public class AppPermissions { 13 | 14 | //权限请求 15 | public static int request_permission_storage = 2; 16 | 17 | /** 18 | * 19 | * 20 | */ 21 | public static String[] permission_storage = new String[]{ 22 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 23 | Manifest.permission.READ_EXTERNAL_STORAGE 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/adapter/CurrentWorkAdapter.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.owant.thinkmap.R; 11 | import com.owant.thinkmap.model.CurrentFileModel; 12 | import com.owant.thinkmap.view.RecycleItemClickListener; 13 | import com.owant.thinkmap.view.RecycleItemLongClickListener; 14 | 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * Created by owant on 27/02/2017. 19 | */ 20 | 21 | public class CurrentWorkAdapter extends RecyclerView.Adapter { 22 | 23 | public Context mContext; 24 | public ArrayList mLists; 25 | 26 | public RecycleItemClickListener mRecycleItemClickListener; 27 | public RecycleItemLongClickListener mRecycleItemLongClickListener; 28 | 29 | public CurrentWorkAdapter(Context mContext, ArrayList mLists) { 30 | this.mContext = mContext; 31 | this.mLists = mLists; 32 | } 33 | 34 | @Override 35 | public CurrentFileViewHold onCreateViewHolder(ViewGroup parent, int viewType) { 36 | View view = LayoutInflater.from(mContext).inflate(R.layout.item_current_file, parent, false); 37 | CurrentFileViewHold currentFileViewHold = new CurrentFileViewHold( 38 | view, 39 | mRecycleItemClickListener, 40 | mRecycleItemLongClickListener); 41 | 42 | return currentFileViewHold; 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(CurrentFileViewHold holder, int position) { 47 | CurrentFileModel fileModel = mLists.get(position); 48 | holder.rootValue.setText(fileModel.mapRoot); 49 | holder.filePath.setText(fileModel.filePath); 50 | } 51 | 52 | @Override 53 | public int getItemCount() { 54 | return mLists.size(); 55 | } 56 | 57 | public void setRecycleItemClickListener(RecycleItemClickListener recycleItemClickListener) { 58 | mRecycleItemClickListener = recycleItemClickListener; 59 | } 60 | 61 | public void setRecycleItemLongClickListener(RecycleItemLongClickListener recycleItemLongClickListener) { 62 | mRecycleItemLongClickListener = recycleItemLongClickListener; 63 | } 64 | 65 | static class CurrentFileViewHold extends RecyclerView.ViewHolder { 66 | private TextView rootValue; 67 | private TextView filePath; 68 | private RecycleItemClickListener mListener; 69 | private RecycleItemLongClickListener mLongClickListener; 70 | 71 | public CurrentFileViewHold(final View itemView, 72 | RecycleItemClickListener listener, 73 | RecycleItemLongClickListener longListener) { 74 | super(itemView); 75 | rootValue = (TextView) itemView.findViewById(R.id.owant_file_root_value); 76 | filePath = (TextView) itemView.findViewById(R.id.owant_file_path); 77 | mListener = listener; 78 | mLongClickListener = longListener; 79 | 80 | itemView.setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | if (mListener != null) { 84 | mListener.onItemClick(itemView, getAdapterPosition()); 85 | } 86 | } 87 | }); 88 | 89 | itemView.setOnLongClickListener(new View.OnLongClickListener() { 90 | @Override 91 | public boolean onLongClick(View v) { 92 | if (mLongClickListener != null) { 93 | mLongClickListener.onItemLongClick(itemView, getAdapterPosition()); 94 | } 95 | return false; 96 | } 97 | }); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | 8 | /** 9 | * Created by owant on 22/02/2017. 10 | */ 11 | public abstract class BaseActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | 17 | onBaseIntent(); 18 | 19 | onBasePreLayout(); 20 | 21 | setContentView(onBaseLayoutId(savedInstanceState)); 22 | 23 | onBaseBindView(); 24 | 25 | onLoadData(); 26 | } 27 | 28 | /** 29 | * Intent进来的数据处理 30 | */ 31 | protected abstract void onBaseIntent(); 32 | 33 | /** 34 | * 设置布局之前的处理 35 | */ 36 | protected abstract void onBasePreLayout(); 37 | 38 | /** 39 | * 返回布局文件 40 | * 41 | * @return id 42 | */ 43 | protected abstract int onBaseLayoutId(@Nullable Bundle savedInstanceState); 44 | 45 | protected abstract void onBaseBindView(); 46 | 47 | /** 48 | * 加载数据 49 | */ 50 | protected abstract void onLoadData(); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/base/BaseAlertDialog.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.base; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.IdRes; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.annotation.StyleRes; 8 | import android.support.v7.app.AlertDialog; 9 | import android.view.View; 10 | 11 | /** 12 | * Created by owant on 24/02/2017. 13 | */ 14 | 15 | public abstract class BaseAlertDialog extends AlertDialog { 16 | 17 | private View mainView; 18 | 19 | protected BaseAlertDialog(@NonNull Context context) { 20 | this(context, 0); 21 | } 22 | 23 | protected BaseAlertDialog(@NonNull Context context, @StyleRes int themeResId) { 24 | super(context, themeResId); 25 | } 26 | 27 | @Override 28 | public void setView(View view) { 29 | super.setView(view); 30 | mainView = view; 31 | onBaseBindView(); 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public View findViewById(@IdRes int id) { 37 | if (mainView != null) { 38 | return mainView.findViewById(id); 39 | } 40 | return super.findViewById(id); 41 | } 42 | 43 | protected abstract void onBaseBindView(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | /** 12 | * Created by owant on 22/02/2017. 13 | */ 14 | 15 | public abstract class BaseFragment extends Fragment { 16 | 17 | @Nullable 18 | @Override 19 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 20 | View tabView = inflater.inflate(onBaseLayoutId(), container, false); 21 | return tabView; 22 | } 23 | 24 | protected abstract int onBaseLayoutId(); 25 | 26 | @Override 27 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 28 | super.onActivityCreated(savedInstanceState); 29 | 30 | onBaseBindView(); 31 | 32 | onBaseLoadData(); 33 | } 34 | 35 | protected abstract void onBaseBindView(); 36 | 37 | protected abstract void onBaseLoadData(); 38 | 39 | @Override 40 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 41 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.owant.thinkmap.base; 18 | 19 | public interface BasePresenter { 20 | 21 | void start(); 22 | 23 | void onRecycle(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/base/BaseView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016, The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.owant.thinkmap.base; 18 | 19 | public interface BaseView { 20 | 21 | void setPresenter(T presenter); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/control/MoveAndScaleHandler.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.control; 2 | 3 | import android.content.Context; 4 | import android.view.MotionEvent; 5 | import android.view.ScaleGestureDetector; 6 | import android.view.View; 7 | 8 | import com.nineoldandroids.view.ViewHelper; 9 | 10 | /** 11 | * Created by owant on 09/02/2017. 12 | */ 13 | 14 | public class MoveAndScaleHandler implements ScaleGestureDetector.OnScaleGestureListener { 15 | 16 | static final float max_scale = 1.2f; 17 | static final float min_scale = 0.3f; 18 | 19 | /** 20 | * 作用于的View 21 | */ 22 | private View mView; 23 | 24 | private int lastX = 0; 25 | private int lastY = 0; 26 | 27 | private int mode = 0; 28 | 29 | private ScaleGestureDetector mScaleGestureDetector; 30 | private Context mContext; 31 | 32 | public MoveAndScaleHandler(Context context, View view) { 33 | this.mView = view; 34 | this.mContext = context; 35 | mScaleGestureDetector = new ScaleGestureDetector(mContext, this); 36 | } 37 | 38 | public boolean onTouchEvent(MotionEvent event) { 39 | 40 | int currentX = (int) event.getRawX();//获得手指当前的坐标,相对于屏幕 41 | int currentY = (int) event.getRawY(); 42 | 43 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 44 | case MotionEvent.ACTION_DOWN: 45 | mode = 1; 46 | break; 47 | case MotionEvent.ACTION_UP: 48 | mode = 0; 49 | break; 50 | case MotionEvent.ACTION_POINTER_UP: 51 | //将模式进行为负数这样,多指下,抬起不会触发移动 52 | mode = -2; 53 | break; 54 | case MotionEvent.ACTION_POINTER_DOWN: 55 | mode += 1; 56 | break; 57 | 58 | case MotionEvent.ACTION_MOVE: 59 | if (mode >= 2) { 60 | //缩放 61 | //mScaleGestureDetector.onTouchEvent(event); 62 | 63 | } else if (mode == 1) { 64 | int deltaX = currentX - lastX; 65 | int deltaY = currentY - lastY; 66 | 67 | int translationX = (int) ViewHelper.getTranslationX(mView) + deltaX; 68 | int translationY = (int) ViewHelper.getTranslationY(mView) + deltaY; 69 | 70 | ViewHelper.setTranslationX(mView, translationX); 71 | ViewHelper.setTranslationY(mView, translationY); 72 | } 73 | break; 74 | } 75 | 76 | lastX = currentX; 77 | lastY = currentY; 78 | 79 | return true; 80 | 81 | } 82 | 83 | /** 84 | * 两点之间的距离 85 | * 86 | * @param event 87 | * @return 88 | */ 89 | private float spacing(MotionEvent event) { 90 | float x = event.getX(0) - event.getX(1); 91 | float y = event.getY(0) - event.getY(1); 92 | return (float) Math.sqrt(x * x + y * y); 93 | } 94 | 95 | @Override 96 | public boolean onScale(ScaleGestureDetector detector) { 97 | 98 | float scaleFactor = detector.getScaleFactor(); 99 | 100 | if (scaleFactor >= max_scale) { 101 | scaleFactor = max_scale; 102 | } 103 | if (scaleFactor <= min_scale) { 104 | scaleFactor = min_scale; 105 | } 106 | 107 | float old = mView.getScaleX(); 108 | if (Math.abs(scaleFactor - old) > 0.6 || Math.abs(scaleFactor - old) < 0.02) { 109 | //忽略 110 | } else { 111 | ViewHelper.setScaleX(mView, scaleFactor); 112 | ViewHelper.setScaleY(mView, scaleFactor); 113 | } 114 | 115 | return false; 116 | } 117 | 118 | @Override 119 | public boolean onScaleBegin(ScaleGestureDetector detector) { 120 | return true; 121 | } 122 | 123 | @Override 124 | public void onScaleEnd(ScaleGestureDetector detector) { 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/drawable/GravityCompoundDrawable.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.drawable; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.ColorFilter; 5 | import android.graphics.PixelFormat; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.annotation.IntRange; 8 | import android.support.annotation.Nullable; 9 | 10 | /** 11 | * Created by owant on 01/04/2017. 12 | */ 13 | 14 | public class GravityCompoundDrawable extends Drawable { 15 | 16 | // inner Drawable 17 | private final Drawable mDrawable; 18 | 19 | public GravityCompoundDrawable(Drawable drawable) { 20 | mDrawable = drawable; 21 | } 22 | 23 | @Override 24 | public int getIntrinsicWidth() { 25 | return mDrawable.getIntrinsicWidth(); 26 | } 27 | 28 | @Override 29 | public int getIntrinsicHeight() { 30 | return mDrawable.getIntrinsicHeight(); 31 | } 32 | 33 | @Override 34 | public void draw(Canvas canvas) { 35 | int halfCanvas= canvas.getHeight() / 2; 36 | int halfDrawable = mDrawable.getIntrinsicHeight() / 2; 37 | 38 | // align to top 39 | canvas.save(); 40 | canvas.translate(0, -halfCanvas + halfDrawable); 41 | mDrawable.draw(canvas); 42 | canvas.restore(); 43 | } 44 | 45 | @Override 46 | public void setAlpha(@IntRange(from = 0, to = 255) int alpha) { 47 | 48 | } 49 | 50 | @Override 51 | public void setColorFilter(@Nullable ColorFilter colorFilter) { 52 | 53 | } 54 | 55 | @Override 56 | public int getOpacity() { 57 | return PixelFormat.TRANSPARENT; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/file/Conf.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.file; 2 | 3 | /** 4 | * Created by owant on 25/02/2017. 5 | * conf.txt 6 | */ 7 | 8 | public class Conf { 9 | public String app_version; 10 | public String android_version; 11 | public String map_name; 12 | public String date; 13 | 14 | @Override 15 | public String toString() { 16 | return "Conf{" + 17 | "app_version='" + app_version + '\'' + 18 | ", android_version='" + android_version + '\'' + 19 | ", map_name='" + map_name + '\'' + 20 | ", date='" + date + '\'' + 21 | '}'; 22 | } 23 | 24 | public static void main(String[] args) { 25 | Conf conf = new Conf(); 26 | conf.android_version = "android5.0"; 27 | conf.app_version = "1.0.1"; 28 | conf.date = "2017-2-27"; 29 | System.out.println(conf.toString()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/file/OwantFileCreate.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.file; 2 | 3 | import android.os.Environment; 4 | import android.util.Log; 5 | 6 | import com.owant.thinkmap.AppConstants; 7 | import com.owant.thinkmap.model.TreeModel; 8 | import com.owant.thinkmap.util.MakeZipClient; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.InvalidClassException; 17 | import java.io.ObjectInputStream; 18 | import java.io.ObjectOutputStream; 19 | import java.util.zip.ZipEntry; 20 | import java.util.zip.ZipFile; 21 | 22 | /** 23 | * Created by owant on 25/02/2017. 24 | * (要进行清理) 25 | * 1.在owantmaps里创建一个temp_create_file文件夹; 26 | * 2.content文件进行写序列画的tree对象; 27 | * 3.创建一个conf.txt文件进行保存文件基本信息,修改日期,文件名,系统的版本; 28 | * 4.为file_name_temp和conf.txt进行压缩为owant文件; 29 | * 5.删除create_file文件夹下的所有文件; 30 | */ 31 | public class OwantFileCreate { 32 | 33 | private final static String TAG = "OwantFileCreate"; 34 | 35 | public void createOwantMapsDirectory() { 36 | if (hansSDCard()) { 37 | String map_path = Environment.getExternalStorageDirectory().getPath() + AppConstants.owant_maps; 38 | File owantMapDirectory = new File(map_path); 39 | if (!owantMapDirectory.exists()) { 40 | boolean mkdir = owantMapDirectory.mkdirs(); 41 | Log.i(TAG, "创建owantmaps文件路径:" + mkdir + owantMapDirectory.getAbsolutePath()); 42 | } 43 | } else { 44 | Log.e(TAG, "createOwantMapsDirectory: 没有内存卡!"); 45 | } 46 | } 47 | 48 | public void createTempDirectory() { 49 | if (hansSDCard()) { 50 | String path = Environment.getExternalStorageDirectory().getPath() + AppConstants.owant_maps + AppConstants.temp_create_file; 51 | File owantMapDirectory = new File(path); 52 | if (!owantMapDirectory.exists()) { 53 | owantMapDirectory.mkdirs(); 54 | Log.i(TAG, "创建Temp文件夹:" + path); 55 | } 56 | } else { 57 | Log.e(TAG, "createTempDirectory: 没有内存卡!"); 58 | return; 59 | } 60 | 61 | 62 | } 63 | 64 | public void writeContent(Object object) { 65 | try { 66 | 67 | String content_path = Environment.getExternalStorageDirectory().getPath() + 68 | AppConstants.owant_maps + 69 | AppConstants.temp_create_file + "content"; 70 | 71 | writeTreeObject(content_path, object); 72 | 73 | } catch (IOException e) { 74 | e.printStackTrace(); 75 | } 76 | } 77 | 78 | public void writeConf(Conf conf) { 79 | try { 80 | String conf_path = Environment.getExternalStorageDirectory().getPath() + 81 | AppConstants.owant_maps + 82 | AppConstants.temp_create_file + "conf.txt"; 83 | 84 | writeFile(conf_path, conf.toString()); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | } 89 | 90 | public void makeOwantFile(String saveName) { 91 | MakeZipClient client = new MakeZipClient(); 92 | String temp_path = Environment.getExternalStorageDirectory().getPath() + 93 | AppConstants.owant_maps + AppConstants.temp_create_file; 94 | String savePath = Environment.getExternalStorageDirectory().getPath() + 95 | AppConstants.owant_maps + saveName; 96 | if (!savePath.endsWith(".owant")) { 97 | savePath = savePath + ".owant"; 98 | } 99 | File saveFile = new File(savePath); 100 | client.create(temp_path, saveFile); 101 | 102 | Log.i(TAG, "创建owant文件成功" + savePath); 103 | } 104 | 105 | public void deleteTemp() { 106 | String temp_path = Environment.getExternalStorageDirectory().getPath() 107 | + AppConstants.owant_maps + 108 | AppConstants.temp_create_file; 109 | 110 | File file = new File(temp_path); 111 | delete(file); 112 | } 113 | 114 | public String readConf(String zipFilePath) { 115 | String info = readZipFile(zipFilePath, AppConstants.conf); 116 | return info; 117 | } 118 | 119 | public Object readContentObject(String zipFilePath) throws ClassNotFoundException, InvalidClassException { 120 | Object o = null; 121 | o = readZipFileObject(zipFilePath, AppConstants.content); 122 | return o; 123 | } 124 | 125 | private void delete(File file) { 126 | if (file.isFile()) { 127 | file.delete(); 128 | return; 129 | } 130 | if (file.isDirectory()) { 131 | File[] childFiles = file.listFiles(); 132 | if (childFiles == null || childFiles.length == 0) { 133 | file.delete(); 134 | return; 135 | } 136 | for (int i = 0; i < childFiles.length; i++) { 137 | delete(childFiles[i]); 138 | } 139 | file.delete(); 140 | } 141 | } 142 | 143 | private void writeTreeObject(String filePath, Object object) throws IOException { 144 | FileOutputStream fos = new FileOutputStream(filePath); 145 | ObjectOutputStream oos = new ObjectOutputStream(fos); 146 | oos.writeObject(object); 147 | oos.close(); 148 | } 149 | 150 | public TreeModel readTreeObject(String filePath) throws IOException, ClassNotFoundException, InvalidClassException { 151 | TreeModel tree; 152 | FileInputStream fos = new FileInputStream(filePath); 153 | ObjectInputStream ois = new ObjectInputStream(fos); 154 | tree = (TreeModel) ois.readObject(); 155 | return tree; 156 | } 157 | 158 | private void writeFile(String path, String fileContext) throws IOException { 159 | FileOutputStream fos = new FileOutputStream(path); 160 | fos.write(fileContext.getBytes("iso8859-1")); 161 | fos.close(); 162 | } 163 | 164 | private String readFile(String path) throws IOException { 165 | FileInputStream fis = new FileInputStream(path); 166 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 167 | byte[] buf = new byte[1024]; 168 | int len = 0; 169 | while ((len = fis.read(buf)) != -1) { 170 | baos.write(buf, 0, len); 171 | } 172 | fis.close(); 173 | baos.close(); 174 | return baos.toString(); 175 | } 176 | 177 | public boolean hansSDCard() { 178 | return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); 179 | } 180 | 181 | private Object readZipFileObject(String filePath, String fileName) throws ClassNotFoundException, InvalidClassException { 182 | InputStream inputStream = null; 183 | ZipFile zipFile = null; 184 | ObjectInputStream objectInputStream = null; 185 | Object targetObject = null; 186 | try { 187 | File file = new File(filePath); 188 | zipFile = new ZipFile(file); 189 | ZipEntry zipEntry = new ZipEntry(fileName); 190 | inputStream = zipFile.getInputStream(zipEntry); 191 | objectInputStream = new ObjectInputStream(inputStream); 192 | targetObject = objectInputStream.readObject(); 193 | zipFile.close(); 194 | inputStream.close(); 195 | objectInputStream.close(); 196 | } catch (IOException e) { 197 | e.printStackTrace(); 198 | } finally { 199 | if (zipFile != null) { 200 | try { 201 | zipFile.close(); 202 | } catch (IOException e) { 203 | e.printStackTrace(); 204 | } 205 | } 206 | if (inputStream != null) { 207 | try { 208 | inputStream.close(); 209 | } catch (IOException e) { 210 | e.printStackTrace(); 211 | } 212 | } 213 | if (objectInputStream != null) { 214 | try { 215 | objectInputStream.close(); 216 | } catch (IOException e) { 217 | e.printStackTrace(); 218 | } 219 | } 220 | } 221 | return targetObject; 222 | } 223 | 224 | private String readZipFile(String filePath, String fileName) { 225 | StringBuffer buffer = new StringBuffer(); 226 | InputStream inputStream = null; 227 | ZipFile zipFile = null; 228 | try { 229 | File file = new File(filePath); 230 | zipFile = new ZipFile(file); 231 | ZipEntry zipEntry = new ZipEntry(fileName); 232 | inputStream = zipFile.getInputStream(zipEntry); 233 | byte[] bytes = new byte[1024]; 234 | int len; 235 | while ((len = inputStream.read(bytes)) != -1) { 236 | buffer.append(new String(bytes, 0, len)); 237 | } 238 | inputStream.close(); 239 | zipFile.close(); 240 | } catch (IOException e) { 241 | e.printStackTrace(); 242 | } finally { 243 | if (zipFile != null) { 244 | try { 245 | zipFile.close(); 246 | } catch (IOException e) { 247 | e.printStackTrace(); 248 | } 249 | } 250 | if (inputStream != null) { 251 | try { 252 | inputStream.close(); 253 | } catch (IOException e) { 254 | e.printStackTrace(); 255 | } 256 | } 257 | } 258 | return buffer.toString(); 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/file/ZipTool.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.file; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.Enumeration; 9 | import java.util.zip.ZipEntry; 10 | import java.util.zip.ZipFile; 11 | 12 | /** 13 | * Created by owant on 17/03/2017. 14 | */ 15 | 16 | public class ZipTool { 17 | 18 | /** 19 | * 解压到指定目录 20 | */ 21 | public static void unZipFiles(String zipPath, String descDir) throws IOException { 22 | unZipFiles(new File(zipPath), descDir); 23 | } 24 | 25 | /** 26 | * 解压文件到指定目录 27 | */ 28 | public static void unZipFiles(File zipFile, String descDir) throws IOException { 29 | File pathFile = new File(descDir); 30 | if (!pathFile.exists()) { 31 | pathFile.mkdirs(); 32 | } 33 | ZipFile zip = new ZipFile(zipFile); 34 | for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { 35 | ZipEntry entry = (ZipEntry) entries.nextElement(); 36 | String zipEntryName = entry.getName(); 37 | 38 | System.out.println("zipEntryName="+zipEntryName); 39 | 40 | InputStream in = zip.getInputStream(entry); 41 | String outPath = (descDir + zipEntryName).replaceAll("\\*", "/"); 42 | 43 | //判断路径是否存在,不存在则创建文件路径 44 | File file = new File(outPath.substring(0, outPath.lastIndexOf('/'))); 45 | if (!file.exists()) { 46 | file.mkdirs(); 47 | } 48 | //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压 49 | if (new File(outPath).isDirectory()) { 50 | continue; 51 | } 52 | //输出文件路径信息 53 | System.out.println("outPath=" + outPath); 54 | 55 | OutputStream out = new FileOutputStream(outPath); 56 | byte[] buf1 = new byte[1024]; 57 | int len; 58 | while ((len = in.read(buf1)) > 0) { 59 | out.write(buf1, 0, len); 60 | } 61 | in.close(); 62 | out.close(); 63 | } 64 | System.out.println("******************解压完毕********************"); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/line/EaseCubicInterpolator.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.line; 2 | 3 | import android.graphics.PointF; 4 | import android.view.animation.Interpolator; 5 | 6 | /** 7 | * 贝塞尔曲线的加速器 8 | * 网站生成贝斯尔曲线的网站 http://cubic-bezier.com/ 9 | * 讲解网站 http://www.tuicool.com/articles/3yANji 10 | * 11 | * 使用列子:new EaseCubicInterpolator(0.31f, 0.85f,0.77f, 0.14f); 12 | */ 13 | public class EaseCubicInterpolator implements Interpolator { 14 | 15 | private final static int ACCURACY = 4096; 16 | private int mLastI = 0; 17 | private final PointF mControlPoint1 = new PointF(); 18 | private final PointF mControlPoint2 = new PointF(); 19 | 20 | /** 21 | * 设置中间两个控制点.
22 | *

23 | * 在线工具: http://cubic-bezier.com/
24 | * 25 | * @param x1 26 | * @param y1 27 | * @param x2 28 | * @param y2 29 | */ 30 | public EaseCubicInterpolator(float x1, float y1, float x2, float y2) { 31 | mControlPoint1.x = x1; 32 | mControlPoint1.y = y1; 33 | mControlPoint2.x = x2; 34 | mControlPoint2.y = y2; 35 | } 36 | 37 | @Override 38 | public float getInterpolation(float input) { 39 | float t = input; 40 | 41 | // 近似求解t的值[0,1] 42 | for (int i = mLastI; i < ACCURACY; i++) { 43 | t = 1.0f * i / ACCURACY; 44 | double x = cubicCurves(t, 0, mControlPoint1.x, mControlPoint2.x, 1); 45 | if (x >= input) { 46 | mLastI = i; 47 | break; 48 | } 49 | } 50 | 51 | double value = cubicCurves(t, 0, mControlPoint1.y, mControlPoint2.y, 1); 52 | if (value > 0.999d) { 53 | value = 1; 54 | mLastI = 0; 55 | } 56 | return (float) value; 57 | } 58 | 59 | /** 60 | * 求三次贝塞尔曲线(四个控制点)一个点某个维度的值.
61 | *

62 | * 参考资料: http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/ 63 | * 64 | * @param t 取值[0, 1] 65 | * @param value0 66 | * @param value1 67 | * @param value2 68 | * @param value3 69 | * @return 70 | */ 71 | 72 | public static double cubicCurves(double t, double value0, double value1, 73 | double value2, double value3) { 74 | double value; 75 | double u = 1 - t; 76 | double tt = t * t; 77 | double uu = u * u; 78 | double uuu = uu * u; 79 | double ttt = tt * t; 80 | value = uuu * value0; 81 | value += 3 * uu * t * value1; 82 | value += 3 * u * tt * value2; 83 | value += ttt * value3; 84 | 85 | return value; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/line/ReboundInterpolator.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.line; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.animation.Interpolator; 6 | 7 | public class ReboundInterpolator implements Interpolator { 8 | /** 9 | * Value at which the interpolation changes from decelerate to bounce 10 | */ 11 | private static final float UNION = 0.2f; 12 | 13 | public ReboundInterpolator() { 14 | } 15 | 16 | public ReboundInterpolator(Context context, AttributeSet attrs) { 17 | } 18 | 19 | @Override 20 | public float getInterpolation(float input) { 21 | if (input < UNION) { 22 | // Decelerate interpolator 23 | float value = mapRange(input, 0f, UNION, 0f, 1f); 24 | return getDecelerateInterpolation(value); 25 | } else { 26 | // Bounce interpolator 27 | float value = mapRange(input, UNION, 1f, 0f, 1f); 28 | return 1f - getBounceInterpolation(value); 29 | } 30 | } 31 | 32 | /** 33 | * @param input Input value 34 | * @return Output value 35 | * @see {@link android.view.animation.DecelerateInterpolator} 36 | */ 37 | private float getDecelerateInterpolation(float input) { 38 | return 1.0f - (1.0f - input) * (1.0f - input); 39 | } 40 | 41 | /** 42 | * @param t Input value 43 | * @return Output value 44 | * @see {@link android.view.animation.BounceInterpolator} 45 | */ 46 | private float getBounceInterpolation(float t) { 47 | // Change for the interpolation ends in 1.0 48 | if (t == 1f) return 1f; 49 | // _b(t) = t * t * 8 50 | // bs(t) = _b(t) for t < 0.3535 51 | // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408 52 | // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644 53 | // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0 54 | // b(t) = bs(t * 1.1226) 55 | t *= 1.1226f; 56 | if (t < 0.3535f) return bounce(t); 57 | else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f; 58 | else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f; 59 | else return bounce(t - 1.0435f) + 0.95f; 60 | } 61 | 62 | private static float bounce(float t) { 63 | return t * t * 8.0f; 64 | } 65 | 66 | /** 67 | * Maps value which is in the range fromLow and fromHigh to it's corresponding value in the range toLow, toHigh 68 | * 69 | * @param value Input value to convert 70 | * @param fromLow Lowest value in the range of input value 71 | * @param fromHigh Highest value in the range of input value 72 | * @param toLow Lowest value in the range of output value 73 | * @param toHigh Highest value in the range of output value 74 | * @return Output value converted to the range 75 | * @see Tylos / Map Range 76 | */ 77 | private static float mapRange(float value, float fromLow, float fromHigh, float toLow, float toHigh) { 78 | return toLow + (((value - fromLow) / (fromHigh - fromLow)) * (toHigh - toLow)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/manager/ThreadPoolManager.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.manager; 2 | 3 | import java.util.concurrent.Executors; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | 6 | /** 7 | * Created by owant on 17/03/2017. 8 | */ 9 | 10 | public class ThreadPoolManager { 11 | 12 | private ThreadPoolExecutor mPoolExecutor; 13 | private final static int default_thread_size = 4; 14 | 15 | private static class ThreadPoolManagerHolder { 16 | private static ThreadPoolManager instance = new ThreadPoolManager(); 17 | } 18 | 19 | private ThreadPoolManager() { 20 | mPoolExecutor = (ThreadPoolExecutor) Executors 21 | .newFixedThreadPool(getBestThreadSize()); 22 | } 23 | 24 | private int getBestThreadSize() { 25 | return default_thread_size; 26 | } 27 | 28 | public static ThreadPoolManager getInstance() { 29 | return ThreadPoolManagerHolder.instance; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/model/CurrentFileModel.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.model; 2 | 3 | /** 4 | * Created by owant on 27/02/2017. 5 | */ 6 | 7 | public class CurrentFileModel { 8 | //文件名字 9 | public String fileName; 10 | //修改时间 11 | public String editTime; 12 | //文件路径 13 | public String filePath; 14 | //图片跟节点 15 | public String mapRoot; 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/model/ForTreeItem.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by owant on 09/03/2017. 7 | */ 8 | 9 | public interface ForTreeItem> extends Serializable{ 10 | void next(int msg, T next); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/model/NodeModel.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.LinkedList; 5 | 6 | /** 7 | * Created by owant on 09/02/2017. 8 | */ 9 | public class NodeModel implements Serializable { 10 | 11 | 12 | /** 13 | * the parent node,if root node parent node=null; 14 | */ 15 | public NodeModel parentNode; 16 | 17 | /** 18 | * the data value 19 | */ 20 | public T value; 21 | 22 | /** 23 | * have the child nodes 24 | */ 25 | public LinkedList> childNodes; 26 | 27 | /** 28 | * focus tag for the tree add nodes 29 | */ 30 | public transient boolean focus = false; 31 | 32 | /** 33 | * index of the tree floor 34 | */ 35 | public int floor; 36 | 37 | public boolean hidden = false; 38 | 39 | public NodeModel(T value) { 40 | this.value = value; 41 | this.childNodes = new LinkedList<>(); 42 | 43 | this.focus = false; 44 | this.parentNode = null; 45 | } 46 | 47 | public NodeModel getParentNode() { 48 | return parentNode; 49 | } 50 | 51 | public void setParentNode(NodeModel parentNode) { 52 | this.parentNode = parentNode; 53 | } 54 | 55 | public T getValue() { 56 | return value; 57 | } 58 | 59 | public void setValue(T value) { 60 | this.value = value; 61 | } 62 | 63 | public LinkedList> getChildNodes() { 64 | return childNodes; 65 | } 66 | 67 | public void setChildNodes(LinkedList> childNodes) { 68 | this.childNodes = childNodes; 69 | } 70 | 71 | public boolean isFocus() { 72 | return focus; 73 | } 74 | 75 | public void setFocus(boolean focus) { 76 | this.focus = focus; 77 | } 78 | 79 | public int getFloor() { 80 | return floor; 81 | } 82 | 83 | public void setFloor(int floor) { 84 | this.floor = floor; 85 | } 86 | 87 | public boolean isHidden() { 88 | return hidden; 89 | } 90 | 91 | public void setHidden(boolean hidden) { 92 | this.hidden = hidden; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/model/TreeModel.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.model; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.ObjectInputStream; 7 | import java.io.ObjectOutputStream; 8 | import java.io.Serializable; 9 | import java.util.ArrayDeque; 10 | import java.util.ArrayList; 11 | import java.util.Deque; 12 | import java.util.LinkedList; 13 | import java.util.Stack; 14 | 15 | /** 16 | * Created by owant on 09/02/2017. 17 | */ 18 | public class TreeModel implements Serializable { 19 | 20 | /** 21 | * the root for the tree 22 | */ 23 | private NodeModel rootNode; 24 | 25 | /** 26 | * 模型里的接口是不用序列号的 27 | */ 28 | 29 | private transient ForTreeItem> mForTreeItem; 30 | 31 | public TreeModel(NodeModel rootNode) { 32 | this.rootNode = rootNode; 33 | } 34 | 35 | /** 36 | * add the node in some father node 37 | * 38 | * @param start 39 | * @param nodes 40 | */ 41 | public void addNode(NodeModel start, NodeModel... nodes) { 42 | int index = 1; 43 | NodeModel temp = start; 44 | if (temp.getParentNode() != null) { 45 | index = temp.getParentNode().floor; 46 | } 47 | 48 | LinkedList> childNodes = temp.getChildNodes(); 49 | 50 | for (NodeModel t : nodes) { 51 | t.setParentNode(start); 52 | t.setFloor(index); 53 | 54 | //校验是否存在 55 | boolean exist = false; 56 | for (NodeModel hash : childNodes) { 57 | if (hash == t) { 58 | exist = true; 59 | continue; 60 | } 61 | } 62 | if (!exist) 63 | start.getChildNodes().add(t); 64 | } 65 | } 66 | 67 | public boolean removeNode(NodeModel starNode, NodeModel deleteNote) { 68 | boolean rm = false; 69 | int size = starNode.getChildNodes().size(); 70 | if (size > 0) { 71 | rm = starNode.getChildNodes().remove(deleteNote); 72 | } 73 | return rm; 74 | } 75 | 76 | public boolean inTree(NodeModel starNode, NodeModel deleteNote) { 77 | boolean in = false; 78 | Deque> queue = new ArrayDeque<>(); 79 | NodeModel rootNode = starNode; 80 | queue.add(rootNode); 81 | 82 | while (!queue.isEmpty()) { 83 | rootNode = (NodeModel) queue.poll(); 84 | if (rootNode == deleteNote) { 85 | in = true; 86 | } 87 | 88 | LinkedList> childNodes = rootNode.getChildNodes(); 89 | if (childNodes.size() > 0) { 90 | for (NodeModel item : childNodes) { 91 | queue.add(item); 92 | } 93 | } 94 | } 95 | return in; 96 | } 97 | 98 | public NodeModel getRootNode() { 99 | return rootNode; 100 | } 101 | 102 | public void setRootNode(NodeModel rootNode) { 103 | this.rootNode = rootNode; 104 | } 105 | 106 | /** 107 | * 同一个父节点的上下 108 | * 109 | * @param midPreNode 110 | * @return 111 | */ 112 | private NodeModel getLowNode(NodeModel midPreNode) { 113 | NodeModel find = null; 114 | NodeModel parentNode = midPreNode.getParentNode(); 115 | 116 | if (parentNode != null && parentNode.getChildNodes().size() >= 2) { 117 | Deque> queue = new ArrayDeque<>(); 118 | NodeModel rootNode = parentNode; 119 | queue.add(rootNode); 120 | boolean up = false; 121 | while (!queue.isEmpty()) { 122 | 123 | rootNode = (NodeModel) queue.poll(); 124 | if (up) { 125 | if (rootNode.getFloor() == midPreNode.getFloor()) { 126 | find = rootNode; 127 | } 128 | break; 129 | } 130 | 131 | //到了该元素 132 | if (rootNode == midPreNode) up = true; 133 | LinkedList> childNodes = rootNode.getChildNodes(); 134 | if (childNodes.size() > 0) { 135 | for (NodeModel item : childNodes) { 136 | queue.add(item); 137 | } 138 | } 139 | } 140 | } 141 | return find; 142 | } 143 | 144 | private NodeModel getPreNode(NodeModel midPreNode) { 145 | 146 | NodeModel parentNode = midPreNode.getParentNode(); 147 | NodeModel find = null; 148 | 149 | if (parentNode != null && parentNode.getChildNodes().size() > 0) { 150 | 151 | Deque> queue = new ArrayDeque<>(); 152 | NodeModel rootNode = parentNode; 153 | queue.add(rootNode); 154 | 155 | while (!queue.isEmpty()) { 156 | rootNode = (NodeModel) queue.poll(); 157 | //到了该元素 158 | if (rootNode == midPreNode) { 159 | //返回之前的值 160 | break; 161 | } 162 | 163 | find = rootNode; 164 | LinkedList> childNodes = rootNode.getChildNodes(); 165 | if (childNodes.size() > 0) { 166 | for (NodeModel item : childNodes) { 167 | queue.add(item); 168 | } 169 | } 170 | } 171 | 172 | if (find != null && find.getFloor() != midPreNode.getFloor()) { 173 | find = null; 174 | } 175 | } 176 | return find; 177 | } 178 | 179 | public ArrayList> getAllLowNodes(NodeModel addNode) { 180 | ArrayList> array = new ArrayList<>(); 181 | NodeModel parentNode = addNode.getParentNode(); 182 | while (parentNode != null) { 183 | NodeModel lowNode = getLowNode(parentNode); 184 | while (lowNode != null) { 185 | array.add(lowNode); 186 | lowNode = getLowNode(lowNode); 187 | } 188 | parentNode = parentNode.getParentNode(); 189 | } 190 | return array; 191 | } 192 | 193 | public ArrayList> getAllPreNodes(NodeModel addNode) { 194 | ArrayList> array = new ArrayList<>(); 195 | NodeModel parentNode = addNode.getParentNode(); 196 | while (parentNode != null) { 197 | NodeModel lowNode = getPreNode(parentNode); 198 | while (lowNode != null) { 199 | array.add(lowNode); 200 | lowNode = getPreNode(lowNode); 201 | } 202 | parentNode = parentNode.getParentNode(); 203 | } 204 | return array; 205 | } 206 | 207 | public LinkedList> getNodeChildNodes(NodeModel node) { 208 | return node.getChildNodes(); 209 | } 210 | 211 | public void ergodicTreeInDeep(int msg) { 212 | Stack> stack = new Stack<>(); 213 | NodeModel rootNode = getRootNode(); 214 | stack.add(rootNode); 215 | while (!stack.isEmpty()) { 216 | NodeModel pop = stack.pop(); 217 | if (mForTreeItem != null) { 218 | mForTreeItem.next(msg, pop); 219 | } 220 | LinkedList> childNodes = pop.getChildNodes(); 221 | for (NodeModel item : childNodes) { 222 | stack.add(item); 223 | } 224 | } 225 | } 226 | 227 | public void ergodicTreeInWith(int msg) { 228 | Deque> queue = new ArrayDeque<>(); 229 | NodeModel rootNode = getRootNode(); 230 | queue.add(rootNode); 231 | while (!queue.isEmpty()) { 232 | rootNode = (NodeModel) queue.poll(); 233 | if (mForTreeItem != null) { 234 | mForTreeItem.next(msg, rootNode); 235 | } 236 | LinkedList> childNodes = rootNode.getChildNodes(); 237 | if (childNodes.size() > 0) { 238 | for (NodeModel item : childNodes) { 239 | queue.add(item); 240 | } 241 | } 242 | } 243 | } 244 | 245 | public void addForTreeItem(ForTreeItem> forTreeItem) { 246 | this.mForTreeItem = forTreeItem; 247 | } 248 | 249 | public Object deepClone() throws IOException, ClassNotFoundException { 250 | ByteArrayOutputStream bo=new ByteArrayOutputStream(); 251 | ObjectOutputStream oo=new ObjectOutputStream(bo); 252 | oo.writeObject(this); 253 | 254 | ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 255 | ObjectInputStream oi=new ObjectInputStream(bi); 256 | return(oi.readObject()); 257 | } 258 | 259 | 260 | 261 | } 262 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/net/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.net; 2 | 3 | /** 4 | * Created by owant on 17/03/2017. 5 | */ 6 | 7 | public class BaseResponse { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/test/ExampleCreator.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.test; 2 | 3 | import com.owant.thinkmap.file.Conf; 4 | import com.owant.thinkmap.file.OwantFileCreate; 5 | import com.owant.thinkmap.model.NodeModel; 6 | import com.owant.thinkmap.model.TreeModel; 7 | import com.owant.thinkmap.util.AndroidUtil; 8 | 9 | import java.text.SimpleDateFormat; 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | import java.util.Locale; 13 | 14 | /** 15 | * Created by owant on 31/03/2017. 16 | */ 17 | 18 | public class ExampleCreator { 19 | 20 | public static void main(String[] args) { 21 | 22 | } 23 | 24 | 25 | public static String format = "NodeModel node{0} = new NodeModel<>(\"{0}\");"; 26 | 27 | public static void createTreeNodes() { 28 | for (char i = 'A'; i < 'Z'; i++) { 29 | String value = format; 30 | value = value.replace("{0}", i + ""); 31 | System.out.println(value); 32 | } 33 | } 34 | 35 | public static void createExampleMapVersion() { 36 | 37 | NodeModel root = new NodeModel<>("ThinkMap版本情况"); 38 | TreeModel treeModel = new TreeModel<>(root); 39 | 40 | NodeModel version1 = new NodeModel<>("V1.0.1"); 41 | NodeModel version2 = new NodeModel<>("V1.0.2"); 42 | NodeModel version3 = new NodeModel<>("V1.0.3"); 43 | NodeModel version4 = new NodeModel<>("V1.0.4"); 44 | 45 | treeModel.addNode(root, version1, version2, version3, version4); 46 | 47 | //版本1的情况 48 | NodeModel v1_draw_tree = new NodeModel<>("绘制树形结构"); 49 | NodeModel v1_add_child_note = new NodeModel<>("添加子节点"); 50 | NodeModel v1_add_node = new NodeModel<>("添加同层节点"); 51 | NodeModel v1_front = new NodeModel<>("对焦中心"); 52 | NodeModel v1_map_move = new NodeModel<>("视图移动"); 53 | NodeModel v1_open_owant_file = new NodeModel<>("打开.owant文件"); 54 | 55 | treeModel.addNode(version1, v1_draw_tree, v1_add_child_note, 56 | v1_add_node, v1_front, v1_map_move, v1_open_owant_file); 57 | 58 | //版本2情况 59 | NodeModel v2_fixed_location = new NodeModel<>("Fixed位置错误"); 60 | NodeModel v2_add_handle = new NodeModel<>("添加了缩放手势"); 61 | NodeModel v2_tree_manager = new NodeModel<>("抽取TreeLayoutManger\n提供更多的Style可能"); 62 | NodeModel v2_fixed_click = new NodeModel<>("Fixed长按和点击问题"); 63 | NodeModel v2_add_example = new NodeModel<>("添加演示例子"); 64 | 65 | treeModel.addNode(version2, v2_fixed_location, v2_add_handle, v2_tree_manager, 66 | v2_tree_manager, v2_fixed_click, v2_add_example); 67 | 68 | //版本3情况 69 | NodeModel v3_android4 = new NodeModel<>("Fixed Android4.0出现BUG"); 70 | NodeModel v3_splash = new NodeModel<>("添加欢迎界面"); 71 | NodeModel v3_permission = new NodeModel<>("修复动态权限申请问题"); 72 | NodeModel v3_review = new NodeModel<>("ReView优化"); 73 | 74 | treeModel.addNode(version3, v3_android4, v3_splash, v3_permission, v3_review); 75 | 76 | 77 | //版本4情況 78 | NodeModel v4_fixed_scale_light = new NodeModel<>("Fixed 缩放出现抖动"); 79 | NodeModel v4_review = new NodeModel<>("ReView优化,Github上\n建立release分支"); 80 | treeModel.addNode(version4, v4_fixed_scale_light, v4_review); 81 | 82 | 83 | //穿件owant文件 84 | OwantFileCreate owantFileCreate = new OwantFileCreate(); 85 | 86 | //创建文件夹 87 | owantFileCreate.createOwantMapsDirectory(); 88 | //删除临时文件 89 | owantFileCreate.createTempDirectory(); 90 | //写入内容 91 | owantFileCreate.writeContent(treeModel); 92 | 93 | Conf conf = new Conf(); 94 | Date time = Calendar.getInstance().getTime(); 95 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); 96 | conf.date = simpleDateFormat.format(time); 97 | conf.app_version = "v1.0.4"; 98 | conf.android_version = AndroidUtil.getAndroidSystemVersion(); 99 | conf.map_name = treeModel.getRootNode().getValue(); 100 | 101 | //写入配置 102 | owantFileCreate.writeConf(conf); 103 | //创建压缩包 104 | owantFileCreate.makeOwantFile("演示-App版本情况"); 105 | //删除临时文件 106 | owantFileCreate.deleteTemp(); 107 | } 108 | 109 | public static void createExampleHowToUse() { 110 | 111 | NodeModel root = new NodeModel<>("ThinkMap使用教程"); 112 | TreeModel treeModel = new TreeModel<>(root); 113 | 114 | NodeModel subNode = new NodeModel<>("SubNode"); 115 | NodeModel node = new NodeModel<>("Node"); 116 | NodeModel frontView = new NodeModel<>("FrontView"); 117 | NodeModel codeMode = new NodeModel<>("CodeMode"); 118 | 119 | treeModel.addNode(root, subNode, node, frontView, codeMode); 120 | 121 | NodeModel subNode1 = new NodeModel<>("添加子节点"); 122 | NodeModel node1 = new NodeModel<>("添加同层节点"); 123 | NodeModel frontView1 = new NodeModel<>("对焦中心"); 124 | NodeModel codeMode1 = new NodeModel<>("编码模式"); 125 | 126 | treeModel.addNode(subNode, subNode1); 127 | treeModel.addNode(node, node1); 128 | treeModel.addNode(frontView, frontView1); 129 | treeModel.addNode(codeMode, codeMode1); 130 | 131 | //穿件owant文件 132 | OwantFileCreate owantFileCreate = new OwantFileCreate(); 133 | owantFileCreate.createOwantMapsDirectory(); 134 | owantFileCreate.createTempDirectory(); 135 | owantFileCreate.writeContent(treeModel); 136 | 137 | Conf conf = new Conf(); 138 | Date time = Calendar.getInstance().getTime(); 139 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); 140 | conf.date = simpleDateFormat.format(time); 141 | conf.app_version = "v1.0.3"; 142 | conf.android_version = AndroidUtil.getAndroidSystemVersion(); 143 | conf.map_name = treeModel.getRootNode().getValue(); 144 | owantFileCreate.writeConf(conf); 145 | owantFileCreate.makeOwantFile("演示-使用教程"); 146 | owantFileCreate.deleteTemp(); 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/EditAlertDialog.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.StyleRes; 6 | import android.text.Editable; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.view.animation.Animation; 10 | import android.view.animation.CycleInterpolator; 11 | import android.view.animation.TranslateAnimation; 12 | import android.widget.Button; 13 | import android.widget.EditText; 14 | import android.widget.ImageView; 15 | import android.widget.RelativeLayout; 16 | import android.widget.TextView; 17 | 18 | import com.owant.thinkmap.AppConstants; 19 | import com.owant.thinkmap.R; 20 | import com.owant.thinkmap.base.BaseAlertDialog; 21 | import com.owant.thinkmap.model.NodeModel; 22 | import com.owant.thinkmap.util.AndroidUtil; 23 | import com.owant.thinkmap.util.LOG; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * Created by owant on 24/02/2017. 29 | */ 30 | public class EditAlertDialog extends BaseAlertDialog { 31 | 32 | private TextView dialog_edit_tv_title; 33 | private EditText dialog_edit_et_input; 34 | private Button dialog_btn_enter; 35 | private Button dialog_btn_delete; 36 | private ImageView dialog_edit_iv_input_clear; 37 | private TextView dialog_edit_tv_had_same_file; 38 | private RelativeLayout dialog_edit_check_state; 39 | 40 | private String conditonDeleteTextValue; 41 | private String conditonEnterTextValue; 42 | 43 | private EnterCallBack enterCallBack; 44 | private DeleteCallBack deleteCallBack; 45 | 46 | private NodeModel nodeModel; 47 | private List checkLists; 48 | 49 | 50 | public EditAlertDialog(@NonNull Context context) { 51 | this(context, 0); 52 | } 53 | 54 | public EditAlertDialog(@NonNull Context context, @StyleRes int themeResId) { 55 | super(context, R.style.DivDialog); 56 | } 57 | 58 | @Override 59 | protected void onBaseBindView() { 60 | dialog_edit_tv_title = (TextView) findViewById(R.id.dialog_edit_tv_title); 61 | dialog_edit_et_input = (EditText) findViewById(R.id.dialog_edit_et_input); 62 | dialog_btn_enter = (Button) findViewById(R.id.dialog_btn_enter); 63 | dialog_btn_delete = (Button) findViewById(R.id.dialog_btn_delete); 64 | dialog_edit_iv_input_clear = (ImageView) findViewById(R.id.dialog_edit_iv_input_clear); 65 | dialog_edit_check_state = (RelativeLayout) findViewById(R.id.dialog_edit_check_state); 66 | dialog_edit_tv_had_same_file = (TextView) findViewById(R.id.dialog_edit_tv_had_same_file); 67 | 68 | if (dialog_btn_enter != null) { 69 | dialog_btn_enter.setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View v) { 72 | if (enterCallBack != null) { 73 | String value = getInput().toString() + ""; 74 | //同名文件提示更改 75 | if (checkLists != null) { 76 | if (AppConstants.CONFIG_DEBUG) { 77 | for (String str : checkLists) { 78 | LOG.jLogi("list=%s", str); 79 | } 80 | } 81 | 82 | LOG.jLogi("value=%s", value); 83 | if (checkLists.contains(value)) { 84 | dialog_edit_tv_had_same_file.setVisibility(View.VISIBLE); 85 | dialog_edit_tv_had_same_file.setText(getContext(). 86 | getResources().getString(R.string.same_name_file)); 87 | Animation shake = new TranslateAnimation(0, 10, 0, 0); 88 | shake.setDuration(1000); 89 | //重三次 90 | shake.setInterpolator(new CycleInterpolator(7)); 91 | dialog_edit_check_state.startAnimation(shake); 92 | return; 93 | 94 | } else if (TextUtils.isEmpty(value)) { 95 | dialog_edit_tv_had_same_file.setVisibility(View.VISIBLE); 96 | dialog_edit_tv_had_same_file.setText(getContext(). 97 | getResources().getString(R.string.file_name_empty)); 98 | 99 | Animation shake = new TranslateAnimation(0, 10, 0, 0); 100 | shake.setDuration(1000); 101 | //重三次 102 | shake.setInterpolator(new CycleInterpolator(7)); 103 | dialog_edit_check_state.startAnimation(shake); 104 | return; 105 | } else { 106 | dialog_edit_tv_had_same_file.setVisibility(View.INVISIBLE); 107 | } 108 | } 109 | 110 | 111 | enterCallBack.onEdit(value); 112 | AndroidUtil.hideKeyboard(getContext(), dialog_edit_et_input); 113 | } 114 | } 115 | }); 116 | } 117 | 118 | if (dialog_edit_iv_input_clear != null) { 119 | dialog_edit_iv_input_clear.setOnClickListener(new View.OnClickListener() { 120 | @Override 121 | public void onClick(View v) { 122 | setInput(""); 123 | } 124 | }); 125 | } 126 | 127 | if (dialog_btn_delete != null) { 128 | dialog_btn_delete.setOnClickListener(new View.OnClickListener() { 129 | @Override 130 | public void onClick(View v) { 131 | if (deleteCallBack != null) { 132 | 133 | if (dialog_edit_tv_title.getText() == EditAlertDialog.this.getContext() 134 | .getResources().getString(R.string.save_file)) { 135 | deleteCallBack.onDelete(); 136 | 137 | } else if (nodeModel != null) { 138 | //根节点不能进行删除 139 | NodeModel parentNode = nodeModel.getParentNode(); 140 | if (parentNode != null) { 141 | deleteCallBack.onDeleteModel(nodeModel); 142 | } 143 | } 144 | 145 | } 146 | dismiss(); 147 | AndroidUtil.hideKeyboard(getContext(), dialog_edit_et_input); 148 | } 149 | }); 150 | } 151 | } 152 | 153 | public void setDivTitle(String title) { 154 | dialog_edit_tv_title.setText(title); 155 | } 156 | 157 | private Editable getInput() { 158 | return dialog_edit_et_input.getText(); 159 | } 160 | 161 | public void setInput(String value) { 162 | if (dialog_edit_et_input != null) { 163 | dialog_edit_et_input.setText(value); 164 | } 165 | } 166 | 167 | public void setConditionEnterTextValue(String conditionEnterTextValue) { 168 | this.conditonEnterTextValue = conditionEnterTextValue; 169 | if (dialog_btn_enter != null) { 170 | dialog_btn_enter.setText(conditionEnterTextValue); 171 | } 172 | } 173 | 174 | public void setConditionDeleteTextValue(String conditionDeleteTextValue) { 175 | this.conditonDeleteTextValue = conditionDeleteTextValue; 176 | if (dialog_btn_delete != null) { 177 | dialog_btn_delete.setText(conditionDeleteTextValue); 178 | } 179 | } 180 | 181 | public void setCheckLists(List checkLists) { 182 | this.checkLists = checkLists; 183 | } 184 | 185 | public void setNodeModel(NodeModel nodeModel) { 186 | this.nodeModel = nodeModel; 187 | if (nodeModel.getParentNode() == null) { 188 | if (dialog_btn_delete != null) { 189 | dialog_btn_delete.setEnabled(false); 190 | } 191 | } else { 192 | if (dialog_btn_delete != null) { 193 | dialog_btn_delete.setEnabled(true); 194 | } 195 | } 196 | } 197 | 198 | public void addEnterCallBack(EnterCallBack callBack) { 199 | this.enterCallBack = callBack; 200 | } 201 | 202 | public void addDeleteCallBack(DeleteCallBack callBack) { 203 | deleteCallBack = callBack; 204 | } 205 | 206 | public void clearInput() { 207 | setInput(""); 208 | } 209 | 210 | public interface EnterCallBack { 211 | void onEdit(String value); 212 | } 213 | 214 | public interface DeleteCallBack { 215 | void onDeleteModel(NodeModel nodeModel); 216 | 217 | void onDelete(); 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.PackageManager; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.annotation.RequiresApi; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.widget.Toast; 13 | 14 | import com.owant.thinkmap.AppPermissions; 15 | import com.owant.thinkmap.R; 16 | import com.owant.thinkmap.base.BaseActivity; 17 | import com.owant.thinkmap.ui.workspace.WorkSpaceActivity; 18 | import com.owant.thinkmap.util.AndroidUtil; 19 | 20 | public class SplashActivity extends BaseActivity { 21 | 22 | @Override 23 | protected void onBaseIntent() { 24 | 25 | } 26 | 27 | @Override 28 | protected void onBasePreLayout() { 29 | 30 | } 31 | 32 | @Override 33 | protected int onBaseLayoutId(@Nullable Bundle savedInstanceState) { 34 | return R.layout.activity_splash; 35 | } 36 | 37 | @Override 38 | protected void onBaseBindView() { 39 | 40 | if (AndroidUtil.isMPermission()) { 41 | if (ContextCompat.checkSelfPermission(SplashActivity.this, 42 | AppPermissions.permission_storage[0]) != PackageManager.PERMISSION_GRANTED || 43 | ContextCompat.checkSelfPermission(SplashActivity.this, 44 | AppPermissions.permission_storage[1]) != PackageManager.PERMISSION_GRANTED) { 45 | 46 | requestStoragePermission(); 47 | 48 | } else { 49 | intentToWorkSpace(); 50 | } 51 | 52 | } else { 53 | 54 | intentToWorkSpace(); 55 | } 56 | 57 | } 58 | 59 | private void intentToWorkSpace() { 60 | new Thread(new Runnable() { 61 | 62 | @Override 63 | public void run() { 64 | try { 65 | Thread.sleep(1200); 66 | Intent intent = new Intent(SplashActivity.this, WorkSpaceActivity.class); 67 | startActivity(intent); 68 | SplashActivity.this.finish(); 69 | 70 | } catch (InterruptedException e) { 71 | e.printStackTrace(); 72 | } 73 | } 74 | }).start(); 75 | } 76 | 77 | @Override 78 | protected void onLoadData() { 79 | 80 | } 81 | 82 | /** 83 | * 请求内存卡权限 84 | */ 85 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) 86 | private void requestStoragePermission() { 87 | ActivityCompat.requestPermissions(SplashActivity.this 88 | , AppPermissions.permission_storage, 89 | AppPermissions.request_permission_storage); 90 | } 91 | 92 | @Override 93 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 94 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 95 | if (requestCode == AppPermissions.request_permission_storage) { 96 | if (AndroidUtil.verifyPermissions(grantResults)) { 97 | intentToWorkSpace(); 98 | } else { 99 | Toast.makeText(this, "the permission denied!", Toast.LENGTH_SHORT).show(); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/about/AboutUsActivity.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.about; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.MenuItem; 6 | 7 | import com.owant.thinkmap.R; 8 | import com.owant.thinkmap.base.BaseActivity; 9 | 10 | /** 11 | * Created by owant on 30/03/2017. 12 | */ 13 | 14 | public class AboutUsActivity extends BaseActivity { 15 | 16 | @Override 17 | protected void onBaseIntent() { 18 | 19 | } 20 | 21 | @Override 22 | protected void onBasePreLayout() { 23 | 24 | } 25 | 26 | @Override 27 | protected int onBaseLayoutId(@Nullable Bundle savedInstanceState) { 28 | return R.layout.activity_about_us; 29 | } 30 | 31 | @Override 32 | protected void onBaseBindView() { 33 | getSupportActionBar().setTitle(R.string.about); 34 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 35 | } 36 | 37 | @Override 38 | protected void onLoadData() { 39 | 40 | } 41 | 42 | @Override 43 | public boolean onOptionsItemSelected(MenuItem item) { 44 | int itemId = item.getItemId(); 45 | switch (itemId) { 46 | case android.R.id.home: 47 | finish(); 48 | break; 49 | } 50 | return super.onOptionsItemSelected(item); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/codemode/CodeModeActivity.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.codemode; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.owant.thinkmap.R; 7 | import com.owant.thinkmap.base.BaseActivity; 8 | 9 | /** 10 | * Created by owant on 14/03/2017. 11 | */ 12 | 13 | public class CodeModeActivity extends BaseActivity { 14 | 15 | @Override 16 | protected void onBaseIntent() { 17 | 18 | } 19 | 20 | @Override 21 | protected void onBasePreLayout() { 22 | 23 | } 24 | 25 | @Override 26 | protected int onBaseLayoutId(@Nullable Bundle savedInstanceState) { 27 | return R.layout.activity_code_model; 28 | } 29 | 30 | @Override 31 | protected void onBaseBindView() { 32 | 33 | } 34 | 35 | @Override 36 | protected void onLoadData() { 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/editmap/EditMapContract.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.editmap; 2 | 3 | import com.owant.thinkmap.base.BasePresenter; 4 | import com.owant.thinkmap.base.BaseView; 5 | import com.owant.thinkmap.model.NodeModel; 6 | import com.owant.thinkmap.model.TreeModel; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Created by owant on 21/03/2017. 12 | */ 13 | 14 | public interface EditMapContract { 15 | 16 | interface Presenter extends BasePresenter { 17 | 18 | /** 19 | * 设置读取的文件路径 20 | */ 21 | void setLoadMapPath(String path); 22 | 23 | /** 24 | * 刷新文件路径下的owant文件集合 25 | */ 26 | void refreshOwantFilesLists(); 27 | 28 | /** 29 | * 读取owant文件 30 | */ 31 | void readOwantFile(); 32 | 33 | /** 34 | * 创建默认的TreeModel 35 | */ 36 | void createDefaultTreeModel(); 37 | 38 | /** 39 | * 添加节点 40 | */ 41 | void addNote(); 42 | 43 | /** 44 | * 添加子节点 45 | */ 46 | void addSubNote(); 47 | 48 | /** 49 | * 编辑节点 50 | */ 51 | void editNote(); 52 | 53 | /** 54 | * 对焦中心 55 | */ 56 | void focusMid(); 57 | 58 | /** 59 | * 保存文件 60 | */ 61 | void saveFile(); 62 | 63 | /** 64 | * 进行保存 65 | */ 66 | void doSaveFile(String fileName); 67 | 68 | /** 69 | * 设置树形模型 70 | * 71 | * @param treeModel 72 | */ 73 | void setTreeModel(TreeModel treeModel); 74 | 75 | /** 76 | * 获取树形模型 77 | * 78 | * @return 树形模型 79 | */ 80 | TreeModel getTreeModel(); 81 | 82 | /** 83 | * 获取文件目录下的owant文件集合 84 | * 85 | * @return owant文件集合 86 | */ 87 | List getOwantLists(); 88 | 89 | String getSaveInput(); 90 | } 91 | 92 | interface View extends BaseView { 93 | 94 | /** 95 | * 显示加载文件 96 | */ 97 | void showLoadingFile(); 98 | 99 | /** 100 | * 设置树形结构数据 101 | * 102 | * @param treeModel 103 | */ 104 | void setTreeViewData(TreeModel treeModel); 105 | 106 | /** 107 | * 隐藏加载数据 108 | */ 109 | void hideLoadingFile(); 110 | 111 | /** 112 | * 显示添加节点 113 | */ 114 | void showAddNoteDialog(); 115 | 116 | /** 117 | * 显示添加子节点 118 | */ 119 | void showAddSubNoteDialog(); 120 | 121 | /** 122 | * 显示编辑节点 123 | */ 124 | void showEditNoteDialog(); 125 | 126 | /** 127 | * 显示保存数据 128 | * 129 | * @param fileName 130 | */ 131 | void showSaveFileDialog(String fileName); 132 | 133 | /** 134 | * 对焦中心 135 | */ 136 | void focusingMid(); 137 | 138 | /** 139 | * 获得默认root节点的text 140 | * 141 | * @return 142 | */ 143 | String getDefaultPlanStr(); 144 | 145 | /** 146 | * 获得最近对焦 147 | * 148 | * @return 149 | */ 150 | NodeModel getCurrentFocusNode(); 151 | 152 | /** 153 | * 获取Plan的默认字符 154 | * 155 | * @return My Plan 156 | */ 157 | String getDefaultSaveFilePath(); 158 | 159 | /** 160 | * 获得app的版本 161 | * 162 | * @return 版本号 163 | */ 164 | String getAppVersion(); 165 | 166 | void finishActivity(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/editmap/EditMapPresenter.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.editmap; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.owant.thinkmap.AppConstants; 6 | import com.owant.thinkmap.file.Conf; 7 | import com.owant.thinkmap.file.OwantFileCreate; 8 | import com.owant.thinkmap.model.NodeModel; 9 | import com.owant.thinkmap.model.TreeModel; 10 | import com.owant.thinkmap.util.AndroidUtil; 11 | import com.owant.thinkmap.util.LOG; 12 | import com.owant.thinkmap.util.StringTool; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.io.InvalidClassException; 17 | import java.text.SimpleDateFormat; 18 | import java.util.ArrayList; 19 | import java.util.Calendar; 20 | import java.util.Date; 21 | import java.util.LinkedList; 22 | import java.util.List; 23 | import java.util.Locale; 24 | import java.util.Stack; 25 | 26 | /** 27 | * Created by owant on 21/03/2017. 28 | */ 29 | public class EditMapPresenter implements EditMapContract.Presenter { 30 | 31 | private EditMapContract.View mView; 32 | 33 | private boolean mIsCreate; 34 | private String mFilePath; 35 | private String mDefaultFilePath; 36 | private String mFileName; 37 | private TreeModel mTreeModel; 38 | 39 | private TreeModel mOldTreeModel; 40 | 41 | private String[] mOwantFilesArray; 42 | 43 | public EditMapPresenter(EditMapContract.View view) { 44 | mView = view; 45 | } 46 | 47 | @Override 48 | public void start() { 49 | mIsCreate = true; 50 | mFileName = mView.getDefaultPlanStr(); 51 | mView.showLoadingFile(); 52 | } 53 | 54 | @Override 55 | public void onRecycle() { 56 | mOwantFilesArray = null; 57 | mTreeModel = null; 58 | } 59 | 60 | @Override 61 | public void setLoadMapPath(String path) { 62 | // 获取到是否是编辑文件 63 | // 文件的名字 64 | // 文件路径下的owant file lists 65 | mIsCreate = false; 66 | 67 | LOG.jLogi("owant file path=%s", path); 68 | mFilePath = path; 69 | 70 | String saveFileName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); 71 | mFileName = saveFileName; 72 | 73 | refreshOwantFilesLists(); 74 | } 75 | 76 | @Override 77 | public void createDefaultTreeModel() { 78 | NodeModel plan = new NodeModel<>(mView.getDefaultPlanStr()); 79 | mTreeModel = new TreeModel<>(plan); 80 | mView.setTreeViewData(mTreeModel); 81 | refreshOwantFilesLists(); 82 | } 83 | 84 | @Override 85 | public void refreshOwantFilesLists() { 86 | if (!TextUtils.isEmpty(mFilePath)) { 87 | File editFilePath = new File(mFilePath); 88 | String[] lists = editFilePath.getParentFile().list(); 89 | 90 | //设置存在的owant集合 91 | sortFiles(lists); 92 | 93 | } else { 94 | // 默认文件路径 95 | mDefaultFilePath = mView.getDefaultSaveFilePath(); 96 | File file = new File(mDefaultFilePath); 97 | if (!file.exists()) { 98 | file.mkdirs(); 99 | LOG.jLogi("create default file path=%s", "true"); 100 | } 101 | LOG.jLogi("defaultFilePath=%s", mDefaultFilePath); 102 | if (file.exists()) { 103 | String[] lists = file.list(); 104 | sortFiles(lists); 105 | } else { 106 | LOG.jLoge("defaultPath is empty!"); 107 | } 108 | } 109 | } 110 | 111 | private void sortFiles(String[] lists) { 112 | ArrayList owantFiles = new ArrayList<>(); 113 | for (String fileName : lists) { 114 | if (fileName.endsWith(".owant")) { 115 | LOG.jLogi("file=%s", fileName); 116 | fileName = fileName.substring(0, fileName.lastIndexOf(".")); 117 | if (!StringTool.isEmpty(fileName)) { 118 | owantFiles.add(fileName); 119 | } 120 | 121 | //编辑模式,不能修改文件名字 122 | if (!mIsCreate) { 123 | owantFiles.remove(fileName); 124 | } 125 | } 126 | } 127 | 128 | if (owantFiles.size() > 0) { 129 | mOwantFilesArray = owantFiles.toArray(new String[owantFiles.size()]); 130 | if (AppConstants.CONFIG_DEBUG) { 131 | for (String str : mOwantFilesArray) { 132 | LOG.jLogi("mOwantFilesArray str=%s", str); 133 | } 134 | } 135 | } 136 | 137 | } 138 | 139 | @Override 140 | public void readOwantFile() { 141 | //读取owant文件 142 | if (!StringTool.isEmpty(mFilePath)) { 143 | try { 144 | OwantFileCreate owantFileCreate = new OwantFileCreate(); 145 | LOG.jLogi("filePath=%s", mFilePath); 146 | Object o = owantFileCreate.readContentObject(mFilePath); 147 | TreeModel tree = (TreeModel) o; 148 | mTreeModel = tree; 149 | mView.setTreeViewData(mTreeModel); 150 | 151 | mIsCreate = false; 152 | //拷贝一份 153 | mOldTreeModel = (TreeModel) mTreeModel.deepClone(); 154 | 155 | } catch (ClassNotFoundException e) { 156 | e.printStackTrace(); 157 | } catch (InvalidClassException e) { 158 | e.printStackTrace(); 159 | } catch (IOException e) { 160 | e.printStackTrace(); 161 | } 162 | } 163 | } 164 | 165 | @Override 166 | public void addNote() { 167 | mView.showAddNoteDialog(); 168 | } 169 | 170 | @Override 171 | public void addSubNote() { 172 | mView.showAddSubNoteDialog(); 173 | } 174 | 175 | @Override 176 | public void editNote() { 177 | mView.showEditNoteDialog(); 178 | } 179 | 180 | @Override 181 | public void focusMid() { 182 | mView.focusingMid(); 183 | } 184 | 185 | @Override 186 | public void saveFile() { 187 | //TODO 进行判断是否改变了文本 188 | //只有在编剧模式下才进行判断其他的跳过 189 | boolean equals = false; 190 | if (!mIsCreate) { 191 | //进行判断 192 | equals = isEqualsOldTreeModel(); 193 | } 194 | 195 | if (equals) { 196 | LOG.jLogi("no change =%s", "true"); 197 | mView.finishActivity(); 198 | } else { 199 | LOG.jLogi("change =%s", "false"); 200 | mView.showSaveFileDialog(mFilePath); 201 | } 202 | } 203 | 204 | private boolean isEqualsOldTreeModel() { 205 | boolean equals = false; 206 | TreeModel temp = mTreeModel; 207 | TreeModel compareTemp = mOldTreeModel; 208 | 209 | StringBuffer tempBuffer = new StringBuffer(); 210 | Stack> stack = new Stack<>(); 211 | NodeModel rootNode = temp.getRootNode(); 212 | stack.add(rootNode); 213 | while (!stack.isEmpty()) { 214 | NodeModel pop = stack.pop(); 215 | tempBuffer.append(pop.value); 216 | LinkedList> childNodes = pop.getChildNodes(); 217 | for (NodeModel item : childNodes) { 218 | stack.add(item); 219 | } 220 | } 221 | 222 | StringBuffer compareTempBuffer = new StringBuffer(); 223 | Stack> stackThis = new Stack<>(); 224 | NodeModel rootNodeThis = compareTemp.getRootNode(); 225 | stackThis.add(rootNodeThis); 226 | while (!stackThis.isEmpty()) { 227 | NodeModel pop = stackThis.pop(); 228 | compareTempBuffer.append(pop.value); 229 | LinkedList> childNodes = pop.getChildNodes(); 230 | for (NodeModel item : childNodes) { 231 | stackThis.add(item); 232 | } 233 | } 234 | 235 | if (compareTempBuffer.toString().equals(tempBuffer.toString())) { 236 | equals = true; 237 | } 238 | return equals; 239 | } 240 | 241 | @Override 242 | public void doSaveFile(String fileName) { 243 | OwantFileCreate owantFileCreate = new OwantFileCreate(); 244 | owantFileCreate.createOwantMapsDirectory(); 245 | owantFileCreate.createTempDirectory(); 246 | 247 | Conf conf = new Conf(); 248 | Date time = Calendar.getInstance().getTime(); 249 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); 250 | conf.date = simpleDateFormat.format(time); 251 | conf.app_version = mView.getAppVersion(); 252 | conf.android_version = AndroidUtil.getAndroidSystemVersion(); 253 | conf.map_name = mTreeModel.getRootNode().getValue(); 254 | owantFileCreate.writeConf(conf); 255 | 256 | owantFileCreate.writeContent(mTreeModel); 257 | 258 | // //如果是创建模式 259 | // if (mIsCreate) { 260 | // owantFileCreate.makeOwantFile(mTreeModel.getRootNode().getValue()); 261 | // } else { 262 | // owantFileCreate.makeOwantFile(mFileName); 263 | // } 264 | owantFileCreate.makeOwantFile(fileName); 265 | owantFileCreate.deleteTemp(); 266 | } 267 | 268 | @Override 269 | public void setTreeModel(TreeModel treeModel) { 270 | mTreeModel = treeModel; 271 | mView.setTreeViewData(mTreeModel); 272 | } 273 | 274 | @Override 275 | public TreeModel getTreeModel() { 276 | return mTreeModel; 277 | } 278 | 279 | @Override 280 | public List getOwantLists() { 281 | List list = new ArrayList(); 282 | LOG.jLogi("isCreate=%s", mIsCreate); 283 | if (mOwantFilesArray != null) { 284 | for (String s : mOwantFilesArray) { 285 | list.add(s); 286 | LOG.jLogi("exist file=%s", s); 287 | } 288 | } else { 289 | LOG.jLogi("mOwantFilesArray is empty"); 290 | } 291 | return list; 292 | } 293 | 294 | @Override 295 | public String getSaveInput() { 296 | if (mIsCreate) { 297 | return mTreeModel.getRootNode().getValue(); 298 | } else { 299 | return mFileName; 300 | } 301 | } 302 | 303 | } 304 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/splash/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.splash; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.PackageManager; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.app.ActivityCompat; 9 | import android.support.v4.content.ContextCompat; 10 | import android.widget.Toast; 11 | 12 | import com.owant.thinkmap.AppPermissions; 13 | import com.owant.thinkmap.R; 14 | import com.owant.thinkmap.base.BaseActivity; 15 | import com.owant.thinkmap.ui.workspace.WorkSpaceActivity; 16 | import com.owant.thinkmap.util.AndroidUtil; 17 | 18 | public class SplashActivity extends BaseActivity { 19 | 20 | @Override 21 | protected void onBaseIntent() { 22 | 23 | } 24 | 25 | @Override 26 | protected void onBasePreLayout() { 27 | 28 | } 29 | 30 | @Override 31 | protected int onBaseLayoutId(@Nullable Bundle savedInstanceState) { 32 | return R.layout.activity_splash; 33 | } 34 | 35 | @Override 36 | protected void onBaseBindView() { 37 | 38 | if (AndroidUtil.isMPermission()) { 39 | if (ContextCompat.checkSelfPermission(SplashActivity.this, 40 | AppPermissions.permission_storage[0]) != PackageManager.PERMISSION_GRANTED || 41 | ContextCompat.checkSelfPermission(SplashActivity.this, 42 | AppPermissions.permission_storage[1]) != PackageManager.PERMISSION_GRANTED) { 43 | 44 | requestStoragePermission(); 45 | 46 | } else { 47 | intentToWorkSpace(); 48 | } 49 | 50 | } else { 51 | intentToWorkSpace(); 52 | } 53 | 54 | } 55 | 56 | private void intentToWorkSpace() { 57 | new Thread(new Runnable() { 58 | @Override 59 | public void run() { 60 | try { 61 | Thread.sleep(1200); 62 | Intent intent = new Intent(SplashActivity.this, WorkSpaceActivity.class); 63 | startActivity(intent); 64 | SplashActivity.this.finish(); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | }).start(); 70 | } 71 | 72 | @Override 73 | protected void onLoadData() { 74 | 75 | } 76 | 77 | /** 78 | * 请求内存卡权限 79 | */ 80 | private void requestStoragePermission() { 81 | ActivityCompat.requestPermissions(SplashActivity.this 82 | , AppPermissions.permission_storage, 83 | AppPermissions.request_permission_storage); 84 | } 85 | 86 | @Override 87 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 88 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 89 | if (requestCode == AppPermissions.request_permission_storage) { 90 | if (AndroidUtil.verifyPermissions(grantResults)) { 91 | intentToWorkSpace(); 92 | } else { 93 | Toast.makeText(this, "the permission denied!", Toast.LENGTH_SHORT).show(); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/workspace/WorkSpaceContract.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.workspace; 2 | 3 | import com.owant.thinkmap.base.BasePresenter; 4 | import com.owant.thinkmap.base.BaseView; 5 | import com.owant.thinkmap.model.CurrentFileModel; 6 | 7 | import java.io.InputStream; 8 | import java.util.ArrayList; 9 | 10 | /** 11 | * Created by owant on 24/03/2017. 12 | */ 13 | public interface WorkSpaceContract { 14 | 15 | interface Presenter extends BasePresenter { 16 | 17 | /** 18 | * 空ListView的提示 19 | */ 20 | void onEmptyView(); 21 | 22 | /** 23 | * 加载owant的example示例 24 | * 25 | * @param inputStream 26 | */ 27 | void onLoadExamples(InputStream inputStream); 28 | 29 | /** 30 | * 加载Owant文件 31 | */ 32 | void onLoadOwantData(); 33 | 34 | /** 35 | * 删除Item 36 | * 37 | * @param position 38 | */ 39 | void removeItemFile(int position); 40 | 41 | String getItemFilePath(int position); 42 | } 43 | 44 | interface View extends BaseView { 45 | 46 | /** 47 | * 显示空的View 48 | */ 49 | void showEmptyView(); 50 | 51 | /** 52 | * 是否需要加载owant示例 53 | * 54 | * @return 55 | */ 56 | boolean shouldLoadExample(); 57 | 58 | /** 59 | * 重置owant示例不用加载示例 60 | */ 61 | void changeExampleVersion(String version); 62 | 63 | /** 64 | * 设置ListView的数据 65 | * 66 | * @param listData 67 | */ 68 | void setListData(ArrayList listData); 69 | 70 | /** 71 | * 刷新ListView的数据 72 | */ 73 | void refreshListData(); 74 | 75 | String getOwantDefaultPath(); 76 | 77 | String getExampleVersion(); 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/ui/workspace/WorkSpacePresenter.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.ui.workspace; 2 | 3 | import com.owant.thinkmap.AppConstants; 4 | import com.owant.thinkmap.file.ZipTool; 5 | import com.owant.thinkmap.model.CurrentFileModel; 6 | import com.owant.thinkmap.util.AndroidUtil; 7 | import com.owant.thinkmap.util.LOG; 8 | 9 | import java.io.File; 10 | import java.io.FileNotFoundException; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * Created by owant on 24/03/2017. 18 | */ 19 | 20 | public class WorkSpacePresenter implements WorkSpaceContract.Presenter { 21 | 22 | private WorkSpaceContract.View mView; 23 | private ArrayList mLists; 24 | 25 | private String mDefaultPath; 26 | 27 | public WorkSpacePresenter(WorkSpaceContract.View view) { 28 | mView = view; 29 | } 30 | 31 | @Override 32 | public void start() { 33 | mLists = new ArrayList<>(); 34 | } 35 | 36 | @Override 37 | public void onRecycle() { 38 | 39 | } 40 | 41 | @Override 42 | public void onEmptyView() { 43 | mView.showEmptyView(); 44 | } 45 | 46 | @Override 47 | public void onLoadExamples(InputStream ism) { 48 | boolean state = mView.shouldLoadExample(); 49 | if (state) { 50 | new Thread(new CopOwantExamples(ism)).start(); 51 | } 52 | } 53 | 54 | @Override 55 | public void onLoadOwantData() { 56 | if (mDefaultPath == null) { 57 | mDefaultPath = mView.getOwantDefaultPath(); 58 | } 59 | 60 | File saveFileParent = new File(mDefaultPath); 61 | mLists.clear(); 62 | if (saveFileParent.exists()) { 63 | File[] files = saveFileParent.listFiles(); 64 | for (File v : files) { 65 | if (v.isFile() && v.getAbsolutePath().endsWith(".owant")) { 66 | CurrentFileModel model = new CurrentFileModel(); 67 | model.filePath = v.getAbsolutePath(); 68 | model.editTime = AndroidUtil.transferLongToDate("yyyy-MM-dd HH:mm:ss", v.lastModified()); 69 | String fileName = v.getName(); 70 | if (fileName.indexOf(".") > 0) { 71 | fileName = fileName.substring(0, fileName.indexOf(".")); 72 | } 73 | model.mapRoot = fileName; 74 | mLists.add(model); 75 | } 76 | } 77 | } 78 | mView.setListData(mLists); 79 | } 80 | 81 | @Override 82 | public void removeItemFile(int position) { 83 | CurrentFileModel currentFileModel = mLists.get(position); 84 | File file = new File(currentFileModel.filePath); 85 | if (file.exists()) { 86 | file.delete(); 87 | mLists.remove(currentFileModel); 88 | } 89 | } 90 | 91 | @Override 92 | public String getItemFilePath(int position) { 93 | return mLists.get(position).filePath; 94 | } 95 | 96 | /** 97 | * 拷贝raw下的示例文件到内存卡 98 | */ 99 | private class CopOwantExamples implements Runnable { 100 | 101 | private InputStream mInputStream; 102 | 103 | public CopOwantExamples(InputStream is) { 104 | mInputStream = is; 105 | } 106 | 107 | @Override 108 | public void run() { 109 | try { 110 | FileOutputStream fos = null; 111 | InputStream inputStream = null; 112 | try { 113 | String sdCardPath = mView.getOwantDefaultPath(); 114 | String saveExamplesPath = sdCardPath + AppConstants.examples_names; 115 | LOG.jLogi("copExamplesToStorage:%s", saveExamplesPath); 116 | File saveFile = new File(saveExamplesPath); 117 | if (!saveFile.exists()) { 118 | saveFile.getParentFile().mkdirs(); 119 | saveFile.createNewFile(); 120 | } 121 | fos = new FileOutputStream(saveFile); 122 | inputStream = mInputStream; 123 | 124 | byte[] buffer = new byte[1024]; 125 | int count; 126 | while ((count = inputStream.read(buffer)) > 0) { 127 | fos.write(buffer, 0, count); 128 | fos.flush(); 129 | } 130 | 131 | ZipTool.unZipFiles( 132 | saveExamplesPath, 133 | mView.getOwantDefaultPath()); 134 | 135 | mView.changeExampleVersion(mView.getExampleVersion()); 136 | 137 | onLoadOwantData(); 138 | 139 | } catch (FileNotFoundException e) { 140 | e.printStackTrace(); 141 | } catch (IOException e) { 142 | e.printStackTrace(); 143 | } finally { 144 | if (fos != null) { 145 | try { 146 | fos.close(); 147 | } catch (IOException e) { 148 | e.printStackTrace(); 149 | } 150 | } 151 | if (inputStream != null) { 152 | try { 153 | inputStream.close(); 154 | } catch (IOException e) { 155 | e.printStackTrace(); 156 | } 157 | } 158 | } 159 | 160 | } catch (Exception e) { 161 | e.printStackTrace(); 162 | } 163 | } 164 | } 165 | 166 | 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/AndroidUtil.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.content.ComponentName; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.content.pm.PackageManager; 10 | import android.net.ConnectivityManager; 11 | import android.net.NetworkInfo; 12 | import android.net.wifi.WifiManager; 13 | import android.os.Build; 14 | import android.support.annotation.RequiresApi; 15 | import android.support.v7.app.AlertDialog; 16 | import android.text.TextUtils; 17 | import android.view.MotionEvent; 18 | import android.view.View; 19 | import android.view.inputmethod.InputMethodManager; 20 | import android.widget.EditText; 21 | import android.widget.Toast; 22 | 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.lang.reflect.Method; 25 | import java.text.SimpleDateFormat; 26 | import java.util.Date; 27 | import java.util.List; 28 | import java.util.Locale; 29 | 30 | public class AndroidUtil { 31 | 32 | /** 33 | * 隐藏键盘 34 | */ 35 | public static void hideKeyboard(Context context, View view) { 36 | InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); 37 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 38 | } 39 | 40 | public static boolean isShouldHideInput(View inputView, MotionEvent event) { 41 | boolean should = false; 42 | if (inputView != null && (inputView instanceof EditText)) { 43 | int[] leftTop = {0, 0}; 44 | inputView.getLocationInWindow(leftTop); 45 | int left = leftTop[0]; 46 | int top = leftTop[1]; 47 | 48 | int bottom = top + inputView.getHeight(); 49 | int right = left + inputView.getWidth(); 50 | 51 | if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom) { 52 | should = false; 53 | } else { 54 | should = true; 55 | } 56 | } 57 | return should; 58 | } 59 | 60 | 61 | /** 62 | * 显示Toast的信息 63 | * 64 | * @param mContext 65 | * @param toastInfo 66 | */ 67 | public static void showToast(Context mContext, String toastInfo) { 68 | Toast mToast = Toast.makeText(mContext, toastInfo, Toast.LENGTH_SHORT); 69 | mToast.show(); 70 | } 71 | 72 | /** 73 | * 判断网络是否可用 74 | */ 75 | public static boolean isNetworkAvailable(Context context) { 76 | boolean netStatus = false; 77 | ConnectivityManager connectManager = (ConnectivityManager) context 78 | .getSystemService(Context.CONNECTIVITY_SERVICE); 79 | NetworkInfo networkInfo = connectManager.getActiveNetworkInfo(); 80 | 81 | if (networkInfo != null) { 82 | netStatus = networkInfo.isAvailable(); 83 | } 84 | return netStatus; 85 | } 86 | 87 | /** 88 | * 打开设置网络 89 | * 90 | * @param mContext 91 | */ 92 | public static void openSettingsConn(Context mContext, Integer requestCode) { 93 | Intent settings = null; 94 | // SDK>15,就是3.0以上的版本 95 | if (Build.VERSION.SDK_INT >= 15) { 96 | settings = new Intent(android.provider.Settings.ACTION_SETTINGS); 97 | } else { 98 | settings = new Intent(); 99 | ComponentName component = new ComponentName("com.android.settings", 100 | "com.android.setttins.WirelessSettings"); 101 | settings.setAction("android.intent.action.VIEW"); 102 | 103 | } 104 | 105 | if (requestCode == null) { 106 | mContext.startActivity(settings); 107 | } else { 108 | ((Activity) mContext).startActivityForResult(settings, requestCode); 109 | } 110 | } 111 | 112 | public static void openSettingsConn(Context mContext) { 113 | openSettingsConn(mContext, null); 114 | } 115 | 116 | 117 | public static String getCurrentSSID(Context context) { 118 | String ssid = ""; 119 | WifiManager wifiManager = (WifiManager) context.getApplicationContext() 120 | .getSystemService(Context.WIFI_SERVICE); 121 | if (wifiManager.isWifiEnabled()) { 122 | ssid = wifiManager.getConnectionInfo().getSSID(); 123 | ssid = ssid.replaceAll("\"", ""); 124 | if (TextUtils.equals("", ssid)) { 125 | ssid = ""; 126 | } 127 | } 128 | return ssid; 129 | } 130 | 131 | /** 132 | * 创建并显示一个只包含“是”与“否”按钮简单对话框 133 | * 134 | * @param context 135 | * @param title 136 | * @param callback 137 | */ 138 | public static void showAlertDialog(final Context context, final String title, final DialogCallback callback) { 139 | new AlertDialog.Builder(context) 140 | .setTitle(title) 141 | .setPositiveButton("是", new DialogInterface.OnClickListener() { 142 | @Override 143 | public void onClick(DialogInterface dialog, int which) { 144 | callback.onPositive(); 145 | } 146 | }) 147 | .setNegativeButton("否", new DialogInterface.OnClickListener() { 148 | @Override 149 | public void onClick(DialogInterface dialog, int which) { 150 | dialog.dismiss(); 151 | } 152 | }).show(); 153 | } 154 | 155 | /** 156 | * 点击对话框确定按钮后的回调接口 157 | */ 158 | public interface DialogCallback { 159 | void onPositive(); 160 | } 161 | 162 | /** 163 | * 检测当前App是否在前台运行 164 | * 165 | * @param context 166 | * @return true 前台运行,false 后台运行 167 | */ 168 | public static boolean isAppForeground(Context context) { 169 | ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 170 | List runningTasks = activityManager.getRunningTasks(Integer.MAX_VALUE); 171 | 172 | // 正在运行的应用 173 | ActivityManager.RunningTaskInfo foregroundTask = runningTasks.get(0); 174 | String packageName = foregroundTask.topActivity.getPackageName(); 175 | String myPackageName = context.getPackageName(); 176 | 177 | // 比较包名 178 | return packageName.equals(myPackageName); 179 | } 180 | 181 | public static String getAppVersion(Context context) { 182 | String myVersion = "v "; 183 | try { 184 | myVersion = myVersion + context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; 185 | } catch (PackageManager.NameNotFoundException e) { 186 | e.printStackTrace(); 187 | } 188 | return myVersion; 189 | } 190 | 191 | public static String getAndroidSystemVersion() { 192 | return "android " + Build.VERSION.SDK_INT; 193 | } 194 | 195 | public static String transferLongToDate(String dateFormat, Long millSec) { 196 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormat, Locale.CHINA); 197 | Date date = new Date(millSec); 198 | return sdf.format(date); 199 | } 200 | 201 | /** 202 | * 判断是否为android 6.0 203 | * 204 | * @return true or false 205 | */ 206 | public static boolean isMPermission() { 207 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 208 | return true; 209 | } else { 210 | return false; 211 | } 212 | } 213 | 214 | /** 215 | * Check that all given permissions have been granted by verifying that each entry in the 216 | * given array is of the value {@link PackageManager#PERMISSION_GRANTED}. 217 | * 218 | * @see Activity#onRequestPermissionsResult(int, String[], int[]) 219 | */ 220 | public static boolean verifyPermissions(int[] grantResults) { 221 | // At least one result must be checked. 222 | if (grantResults.length < 1) { 223 | return false; 224 | } 225 | 226 | // Verify that each required permission has been granted, otherwise return false. 227 | for (int result : grantResults) { 228 | if (result != PackageManager.PERMISSION_GRANTED) { 229 | return false; 230 | } 231 | } 232 | return true; 233 | } 234 | 235 | } 236 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/DensityUtils.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | import android.content.Context; 4 | import android.util.TypedValue; 5 | 6 | /** 7 | * 单位转换 工具类
8 | */ 9 | public class DensityUtils { 10 | 11 | /** 12 | * dp转px 13 | */ 14 | public static int dp2px(Context context, float dpVal) { 15 | int result = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources() 16 | .getDisplayMetrics()); 17 | return result; 18 | } 19 | 20 | /** 21 | * sp转px 22 | */ 23 | public static int sp2px(Context context, float spVal) { 24 | int result = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getResources() 25 | .getDisplayMetrics()); 26 | return result; 27 | } 28 | 29 | /** 30 | * px转dp 31 | */ 32 | public static int px2dp(Context context, float pxVal) { 33 | final float scale = context.getResources().getDisplayMetrics().density; 34 | int result = (int) (pxVal / scale); 35 | return result; 36 | } 37 | 38 | /** 39 | * px转sp 40 | */ 41 | public static float px2sp(Context context, float pxVal) { 42 | int result = (int) (pxVal / context.getResources().getDisplayMetrics().scaledDensity); 43 | return result; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/LOG.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | import com.owant.thinkmap.AppConstants; 4 | 5 | /** 6 | * Created by owant on 22/03/2017. 7 | */ 8 | 9 | public class LOG { 10 | 11 | public static void jLogi(String format, Object... args) { 12 | if (AppConstants.CONFIG_DEBUG) { 13 | StringBuffer ft = new StringBuffer(format); 14 | if (!ft.toString().endsWith("\n")) { 15 | ft.append("\n"); 16 | } 17 | System.out.printf(ft.toString(), args); 18 | } 19 | } 20 | 21 | public static void jLoge(String format, Object... args) { 22 | if (AppConstants.CONFIG_DEBUG) { 23 | StringBuffer ft = new StringBuffer(format); 24 | if (!ft.toString().endsWith("\n")) { 25 | ft.append("\n"); 26 | } 27 | System.err.printf(ft.toString(), args); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/LooperFlag.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | /** 4 | * Created by OlaWang on 2017/7/12. 5 | */ 6 | 7 | /** 8 | * This util support the looper sate callback. 9 | * if you input the {@link LooperFlag#loopBody} value of {1,2,3} 10 | * you call the {@link LooperFlag#next()} 11 | * the callback will return the 1,2,3,1,2,3,1,2,3.... 12 | * 13 | * @param 14 | */ 15 | public class LooperFlag { 16 | 17 | private T[] loopBody; 18 | private LooperListener mListener; 19 | private int point = 0; 20 | 21 | public LooperFlag(T[] loopBody, LooperListener listener) { 22 | this.loopBody = loopBody; 23 | mListener = listener; 24 | } 25 | 26 | public T next() { 27 | point += 1; 28 | if (point == loopBody.length) { 29 | point = 0; 30 | } 31 | 32 | if (mListener != null) { 33 | mListener.onLooper(loopBody[point]); 34 | } 35 | 36 | return loopBody[point]; 37 | } 38 | 39 | public void setLooperListener(LooperListener listener) { 40 | mListener = listener; 41 | } 42 | 43 | public interface LooperListener { 44 | void onLooper(T item); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/MakeZipClient.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.zip.ZipEntry; 11 | import java.util.zip.ZipOutputStream; 12 | 13 | /** 14 | * Created by owant on 2016/9/1. 15 | */ 16 | public class MakeZipClient { 17 | 18 | private List arrayFiles; 19 | private String sourcePath; 20 | private File saveFilePath; 21 | 22 | public void create(String sourcePath, File savePath) { 23 | arrayFiles = new ArrayList<>(); 24 | this.sourcePath = sourcePath; 25 | this.saveFilePath = savePath; 26 | 27 | //遍历文件下文件 28 | findAllFiles(sourcePath); 29 | //生产.owant 30 | makeZipFile(arrayFiles.toArray(new File[arrayFiles.size()]), saveFilePath); 31 | } 32 | 33 | /** 34 | * 找到所有输入文件夹路径下的所有文件 35 | * 36 | * @param filePath 37 | */ 38 | private void findAllFiles(String filePath) { 39 | if (filePath == null || filePath.trim().length() == 0) { 40 | System.out.println("请输入文件路径!"); 41 | return; 42 | } 43 | 44 | File sourceFile = new File(filePath); 45 | if (!sourceFile.exists()) { 46 | System.out.println("输入的文件路径不存在!"); 47 | return; 48 | } else {//遍历该目录下所有的文件 49 | if (sourceFile.isDirectory()) {//文件夹 50 | File[] subFiles = sourceFile.listFiles(); 51 | for (File f : subFiles) { 52 | findAllFiles(f.getAbsolutePath()); 53 | } 54 | } else {//文件 55 | System.out.println("找到文件:\t" + sourceFile.getAbsolutePath()); 56 | arrayFiles.add(sourceFile); 57 | } 58 | } 59 | } 60 | 61 | private void makeZipFile(File[] files, File zipNameFile) { 62 | //建立一个写入流 63 | FileOutputStream fos; 64 | try { 65 | fos = new FileOutputStream(zipNameFile); 66 | //建立一个写入压缩流 67 | ZipOutputStream zos = new ZipOutputStream(fos); 68 | byte[] buffer = new byte[1024]; 69 | for (File file : files) { 70 | //截取掉前面的字符 71 | String cutPath = file.getAbsolutePath().substring(sourcePath.length()); 72 | System.out.println("entry:" + cutPath); 73 | ZipEntry entry = new ZipEntry(cutPath); 74 | FileInputStream fis = new FileInputStream(file); 75 | zos.putNextEntry(entry); 76 | int read = 0; 77 | while ((read = fis.read(buffer)) != -1) { 78 | zos.write(buffer, 0, read); 79 | } 80 | 81 | zos.closeEntry(); 82 | fis.close(); 83 | } 84 | zos.close(); 85 | fos.close(); 86 | } catch (FileNotFoundException e) { 87 | e.printStackTrace(); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | 94 | public static void main(String[] arg) { 95 | // String sourcePath = "/Users/owant/Desktop/create_file"; 96 | // MakeZipClient client = new MakeZipClient(); 97 | // File saveFile = new File("/Users/owant/Desktop/myplan.owant"); 98 | // client.create(sourcePath, saveFile); 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/SharePreUtil.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Build; 6 | 7 | /** 8 | * Created by owant on 2016/9/1. 9 | */ 10 | public class SharePreUtil { 11 | private static final String PREFRENCE_NAME = "base_pre"; 12 | private SharedPreferences mSharedPrefs; 13 | 14 | private SharePreUtil() { 15 | } 16 | 17 | private static class InstanceHolder { 18 | public static SharePreUtil sInstance = new SharePreUtil(); 19 | } 20 | 21 | public static SharePreUtil getInstance() { 22 | return InstanceHolder.sInstance; 23 | } 24 | 25 | public void init(Context context) { 26 | mSharedPrefs = context.getSharedPreferences(PREFRENCE_NAME, Context.MODE_PRIVATE); 27 | } 28 | 29 | public String getString(String key) { 30 | if (mSharedPrefs == null) return null; 31 | return mSharedPrefs.getString(key, ""); 32 | } 33 | 34 | public void putString(String key, String value) { 35 | if (mSharedPrefs == null) return; 36 | SharedPreferences.Editor editor = mSharedPrefs.edit(); 37 | editor.putString(key, value); 38 | if (Build.VERSION.SDK_INT >= 15) 39 | editor.apply(); 40 | else 41 | editor.commit(); 42 | } 43 | 44 | public void remove(String key) { 45 | SharedPreferences.Editor editor = mSharedPrefs.edit(); 46 | editor.remove(key); 47 | 48 | if (Build.VERSION.SDK_INT >=15) { 49 | editor.apply(); 50 | } else { 51 | editor.commit(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/StringTool.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util; 2 | 3 | /** 4 | * Created by owant on 22/03/2017. 5 | * 脱开Android包 6 | */ 7 | 8 | public class StringTool { 9 | 10 | /** 11 | * Returns true if the string is null or 0-length. 12 | * 13 | * @param str the string to be examined 14 | * @return true if str is null or zero length 15 | */ 16 | public static boolean isEmpty(CharSequence str) { 17 | if (str == null || str.length() == 0) 18 | return true; 19 | else 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/code/BindView.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owant/ThinkMap/80be866bb34fd4acb44204192e4a564f3de7e60f/app/src/main/java/com/owant/thinkmap/util/code/BindView.jar -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/util/code/BindViewTool.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.util.code; 2 | 3 | import org.xmlpull.v1.XmlPullParser; 4 | import org.xmlpull.v1.XmlPullParserException; 5 | import org.xmlpull.v1.XmlPullParserFactory; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by owant on 19/10/2016. 16 | * 查找XML布局下的控件,进行生产findViewById的代码 17 | */ 18 | 19 | public class BindViewTool { 20 | 21 | final static String input_key_i = "-i"; 22 | final static String input_key_f = "-f"; 23 | final static String input_key_p = "-p"; 24 | 25 | /** 26 | * private TextView info; 27 | */ 28 | private static final String declare_format = "private {0} {1};"; 29 | 30 | /** 31 | * info=(TextView)findViewById(R.id.text); 32 | * info=(TextView)getView().findViewById(R.id.text); 33 | */ 34 | private static final String find_view_format = "{0} = ({1}){2}findViewById({3});"; 35 | 36 | private static boolean isFragment = false; 37 | /** 38 | * 忽略的标识,默认表示为_ 39 | */ 40 | private static String ignoreMark = "_"; 41 | 42 | //找到了需要绑定的View 43 | private static ArrayList bindViews = new ArrayList<>(); 44 | 45 | public static void main(String[] arg) { 46 | 47 | if (arg.length >= 2) { 48 | boolean inp = false; 49 | InputMode mode = new InputMode(); 50 | for (String str : arg) { 51 | if (mode.getState().equals(input_key_f)) { 52 | isFragment = Boolean.valueOf(str); 53 | } else if (mode.getState().equals(input_key_p)) { 54 | bindView(str, false); 55 | inp = true; 56 | } else if (mode.getState().equals(input_key_i)) { 57 | ignoreMark = str; 58 | } 59 | if (!inp) { 60 | mode.setState(str); 61 | } 62 | } 63 | 64 | } else if (arg.length == 1) { 65 | bindView(arg[0], false); 66 | } 67 | 68 | printfResult(); 69 | } 70 | 71 | public static void bindView(String xmlPath, boolean includeState) { 72 | try { 73 | 74 | InputStream inputStream = new FileInputStream(new File(xmlPath)); 75 | 76 | //bindView的集合 77 | if (!includeState) 78 | bindViews = new ArrayList<>(); 79 | 80 | XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser(); 81 | xmlPullParser.setInput(inputStream, "utf-8"); 82 | 83 | //xml pull parser是以事件触发为设计的代码 84 | int eventType = xmlPullParser.getEventType(); 85 | while (eventType != XmlPullParser.END_DOCUMENT) {//文档结束 86 | switch (eventType) { 87 | case XmlPullParser.START_DOCUMENT://文档开始 88 | break; 89 | case XmlPullParser.START_TAG://标签开始 90 | xmlTagBusiness(xmlPath, xmlPullParser); 91 | break; 92 | case XmlPullParser.END_TAG://标签结束 93 | break; 94 | } 95 | 96 | eventType = xmlPullParser.next(); 97 | } 98 | 99 | } catch (XmlPullParserException e) { 100 | e.printStackTrace(); 101 | } catch (FileNotFoundException e) { 102 | e.printStackTrace(); 103 | } catch (IOException e) { 104 | e.printStackTrace(); 105 | } 106 | 107 | } 108 | 109 | private static void printfResult() { 110 | //打印需要BindView的控件 111 | //打印变量声明 112 | System.out.println("\n\n"); 113 | for (Model m : bindViews) { 114 | String declare = declare_format.replace("{0}", m.mType); 115 | declare = declare.replace("{1}", m.mName); 116 | System.out.println(declare); 117 | } 118 | 119 | System.out.println("\n\n"); 120 | 121 | System.out.println("public void bindViews(){\n"); 122 | for (Model m : bindViews) { 123 | String find = find_view_format.replace("{0}", m.mName); 124 | find = find.replace("{1}", m.mType); 125 | if (isFragment) { 126 | find = find.replace("{2}", "getView()."); 127 | } else { 128 | find = find.replace("{2}", ""); 129 | } 130 | find = find.replace("{3}", "R.id." + m.mId); 131 | System.out.println("\t" + find); 132 | } 133 | System.out.println("}\n"); 134 | } 135 | 136 | private static void xmlTagBusiness(String path, XmlPullParser xmlPullParser) { 137 | //对于这个情况需要进行com.owant.examples.view.DivView 138 | String type = xmlPullParser.getName(); 139 | int pointExist = type.lastIndexOf("."); 140 | if (pointExist != -1) { 141 | type = type.substring(pointExist + 1, type.length()); 142 | } 143 | 144 | if (type.equals("include")) { 145 | 146 | /** 147 | 150 | */ 151 | int count = xmlPullParser.getAttributeCount(); 152 | for (int i = 0; i < count; i++) { 153 | if (xmlPullParser.getAttributeName(i).startsWith("layout")) { 154 | //查找到另一个布局 155 | String layoutFormat = xmlPullParser.getAttributeValue(i); 156 | layoutFormat = layoutFormat.substring(layoutFormat.indexOf("/"), layoutFormat.length()); 157 | 158 | bindView(path.substring(0, path.lastIndexOf("/")) + layoutFormat + ".xml", true); 159 | return; 160 | } 161 | } 162 | 163 | } 164 | 165 | String androidIdValue = null; 166 | int count = xmlPullParser.getAttributeCount(); 167 | for (int i = 0; i < count; i++) { 168 | String androidIdTag = xmlPullParser.getAttributeName(i); 169 | 170 | if (androidIdTag.equals("android:id")) { 171 | String androidIdTagValue = xmlPullParser.getAttributeValue(i); 172 | if (androidIdTagValue.startsWith("@+id/")) { 173 | androidIdValue = androidIdTagValue.replace("@+id/", ""); 174 | 175 | //ignore 176 | if (androidIdValue.startsWith(ignoreMark)) { 177 | continue; 178 | } 179 | 180 | if (androidIdValue != null) { 181 | Model model = new Model(); 182 | model.mId = androidIdValue; 183 | String name = translationName(model.mId); 184 | model.mName = name; 185 | model.mType = type; 186 | bindViews.add(model); 187 | } 188 | continue; 189 | } 190 | } 191 | } 192 | } 193 | 194 | /** 195 | * edit_map_tree_view转化为editMapTreeView 196 | * 197 | * @param idValue 198 | * @return 199 | */ 200 | private static String translationName(String idValue) { 201 | boolean shouldUp = false; 202 | char[] chars = idValue.toCharArray(); 203 | StringBuffer buffer = new StringBuffer(); 204 | for (char ch : chars) { 205 | 206 | if (shouldUp) { 207 | ch = Character.toUpperCase(ch); 208 | buffer.append(ch); 209 | shouldUp = false; 210 | 211 | } else { 212 | if (ch == '_') { 213 | shouldUp = true; 214 | } else { 215 | shouldUp = false; 216 | buffer.append(ch); 217 | } 218 | } 219 | } 220 | return buffer.toString(); 221 | } 222 | 223 | public static class Model { 224 | public String mType; 225 | public String mName; 226 | public String mId; 227 | } 228 | 229 | public static class InputMode { 230 | 231 | public String state = ""; 232 | 233 | public void setState(String input) { 234 | if (input.equals(input_key_f)) { 235 | state = input_key_f; 236 | } else if (input.equals(input_key_i)) { 237 | state = input_key_i; 238 | } else if (input.equals(input_key_p)) { 239 | state = input_key_p; 240 | } else { 241 | state = ""; 242 | } 243 | } 244 | 245 | public String getState() { 246 | return state; 247 | } 248 | } 249 | } 250 | 251 | 252 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/NodeView.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.Drawable; 7 | import android.util.AttributeSet; 8 | import android.widget.TextView; 9 | 10 | import com.owant.thinkmap.R; 11 | import com.owant.thinkmap.model.NodeModel; 12 | 13 | 14 | /** 15 | * Created by owant on 09/02/2017. 16 | */ 17 | @SuppressLint("AppCompatCustomView") 18 | public class NodeView extends TextView{ 19 | 20 | public NodeModel treeNode = null; 21 | 22 | public NodeView(Context context) { 23 | this(context, null, 0); 24 | } 25 | 26 | public NodeView(Context context, AttributeSet attrs) { 27 | this(context, attrs, 0); 28 | } 29 | 30 | public NodeView(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | 33 | setTextColor(Color.WHITE); 34 | setPadding(12, 10, 12, 10); 35 | 36 | Drawable drawable = context.getResources().getDrawable(R.drawable.node_view_bg); 37 | setBackgroundDrawable(drawable); 38 | } 39 | 40 | public NodeModel getTreeNode() { 41 | return treeNode; 42 | } 43 | 44 | public void setTreeNode(NodeModel treeNode) { 45 | this.treeNode = treeNode; 46 | setSelected(treeNode.isFocus()); 47 | setText(treeNode.getValue()); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/RecycleItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by owant on 2016/7/29. 7 | */ 8 | public interface RecycleItemClickListener { 9 | void onItemClick(View view, int position); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/RecycleItemLongClickListener.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by owant on 07/09/2017. 7 | */ 8 | 9 | public interface RecycleItemLongClickListener { 10 | void onItemLongClick(View view, int position); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/RightTreeLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | 6 | import com.owant.thinkmap.model.ForTreeItem; 7 | import com.owant.thinkmap.model.NodeModel; 8 | import com.owant.thinkmap.model.TreeModel; 9 | 10 | import java.io.Serializable; 11 | import java.util.ArrayDeque; 12 | import java.util.ArrayList; 13 | import java.util.Deque; 14 | import java.util.LinkedList; 15 | 16 | /** 17 | * Created by owant on 08/03/2017. 18 | */ 19 | public class RightTreeLayoutManager implements TreeLayoutManager { 20 | 21 | final int msg_standard_layout = 1; 22 | final int msg_correct_layout = 2; 23 | final int msg_box_call_back = 3; 24 | 25 | private ViewBox mViewBox; 26 | private int mDy; 27 | private int mDx; 28 | private int mHeight; 29 | 30 | public RightTreeLayoutManager(int dx, int dy, int height) { 31 | mViewBox = new ViewBox(); 32 | 33 | this.mDx = dx; 34 | this.mDy = dy; 35 | this.mHeight = height; 36 | } 37 | 38 | @Override 39 | public void onTreeLayout(final TreeView treeView) { 40 | 41 | final TreeModel mTreeModel = treeView.getTreeModel(); 42 | if (mTreeModel != null) { 43 | 44 | View rootView = treeView.findNodeViewFromNodeModel(mTreeModel.getRootNode()); 45 | if (rootView != null) { 46 | 47 | //根节点位置 48 | rootTreeViewLayout((NodeView) rootView); 49 | } 50 | 51 | mTreeModel.addForTreeItem(new ForTreeItem>() { 52 | @Override 53 | public void next(int msg, NodeModel next) { 54 | doNext(msg, next, treeView); 55 | } 56 | }); 57 | 58 | //基本布局 59 | mTreeModel.ergodicTreeInWith(msg_standard_layout); 60 | 61 | //纠正 62 | mTreeModel.ergodicTreeInWith(msg_correct_layout); 63 | 64 | mViewBox.clear(); 65 | mTreeModel.ergodicTreeInDeep(msg_box_call_back); 66 | } 67 | } 68 | 69 | 70 | @Override 71 | public ViewBox onTreeLayoutCallBack() { 72 | if (mViewBox != null) { 73 | return mViewBox; 74 | } else { 75 | return null; 76 | } 77 | } 78 | 79 | private void doNext(int msg, NodeModel next, TreeView treeView) { 80 | View view = treeView.findNodeViewFromNodeModel(next); 81 | 82 | if (msg == msg_standard_layout) { 83 | //标准分布 84 | standardLayout(treeView, (NodeView) view); 85 | } else if (msg == msg_correct_layout) { 86 | //纠正 87 | correctLayout(treeView, (NodeView) view); 88 | } else if (msg == msg_box_call_back) { 89 | 90 | //View的大小变化 91 | int left = view.getLeft(); 92 | int top = view.getTop(); 93 | int bottom = view.getBottom(); 94 | int right = view.getRight(); 95 | 96 | // ******* 97 | // * * 98 | // * * 99 | // ******* 100 | 101 | if (left < mViewBox.left) { 102 | mViewBox.left = left; 103 | } 104 | if (top < mViewBox.top) { 105 | mViewBox.top = top; 106 | } 107 | if (bottom > mViewBox.bottom) { 108 | mViewBox.bottom = bottom; 109 | } 110 | if (right > mViewBox.right) { 111 | mViewBox.right = right; 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * 布局纠正 118 | * 119 | * @param treeView 120 | * @param next 121 | */ 122 | public void correctLayout(TreeView treeView, NodeView next) { 123 | 124 | TreeModel mTree = treeView.getTreeModel(); 125 | int count = next.getTreeNode().getChildNodes().size(); 126 | 127 | if (next.getParent() != null && count >= 2) { 128 | NodeModel tn = next.getTreeNode().getChildNodes().get(0); 129 | NodeModel bn = next.getTreeNode().getChildNodes().get(count - 1); 130 | Log.i("see fc", next.getTreeNode().getValue() + ":" + tn.getValue() + "," + bn.getValue()); 131 | 132 | int topDr = next.getTop() - treeView.findNodeViewFromNodeModel(tn).getBottom() + mDy; 133 | int bnDr = treeView.findNodeViewFromNodeModel(bn).getTop() - next.getBottom() + mDy; 134 | 135 | //上移动 136 | ArrayList> allLowNodes = mTree.getAllLowNodes(bn); 137 | ArrayList> allPreNodes = mTree.getAllPreNodes(tn); 138 | 139 | for (NodeModel low : allLowNodes) { 140 | NodeView view = (NodeView) treeView.findNodeViewFromNodeModel(low); 141 | moveNodeLayout(treeView, view, bnDr); 142 | } 143 | 144 | for (NodeModel pre : allPreNodes) { 145 | NodeView view = (NodeView) treeView.findNodeViewFromNodeModel(pre); 146 | moveNodeLayout(treeView, view, -topDr); 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * 标准分布 153 | * 154 | * @param treeView 155 | * @param rootView 156 | */ 157 | private void standardLayout(TreeView treeView, NodeView rootView) { 158 | NodeModel treeNode = rootView.getTreeNode(); 159 | if (treeNode != null) { 160 | //所有的子节点 161 | LinkedList> childNodes = treeNode.getChildNodes(); 162 | int size = childNodes.size(); 163 | int mid = size / 2; 164 | int r = size % 2; 165 | 166 | //基线 167 | // b 168 | // a------- 169 | // c 170 | // 171 | int left = rootView.getRight() + mDx; 172 | int top = rootView.getTop() + rootView.getMeasuredHeight() / 2; 173 | 174 | int right = 0; 175 | int bottom = 0; 176 | 177 | if (size == 0) { 178 | return; 179 | } else if (size == 1) { 180 | NodeView midChildNodeView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(0)); 181 | 182 | top = top - midChildNodeView.getMeasuredHeight() / 2; 183 | right = left + midChildNodeView.getMeasuredWidth(); 184 | bottom = top + midChildNodeView.getMeasuredHeight(); 185 | midChildNodeView.layout(left, top, right, bottom); 186 | } else { 187 | 188 | int topLeft = left; 189 | int topTop = top; 190 | int topRight = 0; 191 | int topBottom = 0; 192 | 193 | int bottomLeft = left; 194 | int bottomTop = top; 195 | int bottomRight = 0; 196 | int bottomBottom = 0; 197 | 198 | if (r == 0) {//偶数 199 | for (int i = mid - 1; i >= 0; i--) { 200 | NodeView topView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(i)); 201 | NodeView bottomView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(size - i - 1)); 202 | 203 | 204 | if (i == mid - 1) { 205 | topTop = topTop - mDy / 2 - topView.getMeasuredHeight(); 206 | topRight = topLeft + topView.getMeasuredWidth(); 207 | topBottom = topTop + topView.getMeasuredHeight(); 208 | 209 | bottomTop = bottomTop + mDy / 2; 210 | bottomRight = bottomLeft + bottomView.getMeasuredWidth(); 211 | bottomBottom = bottomTop + bottomView.getMeasuredHeight(); 212 | } else { 213 | topTop = topTop - mDy - topView.getMeasuredHeight(); 214 | topRight = topLeft + topView.getMeasuredWidth(); 215 | topBottom = topTop + topView.getMeasuredHeight(); 216 | 217 | bottomTop = bottomTop + mDy; 218 | bottomRight = bottomLeft + bottomView.getMeasuredWidth(); 219 | bottomBottom = bottomTop + bottomView.getMeasuredHeight(); 220 | } 221 | 222 | topView.layout(topLeft, topTop, topRight, topBottom); 223 | bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); 224 | 225 | bottomTop = bottomView.getBottom(); 226 | } 227 | 228 | } else { 229 | NodeView midView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(mid)); 230 | midView.layout(left, top - midView.getMeasuredHeight() / 2, left + midView.getMeasuredWidth(), 231 | top - midView.getMeasuredHeight() / 2 + midView.getMeasuredHeight()); 232 | 233 | topTop = midView.getTop(); 234 | bottomTop = midView.getBottom(); 235 | 236 | for (int i = mid - 1; i >= 0; i--) { 237 | NodeView topView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(i)); 238 | NodeView bottomView = (NodeView) treeView.findNodeViewFromNodeModel(childNodes.get(size - i - 1)); 239 | 240 | topTop = topTop - mDy - topView.getMeasuredHeight(); 241 | topRight = topLeft + topView.getMeasuredWidth(); 242 | topBottom = topTop + topView.getMeasuredHeight(); 243 | 244 | bottomTop = bottomTop + mDy; 245 | bottomRight = bottomLeft + bottomView.getMeasuredWidth(); 246 | bottomBottom = bottomTop + bottomView.getMeasuredHeight(); 247 | 248 | topView.layout(topLeft, topTop, topRight, topBottom); 249 | bottomView.layout(bottomLeft, bottomTop, bottomRight, bottomBottom); 250 | bottomTop = bottomView.getBottom(); 251 | } 252 | } 253 | } 254 | } 255 | } 256 | 257 | /** 258 | * 移动 259 | * 260 | * @param rootView 261 | * @param dy 262 | */ 263 | private void moveNodeLayout(TreeView superTreeView, NodeView rootView, int dy) { 264 | 265 | Deque> queue = new ArrayDeque<>(); 266 | NodeModel rootNode = rootView.getTreeNode(); 267 | queue.add(rootNode); 268 | while (!queue.isEmpty()) { 269 | rootNode = queue.poll(); 270 | rootView = (NodeView) superTreeView.findNodeViewFromNodeModel(rootNode); 271 | int l = rootView.getLeft(); 272 | int t = rootView.getTop() + dy; 273 | rootView.layout(l, t, l + rootView.getMeasuredWidth(), t + rootView.getMeasuredHeight()); 274 | 275 | LinkedList> childNodes = rootNode.getChildNodes(); 276 | for (NodeModel item : childNodes) { 277 | queue.add(item); 278 | } 279 | } 280 | } 281 | 282 | 283 | /** 284 | * root节点的定位 285 | * 286 | * @param rootView 287 | */ 288 | private void rootTreeViewLayout(NodeView rootView) { 289 | int lr = mDy; 290 | int tr = mDx; 291 | int rr = lr + rootView.getMeasuredWidth(); 292 | int br = tr + rootView.getMeasuredHeight(); 293 | rootView.layout(lr, tr, rr, br); 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/TreeLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | /** 4 | * Created by owant on 07/03/2017. 5 | */ 6 | 7 | public interface TreeLayoutManager { 8 | /** 9 | * 进行树形结构的位置计算 10 | */ 11 | void onTreeLayout(TreeView treeView); 12 | 13 | /** 14 | * 位置分布好后的回调,用于确认ViewGroup的大小 15 | */ 16 | ViewBox onTreeLayoutCallBack(); 17 | 18 | /** 19 | * 修正位置 20 | * 21 | * @param treeView 22 | * @param next 23 | */ 24 | void correctLayout(TreeView treeView, NodeView next); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/TreeViewItemClick.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by owant on 18/02/2017. 7 | */ 8 | 9 | public interface TreeViewItemClick { 10 | void onItemClick(View item); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/TreeViewItemLongClick.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by owant on 24/02/2017. 7 | */ 8 | 9 | public interface TreeViewItemLongClick { 10 | void onLongClick(View view); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/owant/thinkmap/view/ViewBox.java: -------------------------------------------------------------------------------- 1 | package com.owant.thinkmap.view; 2 | 3 | /** 4 | * Created by owant on 06/03/2017. 5 | * 用于记录当前树形图的大小 6 | */ 7 | public class ViewBox { 8 | 9 | public int top; 10 | public int left; 11 | public int right; 12 | public int bottom; 13 | 14 | public void clear() { 15 | this.top = 0; 16 | this.left = 0; 17 | this.right = 0; 18 | this.bottom = 0; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return "ViewBox{" + 24 | "top=" + top + 25 | ", left=" + left + 26 | ", right=" + right + 27 | ", bottom=" + bottom + 28 | '}'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/big_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/color/tab_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_edit_input_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/enter_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/node_view_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_purple.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v21/div_edit_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 |