├── .gitignore ├── AndroidProjects.iml ├── ChangeLog.md ├── HeartBeat.iml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── maxiee │ │ └── heartbeat │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── donate_list.html │ ├── label_event_thought.html │ ├── licenses.html │ └── what_heartbeat_is.html │ ├── java │ └── com │ │ └── maxiee │ │ └── heartbeat │ │ ├── HeartBeatApplication.java │ │ ├── backup │ │ ├── BackupAllTask.java │ │ ├── BackupManager.java │ │ ├── FileDES.java │ │ └── RestoreAllTask.java │ │ ├── common │ │ ├── DialogAsyncTask.java │ │ ├── FileUtils.java │ │ ├── FixedHeightScrollingViewBehavior.java │ │ ├── GalleryUtils.java │ │ ├── ThemeUtils.java │ │ ├── TimeUtils.java │ │ ├── cloudview │ │ │ ├── Cloud.java │ │ │ ├── CloudTag.java │ │ │ └── CloudView.java │ │ └── tagview │ │ │ ├── Constants.java │ │ │ ├── Tag.java │ │ │ └── TagView.java │ │ ├── data │ │ ├── BaseEventManager.java │ │ ├── DataManager.java │ │ ├── EventManager.java │ │ └── TodayManager.java │ │ ├── database │ │ ├── DatabaseHelper.java │ │ ├── api │ │ │ ├── AddCrashApi.java │ │ │ ├── BaseDBApi.java │ │ │ ├── GetAllCrashesApi.java │ │ │ ├── GetCountByNameApi.java │ │ │ ├── GetCountSpecDayApi.java │ │ │ └── ImageUriUpgradeApi.java │ │ ├── tables │ │ │ ├── CrashTable.java │ │ │ ├── EventImageRelationTable.java │ │ │ ├── EventLabelRelationTable.java │ │ │ ├── EventThoughtRelationTable.java │ │ │ ├── EventsTable.java │ │ │ ├── ImageTable.java │ │ │ ├── LabelsTable.java │ │ │ ├── ThoughtResTable.java │ │ │ └── ThoughtsTable.java │ │ └── utils │ │ │ ├── DatabaseUtils.java │ │ │ ├── EventUtils.java │ │ │ ├── ImageUtils.java │ │ │ ├── LabelUtils.java │ │ │ └── ThoughtUtils.java │ │ ├── model │ │ ├── Crash.java │ │ ├── DayCard.java │ │ ├── Event.java │ │ ├── Image.java │ │ ├── Label.java │ │ ├── ThoughtRes.java │ │ └── Thoughts.java │ │ ├── provider │ │ ├── Constant.java │ │ ├── HeartBeatContentProvider.java │ │ ├── IProviderEventDelegate.java │ │ ├── IProviderThoughtDelegate.java │ │ ├── ProviderEventDelegate.java │ │ └── ProviderThoughtDelegete.java │ │ ├── support │ │ ├── CrashHandler.java │ │ └── StopWatch.java │ │ ├── ui │ │ ├── AddEditThoughtActivity.java │ │ ├── AddEventActivity.java │ │ ├── CrashDetailActivity.java │ │ ├── CrashListActivity.java │ │ ├── EntryActivity.java │ │ ├── EventDetailActivity.java │ │ ├── GalleryActivity.java │ │ ├── HelpCenterActivity.java │ │ ├── HelpCenterDetailActivity.java │ │ ├── LabelDetailActivity.java │ │ ├── MainActivity.java │ │ ├── PatternActivity.java │ │ ├── SearchResultActivity.java │ │ ├── SettingsActivity.java │ │ ├── adapter │ │ │ ├── CrashListAdapter.java │ │ │ ├── DayCardEventAdapter.java │ │ │ ├── EventListAdapter.java │ │ │ ├── HelpListAdapter.java │ │ │ ├── ThoughtTimeaxisAdapter.java │ │ │ └── TodayEventAdapter.java │ │ ├── common │ │ │ ├── BaseActivity.java │ │ │ ├── HintSearchBox.java │ │ │ ├── RecyclerInsetsDecoration.java │ │ │ ├── ScrollingFABBehavior.java │ │ │ └── mdheaderview │ │ │ │ ├── MDHeaderView.java │ │ │ │ └── TriView.java │ │ └── fragments │ │ │ ├── EventListFragment.java │ │ │ ├── EventTodayFragment.java │ │ │ ├── LabelCloudFragment.java │ │ │ ├── SettingsFragment.java │ │ │ └── StatisticsFragment.java │ │ └── widget │ │ └── HeartBeatWidgetProvider.java │ └── res │ ├── drawable-hdpi │ ├── ic_action_add.png │ ├── ic_action_content_copy.png │ ├── ic_action_dashboard.png │ ├── ic_action_done.png │ ├── ic_action_label.png │ ├── ic_action_list.png │ ├── ic_action_messenger.png │ ├── ic_action_photo.png │ ├── ic_action_reorder.png │ ├── ic_action_search.png │ ├── ic_action_share.png │ ├── ic_action_theaters.png │ ├── ic_action_today.png │ └── ic_action_trending_up.png │ ├── drawable-mdpi │ ├── ic_action_add.png │ ├── ic_action_content_copy.png │ ├── ic_action_dashboard.png │ ├── ic_action_done.png │ ├── ic_action_label.png │ ├── ic_action_list.png │ ├── ic_action_messenger.png │ ├── ic_action_photo.png │ ├── ic_action_reorder.png │ ├── ic_action_search.png │ ├── ic_action_share.png │ ├── ic_action_theaters.png │ ├── ic_action_today.png │ └── ic_action_trending_up.png │ ├── drawable-xhdpi │ ├── ic_action_add.png │ ├── ic_action_content_copy.png │ ├── ic_action_dashboard.png │ ├── ic_action_done.png │ ├── ic_action_label.png │ ├── ic_action_list.png │ ├── ic_action_messenger.png │ ├── ic_action_photo.png │ ├── ic_action_reorder.png │ ├── ic_action_search.png │ ├── ic_action_share.png │ ├── ic_action_theaters.png │ ├── ic_action_today.png │ └── ic_action_trending_up.png │ ├── drawable-xxhdpi │ ├── ic_action_add.png │ ├── ic_action_content_copy.png │ ├── ic_action_dashboard.png │ ├── ic_action_done.png │ ├── ic_action_label.png │ ├── ic_action_list.png │ ├── ic_action_messenger.png │ ├── ic_action_photo.png │ ├── ic_action_reorder.png │ ├── ic_action_search.png │ ├── ic_action_share.png │ ├── ic_action_theaters.png │ ├── ic_action_today.png │ └── ic_action_trending_up.png │ ├── drawable-xxxhdpi │ ├── ic_action_add.png │ ├── ic_action_content_copy.png │ ├── ic_action_dashboard.png │ ├── ic_action_done.png │ ├── ic_action_label.png │ ├── ic_action_list.png │ ├── ic_action_messenger.png │ ├── ic_action_photo.png │ ├── ic_action_reorder.png │ ├── ic_action_search.png │ ├── ic_action_share.png │ ├── ic_action_theaters.png │ ├── ic_action_today.png │ └── ic_action_trending_up.png │ ├── drawable │ ├── card.xml │ ├── circle_timeaxis.xml │ ├── empty_bg.png │ ├── empty_bg1.png │ └── empty_bg2.png │ ├── layout │ ├── activity_add_edit_thought.xml │ ├── activity_add_event.xml │ ├── activity_crash_detail.xml │ ├── activity_crash_list.xml │ ├── activity_entry.xml │ ├── activity_event_detail.xml │ ├── activity_gallery.xml │ ├── activity_help_center.xml │ ├── activity_help_center_detail.xml │ ├── activity_label_detail.xml │ ├── activity_main.xml │ ├── activity_pattern.xml │ ├── activity_search_result.xml │ ├── activity_settings.xml │ ├── dialog_edit_event.xml │ ├── dialog_edit_thought.xml │ ├── dialog_new_label.xml │ ├── dialog_new_thought.xml │ ├── fragment_event_list.xml │ ├── fragment_event_today.xml │ ├── fragment_label_cloud.xml │ ├── fragment_statistics.xml │ ├── include_activity_main.xml │ ├── item_crash_card.xml │ ├── item_day_card.xml │ ├── item_day_card_item.xml │ ├── item_event_card.xml │ ├── item_help_center.xml │ ├── item_thought_timeaxis.xml │ ├── item_today_header.xml │ ├── tagview_item.xml │ ├── toolbar.xml │ └── widget.xml │ ├── menu │ ├── dialog_edit_thought.xml │ ├── dialog_new_thought.xml │ ├── drawer_view.xml │ ├── fragment_eventlist_type.xml │ ├── menu_crash_detail.xml │ ├── menu_event_detail.xml │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── tagview_attr.xml │ └── xml │ ├── settings.xml │ └── widget_info.xml ├── attitude.iml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon.png ├── multi-image-selector ├── .gitignore ├── build.gradle ├── multi-image-selector.iml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── nereo │ │ └── multi_image_selector │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── nereo │ │ └── multi_image_selector │ │ ├── MultiImageSelectorActivity.java │ │ ├── MultiImageSelectorFragment.java │ │ ├── adapter │ │ ├── FolderAdapter.java │ │ └── ImageGridAdapter.java │ │ ├── bean │ │ ├── Folder.java │ │ └── Image.java │ │ ├── utils │ │ ├── FileUtils.java │ │ ├── ScreenUtils.java │ │ └── TimeUtils.java │ │ └── view │ │ ├── SquareFrameLayout.java │ │ └── SquaredImageView.java │ └── res │ ├── color │ ├── default_text_color.xml │ └── folder_text_color.xml │ ├── drawable-xhdpi │ ├── btn_back.png │ ├── default_check_s.png │ ├── ic_menu_back.png │ └── selector_indicator.png │ ├── drawable-xxhdpi │ ├── asv.png │ ├── asy.png │ ├── btn_selected.png │ ├── btn_unselected.png │ ├── default_check.png │ ├── default_error.png │ └── text_indicator.png │ ├── drawable │ └── action_btn.xml │ ├── layout-v14 │ └── fragment_multi_image.xml │ ├── layout │ ├── activity_default.xml │ ├── cmp_customer_actionbar.xml │ ├── fragment_multi_image.xml │ ├── list_item_camera.xml │ ├── list_item_folder.xml │ └── list_item_image.xml │ ├── values-sw360dp │ └── dimens.xml │ ├── values-sw480dp │ └── dimens.xml │ ├── values-sw720dp │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── dimens.xml │ └── strings.xml ├── screenshot.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | .gradle 30 | /local.properties 31 | /.idea/workspace.xml 32 | /.idea/libraries 33 | .DS_Store 34 | /build 35 | /captures 36 | -------------------------------------------------------------------------------- /AndroidProjects.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /HeartBeat.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 | compileSdkVersion 23 5 | buildToolsVersion '23.0.2' 6 | 7 | defaultConfig { 8 | applicationId "com.maxiee.heartbeat" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 29 12 | versionName "0.9.5" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | repositories { 23 | mavenCentral() 24 | maven { url "https://jitpack.io" } 25 | maven { url "https://oss.sonatype.org/content/repositories/snapshots"} 26 | } 27 | 28 | dependencies { 29 | compile fileTree(include: ['*.jar'], dir: 'libs') 30 | compile 'com.github.bumptech.glide:glide:3.6.1' 31 | compile 'com.github.PhilJay:MPAndroidChart:v2.1.0' 32 | compile 'com.quinny898.library.persistentsearch:library:1.1.0-SNAPSHOT' 33 | compile 'com.eftimoff:android-patternview:1.0.2@aar' 34 | compile 'com.android.support:appcompat-v7:23.1.1' 35 | compile 'com.android.support:design:23.1.1' 36 | compile 'com.android.support:cardview-v7:23.1.1' 37 | compile 'com.android.support:recyclerview-v7:23.1.1' 38 | compile 'com.commit451:PhotoView:1.2.4' 39 | compile 'com.jakewharton:butterknife:7.0.1' 40 | compile 'com.wdullaer:materialdatetimepicker:2.1.0' 41 | compile project(':multi-image-selector') 42 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2' 43 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 44 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' 45 | } 46 | -------------------------------------------------------------------------------- /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 /home/maxiee/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/maxiee/heartbeat/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/HeartBeatApplication.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat; 2 | 3 | import android.app.Application; 4 | 5 | import com.squareup.leakcanary.LeakCanary; 6 | 7 | /** 8 | * Created by maxiee on 16/4/18. 9 | */ 10 | public class HeartBeatApplication extends Application { 11 | 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | LeakCanary.install(this); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/backup/BackupAllTask.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.backup; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.os.AsyncTask; 6 | import android.widget.Toast; 7 | 8 | import com.maxiee.heartbeat.R; 9 | 10 | /** 11 | * Created by maxiee on 16/4/21. 12 | */ 13 | public class BackupAllTask extends AsyncTask { 14 | private Context mContext; 15 | ProgressDialog mProgressDialog; 16 | 17 | public BackupAllTask(Context context) { 18 | mContext = context; 19 | } 20 | 21 | @Override 22 | protected void onPreExecute() { 23 | mProgressDialog = new ProgressDialog(mContext); 24 | mProgressDialog.setMessage(mContext.getString(R.string.backuping)); 25 | mProgressDialog.setCancelable(false); 26 | mProgressDialog.show(); 27 | } 28 | 29 | @Override 30 | protected String doInBackground(Void... params) { 31 | return BackupManager.backupAll(mContext); 32 | } 33 | 34 | @Override 35 | protected void onPostExecute(String ret) { 36 | mProgressDialog.cancel(); 37 | if (ret != null) { 38 | Toast.makeText( 39 | mContext, mContext.getString(R.string.backup_ok), 40 | Toast.LENGTH_LONG).show(); 41 | } else { 42 | Toast.makeText( 43 | mContext, mContext.getString(R.string.backup_failed), 44 | Toast.LENGTH_LONG).show(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/backup/FileDES.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.backup; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.security.Key; 9 | 10 | import javax.crypto.Cipher; 11 | import javax.crypto.CipherInputStream; 12 | import javax.crypto.spec.SecretKeySpec; 13 | 14 | /** 15 | * Created by maxiee on 15-8-12. 16 | */ 17 | public class FileDES { 18 | private final static String KEY_RULE = "maxieejudy"; 19 | 20 | private static Key initKey() { 21 | byte[] keyByte = KEY_RULE.getBytes(); 22 | byte[] byteTemp = new byte[8]; 23 | for (int i=0; i 0) { 40 | os.write(buffer, 0, len); 41 | os.flush(); 42 | } 43 | os.close(); 44 | cin.close(); 45 | is.close(); 46 | } catch (Exception e) {e.printStackTrace();} 47 | } 48 | 49 | public static boolean doDecryptFile (InputStream in, OutputStream os) throws Exception{ 50 | if (in == null) return false; 51 | Cipher decryptCipher = Cipher.getInstance("DES"); 52 | decryptCipher.init(Cipher.DECRYPT_MODE, initKey()); 53 | CipherInputStream cin = new CipherInputStream(in, decryptCipher); 54 | byte[] buffer = new byte[1024]; 55 | int len; 56 | while ((len=cin.read(buffer)) > 0) { 57 | os.write(buffer, 0, len); 58 | } 59 | cin.close(); 60 | return true; 61 | } 62 | 63 | public static boolean doDecryptFileNotClose (InputStream in, OutputStream os) throws Exception{ 64 | if (in == null) return false; 65 | Cipher decryptCipher = Cipher.getInstance("DES"); 66 | decryptCipher.init(Cipher.DECRYPT_MODE, initKey()); 67 | CipherInputStream cin = new CipherInputStream(in, decryptCipher); 68 | byte[] buffer = new byte[1024]; 69 | int len; 70 | while ((len=cin.read(buffer)) > 0) { 71 | os.write(buffer, 0, len); 72 | } 73 | return true; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/backup/RestoreAllTask.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.backup; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.AsyncTask; 7 | import android.widget.Toast; 8 | 9 | import com.maxiee.heartbeat.R; 10 | 11 | /** 12 | * Created by maxiee on 16/4/21. 13 | */ 14 | public class RestoreAllTask extends AsyncTask{ 15 | private Context mContext; 16 | ProgressDialog mProgressDialog; 17 | 18 | public RestoreAllTask(Context context) { 19 | mContext = context; 20 | } 21 | 22 | @Override 23 | protected void onPreExecute() { 24 | mProgressDialog = new ProgressDialog(mContext); 25 | mProgressDialog.setMessage(mContext.getString(R.string.restoring)); 26 | mProgressDialog.setCancelable(false); 27 | mProgressDialog.show(); 28 | } 29 | 30 | @Override 31 | protected String doInBackground(Intent... params) { 32 | return BackupManager.restoreAll(mContext, params[0]); 33 | } 34 | 35 | @Override 36 | protected void onPostExecute(String s) { 37 | mProgressDialog.cancel(); 38 | Toast.makeText(mContext, s, Toast.LENGTH_LONG).show(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/common/DialogAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.common; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.os.AsyncTask; 7 | import android.support.v7.app.AlertDialog; 8 | 9 | 10 | /** 11 | * Created by maxiee on 15-5-17. 12 | */ 13 | public abstract class DialogAsyncTask extends AsyncTask{ 14 | 15 | private ProgressDialog progressDialog; 16 | private Context mContext; 17 | protected boolean mTaskSuccess = false; 18 | 19 | public DialogAsyncTask(Context context) { 20 | mContext = context; 21 | } 22 | 23 | @Override 24 | protected void onPreExecute() { 25 | super.onPreExecute(); 26 | progressDialog = new ProgressDialog(mContext); 27 | progressDialog.setMessage("正在提交"); 28 | progressDialog.setCancelable(false); 29 | progressDialog.show(); 30 | } 31 | 32 | @Override 33 | protected void onPostExecute(String msg) { 34 | super.onPostExecute(msg); 35 | progressDialog.dismiss(); 36 | 37 | if (mTaskSuccess) { 38 | showSuccessDialog(msg); 39 | } else { 40 | showFailedDialog(msg); 41 | } 42 | } 43 | 44 | private void showSuccessDialog(String msg) { 45 | new AlertDialog.Builder(mContext) 46 | .setMessage(msg) 47 | .setCancelable(false) 48 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 49 | @Override 50 | public void onClick(DialogInterface dialog, int id) { 51 | dialog.dismiss(); 52 | onFinish(); 53 | } 54 | }) 55 | .create() 56 | .show(); 57 | } 58 | 59 | private void showFailedDialog(String msg) { 60 | new AlertDialog.Builder(mContext) 61 | .setMessage(msg) 62 | .setCancelable(true) 63 | .setNegativeButton(android.R.string.cancel, null) 64 | .create() 65 | .show(); 66 | } 67 | 68 | public Context getmContext() { 69 | return mContext; 70 | } 71 | 72 | public abstract void onFinish(); 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/common/FixedHeightScrollingViewBehavior.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.common; 2 | 3 | /** 4 | * Created by maxiee on 15-6-13. 5 | * 6 | * The cheesesquare project has a bug: 7 | * in layouts using CoordinatorLayout, when there is only one CardView, 8 | * it will display incorrectly. 9 | * 10 | * This class is copy by EmmanuelVinas's Gist which will fix this problem. 11 | * how-to use: 12 | * app:layout_behavior="com.maxiee.attitude.common.FixedHeightScrollingViewBehavior" 13 | */ 14 | import android.content.Context; 15 | import android.support.design.widget.AppBarLayout; 16 | import android.support.design.widget.CoordinatorLayout; 17 | import android.support.v4.view.ViewCompat; 18 | import android.util.AttributeSet; 19 | import android.view.View; 20 | 21 | import java.util.List; 22 | 23 | public class FixedHeightScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior{ 24 | 25 | public FixedHeightScrollingViewBehavior() { 26 | } 27 | 28 | public FixedHeightScrollingViewBehavior(Context context, AttributeSet attrs) { 29 | super(context, attrs); 30 | } 31 | 32 | public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { 33 | if(child.getLayoutParams().height == -1) { 34 | List dependencies = parent.getDependencies(child); 35 | if(dependencies.isEmpty()) { 36 | return false; 37 | } 38 | 39 | AppBarLayout appBar = findFirstAppBarLayout(dependencies); 40 | if(appBar != null && ViewCompat.isLaidOut(appBar)) { 41 | if(ViewCompat.getFitsSystemWindows(appBar)) { 42 | ViewCompat.setFitsSystemWindows(child, true); 43 | } 44 | 45 | int scrollRange = appBar.getTotalScrollRange(); 46 | int height = parent.getHeight() - appBar.getMeasuredHeight() + Math.min(scrollRange, parent.getHeight()- heightUsed); 47 | int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); 48 | parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed); 49 | return true; 50 | } 51 | } 52 | 53 | return false; 54 | } 55 | 56 | private static AppBarLayout findFirstAppBarLayout(List views) { 57 | int i = 0; 58 | 59 | for(int z = views.size(); i < z; ++i) { 60 | View view = (View)views.get(i); 61 | if(view instanceof AppBarLayout) { 62 | return (AppBarLayout)view; 63 | } 64 | } 65 | 66 | return null; 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/common/cloudview/Cloud.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.common.cloudview; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * Created by maxiee on 15-6-24. 12 | * 13 | * Modified from: luixal/android-tagcloud 14 | * https://github.com/luixal/android-tagcloud 15 | * 16 | */ 17 | public class Cloud { 18 | 19 | public enum Rounding { 20 | CEIL, 21 | FLOOR, 22 | ROUND 23 | } 24 | 25 | private Map cloud = new HashMap<>(); 26 | 27 | private double minWeight = 0.0; 28 | private double maxWeight = 4.0; 29 | 30 | private int maxTagToDisplay = 50; 31 | 32 | /* tags having score under the threshold are excluded. */ 33 | private double threshold = 0.0; 34 | 35 | /* tags' timestamp older than tagLifetime are excluded. */ 36 | private long tagLifetime = -1; 37 | 38 | private Rounding rounding = Rounding.CEIL; 39 | 40 | public Cloud() {} 41 | 42 | public void addTag(CloudTag tag) { 43 | if (tag == null) { 44 | return; 45 | } 46 | 47 | String key = tag.getName(); 48 | if (cloud.containsKey(key)) { 49 | tag.addScore(cloud.get(key).getScore()); 50 | } 51 | 52 | cloud.put(key, tag); 53 | } 54 | 55 | public void addTags(Collection tags) { 56 | if (tags == null) { 57 | return; 58 | } 59 | 60 | Iterator it = tags.iterator(); 61 | while (it.hasNext()) { 62 | addTag(it.next()); 63 | } 64 | } 65 | 66 | protected List getOutputTags() { 67 | List emptyList = new LinkedList<>(); 68 | 69 | if (getCloud() == null) { 70 | return emptyList; 71 | } 72 | 73 | List result = new LinkedList<>(); 74 | Iterator it = getCloud().values().iterator(); 75 | CloudTag tag; 76 | 77 | double max = 0.0; 78 | 79 | while (it.hasNext()) { 80 | tag = it.next(); 81 | 82 | // if (tag.getScore() < threshold || 83 | // tag.getTimestamp() < tagLifetime) { 84 | // continue; 85 | // } 86 | 87 | result.add(tag); 88 | 89 | if (tag.getScore() > max) { 90 | max = tag.getScore(); 91 | } 92 | } 93 | 94 | return result; 95 | } 96 | 97 | protected Map getCloud() { 98 | return cloud; 99 | } 100 | 101 | public void setMaxWeight(double maxWeight) { 102 | this.maxWeight = maxWeight; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/common/cloudview/CloudTag.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.common.cloudview; 2 | 3 | /** 4 | * Created by maxiee on 15-6-24. 5 | */ 6 | public class CloudTag { 7 | 8 | private String name; 9 | private double score = 1.0; 10 | private double normScore = 0.0; 11 | private double weight = 10.0; 12 | private long timestamp; 13 | 14 | public CloudTag() {} 15 | 16 | public CloudTag(String name) { 17 | this.name = name; 18 | } 19 | 20 | public CloudTag(String name, int score) { 21 | this.name = name; 22 | this.score = score; 23 | } 24 | 25 | public double getScore() { 26 | return score; 27 | } 28 | 29 | public long getTimestamp() { 30 | return timestamp; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public int getWeightInt() { 38 | return (int) Math.ceil(score * weight); 39 | } 40 | 41 | public void setWeight(double weight) { 42 | this.weight = weight; 43 | } 44 | 45 | public void addScore(double val) { 46 | score += val; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/common/tagview/Constants.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.common.tagview; 2 | 3 | import android.graphics.Color; 4 | 5 | /** 6 | * Created by maxiee on 15-6-16. 7 | * 8 | * Modify from kaedea/Android-Cloud-TagView-Plus (https://github.com/kaedea/Android-Cloud-TagView-Plus) 9 | * 10 | */ 11 | public class Constants { 12 | 13 | //use dp and sp, not px 14 | 15 | //----------------- separator TagView-----------------// 16 | public static final float DEFAULT_LINE_MARGIN = 5; 17 | public static final float DEFAULT_TAG_MARGIN = 5; 18 | public static final float DEFAULT_TAG_TEXT_PADDING_LEFT = 8; 19 | public static final float DEFAULT_TAG_TEXT_PADDING_TOP = 5; 20 | public static final float DEFAULT_TAG_TEXT_PADDING_RIGHT = 8; 21 | public static final float DEFAULT_TAG_TEXT_PADDING_BOTTOM = 5; 22 | 23 | public static final float LAYOUT_WIDTH_OFFSET = 2; 24 | 25 | //----------------- separator Tag Item-----------------// 26 | public static final float DEFAULT_TAG_TEXT_SIZE = 14f; 27 | public static final float DEFAULT_TAG_DELETE_INDICATOR_SIZE = 14f; 28 | public static final float DEFAULT_TAG_LAYOUT_BORDER_SIZE = 0f; 29 | public static final float DEFAULT_TAG_RADIUS = 10; 30 | public static final int DEFAULT_TAG_LAYOUT_COLOR = Color.parseColor("#EF9A9A"); 31 | public static final int DEFAULT_TAG_LAYOUT_COLOR_PRESS = Color.parseColor("#88363636"); 32 | public static final int DEFAULT_TAG_TEXT_COLOR = Color.parseColor("#ffffff"); 33 | public static final int DEFAULT_TAG_DELETE_INDICATOR_COLOR = Color.parseColor("#ffffff"); 34 | public static final int DEFAULT_TAG_LAYOUT_BORDER_COLOR = Color.parseColor("#ffffff"); 35 | public static final String DEFAULT_TAG_DELETE_ICON = "×"; 36 | public static final boolean DEFAULT_TAG_IS_DELETABLE = false; 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/data/BaseEventManager.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.data; 2 | 3 | import android.content.Context; 4 | 5 | import com.maxiee.heartbeat.model.Event; 6 | 7 | import java.util.ArrayList; 8 | 9 | /** 10 | * Created by maxiee on 15/11/10. 11 | */ 12 | abstract class BaseEventManager { 13 | 14 | protected Context mContext; 15 | protected ArrayList mEventList; 16 | 17 | public BaseEventManager(Context context) { 18 | mContext = context; 19 | } 20 | 21 | abstract void reload(); 22 | 23 | public ArrayList getEvents() { 24 | return mEventList; 25 | } 26 | 27 | public void addEvent(Event event) { 28 | for (int i=0; i e.getTimestamp()) { 31 | mEventList.add(i, event); 32 | return; 33 | } 34 | } 35 | mEventList.add(event); 36 | } 37 | 38 | public void deleteEvent(long key) { 39 | int indexEvent = findFromList(key, mEventList); 40 | if (indexEvent >= 0) mEventList.remove(indexEvent); 41 | } 42 | 43 | public void updateEvent(Event e) { 44 | int indexEvent = findFromList(e.getId(), mEventList); 45 | mEventList.remove(indexEvent); 46 | addEvent(e); 47 | } 48 | 49 | public boolean isEmpty() { 50 | return mEventList.isEmpty(); 51 | } 52 | 53 | public int size() { 54 | return mEventList.size(); 55 | } 56 | 57 | private static int findFromList(long key, ArrayList list) { 58 | for (int i=0; i mData = new ArrayList<>(); 20 | 21 | public EventManager(Context context) { 22 | super(context); 23 | reload(); 24 | } 25 | 26 | @Override 27 | public void reload() { 28 | if (mEventList != null) mEventList.clear(); 29 | mEventList = EventUtils.getAllEvents(mContext); 30 | reloadDayCardData(); 31 | } 32 | 33 | public void reloadDayCardData() { 34 | StopWatch stopWatch = new StopWatch(TAG, "reloadDayCardData use time"); 35 | mData.clear(); 36 | parseData(mEventList); 37 | stopWatch.stop(); 38 | } 39 | 40 | private void parseData(ArrayList eventList) { 41 | long dayStart = Long.MIN_VALUE; 42 | DayCard dayCard = null; 43 | for (Event e : eventList) { 44 | if (dayCard == null) { 45 | dayStart = TimeUtils.getDayStart(e.getTimestamp()); 46 | dayCard = new DayCard(dayStart, e); 47 | continue; 48 | } 49 | if (TimeUtils.isInSameDay(dayStart, e.getTimestamp())) { 50 | dayCard.addEvent(e); 51 | } else { 52 | mData.add(dayCard); 53 | dayStart = TimeUtils.getDayStart(e.getTimestamp()); 54 | dayCard = new DayCard(dayStart, e); 55 | } 56 | } 57 | if (dayCard != null) mData.add(dayCard); 58 | } 59 | 60 | public ArrayList getDayCardData() {return mData;} 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/data/TodayManager.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.data; 2 | 3 | import android.content.Context; 4 | 5 | import com.maxiee.heartbeat.database.utils.EventUtils; 6 | import com.maxiee.heartbeat.database.utils.ThoughtUtils; 7 | import com.maxiee.heartbeat.model.Event; 8 | 9 | import java.util.ArrayList; 10 | 11 | /** 12 | * Created by maxiee on 15/11/10. 13 | */ 14 | public class TodayManager extends BaseEventManager{ 15 | 16 | public TodayManager(Context context) { 17 | super(context); 18 | mEventList = new ArrayList<>(); 19 | reload(); 20 | } 21 | 22 | @Override 23 | void reload() { 24 | if (mEventList != null) mEventList.clear(); 25 | mEventList.addAll(EventUtils.getToday(mContext)); 26 | } 27 | 28 | @Override 29 | public void addEvent(Event event) { 30 | reload(); 31 | } 32 | 33 | @Override 34 | public void updateEvent(Event e) { 35 | reload(); 36 | } 37 | 38 | public int countTodayThought() { 39 | return ThoughtUtils.getTodayCount(mContext); 40 | } 41 | 42 | public int countTodayEvent() { 43 | return mEventList.size(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/DatabaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | import com.maxiee.heartbeat.database.api.ImageUriUpgradeApi; 8 | import com.maxiee.heartbeat.database.tables.CrashTable; 9 | import com.maxiee.heartbeat.database.tables.EventImageRelationTable; 10 | import com.maxiee.heartbeat.database.tables.EventLabelRelationTable; 11 | import com.maxiee.heartbeat.database.tables.EventThoughtRelationTable; 12 | import com.maxiee.heartbeat.database.tables.EventsTable; 13 | import com.maxiee.heartbeat.database.tables.ImageTable; 14 | import com.maxiee.heartbeat.database.tables.LabelsTable; 15 | import com.maxiee.heartbeat.database.tables.ThoughtResTable; 16 | import com.maxiee.heartbeat.database.tables.ThoughtsTable; 17 | 18 | /** 19 | * Created by maxiee on 15-6-11. 20 | */ 21 | public class DatabaseHelper extends SQLiteOpenHelper { 22 | 23 | private final static String DB_NAME = "heartbeat"; 24 | private final static int DB_VER = 4; 25 | 26 | private static DatabaseHelper instance; 27 | private Context mContext; 28 | 29 | private DatabaseHelper(Context context) { 30 | super(context, DB_NAME, null, DB_VER); 31 | mContext = context; 32 | } 33 | 34 | @Override 35 | public void onCreate(SQLiteDatabase db) { 36 | db.execSQL(EventsTable.CREATE); 37 | db.execSQL(LabelsTable.CREATE); 38 | db.execSQL(EventLabelRelationTable.CREATE); 39 | db.execSQL(ThoughtsTable.CREATE); 40 | db.execSQL(EventThoughtRelationTable.CREATE); 41 | db.execSQL(ImageTable.CREATE); 42 | db.execSQL(EventImageRelationTable.CREATE); 43 | db.execSQL(CrashTable.CREATE); 44 | db.execSQL(ThoughtResTable.CREATE); 45 | } 46 | 47 | @Override 48 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 49 | if (oldVersion == 1) { 50 | db.execSQL(ImageTable.CREATE); 51 | db.execSQL(EventImageRelationTable.CREATE); 52 | } 53 | if (oldVersion <= 2) { 54 | db.execSQL(CrashTable.CREATE); 55 | } 56 | if (oldVersion <= 3) { 57 | db.execSQL(ThoughtResTable.CREATE); 58 | // upgrade items in ImageTable 59 | ImageUriUpgradeApi.exec(mContext, db); 60 | } 61 | } 62 | 63 | public static synchronized DatabaseHelper instance(Context context) { 64 | if (instance == null) { 65 | instance = new DatabaseHelper(context); 66 | } 67 | return instance; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/api/AddCrashApi.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database.api; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | 6 | import com.maxiee.heartbeat.database.tables.CrashTable; 7 | 8 | /** 9 | * Created by maxiee on 15-7-11. 10 | */ 11 | public class AddCrashApi extends BaseDBApi{ 12 | 13 | private String mLog; 14 | 15 | public AddCrashApi(Context context, 16 | String log) { 17 | super(context); 18 | mLog = log; 19 | } 20 | 21 | public void exec() { 22 | ContentValues values = new ContentValues(); 23 | values.put(CrashTable.LOG, mLog); 24 | values.put(CrashTable.TIMESTAMP, System.currentTimeMillis()); 25 | add(CrashTable.NAME, values); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/api/BaseDBApi.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database.api; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | import android.database.sqlite.SQLiteDatabase; 6 | 7 | import com.maxiee.heartbeat.database.DatabaseHelper; 8 | 9 | /** 10 | * Created by maxiee on 15-6-11. 11 | */ 12 | public abstract class BaseDBApi { 13 | 14 | public static final String THOUGHT = "thought"; 15 | public static final String TIMESTAMP = "timestamp"; 16 | 17 | protected DatabaseHelper mDatabaseHelper; 18 | protected Context mContext; 19 | 20 | public BaseDBApi(Context context) { 21 | mDatabaseHelper = DatabaseHelper.instance(context); 22 | mContext = context; 23 | } 24 | 25 | protected long add(String table, ContentValues values) { 26 | SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); 27 | db.beginTransaction(); 28 | long key = db.insert(table, null, values); 29 | db.setTransactionSuccessful(); 30 | db.endTransaction(); 31 | 32 | return key; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/api/GetAllCrashesApi.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database.api; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | 6 | import com.maxiee.heartbeat.database.tables.CrashTable; 7 | import com.maxiee.heartbeat.model.Crash; 8 | 9 | import java.util.ArrayList; 10 | 11 | /** 12 | * Created by maxiee on 15-7-11. 13 | */ 14 | public class GetAllCrashesApi extends BaseDBApi { 15 | public GetAllCrashesApi(Context context) { 16 | super(context); 17 | } 18 | 19 | public ArrayList exec() { 20 | Cursor cursor = mDatabaseHelper.getReadableDatabase().query( 21 | CrashTable.NAME, 22 | new String[] { 23 | CrashTable.LOG, 24 | CrashTable.TIMESTAMP 25 | }, 26 | null, 27 | null, null, null, null 28 | ); 29 | 30 | ArrayList crashes = new ArrayList<>(); 31 | 32 | if (cursor.getCount() < 1) 33 | return crashes; 34 | 35 | cursor.moveToFirst(); 36 | do { 37 | String log = cursor.getString( 38 | cursor.getColumnIndex(CrashTable.LOG) 39 | ); 40 | long timestamp = cursor.getLong( 41 | cursor.getColumnIndex(CrashTable.TIMESTAMP) 42 | ); 43 | crashes.add(0, new Crash(log, timestamp)); 44 | } while (cursor.moveToNext()); 45 | 46 | cursor.close(); 47 | return crashes; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/api/GetCountByNameApi.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database.api; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.database.DatabaseUtils; 6 | 7 | import com.maxiee.heartbeat.database.tables.EventsTable; 8 | import com.maxiee.heartbeat.database.tables.ThoughtsTable; 9 | 10 | /** 11 | * Created by maxiee on 15-7-16. 12 | */ 13 | public class GetCountByNameApi extends BaseDBApi{ 14 | public final static String EVENT = EventsTable.NAME; 15 | public final static String THOUGHT = ThoughtsTable.NAME; 16 | 17 | public GetCountByNameApi(Context context) { 18 | super(context); 19 | } 20 | 21 | public long exec(String table) { 22 | return DatabaseUtils.queryNumEntries(mDatabaseHelper.getReadableDatabase(), table); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/database/api/GetCountSpecDayApi.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.database.api; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | 6 | import com.maxiee.heartbeat.database.tables.EventsTable; 7 | import com.maxiee.heartbeat.database.tables.ThoughtsTable; 8 | 9 | import java.util.Calendar; 10 | 11 | /** 12 | * Created by maxiee on 15-7-16. 13 | */ 14 | public class GetCountSpecDayApi extends BaseDBApi { 15 | public final static String EVENT = EventsTable.NAME; 16 | public final static String THOUGHT = ThoughtsTable.NAME; 17 | 18 | public GetCountSpecDayApi(Context context) { 19 | super(context); 20 | } 21 | 22 | public int exec(Calendar calendarFrom, String tableName) { 23 | Calendar calendarTo = (Calendar) calendarFrom.clone(); 24 | calendarTo.add(Calendar.DAY_OF_MONTH, 1); 25 | 26 | Cursor cursor = mDatabaseHelper.getReadableDatabase().query( 27 | tableName, 28 | new String[] { 29 | EventsTable.ID 30 | }, 31 | EventsTable.TIMESTAMP + ">? and " + EventsTable.TIMESTAMP + " mEventList; 11 | 12 | public DayCard (long timeStamp, Event event) { 13 | mTimeStamp = timeStamp; 14 | mEventList = new ArrayList<>(); 15 | mEventList.add(event); 16 | } 17 | 18 | public void addEvent(Event event) { 19 | mEventList.add(event); 20 | } 21 | 22 | public long getTimeStamp() {return mTimeStamp;} 23 | 24 | public ArrayList getEventList() {return mEventList;} 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/model/Event.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.model; 2 | 3 | /** 4 | * Created by maxiee on 15-6-12. 5 | */ 6 | public class Event { 7 | private String mEvent; 8 | private long timestamp; 9 | private long mId; 10 | 11 | public Event( 12 | int id, 13 | String mEvent, 14 | long timestamp) { 15 | this.mId = id; 16 | this.mEvent = mEvent; 17 | this.timestamp = timestamp; 18 | } 19 | 20 | public Event( 21 | long id, 22 | String mEvent, 23 | long timestamp) { 24 | this.mId = (int) id; 25 | this.mEvent = mEvent; 26 | this.timestamp = timestamp; 27 | } 28 | 29 | public String getEvent() { 30 | return mEvent; 31 | } 32 | 33 | public long getTimestamp() { 34 | return timestamp; 35 | } 36 | 37 | public long getId() { 38 | return mId; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return String.format("[%d][%s]\n", mId, mEvent); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/model/Image.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.model; 2 | 3 | /** 4 | * Created by maxiee on 15/11/10. 5 | */ 6 | public class Image { 7 | private long mId; 8 | private String mPath; 9 | 10 | public Image(long id, String path) { 11 | mId = id; 12 | mPath = path; 13 | } 14 | 15 | public long getId() { 16 | return mId; 17 | } 18 | 19 | public String getPath() { 20 | return mPath; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/model/Label.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.model; 2 | 3 | /** 4 | * Created by maxiee on 15-7-10. 5 | */ 6 | public class Label { 7 | private long mId; 8 | private String mLabel; 9 | 10 | public Label(long key, String label) { 11 | this.mId = key; 12 | this.mLabel = label; 13 | } 14 | 15 | public long getId() {return mId;} 16 | 17 | public String getLabel() {return mLabel;} 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/model/ThoughtRes.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.model; 2 | 3 | /** 4 | * Created by maxiee on 15/11/11. 5 | */ 6 | public class ThoughtRes { 7 | private long id; 8 | private int resType; 9 | private String path; 10 | private long thoughtId; 11 | 12 | public ThoughtRes(long id, int resType, String path, long thoughtId) { 13 | this.id = id; 14 | this.resType = resType; 15 | this.path = path; 16 | this.thoughtId = thoughtId; 17 | } 18 | 19 | public long getId() { 20 | return id; 21 | } 22 | 23 | public void setId(long id) { 24 | this.id = id; 25 | } 26 | 27 | public int getResType() { 28 | return resType; 29 | } 30 | 31 | public void setResType(int resType) { 32 | this.resType = resType; 33 | } 34 | 35 | public String getPath() { 36 | return path; 37 | } 38 | 39 | public void setPath(String path) { 40 | this.path = path; 41 | } 42 | 43 | public long getThoughtId() { 44 | return thoughtId; 45 | } 46 | 47 | public void setThoughtId(long thoughtId) { 48 | this.thoughtId = thoughtId; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/Constant.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | /** 4 | * Created by maxiee on 16/1/10. 5 | */ 6 | public class Constant { 7 | public static final String BASE_URI = "com.maxiee.heartbeat.provider"; 8 | public static final String CATEGORY_EVNET = "event/"; 9 | public static final String CATEGORY_THOUGHT = "thought/"; 10 | public static final String CATEGORY_THOUGHT_RES = "thought_res/"; 11 | 12 | public static final String API_EVENT_RANDOM = CATEGORY_EVNET + "random"; 13 | public static final String API_EVENT_ID = CATEGORY_EVNET + "id/#"; 14 | public static final String API_THOUGHT_EVENT_ID = CATEGORY_THOUGHT + "event_id/#"; 15 | public static final String API_THOUGHT_RES_THOUGHT_ID = CATEGORY_THOUGHT_RES + "thought_id/#"; 16 | 17 | public static final int API_EVENT_RANDOM_CODE = 0; 18 | public static final int API_EVENT_ID_CODE = 1; 19 | public static final int API_THOUGHT_EVENT_ID_CODE = 2; 20 | public static final int API_THOUGHT_RES_THOUGHT_ID_CODE = 3; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/HeartBeatContentProvider.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.content.UriMatcher; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | 9 | /** 10 | * Created by maxiee on 16/1/9. 11 | */ 12 | public class HeartBeatContentProvider extends ContentProvider { 13 | private UriMatcher mMatcher; 14 | private IProviderEventDelegate mEventDelegate; 15 | private IProviderThoughtDelegate mThoughtDelegate; 16 | 17 | @Override 18 | public boolean onCreate() { 19 | initMatcher(); 20 | mEventDelegate = new ProviderEventDelegate(); 21 | mThoughtDelegate = new ProviderThoughtDelegete(); 22 | return false; 23 | } 24 | 25 | @Override 26 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 27 | int code = mMatcher.match(uri); 28 | Cursor cursor = null; 29 | cursor = mEventDelegate.dispatchQuery(code, getContext(), uri); 30 | if (cursor != null) return cursor; 31 | cursor = mThoughtDelegate.dispatchQuery(code, getContext(), uri); 32 | if (cursor != null) return cursor; 33 | return null; 34 | } 35 | 36 | @Override 37 | public String getType(Uri uri) { 38 | return null; 39 | } 40 | 41 | @Override 42 | public Uri insert(Uri uri, ContentValues values) { 43 | return null; 44 | } 45 | 46 | @Override 47 | public int delete(Uri uri, String selection, String[] selectionArgs) { 48 | return 0; 49 | } 50 | 51 | @Override 52 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 53 | return 0; 54 | } 55 | 56 | private void initMatcher() { 57 | mMatcher = new UriMatcher(UriMatcher.NO_MATCH); 58 | //TODO wrap into delegates 59 | mMatcher.addURI(Constant.BASE_URI, Constant.API_EVENT_RANDOM, Constant.API_EVENT_RANDOM_CODE); 60 | mMatcher.addURI(Constant.BASE_URI, Constant.API_EVENT_ID, Constant.API_EVENT_ID_CODE); 61 | mMatcher.addURI(Constant.BASE_URI, Constant.API_THOUGHT_EVENT_ID, Constant.API_THOUGHT_EVENT_ID_CODE); 62 | mMatcher.addURI(Constant.BASE_URI, Constant.API_THOUGHT_RES_THOUGHT_ID, Constant.API_THOUGHT_RES_THOUGHT_ID_CODE); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/IProviderEventDelegate.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | 7 | /** 8 | * Created by maxiee on 16/1/10. 9 | */ 10 | public interface IProviderEventDelegate { 11 | Cursor dispatchQuery(int code, Context context, Uri uri); 12 | Cursor random(Context context); 13 | Cursor byId(Context context, long id); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/IProviderThoughtDelegate.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | 7 | /** 8 | * Created by maxiee on 16/1/31. 9 | */ 10 | public interface IProviderThoughtDelegate { 11 | Cursor dispatchQuery(int code, Context context, Uri uri); 12 | Cursor getThought(Context context, long eventId); 13 | Cursor getThoughtRes(Context context, long thoughtId); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/ProviderEventDelegate.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | import android.content.ContentUris; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | 8 | import com.maxiee.heartbeat.database.api.GetCountByNameApi; 9 | import com.maxiee.heartbeat.database.tables.EventsTable; 10 | import com.maxiee.heartbeat.database.utils.DatabaseUtils; 11 | 12 | import java.util.Random; 13 | 14 | /** 15 | * Created by maxiee on 16/1/10. 16 | */ 17 | public class ProviderEventDelegate implements IProviderEventDelegate { 18 | @Override 19 | public Cursor dispatchQuery(int code, Context context, Uri uri) { 20 | switch (code) { 21 | case Constant.API_EVENT_RANDOM_CODE: { 22 | return random(context); 23 | } 24 | case Constant.API_EVENT_ID_CODE: { 25 | long id = ContentUris.parseId(uri); 26 | return byId(context, id); 27 | } 28 | default: { 29 | return null; 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public Cursor random(Context context) { 36 | long eventCount = new GetCountByNameApi(context).exec(GetCountByNameApi.EVENT); 37 | int randIndex = (int) (new Random().nextDouble() * eventCount); 38 | Cursor cursor = DatabaseUtils.getReadableDatabase(context).rawQuery( 39 | "SELECT " + EventsTable.ID + ", " + EventsTable.EVENT + ", " + EventsTable.TIMESTAMP 40 | + " FROM " + EventsTable.NAME + " LIMIT 1 OFFSET " + String.valueOf(randIndex), null); 41 | return cursor; 42 | } 43 | 44 | @Override 45 | public Cursor byId(Context context, long id) { 46 | Cursor cursor = DatabaseUtils.getReadableDatabase(context).rawQuery( 47 | "SELECT " + EventsTable.ID + ", " + EventsTable.EVENT + ", " + EventsTable.TIMESTAMP 48 | + " FROM " + EventsTable.NAME + " LIMIT 1 OFFSET " + String.valueOf(id), null); 49 | return cursor; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/provider/ProviderThoughtDelegete.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.provider; 2 | 3 | import android.content.ContentUris; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | 8 | import com.maxiee.heartbeat.database.tables.EventThoughtRelationTable; 9 | import com.maxiee.heartbeat.database.tables.ThoughtResTable; 10 | import com.maxiee.heartbeat.database.tables.ThoughtsTable; 11 | import com.maxiee.heartbeat.database.utils.DatabaseUtils; 12 | 13 | /** 14 | * Created by maxiee on 16/1/31. 15 | */ 16 | public class ProviderThoughtDelegete implements IProviderThoughtDelegate{ 17 | @Override 18 | public Cursor dispatchQuery(int code, Context context, Uri uri) { 19 | switch (code) { 20 | case Constant.API_THOUGHT_EVENT_ID_CODE: { 21 | long id = ContentUris.parseId(uri); 22 | return getThought(context, id); 23 | } 24 | case Constant.API_THOUGHT_RES_THOUGHT_ID_CODE: { 25 | long id = ContentUris.parseId(uri); 26 | return getThoughtRes(context, id); 27 | } 28 | default: { 29 | return null; 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public Cursor getThought(Context context, long eventId) { 36 | final String rawSQL = 37 | "SELECT " + ThoughtsTable.NAME + "." + ThoughtsTable.ID + ", " + ThoughtsTable.THOUGHT + ", " + ThoughtsTable.TIMESTAMP + ", " 38 | + EventThoughtRelationTable.EVENT_ID + " FROM " + ThoughtsTable.NAME + " JOIN " + EventThoughtRelationTable.NAME 39 | + " ON " + ThoughtsTable.NAME + "." + ThoughtsTable.ID + "=" + EventThoughtRelationTable.NAME + "." + EventThoughtRelationTable.THOUGHT_ID 40 | + " WHERE " + EventThoughtRelationTable.EVENT_ID + "=?" 41 | + " ORDER BY " + ThoughtsTable.TIMESTAMP + " ASC;"; 42 | return DatabaseUtils.getReadableDatabase(context).rawQuery( 43 | rawSQL, 44 | new String[] { String.valueOf(eventId)}); 45 | } 46 | 47 | @Override 48 | public Cursor getThoughtRes(Context context, long thoughtId) { 49 | return DatabaseUtils.query( 50 | context, ThoughtResTable.NAME, 51 | new String[] {ThoughtResTable.ID, ThoughtResTable.THOUGHT_ID, ThoughtResTable.TYPE, ThoughtResTable.PATH}, 52 | ThoughtResTable.THOUGHT_ID + "=?", 53 | new String[] {String.valueOf(thoughtId)}); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/support/CrashHandler.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.support; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.os.Build; 6 | import android.util.Log; 7 | 8 | import com.maxiee.heartbeat.database.api.AddCrashApi; 9 | 10 | /** 11 | * Created by maxiee on 15-7-11. 12 | * 13 | * Learning from BlackLight (https://github.com/PaperAirplane-Dev-Team/BlackLight) 14 | */ 15 | public class CrashHandler implements Thread.UncaughtExceptionHandler{ 16 | 17 | private static String ANDROID = Build.VERSION.RELEASE; 18 | private static String MODEL = Build.MODEL; 19 | private static String MANUFACTURER = Build.MANUFACTURER; 20 | 21 | public static String VERSION = "Unknown"; 22 | 23 | private Thread.UncaughtExceptionHandler mPrevious; 24 | private Context mContext; 25 | 26 | public void init(Context context) { 27 | mContext = context; 28 | try { 29 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 30 | VERSION = info.versionName + " (" + info.versionCode + ")"; 31 | } catch (Exception e) { 32 | throw new RuntimeException(e); 33 | } 34 | } 35 | 36 | public static void register(Context context) { 37 | new CrashHandler().init(context); 38 | } 39 | 40 | private CrashHandler() { 41 | mPrevious = Thread.currentThread().getUncaughtExceptionHandler(); 42 | Thread.currentThread().setUncaughtExceptionHandler(this); 43 | } 44 | 45 | @Override 46 | public void uncaughtException(Thread thread, Throwable throwable) { 47 | String log = ""; 48 | 49 | log += "Android Version: " + ANDROID + "\n"; 50 | log += "Device Model: " + MODEL + "\n"; 51 | log += "Device Manufacturer: " + MANUFACTURER + "\n"; 52 | log += "App Version: " + VERSION + "\n"; 53 | log += "*********************\n"; 54 | log += throwable.toString() + "\n"; 55 | log += Log.getStackTraceString(throwable); 56 | 57 | new AddCrashApi(mContext, log).exec(); 58 | 59 | if (mPrevious != null) { 60 | mPrevious.uncaughtException(thread, throwable); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/support/StopWatch.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.support; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by maxiee on 15/12/9. 7 | */ 8 | public class StopWatch { 9 | private String mWords, mTag; 10 | private long mCurrent; 11 | 12 | public StopWatch(String tag, String words) { 13 | mTag = tag; 14 | mWords = words; 15 | mCurrent = System.currentTimeMillis(); 16 | } 17 | 18 | public void stop() { 19 | long now = System.currentTimeMillis(); 20 | Log.d(mTag, String.format("[%.4fs]%s\n", (now - mCurrent) / 1000f, mWords)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/CrashDetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.content.ClipData; 4 | import android.content.ClipboardManager; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.widget.TextView; 11 | import android.widget.Toast; 12 | 13 | import com.maxiee.heartbeat.R; 14 | import com.maxiee.heartbeat.model.Crash; 15 | import com.maxiee.heartbeat.ui.common.BaseActivity; 16 | 17 | /** 18 | * Created by maxiee on 15-7-11. 19 | */ 20 | public class CrashDetailActivity extends BaseActivity { 21 | 22 | private Toolbar mToolbar; 23 | private TextView mTvCrash; 24 | private String mCrash; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_crash_detail); 30 | 31 | mToolbar = (Toolbar) findViewById(R.id.toolbar); 32 | setSupportActionBar(mToolbar); 33 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 34 | 35 | mTvCrash = (TextView) findViewById(R.id.tv_crash); 36 | 37 | Intent intent = getIntent(); 38 | mCrash = intent.getStringExtra(Crash.LOG); 39 | mTvCrash.setText(mCrash); 40 | 41 | setTitle(getString(R.string.settings_crash)); 42 | } 43 | 44 | @Override 45 | public boolean onCreateOptionsMenu(Menu menu) { 46 | getMenuInflater().inflate(R.menu.menu_crash_detail, menu); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onOptionsItemSelected(MenuItem item) { 52 | int id = item.getItemId(); 53 | if(id == R.id.clip_board) { 54 | ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); 55 | ClipData clip = ClipData.newPlainText("crash report", mCrash); 56 | clipboard.setPrimaryClip(clip); 57 | Toast.makeText(CrashDetailActivity.this, getString(R.string.copy_finished), Toast.LENGTH_LONG).show(); 58 | } 59 | if(id == R.id.share) { 60 | Intent sendIntent = new Intent(); 61 | sendIntent.setAction(Intent.ACTION_SEND); 62 | sendIntent.putExtra(Intent.EXTRA_TEXT, mCrash); 63 | sendIntent.setType("text/plain"); 64 | startActivity(sendIntent); 65 | } 66 | return super.onOptionsItemSelected(item); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/CrashListActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.MenuItem; 8 | 9 | import com.maxiee.heartbeat.R; 10 | import com.maxiee.heartbeat.database.api.GetAllCrashesApi; 11 | import com.maxiee.heartbeat.model.Crash; 12 | import com.maxiee.heartbeat.ui.adapter.CrashListAdapter; 13 | import com.maxiee.heartbeat.ui.common.BaseActivity; 14 | 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * Created by maxiee on 15-7-11. 19 | */ 20 | public class CrashListActivity extends BaseActivity { 21 | 22 | private Toolbar mToolbar; 23 | private RecyclerView mRecyclerView; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_crash_list); 29 | 30 | mToolbar = (Toolbar) findViewById(R.id.toolbar); 31 | setSupportActionBar(mToolbar); 32 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 33 | 34 | mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview); 35 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 36 | 37 | ArrayList crashes = new GetAllCrashesApi(this).exec(); 38 | mRecyclerView.setAdapter(new CrashListAdapter(crashes)); 39 | 40 | setTitle(getString(R.string.settings_crash)); 41 | } 42 | 43 | @Override 44 | public boolean onOptionsItemSelected(MenuItem item) { 45 | int id = item.getItemId(); 46 | if (id == android.R.id.home) { 47 | this.onBackPressed(); 48 | return true; 49 | } 50 | return super.onOptionsItemSelected(item); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/GalleryActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | import android.view.View; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.maxiee.heartbeat.R; 11 | import com.maxiee.heartbeat.common.GalleryUtils; 12 | import com.maxiee.heartbeat.database.utils.ImageUtils; 13 | import com.maxiee.heartbeat.ui.common.BaseActivity; 14 | 15 | import uk.co.senab.photoview.PhotoView; 16 | import uk.co.senab.photoview.PhotoViewAttacher; 17 | 18 | /** 19 | * Created by maxiee on 15-8-26. 20 | */ 21 | public class GalleryActivity extends BaseActivity { 22 | public static final String EVENT_ID = "event_id"; 23 | public static final String PATH = "path"; 24 | private PhotoView mImage; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_gallery); 30 | 31 | long eventId = getIntent().getLongExtra(EVENT_ID, -1); 32 | String path = ""; 33 | if (eventId == -1) { 34 | path = getIntent().getStringExtra(PATH); 35 | } 36 | 37 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 38 | toolbar.setBackgroundColor(Color.BLACK); 39 | toolbar.setTitle(""); 40 | toolbar.setAlpha(0.6f); 41 | setSupportActionBar(toolbar); 42 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 43 | 44 | mImage = (PhotoView) findViewById(R.id.imageview); 45 | 46 | mImage.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { 47 | @Override 48 | public void onPhotoTap(View view, float x, float y) { 49 | finish(); 50 | } 51 | }); 52 | 53 | if (eventId != -1) { 54 | String imagePath = ImageUtils.getImageByEventId(this, eventId).getPath(); 55 | Glide.with(this).load(GalleryUtils.getImagePath(imagePath)).into(mImage); 56 | } else { 57 | Glide.with(this).load(GalleryUtils.getImagePath(path)).into(mImage); 58 | } 59 | } 60 | 61 | @Override 62 | public boolean onOptionsItemSelected(MenuItem item) { 63 | int id = item.getItemId(); 64 | if (id == android.R.id.home) { 65 | this.onBackPressed(); 66 | return true; 67 | } 68 | return super.onOptionsItemSelected(item); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/HelpCenterActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.MenuItem; 8 | 9 | import com.maxiee.heartbeat.R; 10 | import com.maxiee.heartbeat.ui.adapter.HelpListAdapter; 11 | import com.maxiee.heartbeat.ui.common.BaseActivity; 12 | import com.maxiee.heartbeat.ui.common.RecyclerInsetsDecoration; 13 | 14 | import butterknife.Bind; 15 | import butterknife.ButterKnife; 16 | 17 | /** 18 | * Created by maxiee on 15/12/15. 19 | */ 20 | public class HelpCenterActivity extends BaseActivity { 21 | 22 | public static final String[] TITLES = new String[] { 23 | /*1: */ "心动是一款怎样的记录软件", 24 | /*2: */ "三级信息结构:标签-事件-感想", 25 | /*999: */ "捐赠感谢名单" 26 | }; 27 | 28 | public static final String[] DESCRIPTIONS = new String[] { 29 | /*1: */ "心动是一款怎样的记录软件?背后的理念如何?本文将一一进行阐述……", 30 | /*2: */ "正如前文中说的,心动改进了传统日记的信息组织方式,也就是心……", 31 | /*999: */ "为了表达我的感谢,我建立了这个捐赠感谢名单,每一位捐赠用户……" 32 | }; 33 | 34 | public static final String[] FILENAMES = new String[] { 35 | /*1: */ "what_heartbeat_is.html", 36 | /*2: */ "label_event_thought.html", 37 | /*999: */ "donate_list.html" 38 | }; 39 | 40 | @Bind(R.id.toolbar) Toolbar mToolbar; 41 | @Bind(R.id.recyclerview) RecyclerView mRecyclerView; 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.activity_help_center); 47 | ButterKnife.bind(this); 48 | 49 | setSupportActionBar(mToolbar); 50 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 51 | setTitle(getString(R.string.helpcenter)); 52 | 53 | HelpListAdapter adapter = new HelpListAdapter(TITLES, DESCRIPTIONS, FILENAMES); 54 | 55 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 56 | mRecyclerView.addItemDecoration(new RecyclerInsetsDecoration(this)); 57 | mRecyclerView.setAdapter(adapter); 58 | 59 | } 60 | 61 | @Override 62 | public boolean onOptionsItemSelected(MenuItem item) { 63 | int id = item.getItemId(); 64 | if (id == android.R.id.home) { 65 | this.onBackPressed(); 66 | return true; 67 | } 68 | return super.onOptionsItemSelected(item); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/HelpCenterDetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.MenuItem; 7 | import android.webkit.WebView; 8 | 9 | import com.maxiee.heartbeat.R; 10 | import com.maxiee.heartbeat.ui.common.BaseActivity; 11 | 12 | import butterknife.Bind; 13 | import butterknife.ButterKnife; 14 | 15 | /** 16 | * Created by maxiee on 15/12/16. 17 | */ 18 | public class HelpCenterDetailActivity extends BaseActivity { 19 | public static final String TITLE = "title"; 20 | public static final String FILENAME = "filename"; 21 | private static final String BASE_URL = "file:///android_asset/"; 22 | 23 | @Bind(R.id.toolbar) Toolbar mToolbar; 24 | @Bind(R.id.web) WebView mWebView; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_help_center_detail); 30 | ButterKnife.bind(this); 31 | 32 | Intent i = getIntent(); 33 | String title = i.getStringExtra(TITLE); 34 | String filename = i.getStringExtra(FILENAME); 35 | 36 | setSupportActionBar(mToolbar); 37 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 38 | setTitle(title); 39 | 40 | if (!filename.isEmpty()) { 41 | mWebView.loadUrl(BASE_URL + filename); 42 | } 43 | } 44 | 45 | @Override 46 | public boolean onOptionsItemSelected(MenuItem item) { 47 | int id = item.getItemId(); 48 | if (id == android.R.id.home) { 49 | this.onBackPressed(); 50 | return true; 51 | } 52 | return super.onOptionsItemSelected(item); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/SearchResultActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.RelativeLayout; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.maxiee.heartbeat.R; 15 | import com.maxiee.heartbeat.database.utils.EventUtils; 16 | import com.maxiee.heartbeat.model.Event; 17 | import com.maxiee.heartbeat.ui.adapter.EventListAdapter; 18 | import com.maxiee.heartbeat.ui.common.BaseActivity; 19 | import com.maxiee.heartbeat.ui.common.RecyclerInsetsDecoration; 20 | 21 | import java.util.ArrayList; 22 | 23 | /** 24 | * Created by maxiee on 15-7-21. 25 | */ 26 | public class SearchResultActivity extends BaseActivity{ 27 | private static final String TAG = SearchResultActivity.class.getSimpleName(); 28 | private Toolbar mToolbar; 29 | private RecyclerView mRecyclerView; 30 | private RelativeLayout mEmptyLayout; 31 | private ImageView mImageEmpty; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_search_result); 37 | 38 | mToolbar = (Toolbar) findViewById(R.id.toolbar); 39 | setSupportActionBar(mToolbar); 40 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 41 | 42 | mEmptyLayout = (RelativeLayout) findViewById(R.id.empty); 43 | mImageEmpty = (ImageView) findViewById(R.id.image_empty); 44 | mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview); 45 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mRecyclerView.getContext())); 46 | mRecyclerView.addItemDecoration(new RecyclerInsetsDecoration(this)); 47 | 48 | Intent i = getIntent(); 49 | String search = i.getStringExtra("search"); 50 | 51 | if (!search.isEmpty()) { 52 | setTitle(search); 53 | updateEventList(search); 54 | } 55 | } 56 | 57 | @Override 58 | public boolean onOptionsItemSelected(MenuItem item) { 59 | int id = item.getItemId(); 60 | if (id == android.R.id.home) { 61 | this.onBackPressed(); 62 | return true; 63 | } 64 | return super.onOptionsItemSelected(item); 65 | } 66 | 67 | public void updateEventList(String search) { 68 | ArrayList eventList = EventUtils.searchEvent(this, search); 69 | if (!eventList.isEmpty()) { 70 | mRecyclerView.setAdapter(new EventListAdapter(eventList)); 71 | } else { 72 | mRecyclerView.setVisibility(View.GONE); 73 | mEmptyLayout.setVisibility(View.VISIBLE); 74 | Glide.with(this).load(R.drawable.empty_bg1).into(mImageEmpty); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.Toolbar; 6 | 7 | import com.maxiee.heartbeat.R; 8 | import com.maxiee.heartbeat.ui.common.BaseActivity; 9 | import com.maxiee.heartbeat.ui.fragments.SettingsFragment; 10 | 11 | /** 12 | * Created by maxiee on 15-6-28. 13 | */ 14 | public class SettingsActivity extends BaseActivity { 15 | 16 | private Toolbar mToolbar; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_settings); 22 | 23 | mToolbar = (Toolbar) findViewById(R.id.toolbar); 24 | setSupportActionBar(mToolbar); 25 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 26 | 27 | getFragmentManager() 28 | .beginTransaction() 29 | .replace(R.id.container, new SettingsFragment()) 30 | .commit(); 31 | 32 | setTitle(getString(R.string.action_settings)); 33 | } 34 | 35 | @Override 36 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 37 | super.onActivityResult(requestCode, resultCode, data); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/adapter/CrashListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.maxiee.heartbeat.R; 13 | import com.maxiee.heartbeat.common.TimeUtils; 14 | import com.maxiee.heartbeat.model.Crash; 15 | import com.maxiee.heartbeat.ui.CrashDetailActivity; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * Created by maxiee on 15-7-11. 21 | */ 22 | public class CrashListAdapter extends RecyclerView.Adapter { 23 | 24 | private ArrayList mCrashList; 25 | 26 | public CrashListAdapter(ArrayList crashList) { 27 | this.mCrashList = crashList; 28 | } 29 | 30 | @Override 31 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 32 | View v = LayoutInflater.from(parent.getContext()) 33 | .inflate(R.layout.item_crash_card, parent, false); 34 | return new ViewHolder(v); 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(ViewHolder holder, int position) { 39 | final Crash crash = mCrashList.get(position); 40 | 41 | holder.tvCrash.setText(crash.log); 42 | holder.tvTime.setText( 43 | TimeUtils.parseTime( 44 | holder.mContext, 45 | crash.timeStamp 46 | ) 47 | ); 48 | holder.mView.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | Context context = v.getContext(); 52 | Intent intent = new Intent(context, CrashDetailActivity.class); 53 | intent.putExtra(Crash.LOG, crash.log); 54 | intent.putExtra(Crash.TS, crash.timeStamp); 55 | ((Activity)context).startActivity(intent); 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public int getItemCount() { 62 | return mCrashList.size(); 63 | } 64 | 65 | public class ViewHolder extends RecyclerView.ViewHolder { 66 | public TextView tvCrash, tvTime; 67 | public Context mContext; 68 | public final View mView; 69 | 70 | public ViewHolder(View itemView) { 71 | super(itemView); 72 | mContext = itemView.getContext(); 73 | mView = itemView; 74 | tvCrash = (TextView) itemView.findViewById(R.id.tv_crash); 75 | tvTime = (TextView) itemView.findViewById(R.id.tv_time); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/adapter/HelpListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.maxiee.heartbeat.R; 12 | import com.maxiee.heartbeat.ui.HelpCenterDetailActivity; 13 | 14 | import butterknife.Bind; 15 | import butterknife.ButterKnife; 16 | 17 | /** 18 | * Created by maxiee on 15/12/15. 19 | */ 20 | public class HelpListAdapter extends RecyclerView.Adapter { 21 | 22 | private String[] mTitles; 23 | private String[] mDescriptions; 24 | private String[] mFilenames; 25 | 26 | public HelpListAdapter(String[] titles, String[] descriptions, String[] filenames) { 27 | mTitles = titles; 28 | mDescriptions = descriptions; 29 | mFilenames = filenames; 30 | } 31 | 32 | @Override 33 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 34 | View v = LayoutInflater.from(parent.getContext()) 35 | .inflate(R.layout.item_help_center, parent, false); 36 | return new ViewHolder(v); 37 | } 38 | 39 | @Override 40 | public void onBindViewHolder(ViewHolder holder, int position) { 41 | holder.title.setText(mTitles[position]); 42 | holder.description.setText(mDescriptions[position]); 43 | holder.setOnClickListener(mTitles[position], mFilenames[position]); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return mTitles.length; 49 | } 50 | 51 | public class ViewHolder extends RecyclerView.ViewHolder { 52 | @Bind(R.id.title) TextView title; 53 | @Bind(R.id.description) TextView description; 54 | View v; 55 | 56 | public ViewHolder(View itemView) { 57 | super(itemView); 58 | ButterKnife.bind(this, itemView); 59 | v = itemView; 60 | } 61 | 62 | public void setOnClickListener(final String title, final String filename) { 63 | v.setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View v) { 66 | Context context = v.getContext(); 67 | Intent i = new Intent(context, HelpCenterDetailActivity.class); 68 | i.putExtra(HelpCenterDetailActivity.TITLE, title); 69 | i.putExtra(HelpCenterDetailActivity.FILENAME, filename); 70 | context.startActivity(i); 71 | } 72 | }); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/common/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.common; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import com.maxiee.heartbeat.R; 8 | import com.maxiee.heartbeat.common.ThemeUtils; 9 | 10 | /** 11 | * Created by maxiee on 15/10/22. 12 | */ 13 | public class BaseActivity extends AppCompatActivity{ 14 | private int mCurrentTheme; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | mCurrentTheme = ThemeUtils.getCurrentActivityTheme(this); 20 | setTheme(mCurrentTheme); 21 | if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ 22 | getWindow().setStatusBarColor(ThemeUtils.getAttributeColor(this, R.attr.colorPrimaryDark)); 23 | } 24 | } 25 | 26 | @Override 27 | protected void onResume() { 28 | super.onResume(); 29 | int newTheme = ThemeUtils.getCurrentActivityTheme(this); 30 | if (mCurrentTheme != newTheme) { 31 | recreate(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/common/HintSearchBox.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.common; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.widget.EditText; 7 | 8 | import com.quinny898.library.persistentsearch.SearchBox; 9 | 10 | /** 11 | * Created by maxiee on 15/12/12. 12 | */ 13 | public class HintSearchBox extends SearchBox { 14 | public HintSearchBox(Context context) { 15 | super(context); 16 | } 17 | 18 | public HintSearchBox(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | public HintSearchBox(Context context, AttributeSet attrs, int defStyle) { 23 | super(context, attrs, defStyle); 24 | } 25 | 26 | @Override 27 | public void setLogoText(String text) { 28 | super.setLogoText(text); 29 | View v = this.getRootView(); 30 | EditText search = (EditText)this.findViewById(com.quinny898.library.persistentsearch.R.id.search); 31 | search.setHint(text); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/common/RecyclerInsetsDecoration.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.common; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | import com.maxiee.heartbeat.R; 9 | 10 | 11 | /** 12 | * ItemDecoration implementation that applies an inset margin 13 | * around each child of the RecyclerView. The inset value is controlled 14 | * by a dimension resource. 15 | * 16 | * by Dave Smith at: https://github.com/devunwired/recyclerview-playground 17 | */ 18 | public class RecyclerInsetsDecoration extends RecyclerView.ItemDecoration { 19 | 20 | private int mInsets; 21 | 22 | public RecyclerInsetsDecoration(Context context) { 23 | mInsets = context.getResources().getDimensionPixelSize(R.dimen.insets); 24 | } 25 | 26 | @Override 27 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 28 | 29 | //We can supply forced insets for each item view here in the Rect 30 | super.getItemOffsets(outRect, view, parent, state); 31 | outRect.set(mInsets, mInsets, mInsets, mInsets); 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/common/mdheaderview/TriView.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.common.mdheaderview; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | 12 | import com.maxiee.heartbeat.R; 13 | 14 | /** 15 | * Created by maxiee on 15/11/16. 16 | */ 17 | public class TriView extends View{ 18 | 19 | public static final int SHADOW_SIZE = 10; 20 | 21 | private Paint mPaint; 22 | private Path mPath; 23 | private int mColor; 24 | 25 | public TriView(Context context) { 26 | super(context); 27 | init(context, null); 28 | } 29 | 30 | public TriView(Context context, AttributeSet attrs) { 31 | super(context, attrs); 32 | init(context, attrs); 33 | } 34 | 35 | public TriView(Context context, AttributeSet attrs, int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | init(context, attrs); 38 | } 39 | 40 | public void init (Context context, AttributeSet attrs) { 41 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TriView, 0, 0); 42 | mColor = a.getColor(R.styleable.TriView_tri_color, Color.BLACK); 43 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 44 | mPaint.setStyle(Paint.Style.FILL); 45 | mPath = new Path(); 46 | a.recycle(); 47 | } 48 | 49 | @Override 50 | protected void onDraw(Canvas canvas) { 51 | super.onDraw(canvas); 52 | mPath.moveTo(0, getHeight()); 53 | mPath.lineTo(getWidth() / 2, 0); 54 | mPath.lineTo(getWidth(), getHeight()); 55 | mPath.lineTo(0, getHeight()); 56 | mPaint.setShadowLayer(SHADOW_SIZE, 0, 0, Color.BLACK); 57 | mPaint.setColor(mColor); 58 | canvas.drawPath(mPath, mPaint); 59 | } 60 | 61 | public void setColor(int color) { 62 | mColor = color; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/ui/fragments/EventTodayFragment.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.ui.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.RelativeLayout; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.maxiee.heartbeat.R; 15 | import com.maxiee.heartbeat.data.DataManager; 16 | import com.maxiee.heartbeat.ui.common.RecyclerInsetsDecoration; 17 | 18 | import butterknife.Bind; 19 | import butterknife.ButterKnife; 20 | 21 | /** 22 | * Created by maxiee on 15-6-23. 23 | */ 24 | public class EventTodayFragment extends Fragment{ 25 | 26 | @Bind(R.id.recyclerview) RecyclerView mRecyclerView; 27 | @Bind(R.id.empty) RelativeLayout mEmtpyLayout; 28 | @Bind(R.id.image_empty) ImageView mImageEmpty; 29 | private DataManager mDataManager; 30 | 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 33 | View v = inflater.inflate(R.layout.fragment_event_today, container, false); 34 | ButterKnife.bind(this, v); 35 | 36 | mDataManager = DataManager.getInstance(getContext()); 37 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mRecyclerView.getContext())); 38 | mRecyclerView.addItemDecoration(new RecyclerInsetsDecoration(getContext())); 39 | mRecyclerView.setAdapter(mDataManager.getTodayAdapter()); 40 | updateEventList(); 41 | 42 | return v; 43 | } 44 | 45 | public void updateEventList() { 46 | if (!mDataManager.isTodayEmpty()) { 47 | mRecyclerView.setVisibility(View.VISIBLE); 48 | mEmtpyLayout.setVisibility(View.GONE); 49 | mDataManager.notifyDataSetChanged(); 50 | } else { 51 | mRecyclerView.setVisibility(View.GONE); 52 | mEmtpyLayout.setVisibility(View.VISIBLE); 53 | Glide.with(getActivity()).load(R.drawable.empty_bg2).into(mImageEmpty); 54 | } 55 | } 56 | 57 | @Override 58 | public void onResume() { 59 | super.onResume(); 60 | mDataManager.checkNewDay(); 61 | updateEventList(); 62 | } 63 | 64 | @Override 65 | public void onDestroyView() { 66 | super.onDestroyView(); 67 | ButterKnife.unbind(this); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/maxiee/heartbeat/widget/HeartBeatWidgetProvider.java: -------------------------------------------------------------------------------- 1 | package com.maxiee.heartbeat.widget; 2 | 3 | import android.app.PendingIntent; 4 | import android.appwidget.AppWidgetManager; 5 | import android.appwidget.AppWidgetProvider; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.res.TypedArray; 9 | import android.widget.RemoteViews; 10 | 11 | import com.maxiee.heartbeat.R; 12 | import com.maxiee.heartbeat.common.ThemeUtils; 13 | import com.maxiee.heartbeat.data.DataManager; 14 | import com.maxiee.heartbeat.ui.AddEventActivity; 15 | import com.maxiee.heartbeat.ui.EntryActivity; 16 | 17 | /** 18 | * Created by maxiee on 16/4/26. 19 | */ 20 | public class HeartBeatWidgetProvider extends AppWidgetProvider { 21 | 22 | @Override 23 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 24 | final int n = appWidgetIds.length; 25 | 26 | int currentTheme = ThemeUtils.getCurrentActivityTheme(context); 27 | context.setTheme(currentTheme); 28 | 29 | int attrs[] = {R.attr.colorAccent, R.attr.colorPrimary, R.attr.colorPrimaryDark}; 30 | TypedArray ta = context.obtainStyledAttributes(currentTheme, attrs); 31 | 32 | int colorAccent = ThemeUtils.getAttributeColor(context, R.attr.colorAccent); 33 | int colorPrimary = ThemeUtils.getAttributeColor(context, R.attr.colorPrimary); 34 | int colorPrimaryDark = ThemeUtils.getAttributeColor(context, R.attr.colorPrimaryDark); 35 | 36 | ta.recycle(); 37 | 38 | for (int i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/circle_timeaxis.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/drawable/empty_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/drawable/empty_bg1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/drawable/empty_bg2.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_crash_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_crash_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_entry.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_help_center.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_help_center_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 | 24 | 25 | 29 | 30 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_label_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 21 | 22 | 32 | 33 | 40 | 41 | 42 | 43 | 44 | 45 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_pattern.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 20 | 21 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_search_result.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 26 | 27 | 32 | 39 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit_event.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | 16 | 22 | 23 | 35 | 36 | 42 | 43 | 48 | 49 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit_thought.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_new_label.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_new_thought.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 16 | 17 | 25 | 31 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_event_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 18 | 19 | 20 | 25 | 32 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_event_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 19 | 26 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_label_cloud.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 32 | 39 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 | 28 | 29 | 30 | 31 | 36 | 37 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_crash_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 21 | 22 | 29 | 30 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_day_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 21 | 26 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_day_card_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 26 | 32 | 36 | 40 | 41 | 42 | 49 | 54 | 62 | 63 | 69 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_event_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 31 | 32 | 40 | 41 | 51 | 52 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_help_center.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_thought_timeaxis.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 20 | 21 | 27 | 28 | 34 | 35 | 36 | 37 | 43 | 44 | 50 | 51 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_today_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 27 | 28 | 35 | 36 | 43 | 44 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tagview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 23 | 24 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 15 | 21 | 27 | 34 | 40 | 41 | 42 | 50 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/menu/dialog_edit_thought.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/menu/dialog_new_thought.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/drawer_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 15 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/menu/fragment_eventlist_type.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_crash_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_event_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFF5F5F5 4 | #e7e7e7 5 | #BDBDBD 6 | #96ffffff 7 | 8 | #00000000 9 | 10 | #ffffff 11 | #d4d4d4 12 | #dddddd 13 | #eee 14 | 15 | #00BCD4 16 | #00ACC1 17 | #EF9A9A 18 | 19 | #4CAF50 20 | #388E3C 21 | #FFD600 22 | 23 | #F44336 24 | #D32F2F 25 | #FFAB00 26 | 27 | #303F9F 28 | #1A237E 29 | #AEEA00 30 | 31 | #607D8B 32 | #455A64 33 | #40C4FF 34 | 35 | #9C27B0 36 | #7B1FA2 37 | #FF4081 38 | 39 | #757575 40 | #424242 41 | #FF9100 42 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 35dp 6 | 5dp 7 | 10dp 8 | 2dp 9 | 60dp 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/tagview_attr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /attitude.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.0-rc1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Tue Sep 29 13:56:58 CST 2015 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jan 15 23:52:52 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/icon.png -------------------------------------------------------------------------------- /multi-image-selector/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /multi-image-selector/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile 'com.android.support:appcompat-v7:23.1.1' 24 | compile 'com.squareup.picasso:picasso:2.4.0' 25 | } 26 | -------------------------------------------------------------------------------- /multi-image-selector/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 F:/Nereo/Program/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 | -------------------------------------------------------------------------------- /multi-image-selector/src/androidTest/java/me/nereo/multi_image_selector/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /multi-image-selector/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/bean/Folder.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.bean; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 文件夹 9 | * Created by Nereo on 2015/4/7. 10 | */ 11 | public class Folder { 12 | public String name; 13 | public String path; 14 | public Image cover; 15 | public List images; 16 | 17 | @Override 18 | public boolean equals(Object o) { 19 | try { 20 | Folder other = (Folder) o; 21 | return TextUtils.equals(other.path, path); 22 | }catch (ClassCastException e){ 23 | e.printStackTrace(); 24 | } 25 | return super.equals(o); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/bean/Image.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.bean; 2 | 3 | /** 4 | * 图片实体 5 | * Created by Nereo on 2015/4/7. 6 | */ 7 | public class Image { 8 | public String path; 9 | public String name; 10 | public long time; 11 | 12 | public Image(String path, String name, long time){ 13 | this.path = path; 14 | this.name = name; 15 | this.time = time; 16 | } 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | try { 21 | Image other = (Image) o; 22 | return this.path.equalsIgnoreCase(other.path); 23 | }catch (ClassCastException e){ 24 | e.printStackTrace(); 25 | } 26 | return super.equals(o); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Point; 5 | import android.os.Build; 6 | import android.view.Display; 7 | import android.view.WindowManager; 8 | 9 | /** 10 | * 屏幕工具 11 | * Created by nereo on 15/11/19. 12 | * Updated by nereo on 2016/1/19. 13 | */ 14 | public class ScreenUtils { 15 | 16 | public static Point getScreenSize(Context context){ 17 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 18 | Display display = wm.getDefaultDisplay(); 19 | Point out = new Point(); 20 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { 21 | display.getSize(out); 22 | }else{ 23 | int width = display.getWidth(); 24 | int height = display.getHeight(); 25 | out.set(width, height); 26 | } 27 | return out; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.utils; 2 | 3 | import java.io.File; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | import java.util.Locale; 7 | 8 | /** 9 | * 时间处理工具 10 | * Created by Nereo on 2015/4/8. 11 | */ 12 | public class TimeUtils { 13 | 14 | public static String timeFormat(long timeMillis, String pattern){ 15 | SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.CHINA); 16 | return format.format(new Date(timeMillis)); 17 | } 18 | 19 | public static String formatPhotoDate(long time){ 20 | return timeFormat(time, "yyyy-MM-dd"); 21 | } 22 | 23 | public static String formatPhotoDate(String path){ 24 | File file = new File(path); 25 | if(file.exists()){ 26 | long time = file.lastModified(); 27 | return formatPhotoDate(time); 28 | } 29 | return "1970-01-01"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/view/SquareFrameLayout.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.FrameLayout; 6 | 7 | /** 8 | * Created by nereo on 15/11/10. 9 | */ 10 | public class SquareFrameLayout extends FrameLayout{ 11 | public SquareFrameLayout(Context context) { 12 | super(context); 13 | } 14 | 15 | public SquareFrameLayout(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | @Override 20 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 21 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 22 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/java/me/nereo/multi_image_selector/view/SquaredImageView.java: -------------------------------------------------------------------------------- 1 | package me.nereo.multi_image_selector.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | /** An image view which always remains square with respect to its width. */ 8 | class SquaredImageView extends ImageView { 9 | public SquaredImageView(Context context) { 10 | super(context); 11 | } 12 | 13 | public SquaredImageView(Context context, AttributeSet attrs) { 14 | super(context, attrs); 15 | } 16 | 17 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 18 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 19 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/color/default_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/color/folder_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xhdpi/btn_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xhdpi/btn_back.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xhdpi/default_check_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xhdpi/default_check_s.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xhdpi/ic_menu_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xhdpi/ic_menu_back.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xhdpi/selector_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xhdpi/selector_indicator.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/asv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/asv.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/asy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/asy.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/btn_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/btn_selected.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/btn_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/btn_unselected.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/default_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/default_check.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/default_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/default_error.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable-xxhdpi/text_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxiee/HeartBeat/8e61b4929450c596a21c5df2c4545c74d9b095e3/multi-image-selector/src/main/res/drawable-xxhdpi/text_indicator.png -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/drawable/action_btn.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 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /multi-image-selector/src/main/res/layout-v14/fragment_multi_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 26 | 27 |