diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..7811e7b --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +lifelogpedometer \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a326949 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..adbd147 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..a32268a --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,93 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.3" + defaultConfig { + applicationId "com.dinhcv.lifelogpedometer" + minSdkVersion 19 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + // Enabling multidex support. + multiDexEnabled true + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + signingConfigs { + dev { + storeFile file("../keystores/...") + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + + product { + storeFile file("..keystores/...") + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + + productFlavors { + + dev { + applicationId "com.dinhcv.lifelogpedometer" + applicationIdSuffix "dev" + minSdkVersion 19 + buildConfigField 'String', 'BASE_URL', '"http://clover.timesfun.jp:9001/"' + } + + product { + applicationId "com.dinhcv.lifelogpedometer" + minSdkVersion 19 + buildConfigField 'String', 'BASE_URL', '"http://clover.timesfun.jp:9001/"' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + + // Retrofit + // JSON Parsing + compile 'com.android.support.constraint:constraint-layout:1.0.2' + compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'com.android.support.constraint:constraint-layout:1.0.2' + compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'com.android.support:appcompat-v7:25.3.1' + compile 'com.github.j4velin.colorpicker:colorpicker:1.2.3' + compile 'com.github.j4velin.EazeGraph:EazeGraph:1.0.2' + compile 'com.google.android.apps.dashclock:dashclock-api:2.0.0' + compile 'com.android.support:design:25.3.1' + compile 'com.github.PhilJay:MPAndroidChart:v3.0.2' + compile 'com.google.android.gms:play-services:11.0.4' + compile 'com.google.code.gson:gson:2.7' + compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'de.hdodenhof:circleimageview:2.1.0' + compile 'com.jakewharton:butterknife:8.6.0' + testCompile 'junit:junit:4.12' + // Retrofit + compile 'com.squareup.retrofit2:retrofit:2.1.0' + compile 'com.squareup.picasso:picasso:2.5.2' + compile 'de.hdodenhof:circleimageview:2.1.0' + compile 'com.jakewharton:butterknife:8.6.0' + compile 'com.squareup.retrofit2:retrofit:2.1.0' + compile 'com.squareup.picasso:picasso:2.5.2' + compile 'com.android.support:support-v4:25.3.1' + testCompile 'junit:junit:4.12' + + compile 'com.android.support:multidex:1.0.1' + + annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..ff652d6 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in D:\Android\sdk-android/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src.rar b/app/src.rar new file mode 100644 index 0000000000000000000000000000000000000000..bfea4fb60cb4f353447401e006fa93ecdb3a1740 GIT binary patch literal 200985 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

+ * This method does nothing if there is already an entry for 'date'. + * + * @param date the date in ms since 1970 + * @param steps the step value for 'date'; must be >= 0 + * @return true if a new entry was created, false if there was already an + * entry for 'date' + */ + public boolean insertDayFromBackup(long date, int steps) { + getWritableDatabase().beginTransaction(); + boolean re; + try { + Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"date"}, "date = ?", + new String[]{String.valueOf(date)}, null, null, null); + re = c.getCount() == 0 && steps >= 0; + if (re) { + ContentValues values = new ContentValues(); + values.put("date", date); + values.put("steps", steps); + getWritableDatabase().insert(DB_NAME, null, values); + } + c.close(); + getWritableDatabase().setTransactionSuccessful(); + } finally { + getWritableDatabase().endTransaction(); + } + return re; + } + + /** + * Writes the current steps database to the log + */ + public void logState() { + if (BuildConfig.DEBUG) { + Cursor c = getReadableDatabase() + .query(DB_NAME, null, null, null, null, null, "date DESC", "5"); + c.close(); + } + } + + /** + * Get the total of steps taken without today's value + * + * @return number of steps taken, ignoring today + */ + public int getTotalWithoutToday() { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"SUM(steps)"}, "steps > 0 AND date > 0 AND date < ?", + new String[]{String.valueOf(Utils.getToday())}, null, null, null); + c.moveToFirst(); + int re = c.getInt(0); + c.close(); + return re; + } + + /** + * Get the maximum of steps walked in one day + * + * @return the maximum number of steps walked in one day + */ + public int getRecord() { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"MAX(steps)"}, "date > 0", null, null, null, null); + c.moveToFirst(); + int re = c.getInt(0); + c.close(); + return re; + } + + /** + * Get the maximum of steps walked in one day and the date that happend + * + * @return a pair containing the date (Date) in millis since 1970 and the + * step value (Integer) + */ + public Pair getRecordData() { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"date, steps"}, "date > 0", null, null, null, + "steps DESC", "1"); + c.moveToFirst(); + Pair p = new Pair(new Date(c.getLong(0)), c.getInt(1)); + c.close(); + return p; + } + + /** + * Get the number of steps taken for a specific date. + *

+ * If date is Util.getToday(), this method returns the offset which needs to + * be added to the value returned by getCurrentSteps() to get todays steps. + * + * @param date the date in millis since 1970 + * @return the steps taken on this date or Integer.MIN_VALUE if date doesn't + * exist in the database + */ + public int getSteps(final long date) { + Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"steps"}, "date = ?", + new String[]{String.valueOf(date)}, null, null, null); + c.moveToFirst(); + int re; + if (c.getCount() == 0) re = Integer.MIN_VALUE; + else re = c.getInt(0); + c.close(); + return re; + } + + /** + * Gets the last num entries in descending order of date (newest first) + * + * @param num the number of entries to get + * @return a list of long,integer pair - the first being the date, the second the number of steps + */ + public List> getLastEntries(int num, Date today) { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"date", "steps"}, "date > 0", null, null, null, + "date DESC", String.valueOf(num)); + int max = c.getCount(); + List> result = new ArrayList<>(max); + if (c.moveToFirst()) { + do { + result.add(new Pair<>(c.getLong(0), c.getInt(1))); + } while (c.moveToNext()); + } + + List dateList = getAllDayOfMonth(today); + List> list = new ArrayList<>(); + if (result.size() < dateList.size()) { + for (int i = 0; i < dateList.size(); i++) { + int step = 0; + for (int j = 0; j < result.size(); j++) { + long date1 = result.get(j).first; + long date2 = dateList.get(i); + if (date1 == date2) { + step = result.get(j).second; + } + } + if (i == 3) { + list.add(new Pair<>(dateList.get(i), 6020)); + }else if (i == 4){ + list.add(new Pair<>(dateList.get(i), 3100)); + }else if (i == 2){ + list.add(new Pair<>(dateList.get(i), 6890)); + }else if (i == 5){ + list.add(new Pair<>(dateList.get(i), 2400)); + }else { + list.add(new Pair<>(dateList.get(i), step)); + } + + //list.add(new Pair<>(dateList.get(i), step)); + } + } + + return list; + } + + private List getAllDayOfMonth(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + int month = cal.get(Calendar.MONTH) + 1; + cal.set(Calendar.DAY_OF_MONTH, 0); + List dateList = new ArrayList<>(); + int i = 30; + int monthDyn = month; + while (monthDyn == month) { + + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.DAY_OF_MONTH, i); + + dateList.add(cal.getTimeInMillis()); + i--; + monthDyn = cal.get(Calendar.MONTH) + 1; + } + Debug.normal("Date list size: " + dateList); + dateList.remove(dateList.size() - 1); + return dateList; + } + + /** + * Get the number of steps taken between 'start' and 'end' date + *

+ * Note that todays entry might have a negative value, so take care of that + * if 'end' >= Util.getToday()! + * + * @param start start date in ms since 1970 (steps for this date included) + * @param end end date in ms since 1970 (steps for this date included) + * @return the number of steps from 'start' to 'end'. Can be < 0 as todays + * entry might have negative value + */ + public int getSteps(final long start, final long end) { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"SUM(steps)"}, "date >= ? AND date <= ?", + new String[]{String.valueOf(start), String.valueOf(end)}, null, null, null); + int re; + if (c.getCount() == 0) { + re = 0; + } else { + c.moveToFirst(); + re = c.getInt(0); + } + c.close(); + return re; + } + + /** + * Removes all entries with negative values. + *

+ * Only call this directly after boot, otherwise it might remove the current + * day as the current offset is likely to be negative + */ + void removeNegativeEntries() { + getWritableDatabase().delete(DB_NAME, "steps < ?", new String[]{"0"}); + } + + /** + * Removes invalid entries from the database. + *

+ * Currently, an invalid input is such with steps >= 200,000 + */ + public void removeInvalidEntries() { + getWritableDatabase().delete(DB_NAME, "steps >= ?", new String[]{"200000"}); + } + + /** + * Get the number of 'valid' days (= days with a step value > 0). + *

+ * The current day is also added to this number, even if the value in the + * database might still be < 0. + *

+ * It is safe to divide by the return value as this will be at least 1 (and + * not 0). + * + * @return the number of days with a step value > 0, return will be >= 1 + */ + public int getDays() { + Cursor c = getReadableDatabase() + .query(DB_NAME, new String[]{"COUNT(*)"}, "steps > ? AND date < ? AND date > 0", + new String[]{String.valueOf(0), String.valueOf(Utils.getToday())}, null, + null, null); + c.moveToFirst(); + // todays is not counted yet + int re = c.getInt(0) + 1; + c.close(); + return re <= 0 ? 1 : re; + } + + /** + * Saves the current 'steps since boot' sensor value in the database. + * + * @param steps since boot + */ + public void saveCurrentSteps(int steps) { + ContentValues values = new ContentValues(); + values.put("steps", steps); + if (getWritableDatabase().update(DB_NAME, values, "date = -1", null) == 0) { + values.put("date", -1); + getWritableDatabase().insert(DB_NAME, null, values); + } + } + + /** + * Reads the latest saved value for the 'steps since boot' sensor value. + * + * @return the current number of steps saved in the database or 0 if there + * is no entry + */ + public int getCurrentSteps() { + int re = getSteps(-1); + return re == Integer.MIN_VALUE ? 0 : re; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/PowerReceiver.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/PowerReceiver.java new file mode 100644 index 0000000..ecfd078 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/PowerReceiver.java @@ -0,0 +1,24 @@ +package com.dinhcv.lifelogpedometer.feature; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; + +public class PowerReceiver extends BroadcastReceiver { + @Override + public void onReceive(final Context context, final Intent intent) { + SharedPreferences prefs = context.getSharedPreferences("pedometer", Context.MODE_MULTI_PROCESS); + if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction()) && + !prefs.contains("pauseCount")) { + // if power connected & not already paused, then pause now + context.startService(new Intent(context, SensorListener.class) + .putExtra("action", SensorListener.ACTION_PAUSE)); + } else if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction()) && + prefs.contains("pauseCount")) { + // if power disconnected & currently paused, then resume now + context.startService(new Intent(context, SensorListener.class) + .putExtra("action", SensorListener.ACTION_PAUSE)); + } + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/SensorListener.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/SensorListener.java new file mode 100644 index 0000000..2854c3c --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/SensorListener.java @@ -0,0 +1,221 @@ +package com.dinhcv.lifelogpedometer.feature; + +import android.app.AlarmManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.IBinder; + +import com.dinhcv.lifelogpedometer.activity.PedometerActivity; +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.text.NumberFormat; +import java.util.Locale; + +import static com.dinhcv.lifelogpedometer.utils.Const.STEP_GOAL; + + +/** + * Background service which keeps the step-sensor listener alive to always get + * the number of steps since boot. + *

+ * This service won't be needed any more if there is a way to read the + * step-value without waiting for a sensor event + */ +public class SensorListener extends Service implements SensorEventListener { + + private final static int NOTIFICATION_ID = 1; + private final static long MICROSECONDS_IN_ONE_MINUTE = 60000000; + private final static long SAVE_OFFSET_TIME = AlarmManager.INTERVAL_HOUR; + private final static int SAVE_OFFSET_STEPS = 500; + + public final static String ACTION_PAUSE = "pause"; + + private static int steps; + private static int lastSaveSteps; + private static long lastSaveTime; + + + public final static String ACTION_UPDATE_NOTIFICATION = "updateNotificationState"; + + @Override + public void onAccuracyChanged(final Sensor sensor, int accuracy) { + } + + @Override + public void onSensorChanged(final SensorEvent event) { + if (event.values[0] > Integer.MAX_VALUE) { + return; + } else { + steps = (int) event.values[0]; + updateIfNecessary(); + } + } + + private void updateIfNecessary() { + if (steps > lastSaveSteps + SAVE_OFFSET_STEPS || + (steps > 0 && System.currentTimeMillis() > lastSaveTime + SAVE_OFFSET_TIME)) { + Database db = Database.getInstance(this); + if (db.getSteps(Utils.getToday()) == Integer.MIN_VALUE) { + int pauseDifference = steps - + getSharedPreferences("pedometer", Context.MODE_PRIVATE) + .getInt("pauseCount", steps); + db.insertNewDay(Utils.getToday(), steps - pauseDifference); + if (pauseDifference > 0) { + // update pauseCount for the new day + getSharedPreferences("pedometer", Context.MODE_PRIVATE).edit() + .putInt("pauseCount", steps).commit(); + } + } + db.saveCurrentSteps(steps); + db.close(); + lastSaveSteps = steps; + lastSaveTime = System.currentTimeMillis(); + updateNotificationState(); + } + } + + @Override + public IBinder onBind(final Intent intent) { + return null; + } + + @Override + public int onStartCommand(final Intent intent, int flags, int startId) { + if (intent != null && ACTION_PAUSE.equals(intent.getStringExtra("action"))) { + if (steps == 0) { + Database db = Database.getInstance(this); + steps = db.getCurrentSteps(); + db.close(); + } + SharedPreferences prefs = getSharedPreferences("pedometer", Context.MODE_PRIVATE); + if (prefs.contains("pauseCount")) { // resume counting + int difference = steps - + prefs.getInt("pauseCount", steps); // number of steps taken during the pause + Database db = Database.getInstance(this); + db.addToLastEntry(-difference); + db.close(); + prefs.edit().remove("pauseCount").commit(); + updateNotificationState(); + } else { // pause counting + // cancel restart + ((AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE)) + .cancel(PendingIntent.getService(getApplicationContext(), 2, + new Intent(this, SensorListener.class), + PendingIntent.FLAG_UPDATE_CURRENT)); + prefs.edit().putInt("pauseCount", steps).commit(); + updateNotificationState(); + stopSelf(); + return START_NOT_STICKY; + } + } + + if (intent != null && intent.getBooleanExtra(ACTION_UPDATE_NOTIFICATION, false)) { + updateNotificationState(); + } else { + updateIfNecessary(); + } + + // restart service every hour to save the current step count + ((AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE)) + .set(AlarmManager.RTC, Math.min(Utils.getTomorrow(), + System.currentTimeMillis() + AlarmManager.INTERVAL_HOUR), PendingIntent + .getService(getApplicationContext(), 2, + new Intent(this, SensorListener.class), + PendingIntent.FLAG_UPDATE_CURRENT)); + + return START_STICKY; + } + + @Override + public void onCreate() { + super.onCreate(); + reRegisterSensor(); + updateNotificationState(); + } + + @Override + public void onTaskRemoved(final Intent rootIntent) { + super.onTaskRemoved(rootIntent); + // Restart service in 500 ms + ((AlarmManager) getSystemService(Context.ALARM_SERVICE)) + .set(AlarmManager.RTC, System.currentTimeMillis() + 500, PendingIntent + .getService(this, 3, new Intent(this, SensorListener.class), 0)); + } + + @Override + public void onDestroy() { + super.onDestroy(); + try { + SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); + sm.unregisterListener(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void updateNotificationState() { + SharedPreferences prefs = getSharedPreferences("pedometer", Context.MODE_PRIVATE); + NotificationManager nm = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + if (prefs.getBoolean("notification", true)) { + Database db = Database.getInstance(this); + int today_offset = db.getSteps(Utils.getToday()); + if (steps == 0) + steps = db.getCurrentSteps(); // use saved value if we haven't anything better + db.close(); + Notification.Builder notificationBuilder = new Notification.Builder(this); + if (steps > 0) { + if (today_offset == Integer.MIN_VALUE) today_offset = -steps; + notificationBuilder.setProgress(STEP_GOAL, today_offset + steps, false).setContentText( + today_offset + steps >= STEP_GOAL ? getString(R.string.goal_reached_notification, + NumberFormat.getInstance(Locale.getDefault()) + .format((today_offset + steps))) : + getString(R.string.notification_text, + NumberFormat.getInstance(Locale.getDefault()) + .format((STEP_GOAL - today_offset - steps)))); + } else { + notificationBuilder + .setContentText(getString(R.string.your_progress_will_be_shown_here_soon)); + } + + boolean isPaused = prefs.contains("pauseCount"); + notificationBuilder.setPriority(Notification.PRIORITY_MIN).setShowWhen(false) + .setContentTitle(isPaused ? getString(R.string.ispaused) : + getString(R.string.notification_title)).setContentIntent(PendingIntent + .getActivity(this, 0, new Intent(this, PedometerActivity.class), + PendingIntent.FLAG_UPDATE_CURRENT)) + .setSmallIcon(R.drawable.ic_notification) + .addAction(isPaused ? R.drawable.ic_resume : R.drawable.ic_pause, + isPaused ? getString(R.string.resume) : getString(R.string.pause), + PendingIntent.getService(this, 4, new Intent(this, SensorListener.class) + .putExtra("action", ACTION_PAUSE), + PendingIntent.FLAG_UPDATE_CURRENT)).setOngoing(true); + nm.notify(NOTIFICATION_ID, notificationBuilder.build()); + } else { + nm.cancel(NOTIFICATION_ID); + } + } + + private void reRegisterSensor() { + SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); + try { + sm.unregisterListener(this); + } catch (Exception e) { + e.printStackTrace(); + } + + // enable batching with delay of max 5 min + sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), + SensorManager.SENSOR_DELAY_NORMAL, (int) (5 * MICROSECONDS_IN_ONE_MINUTE)); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ShutdownRecevier.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ShutdownRecevier.java new file mode 100644 index 0000000..0d0dae1 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ShutdownRecevier.java @@ -0,0 +1,36 @@ +package com.dinhcv.lifelogpedometer.feature; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.utils.Utils; + + +public class ShutdownRecevier extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, final Intent intent) { + context.startService(new Intent(context, SensorListener.class)); + + Setting.setPedometerCorrectShutdown(context, true); + + Database db = Database.getInstance(context); + // if it's already a new day, add the temp. steps to the last one + if (db.getSteps(Utils.getToday()) == Integer.MIN_VALUE) { + int steps = db.getCurrentSteps(); + int pauseDifference = steps - Setting.getPedometerPauseCount(context, steps); + db.insertNewDay(Utils.getToday(), steps - pauseDifference); + if (pauseDifference > 0) { + // update pauseCount for the new day + Setting.setPedometerPauseCount(context, steps); + } + } else { + db.addToLastEntry(db.getCurrentSteps()); + } + // current steps will be reset on boot + db.close(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ui/Dialog_Split.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ui/Dialog_Split.java new file mode 100644 index 0000000..9ac4cc9 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/ui/Dialog_Split.java @@ -0,0 +1,63 @@ +package com.dinhcv.lifelogpedometer.feature.ui; +import android.app.Dialog; +import android.content.Context; +import android.content.SharedPreferences; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Utils; + +public abstract class Dialog_Split { + + private static boolean split_active; + + public static Dialog getDialog(final Context c, final int totalSteps) { + final Dialog d = new Dialog(c); + d.setContentView(R.layout.dialog_split); + + final SharedPreferences prefs = c.getSharedPreferences("pedometer", Context.MODE_MULTI_PROCESS); + long split_date = prefs.getLong("split_date", -1); + int split_steps = prefs.getInt("split_steps", totalSteps); + ((TextView) d.findViewById(R.id.steps)).setText(Utils.convert2String2Decimal((totalSteps - split_steps))); + float distance = (totalSteps - split_steps) * Const.STEP_SIZE; + ((TextView) d.findViewById(R.id.distance)) + .setText(Utils.convert2String2Decimal(distance)); + ((TextView) d.findViewById(R.id.date)).setText(c.getString(R.string.since, + java.text.DateFormat.getDateTimeInstance().format(split_date))); + + final View started = d.findViewById(R.id.started); + final View stopped = d.findViewById(R.id.stopped); + + split_active = split_date > 0; + + started.setVisibility(split_active ? View.VISIBLE : View.GONE); + stopped.setVisibility(split_active ? View.GONE : View.VISIBLE); + + final Button startstop = (Button) d.findViewById(R.id.start); + startstop.setText(split_active ? R.string.stop : R.string.start); + startstop.setOnClickListener(new OnClickListener() { + @Override + public void onClick(final View v) { + if (!split_active) { + prefs.edit().putLong("split_date", System.currentTimeMillis()) + .putInt("split_steps", totalSteps).apply(); + split_active = true; + d.dismiss(); + } else { + started.setVisibility(View.GONE); + stopped.setVisibility(View.VISIBLE); + prefs.edit().remove("split_date").remove("split_steps").apply(); + split_active = false; + } + startstop.setText(split_active ? R.string.stop : R.string.start); + } + }); + + + return d; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/LLAPIManagerListener.java b/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/LLAPIManagerListener.java new file mode 100644 index 0000000..b7c7eb7 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/LLAPIManagerListener.java @@ -0,0 +1,10 @@ +package com.dinhcv.lifelogpedometer.interfaces; + +import org.json.JSONArray; +import org.json.JSONObject; + +public interface LLAPIManagerListener { + public void onError(Error error); + public void onSuccess(String json); + public void onSuccess(JSONObject object); +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/OnSelectResultListener.java b/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/OnSelectResultListener.java new file mode 100644 index 0000000..bb894b5 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/interfaces/OnSelectResultListener.java @@ -0,0 +1,7 @@ +package com.dinhcv.lifelogpedometer.interfaces; + +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; + +public interface OnSelectResultListener { + void onSelectedItem(SelectItemInfo selectItemInfo); +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/DummyData.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/DummyData.java new file mode 100644 index 0000000..e8c9973 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/DummyData.java @@ -0,0 +1,75 @@ +package com.dinhcv.lifelogpedometer.model; + +import android.content.Context; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; + +import java.util.ArrayList; +import java.util.List; + +public class DummyData { + + public static List getProvinceList(Context context){ + + List selectItemInfos = new ArrayList<>(); + + selectItemInfos.add( new SelectItemInfo( 1, context.getResources().getString(R.string.city_item_1))); + selectItemInfos.add( new SelectItemInfo( 2, context.getResources().getString(R.string.city_item_2))); + selectItemInfos.add( new SelectItemInfo( 3, context.getResources().getString(R.string.city_item_3))); + selectItemInfos.add( new SelectItemInfo( 4, context.getResources().getString(R.string.city_item_4))); + selectItemInfos.add( new SelectItemInfo( 5, context.getResources().getString(R.string.city_item_5))); + selectItemInfos.add( new SelectItemInfo( 6, context.getResources().getString(R.string.city_item_6))); + selectItemInfos.add( new SelectItemInfo( 7, context.getResources().getString(R.string.city_item_7))); + selectItemInfos.add( new SelectItemInfo( 8, context.getResources().getString(R.string.city_item_8))); + selectItemInfos.add( new SelectItemInfo( 9, context.getResources().getString(R.string.city_item_9))); + selectItemInfos.add( new SelectItemInfo( 10, context.getResources().getString(R.string.city_item_10))); + selectItemInfos.add( new SelectItemInfo( 11, context.getResources().getString(R.string.city_item_11))); + selectItemInfos.add( new SelectItemInfo( 12, context.getResources().getString(R.string.city_item_12))); + selectItemInfos.add( new SelectItemInfo( 13, context.getResources().getString(R.string.city_item_13))); + selectItemInfos.add( new SelectItemInfo( 14, context.getResources().getString(R.string.city_item_14))); + selectItemInfos.add( new SelectItemInfo( 15, context.getResources().getString(R.string.city_item_15))); + selectItemInfos.add( new SelectItemInfo( 16, context.getResources().getString(R.string.city_item_16))); + selectItemInfos.add( new SelectItemInfo( 17, context.getResources().getString(R.string.city_item_17))); + selectItemInfos.add( new SelectItemInfo( 18, context.getResources().getString(R.string.city_item_18))); + selectItemInfos.add( new SelectItemInfo( 19, context.getResources().getString(R.string.city_item_19))); + selectItemInfos.add( new SelectItemInfo( 20, context.getResources().getString(R.string.city_item_20))); + selectItemInfos.add( new SelectItemInfo( 21, context.getResources().getString(R.string.city_item_21))); + selectItemInfos.add( new SelectItemInfo( 22, context.getResources().getString(R.string.city_item_22))); + selectItemInfos.add( new SelectItemInfo( 23, context.getResources().getString(R.string.city_item_23))); + selectItemInfos.add( new SelectItemInfo( 24, context.getResources().getString(R.string.city_item_24))); + selectItemInfos.add( new SelectItemInfo( 25, context.getResources().getString(R.string.city_item_25))); + selectItemInfos.add( new SelectItemInfo( 26, context.getResources().getString(R.string.city_item_26))); + selectItemInfos.add( new SelectItemInfo( 27, context.getResources().getString(R.string.city_item_27))); + selectItemInfos.add( new SelectItemInfo( 28, context.getResources().getString(R.string.city_item_28))); + selectItemInfos.add( new SelectItemInfo( 29, context.getResources().getString(R.string.city_item_29))); + selectItemInfos.add( new SelectItemInfo( 30, context.getResources().getString(R.string.city_item_30))); + selectItemInfos.add( new SelectItemInfo( 31, context.getResources().getString(R.string.city_item_31))); + selectItemInfos.add( new SelectItemInfo( 32, context.getResources().getString(R.string.city_item_32))); + selectItemInfos.add( new SelectItemInfo( 33, context.getResources().getString(R.string.city_item_33))); + selectItemInfos.add( new SelectItemInfo( 34, context.getResources().getString(R.string.city_item_34))); + selectItemInfos.add( new SelectItemInfo( 35, context.getResources().getString(R.string.city_item_35))); + selectItemInfos.add( new SelectItemInfo( 36, context.getResources().getString(R.string.city_item_36))); + selectItemInfos.add( new SelectItemInfo( 37, context.getResources().getString(R.string.city_item_37))); + selectItemInfos.add( new SelectItemInfo( 38, context.getResources().getString(R.string.city_item_38))); + selectItemInfos.add( new SelectItemInfo( 39, context.getResources().getString(R.string.city_item_39))); + selectItemInfos.add( new SelectItemInfo( 40, context.getResources().getString(R.string.city_item_40))); + selectItemInfos.add( new SelectItemInfo( 41, context.getResources().getString(R.string.city_item_41))); + selectItemInfos.add( new SelectItemInfo( 42, context.getResources().getString(R.string.city_item_42))); + selectItemInfos.add( new SelectItemInfo( 43, context.getResources().getString(R.string.city_item_43))); + selectItemInfos.add( new SelectItemInfo( 44, context.getResources().getString(R.string.city_item_44))); + selectItemInfos.add( new SelectItemInfo( 45, context.getResources().getString(R.string.city_item_45))); + selectItemInfos.add( new SelectItemInfo( 46, context.getResources().getString(R.string.city_item_46))); + selectItemInfos.add( new SelectItemInfo( 47, context.getResources().getString(R.string.city_item_47))); + + return selectItemInfos; + } + + public static List getSexList(Context context){ + List listRelationship = new ArrayList<>(); + listRelationship.add(new SelectItemInfo(0,context.getResources().getString(R.string.male))); + listRelationship.add(new SelectItemInfo(1,context.getResources().getString(R.string.female))); + return listRelationship; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/Shareprefer/Setting.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/Shareprefer/Setting.java new file mode 100644 index 0000000..87e8539 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/Shareprefer/Setting.java @@ -0,0 +1,103 @@ +package com.dinhcv.lifelogpedometer.model.Shareprefer; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.dinhcv.lifelogpedometer.utils.Debug; + +import static android.content.Context.MODE_PRIVATE; + +public class Setting { + + private static String PEDOMETER = "pedometer"; + public static String PAUSECOUNT = "pauseCount"; + public static String CORRECTSHUTDOWN = "correctShutdown"; + public static void setPedometer(Context context, String type, String value){ + SharedPreferences.Editor editor = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE).edit(); + editor.putString(type, value); + editor.apply(); + editor.commit(); + } + + public static void removePedometer(Context context, String type){ + SharedPreferences.Editor editor = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE).edit(); + editor.remove(type); + editor.apply(); + } + + public static void setPedometerPauseCount(Context context, int value){ + SharedPreferences.Editor editor = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE).edit(); + editor.putInt(PAUSECOUNT, value); + editor.apply(); + editor.commit(); + } + + public static int getPedometerPauseCount(Context context, int defaulValue){ + SharedPreferences prefs = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE); + int value = prefs.getInt(PAUSECOUNT, defaulValue); + return value; + } + + public static void setPedometerCorrectShutdown(Context context, boolean value){ + SharedPreferences.Editor editor = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE).edit(); + editor.putBoolean(PAUSECOUNT, value); + editor.apply(); + editor.commit(); + } + + public static boolean getPedometerCorrectShutdown(Context context, boolean defaulValue){ + SharedPreferences prefs = context.getSharedPreferences(PEDOMETER, MODE_PRIVATE); + boolean value = prefs.getBoolean(CORRECTSHUTDOWN, defaulValue); + return value; + } + + + // First run app + private static final String USER_DATA_SHAREPRE = "app.user.data"; + public static final String ID_SHAREPRE = "id_data"; + public static final String EMAIL_SHAREPRE = "email_data"; + public static final String USER_SHAREPRE = "user_data"; + public static final String PASS_SHAREPRE = "pass_data"; + public static final String TOKEN_SHAREPRE = "token_data"; + + public static void setUserDataSharepre(Context context, String key, String value){ + SharedPreferences.Editor preferences = context.getSharedPreferences(USER_DATA_SHAREPRE, Context.MODE_PRIVATE).edit(); + preferences.putString(key, null); + preferences.commit(); + } + + public static String getUserDataSharepre(Context context, String key){ + SharedPreferences preferences = context.getSharedPreferences(USER_DATA_SHAREPRE, Context.MODE_PRIVATE); + String value = preferences.getString(key, null); + return value; + } + + private static void clearUserDataSharepre(Context context){ + SharedPreferences.Editor preferences = context.getSharedPreferences(USER_DATA_SHAREPRE, Context.MODE_PRIVATE).edit(); + preferences.clear(); + preferences.apply(); + } + + + private static final String USER_ID_SHAREPRE = "app.user.id.data"; + + public static void setUserIdSharepre(Context context, int value){ + SharedPreferences.Editor preferences = context.getSharedPreferences(USER_ID_SHAREPRE, Context.MODE_PRIVATE).edit(); + preferences.putInt("user_id_data", value); + preferences.commit(); + } + + public static int getUserIdSharepre(Context context){ + SharedPreferences preferences = context.getSharedPreferences(USER_ID_SHAREPRE, Context.MODE_PRIVATE); + int value = preferences.getInt("user_id_data", 0); + return value; + } + + private static void clearUserIdSharepre(Context context){ + SharedPreferences.Editor preferences = context.getSharedPreferences(USER_ID_SHAREPRE, Context.MODE_PRIVATE).edit(); + preferences.clear(); + preferences.apply(); + } + + //*** End add +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/StepModel.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/StepModel.java new file mode 100644 index 0000000..46bc210 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/StepModel.java @@ -0,0 +1,189 @@ +package com.dinhcv.lifelogpedometer.model; + +import com.dinhcv.lifelogpedometer.model.database.entities.m_step; +import com.dinhcv.lifelogpedometer.model.structure.StepInfo; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +public class StepModel { + + private StepInfo entity2StepInfo(m_step e) { + + StepInfo p = new StepInfo(); + + p.setId(e.id); + p.setStep( e.step); + p.setDate( new Date(e.date *1000)); + + return p; + } + + + + public List getStepList(){ + + + List steps = m_step.find( + m_step.class, + null, + null, + null, + null, + null + ); + + if (steps != null){ + Debug.normal("Step Info list Size is: "+steps.size()); + }else { + Debug.warn("Step Info list is null..."); + } + + if (steps.size() >1 ){ + Debug.warn("Found %d Step of List", steps.size()); + } + + //convert to IInfo + + List stepInfos = new ArrayList<>(); + + for (int i = 0; i " + fromDate.getTime()/1000 + " AND time_out < "+ toDate.getTime()/1000; + List steps = m_step.find(m_step.class, + whereStr, + null, + null, + null, + null); + if (steps == null) { + Debug.normal("Step is null"); + return null; + } + + + StepInfo stepInfo = entity2StepInfo(steps.get(0)); + Debug.normal("Login Success"); + + return stepInfo; + + } + + public StepInfo getStepOnMonth(Date date){ + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.add(Calendar.HOUR_OF_DAY, 0); + calendar.add(Calendar.MINUTE, 0); + Date fromDate = calendar.getTime(); + + Calendar calendar1 = Calendar.getInstance(); + calendar1.setTime(date); + calendar1.add(Calendar.HOUR_OF_DAY, 23); + calendar1.add(Calendar.MINUTE, 59); + Date toDate = calendar1.getTime(); + + String whereStr = "date > " + fromDate.getTime()/1000 + " AND time_out < "+ toDate.getTime()/1000; + List steps = m_step.find(m_step.class, + whereStr, + null, + null, + null, + null); + if (steps == null) { + Debug.normal("Step is null"); + return null; + } + + + StepInfo stepInfo = entity2StepInfo(steps.get(0)); + Debug.normal("Login Success"); + + return stepInfo; + + } + + + public boolean saveStepDate(StepInfo stepInfo){ + + m_step step = m_step.findById(m_step.class, stepInfo.getId(), "id"); + if (step == null) { + Debug.normal("User is null. And create new user"); + step = new m_step(); + } + + step.step = stepInfo.getStep(); + step.date = stepInfo.getDate().getTime() /1000; + + long t = step.save(); + if (t < 0){ + Debug.error("Error. Can not save step"); + return false; + } + Debug.normal("Success. Save step success"); + return true; + } + + public boolean deleteStep(int uid){ + String whereStr = "id = ?"; + int status = m_step.delete(m_step.class, + whereStr, + new String[] {String.valueOf(uid)}); + if (status < 0) { + Debug.error("Error. Can delete step"); + return false; + } + Debug.normal("Delete step success"); + + return true; + } + + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_settings.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_settings.java new file mode 100644 index 0000000..90bdf2a --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_settings.java @@ -0,0 +1,34 @@ +package com.dinhcv.lifelogpedometer.model.database.entities; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.dinhcv.lifelogpedometer.model.database.orm.OrmRecord; + +public class m_settings extends OrmRecord { + + @primary_key(autoincrement = false) + public String key_name; + public String value; + + public m_settings(String key_name, String value) { + this.key_name = key_name; + this.value = value; + } + + @Override + protected ContentValues onSetContentValues() { + ContentValues cv = new ContentValues(); + + cv.put("key_name", key_name); + cv.put("value", value); + + return cv; + } + + @Override + protected void onSetValues(Cursor c) { + this.key_name = c.getString(c.getColumnIndex("key_name")); + this.value = c.getString(c.getColumnIndex("value")); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_step.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_step.java new file mode 100644 index 0000000..bef7701 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/entities/m_step.java @@ -0,0 +1,36 @@ +package com.dinhcv.lifelogpedometer.model.database.entities; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.dinhcv.lifelogpedometer.model.database.orm.OrmRecord; + + +public class m_step extends OrmRecord { + + @primary_key(autoincrement = true) + public int id; //uid + + public int step; + public long date; + + @Override + protected ContentValues onSetContentValues() { + ContentValues cv = new ContentValues(); + if (id != 0) { + cv.put("id", id); + } + + cv.put("step", step); + cv.put("date", date); + + return cv; + } + + @Override + protected void onSetValues(Cursor c) { + this.id = c.getInt(c.getColumnIndex("id")); + this.step = c.getInt(c.getColumnIndex("step")); + this.date = c.getLong(c.getColumnIndex("date")); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmDatabaseHelper.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmDatabaseHelper.java new file mode 100644 index 0000000..cb76c37 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmDatabaseHelper.java @@ -0,0 +1,170 @@ +/* + * OrmRecord.java + * TODO Description of class here + + * Author : tupn + * Created : 2/16/2016 + * Modified: $Date: 2016-10-04 18:36:55 +0700 (Tue, 04 Oct 2016) $ + + * Copyright © 2015 www.mdi-astec.vn + **************************************************************************************************/ + +package com.dinhcv.lifelogpedometer.model.database.orm; + +import android.content.Context; +import android.provider.Settings; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.dinhcv.lifelogpedometer.utils.Debug; + + +public class OrmDatabaseHelper extends SQLiteOpenHelper { + + private static final int DATABASE_VERSION = 30; + + private static final String DATABASE_NAME = "lifelog_db_r" + DATABASE_VERSION + ".db"; + + private static OrmDatabaseHelper mDbHelper = null; + + private static List> mOrmRecordClasses = null; + + /** + * Hidden constructor + * @param context Device context + */ + private OrmDatabaseHelper(Context context ) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + + //make more salt by Device-ID + // (this step to make sure each device has difference password for encrypting) + final String deviceId = Settings.Secure.getString( context.getContentResolver(), + Settings.Secure.ANDROID_ID); + + } + + @SuppressWarnings("unchecked") + public static void addOrmRecordClasses( Class[] classes ){ + + mOrmRecordClasses=new ArrayList<>(); + + for( Class cls: classes ) { + mOrmRecordClasses.add( (Class) cls); + } + } + + /** + * Get singleton instance of database + * @return singleton instance of database + */ + public static OrmDatabaseHelper getInstance(){ + return mDbHelper; + } + + /** + * Init function, call before do anything + * @param context Device context + * @return itself, using as builder-pattern + */ + public static OrmDatabaseHelper init(Context context){ + + if( mDbHelper==null ){ + mDbHelper = new OrmDatabaseHelper( context ); + } + + return mDbHelper; + } + + @Override + public void onCreate(SQLiteDatabase db) { + + Debug.normal("[ORM] Create all tables"); + try { + db.beginTransaction(); + for (Class ormRecord : mOrmRecordClasses) { + + OrmRecord orm = (OrmRecord)ormRecord.newInstance(); + + String sqlCmd = orm.onSQLCreateTable(); + + Debug.dbg( "[ORM] Create table: \n" + sqlCmd ); + + db.execSQL( sqlCmd ); + } + db.setTransactionSuccessful(); + db.endTransaction(); + }catch (Exception e ){ + Debug.error("[ORM] ERROR: Cannot create Table database"); + Debug.printStackTrace( e ); + db.endTransaction(); + } + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { + //The first version, do not care upgrade case + if( 1 != i1 ){ + Debug.warn("Database has upgraded, Please check carefully"); + } + } + + /** + * Create a new readable instance of database + * note Call SQLiteDatabase.close() after using ro cleanup data + * @return Readable database instance + */ + public SQLiteDatabase getReadableDatabase() { + + SQLiteDatabase ret; + + long count; + if( OrmRecord.PERFORMANCE_DEBUG ){ + count = new Date().getTime(); + } + + ret = super.getWritableDatabase(); + + + if( OrmRecord.PERFORMANCE_DEBUG ){ + long delta = new Date().getTime() - count; + + Debug.dbg("[########][Performance] Create writable instance %d ms", delta ); + } + + return ret; + } + + /** + * Create a new writable instance of database + * note Call SQLiteDatabase.close() after using ro cleanup data + * @return Readable database writable + */ + public SQLiteDatabase getWritableDatabase() { + + SQLiteDatabase ret; + + long count; + if( OrmRecord.PERFORMANCE_DEBUG ){ + count = new Date().getTime(); + } + + ret = super.getWritableDatabase(); + + if( OrmRecord.PERFORMANCE_DEBUG ){ + long delta = new Date().getTime() - count; + + Debug.dbg("[########][Performance] Create writable instance %d ms", delta ); + } + + return ret; + } +} + +/*************************************************************************************************** + * End of file + **************************************************************************************************/ diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmRecord.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmRecord.java new file mode 100644 index 0000000..37f6011 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/database/orm/OrmRecord.java @@ -0,0 +1,835 @@ +/* + * OrmRecord.java + * TODO Description of class here + + * Author : tupn + * Created : 2/16/2016 + * Modified: $Date: 2016-10-19 14:13:19 +0700 (Wed, 19 Oct 2016) $ + + * Copyright © 2015 www.mdi-astec.vn + **************************************************************************************************/ +package com.dinhcv.lifelogpedometer.model.database.orm; + +import android.content.ContentValues; +import android.database.Cursor; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import android.database.sqlite.SQLiteDatabase; + +import com.dinhcv.lifelogpedometer.utils.Debug; + + +@SuppressWarnings("unused") +public abstract class OrmRecord { + + /** + * Enable debug for check performance of database + */ + public static final boolean PERFORMANCE_DEBUG = false; + + /** + * Enable / Disable performance database
+ * default value = false + */ + protected static boolean OPTIMIZE_PERFORMANCE_DB_DISABLE = false; + + + @Retention(RetentionPolicy.RUNTIME) + public @interface foreign_key { + String table(); + + String id(); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface primary_key { + boolean autoincrement(); + } + + + /* Just use one instance of Db for increasing performance
+ * This is very useful for SQLCipher + */ + private static SQLiteDatabase mTransactionDb = null; + private static SQLiteDatabase mReadableDb = null; + private static SQLiteDatabase mWritableDb = null; + + + /** + * Table name + * + * @return Table name + */ + private String getTableName() { + return getClass().getSimpleName(); + } + + /** + * Create a new writable instance of database + * note Call SQLiteDatabase.close() after using ro cleanup data + * + * @return Readable database writable + */ + protected static SQLiteDatabase getWritableDatabase() { + + if (mWritableDb == null || OPTIMIZE_PERFORMANCE_DB_DISABLE || !mWritableDb.isOpen()) { + mWritableDb = OrmDatabaseHelper.getInstance().getWritableDatabase(); + } + + return mWritableDb; + } + + /** + * Create a new readable instance of database + * note Call SQLiteDatabase.close() after using ro cleanup data + * + * @return Readable database instance + */ + protected static SQLiteDatabase getReadableDatabase() { + + if (mReadableDb == null || OPTIMIZE_PERFORMANCE_DB_DISABLE || !mReadableDb.isOpen()) { + mReadableDb = OrmDatabaseHelper.getInstance().getReadableDatabase(); + } + return mReadableDb; + } + + /** + * Generate SQL command for creating table + * + * @return SQL creating-table + */ + protected String onSQLCreateTable() { + + String tableName = getTableName(); + + Debug.dbg("[ORM]Create table:" + tableName); + + //Add fields + int nPrimaryCount = 0; + Field[] fieldsRaw = this.getClass().getDeclaredFields(); + + //sort + List fields = new ArrayList<>(); + List ending = new ArrayList<>(); + for (Field f : fieldsRaw) { + if (f.getAnnotation(primary_key.class) != null) { + fields.add(0, f); + } else if (f.getAnnotation(foreign_key.class) != null) { + ending.add(f); + } else { + fields.add(f); + } + } + fields.addAll(ending); + + //create SQL table query + String sqlCreateTbl = ""; + String sqlForeignKey = ""; + sqlCreateTbl += "CREATE TABLE IF NOT EXISTS " + tableName + "("; + + for (Field field : fields) { + + String fieldName = field.getName(); + + //attributes + final primary_key primaryKey = field.getAnnotation(primary_key.class); + if (primaryKey != null) { + nPrimaryCount++; + + if (nPrimaryCount > 1) { + Debug.error("ERROR: Have only one Primary key in each table [%s]", tableName); + return null; + } + } + + String type = classToSQLiteDataType(field); + if (type != null) { + sqlCreateTbl += "\n"; + + final foreign_key foreignKey = field.getAnnotation(foreign_key.class); + if (foreignKey != null) { + sqlCreateTbl += " '" + fieldName + "' " + type; + sqlForeignKey += " FOREIGN KEY (" + fieldName + ") REFERENCES " + foreignKey.table() + " (" + foreignKey.id() + ")\n"; + } else { + sqlCreateTbl += " '" + fieldName + "' " + type; + if (primaryKey != null) { + sqlCreateTbl += " PRIMARY KEY " + ((type.compareTo("INTEGER") == 0 && primaryKey.autoincrement()) ? "AUTOINCREMENT" : ""); + } + } + + sqlCreateTbl += ","; + } + } + + //remove ',' character at end of command + if (sqlCreateTbl.endsWith(",")) { + sqlCreateTbl = sqlCreateTbl.substring(0, sqlCreateTbl.length() - 1); + } + + //End + if (!sqlForeignKey.isEmpty()) { + sqlCreateTbl += ",\n"; + sqlCreateTbl += sqlForeignKey; + } + sqlCreateTbl += ");"; + + //Debug + //Debug.dbg( sqlCreateTbl ); + return sqlCreateTbl; + } + + /** + * Get a SQLite type-description of data type + * int --> INTEGER,... + * + * @param field Common filed (int, boolean,...) + * @return description of type by SQLite syntax + */ + private String classToSQLiteDataType(Field field) { + + String cls = field.getType().toString(); + + if (cls.equals(Boolean.class.toString()) || cls.equals("boolean")) { + return "INTEGER"; + } else if (cls.equals(Long.class.toString()) || cls.equals("long")) { + return "INTEGER"; + } else if (cls.equals(Integer.class.toString()) || cls.equals("int")) { + return "INTEGER"; + } else if (cls.equals(Double.class.toString()) || cls.equals("double")) { + return "REAL"; + } else if (cls.equals(Float.class.toString()) || cls.equals("float")) { + return "REAL"; + } else if (cls.equals(String.class.toString())) { + return "TEXT"; + } else if (cls.endsWith("IncrementalChange")) { + //Skip runtime field of Instant Run function + return null; + } else { + Debug.error("[ORM]ERROR: Not support type of field:" + field.getName() + + "\n type:" + cls + + "\n in class:" + this.getClass().getName()); + return null; + } + } + + /** + * Insert row to database table, + * + * @param nullColumnHack nullColumnHack + * @param values Content values + * @return primary id of inserted record
+ * -1 for error + */ + private long insert(String nullColumnHack, ContentValues values) { + Debug.dbg("[ORM] Insert to database table:" + getTableName()); + final SQLiteDatabase db; + + long startTime = new Date().getTime(); + + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getWritableDatabase(); + } + + //TUPN#WORK_AROUND#Bug in SQLCipher # Start + if (!db.isOpen()) { + Debug.dbg("############################################# DATABASE WAS CLOSED ########"); + } + //TUPN#WORK_AROUND#Bug in SQLCipher # End + + + long ret = db.insertWithOnConflict(getTableName(), nullColumnHack, values, SQLiteDatabase.CONFLICT_REPLACE); + if (ret < 0) { + Debug.error("ERROR: Error when inserting database in table:" + getTableName()); + } + + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + + if (PERFORMANCE_DEBUG) { + long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Insert %d ms in table %s", + delta, + getTableName()); + } + return ret; + } + + /** + * Delete a record + * + * @param whereClause where-condition SQLite + * @param whereArgs where-arguments SQLite + * @return number of items, those was deleted successfully + */ + protected int delete(String whereClause, String... whereArgs) { + + long startTime = 0; + if (PERFORMANCE_DEBUG) { + long delta = new Date().getTime(); + } + + final SQLiteDatabase db; + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getWritableDatabase(); + } + + Debug.dbg("[ORM] Delete in table:" + this.getClass().getSimpleName()); + int ret = db.delete(getTableName(), whereClause, whereArgs); + + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Delete %d ms in table %s : whereClause=%s", + delta, + getTableName(), + whereClause); + } + return ret; + } + + /** + * Start a transaction database
+ *

  • Call setTransactionSuccessful() before accept transaction + *
  • Call endTransaction() before finishing + */ + public static void beginTransaction() { + invalidateDb(); + + mTransactionDb = getWritableDatabase(); + mTransactionDb.beginTransaction(); + } + + /** + * Accept a transaction
    + * If don't call this function, your transaction will be canceled + */ + public static void setTransactionSuccessful() { + mTransactionDb.setTransactionSuccessful(); + } + + public static void endTransaction() { + + invalidateDb(); + + mTransactionDb.endTransaction(); + mTransactionDb.close(); + mTransactionDb = null; + } + + @SuppressWarnings("unused") + public static int deleteAll(Class clazz) { + + long startTime = new Date().getTime(); + + final SQLiteDatabase db; + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getWritableDatabase(); + } + + Debug.dbg("[ORM] Delete in table:" + clazz.getSimpleName()); + + int ret = db.delete(clazz.getSimpleName(), null, null); + + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Delete all %d ms in table %s", + delta, + clazz.getSimpleName()); + } + + return ret; + } + + + /** + * Delete record + * + * @param clazz class + * @param whereClause where-clause + * @param whereArgs where-arrguments + * @param Class template + * @return number of items, those was deleted successfully + */ + public static int delete(Class clazz, String whereClause, String[] whereArgs) { + + final String tableName = clazz.getSimpleName(); + + long startTime = new Date().getTime(); + + Debug.dbg("[ORM] Delete data of table:" + tableName); + final SQLiteDatabase db; + + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getWritableDatabase(); + } + + int ret = db.delete(tableName, whereClause, whereArgs); + if (ret < 0) { + Debug.error("ERROR: Error when inserting database in table:" + tableName); + } + + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Delete %d ms in table %s", + delta, + clazz.getSimpleName()); + } + + return ret; + } + + protected static Cursor query(SQLiteDatabase db, Class cls, String whereClause, String[] whereArgs, String groupBy, String orderBy, String limit) { + + final Cursor cursor; + + long startTime = new Date().getTime(); + + cursor = db.query(cls.getSimpleName(), null, whereClause, whereArgs, + groupBy, null, orderBy, limit); + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Query %d ms in table %s : whereClause=%s", + delta, + cls.getSimpleName(), + whereClause); + } + + return cursor; + } + + public static Cursor rawQuery(SQLiteDatabase db, String sqlClause, String[] whereArgs) { + + final Cursor cursor; + + long startTime = new Date().getTime(); + + cursor = db.rawQuery(sqlClause, whereArgs); + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Raw Query %d ms with sqlClause:\n%s", delta, sqlClause); + } + + return cursor; + } + + /** + * Save current record + * @return id of record, these was saved + */ + public long save() { + ContentValues cv = this.onSetContentValues(); + long ret; + + long startTime = new Date().getTime(); + + ret = insert(null, cv); + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Save %d ms in table %s", + delta, + getTableName()); + } + + return ret; + } + + /** + * Find with query + * @param clazz table class + * @param whereClause where clause + * @param whereArgs arguments of Where-clause + * @param groupBy group by + * @param orderBy order by + * @param limit number of record, need to get + * @return List of record, null for not found + */ + @SuppressWarnings("unchecked") + public static List find(Class clazz, String whereClause, String[] whereArgs, String groupBy, String orderBy, String limit) { + + Debug.dbg("[ORM] Query in table:" + clazz.getSimpleName()); + + long startTime = new Date().getTime(); + + final SQLiteDatabase db; + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getReadableDatabase(); + } + + Cursor c = OrmRecord.query(db, clazz, whereClause, whereArgs, groupBy, orderBy, limit); + if (!c.moveToFirst()) { + Debug.normal("[ORM] Not found any matching data in table (%s)", clazz.getSimpleName()); + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + return null; + } else { + + try { + List results = new ArrayList<>(); + do { + OrmRecord log = (OrmRecord) clazz.newInstance(); + + log.onSetValues(c); + + results.add((T) log); + + } while (c.moveToNext()); + + if (results.isEmpty()) { + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + return null; + } + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + return results; + } catch (Exception e) { + Debug.error("ERROR:" + e.getMessage()); + Debug.printStackTrace(e); + } + } + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Find %d ms in table %s", + delta, + clazz.getSimpleName()); + } + + + return null; + } + + + public static List join(Class class1, String key1, Class class2, String key2, + String whereClause, String[] whereArgs, String orderby, String limitSql) { + + long startTime = new Date().getTime(); + + String table1 = class1.getSimpleName(); + String table2 = class2.getSimpleName(); + + Debug.dbg("[ORM] Join 2 table: %s,%s", table1, table2); + final SQLiteDatabase db; + + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getWritableDatabase(); + } + + String query = ""; + + query += "SELECT * FROM " + table1; + query += " INNER JOIN " + table2; + query += " ON " + table1 + "." + key1 + "=" + table2 + "." + key2; + + if (whereClause != null) { + query += " WHERE " + whereClause; + } + + if (orderby != null && !orderby.trim().isEmpty()) { + query += " ORDER BY " + orderby; + } + + if (limitSql != null) { + query += " LIMIT " + limitSql; + } + + Debug.normal("Join query: " + query); + Cursor c = db.rawQuery(query, whereArgs); + if (!c.moveToFirst()) { + Debug.normal("[ORM]Cannot join tables"); + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Join %d ms in table %s", + delta, + class1.getSimpleName()); + } + + return null; + } else { + try { + + List results = new ArrayList<>(); + do { + OrmRecord[] record = new OrmRecord[2]; + + record[0] = (OrmRecord) class1.newInstance(); + record[1] = (OrmRecord) class2.newInstance(); + + record[0].onSetValues(c); + record[1].onSetValues(c); + + results.add(record); + } while (c.moveToNext()); + + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Join %d ms in table %s", + delta, + class1.getSimpleName()); + } + + return results; + } catch (Exception e) { + Debug.error("ERROR:" + e.getMessage()); + Debug.printStackTrace(e); + } + } + c.close(); + + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Join %d ms in table %s", + delta, + class1.getSimpleName()); + } + + return null; + } + + public static int count(Class clazz, String... whereCause) { + + int ret = 0; + final String table = clazz.getSimpleName(); + String whereSql = ""; + + long startTime = new Date().getTime(); + + final String whereField; + //lockup primary key in fields + final String primaryKey = getPrimaryKeyName(clazz); + + //user where sql + if ((whereCause != null) && (whereCause.length > 0)) { + whereSql = " WHERE " + whereCause[0]; + } + + //query + final SQLiteDatabase db; + if (mTransactionDb != null) { + db = mTransactionDb; + } else { + db = getReadableDatabase(); + } + + final String sql = "SELECT COUNT(" + primaryKey + ") FROM " + table + whereSql; + + Cursor c = db.rawQuery(sql, null); + if (!c.moveToFirst()) { + Debug.dbg("[ORM] Cannot get count of table:" + table); + } else { + ret = c.getInt(0); + } + c.close(); + if (mTransactionDb == null && OPTIMIZE_PERFORMANCE_DB_DISABLE) { + db.close(); + } + + if (PERFORMANCE_DEBUG) { + final long delta = new Date().getTime() - startTime; + + Debug.dbg("[########][Performance] Count %d ms in table %s", + delta, + clazz.getSimpleName()); + } + + return ret; + } + + public static List listAll(Class clazz) { + return OrmRecord.find(clazz, null, null, null, null, null); + } + + + /** + * Get all items with ordering + * + * @param clazz class of table + * @param orderBy order by + * @param Class template + * @return List of items + */ + public static List listAll(Class clazz, String orderBy) { + return find(clazz, null, null, null, orderBy, null); + } + + /** + * Find a item by id + * + * @param clazz Class of table + * @param id ID (by string) + * @param primaryKeys a custom primary key + * @param class template + * @return T object if found, null for not found + */ + public static T findById(Class clazz, String id, String... primaryKeys) { + + final String whereField; + if ((primaryKeys == null) || (primaryKeys.length == 0)) { + //lockup primary key in fields + whereField = getPrimaryKeyName(clazz); + } else { + whereField = primaryKeys[0]; + } + + //find with id + List found = OrmRecord.find(clazz, whereField + "='" + id + "'", null, null, null, null); + if ((found == null) || (found.isEmpty())) { + return null; + } + + return found.get(0); + } + + private static String getPrimaryKeyName(Class clazz) { + //lockup primary key in fields + Field[] fields = clazz.getDeclaredFields(); + if ((fields == null) || (fields.length == 0)) { + Debug.error("ERROR: Class (%s) has not any fields", clazz.getName()); + return null; + } + + for (Field f : fields) { + if (f.getAnnotation(primary_key.class) != null) { + return f.getName(); + } + } + + Debug.error("ERROR: Class have not primary_key. Use the first field as primary_key"); + return fields[0].getName(); + } + + /** + * Find by Id number + * + * @param clazz class table + * @param id id of items + * @param primary_key a custom primary key + * @param class template + * @return T object if found + */ + public static T findById(Class clazz, long id, String... primary_key) { + return findById(clazz, String.valueOf(id), primary_key); + } + + /** + * Invalidate current instance of Db + */ + private static void invalidateDb() { + mReadableDb = null; + mWritableDb = null; + } + + protected Double getDoubleOrNull( Cursor c, String column ){ + int i = c.getColumnIndex( column ); + if( c.isNull( i ) ){ + return null; + } + return c.getDouble( i ); + } + + protected Integer getIntegerOrNull( Cursor c, String column ){ + int i = c.getColumnIndex( column ); + if( c.isNull( i ) ){ + return null; + } + return c.getInt( i ); + } + + /** + * Use to set fields to ContentValues of database + * + * @return All values + */ + abstract protected ContentValues onSetContentValues(); + + /** + * Override to set fields of object by Database values + * + * @param c cursor of current row in database + */ + abstract protected void onSetValues(Cursor c); + + public static SQLiteDatabase getTransactionDb() { + return mTransactionDb; + } + + public static SQLiteDatabase getReadableDb() { + return mReadableDb; + } + + public static SQLiteDatabase getWritableDb() { + return mWritableDb; + } +} +/*************************************************************************************************** + * End of file + **************************************************************************************************/ \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/RegisterInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/RegisterInfo.java new file mode 100644 index 0000000..0851dc1 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/RegisterInfo.java @@ -0,0 +1,118 @@ +package com.dinhcv.lifelogpedometer.model.structure; + +import com.google.gson.annotations.SerializedName; + +import java.util.Date; + +public class RegisterInfo { + private String username; + private String password; + private String fullName; + private String nickname; + private Date birthday; + private int height; + private int weight; + private int fatRate; + private int gender = 1; + private String address; + private String profileImage; + private String email; + + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public Date getBirthday() { + return birthday; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + } + + public int getFatRate() { + return fatRate; + } + + public void setFatRate(int fatRate) { + this.fatRate = fatRate; + } + + + public int getGender() { + return gender; + } + + public void setGender(int gender) { + this.gender = gender; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getProfileImage() { + return profileImage; + } + + public void setProfileImage(String profileImage) { + this.profileImage = profileImage; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/SelectItemInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/SelectItemInfo.java new file mode 100644 index 0000000..e061c63 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/SelectItemInfo.java @@ -0,0 +1,32 @@ +package com.dinhcv.lifelogpedometer.model.structure; + +import java.io.Serializable; + +public class SelectItemInfo implements Serializable{ + + private int id; + private String name; + + public SelectItemInfo(int id, String name){ + this.id = id; + this.name = name; + } + + public void setId(int id){ + this.id = id; + } + + public int getId(){ + return id; + } + + public void setName(String name){ + this.name = name; + } + + public String getName(){ + return name; + } + + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/StepInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/StepInfo.java new file mode 100644 index 0000000..2690f7f --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/StepInfo.java @@ -0,0 +1,50 @@ +package com.dinhcv.lifelogpedometer.model.structure; + +import java.util.Date; + +public class StepInfo { + private int id; + private Date date; + private int step; + + public StepInfo(int id, Date date, int step){ + this.id = id; + this.date = date; + this.step = step; + } + + public StepInfo(){ + + } + + public void setId(int storeId){ + this.id = id; + } + + public int getId(){ + return id; + } + + public void setDate(Date date){ + this.date = date; + } + + public Date getDate(){ + return date; + } + + public void setStep(double rate){ + this.step = step; + } + + public int getStep(){ + return step; + } + + public String toString(){ + StringBuilder result = new StringBuilder(); + result.append(" Id = "+id); + result.append(" step = "+step); + return result.toString(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryInfo.java new file mode 100644 index 0000000..0c53e5a --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryInfo.java @@ -0,0 +1,81 @@ +package com.dinhcv.lifelogpedometer.model.structure.history; + +import java.util.HashMap; +import java.util.List; + +public class HistoryInfo { + private int taget; + private int steps; + private int stepRemain; + private double completePercent; + private int time; + private double distance; + private double kcal; + private List dataChart; + + + public int getTaget() { + return taget; + } + + public void setTaget(int taget) { + this.taget = taget; + } + + public int getSteps() { + return steps; + } + + public void setSteps(int steps) { + this.steps = steps; + } + + public int getStepRemain() { + return stepRemain; + } + + public void setStepRemain(int stepRemain) { + this.stepRemain = stepRemain; + } + + public double getCompletePercent() { + return completePercent; + } + + public void setCompletePercent(double completePercent) { + this.completePercent = completePercent; + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + } + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public double getKcal() { + return kcal; + } + + public void setKcal(double kcal) { + this.kcal = kcal; + } + + public void setDataChart(List dataChart){ + this.dataChart = dataChart; + } + + public List getDataChart(){ + return dataChart; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryItemInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryItemInfo.java new file mode 100644 index 0000000..d744af9 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/history/HistoryItemInfo.java @@ -0,0 +1,63 @@ +package com.dinhcv.lifelogpedometer.model.structure.history; + +import java.util.Date; +import java.util.HashMap; + +public class HistoryItemInfo { + private Date date; + private int steps; + private int subStep; + private int time; + private double distance; + private double kcal; + + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public int getSteps() { + return steps; + } + + public void setSteps(int steps) { + this.steps = steps; + } + + public int getSubStep() { + return subStep; + } + + public void setSubStep(int subStep) { + this.subStep = subStep; + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + } + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public double getKcal() { + return kcal; + } + + public void setKcal(double kcal) { + this.kcal = kcal; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/NoticeInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/NoticeInfo.java new file mode 100644 index 0000000..3addb39 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/NoticeInfo.java @@ -0,0 +1,23 @@ +package com.dinhcv.lifelogpedometer.model.structure.home; + +public class NoticeInfo { + private int id; + private String content; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/TagetInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/TagetInfo.java new file mode 100644 index 0000000..68b3af6 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/home/TagetInfo.java @@ -0,0 +1,54 @@ +package com.dinhcv.lifelogpedometer.model.structure.home; + +import java.util.List; + +public class TagetInfo { + private String taget; + private String steps; + private String stepRemain; + private String completePercent; + + private List noticeList; + + + public String getTaget() { + return taget; + } + + public void setTaget(String taget) { + this.taget = taget; + } + + public String getSteps() { + return steps; + } + + public void setSteps(String steps) { + this.steps = steps; + } + + public String getStepRemain() { + return stepRemain; + } + + public void setStepRemain(String stepRemain) { + this.stepRemain = stepRemain; + } + + public String getCompletePercent() { + return completePercent; + } + + public void setCompletePercent(String completePercent) { + this.completePercent = completePercent; + } + + public void setNoticeList(List noticeList){ + this.noticeList = noticeList; + } + + public List getNoticeList(){ + return noticeList; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/RankingInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/RankingInfo.java new file mode 100644 index 0000000..8243b8f --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/RankingInfo.java @@ -0,0 +1,89 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Created by Admin on 8/28/2017. + */ + +public class RankingInfo { + @SerializedName("user_id") + @Expose + private Integer userId; + @SerializedName("username") + @Expose + private String username; + @SerializedName("profile_image") + @Expose + private String profileImage; + @SerializedName("steps") + @Expose + private Integer steps; + @SerializedName("time") + @Expose + private Integer time; + @SerializedName("distance") + @Expose + private Double distance; + @SerializedName("rank") + @Expose + private Integer rank; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getProfileImage() { + return profileImage; + } + + public void setProfileImage(String profileImage) { + this.profileImage = profileImage; + } + + public Integer getSteps() { + return steps; + } + + public void setSteps(Integer steps) { + this.steps = steps; + } + + public Integer getTime() { + return time; + } + + public void setTime(Integer time) { + this.time = time; + } + + public Double getDistance() { + return distance; + } + + public void setDistance(Double distance) { + this.distance = distance; + } + + public Integer getRank() { + return rank; + } + + public void setRank(Integer rank) { + this.rank = rank; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/ResultResponse.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/ResultResponse.java new file mode 100644 index 0000000..de381ba --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/ResultResponse.java @@ -0,0 +1,48 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +/** + * Created by Admin on 8/20/2017. + */ + +import java.util.List; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class ResultResponse { + + @SerializedName("status") + @Expose + private Integer status; + @SerializedName("message") + @Expose + private String message; + @SerializedName("result") + @Expose + private List result = null; + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsDetailInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsDetailInfo.java new file mode 100644 index 0000000..de0427f --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsDetailInfo.java @@ -0,0 +1,178 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +/** + * Created by Admin on 8/20/2017. + */ + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class SnsDetailInfo { + + @SerializedName("group_name") + @Expose + private String groupName; + @SerializedName("walk_mode_active") + @Expose + private int walkModeActive; + @SerializedName("run_mode_active") + @Expose + private int runModeActive; + @SerializedName("bike_mode_active") + @Expose + private int bikeModeActive; + @SerializedName("step_mode_active") + @Expose + private int stepModeActive; + @SerializedName("gym_mode_active") + @Expose + private int gymModeActive; + @SerializedName("beginer_mode_active") + @Expose + private int beginerModeActive; + @SerializedName("goal") + @Expose + private String goal; + @SerializedName("walk_mode_goal") + @Expose + private int walkModeGoal; + @SerializedName("run_mode_goal") + @Expose + private int runModeGoal; + @SerializedName("bike_mode_goal") + @Expose + private int bikeModeGoal; + @SerializedName("step_mode_goal") + @Expose + private Object stepModeGoal; + @SerializedName("gym_mode_goal") + @Expose + private Object gymModeGoal; + @SerializedName("beginer_mode_goal") + @Expose + private Object beginerModeGoal; + @SerializedName("join_group") + @Expose + private int joinGroup; + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public int getWalkModeActive() { + return walkModeActive; + } + + public void setWalkModeActive(int walkModeActive) { + this.walkModeActive = walkModeActive; + } + + public int getRunModeActive() { + return runModeActive; + } + + public void setRunModeActive(int runModeActive) { + this.runModeActive = runModeActive; + } + + public int getBikeModeActive() { + return bikeModeActive; + } + + public void setBikeModeActive(int bikeModeActive) { + this.bikeModeActive = bikeModeActive; + } + + public int getStepModeActive() { + return stepModeActive; + } + + public void setStepModeActive(int stepModeActive) { + this.stepModeActive = stepModeActive; + } + + public int getGymModeActive() { + return gymModeActive; + } + + public void setGymModeActive(int gymModeActive) { + this.gymModeActive = gymModeActive; + } + + public int getBeginerModeActive() { + return beginerModeActive; + } + + public void setBeginerModeActive(int beginerModeActive) { + this.beginerModeActive = beginerModeActive; + } + + public String getGoal() { + return goal; + } + + public void setGoal(String goal) { + this.goal = goal; + } + + public int getWalkModeGoal() { + return walkModeGoal; + } + + public void setWalkModeGoal(int walkModeGoal) { + this.walkModeGoal = walkModeGoal; + } + + public int getRunModeGoal() { + return runModeGoal; + } + + public void setRunModeGoal(int runModeGoal) { + this.runModeGoal = runModeGoal; + } + + public int getBikeModeGoal() { + return bikeModeGoal; + } + + public void setBikeModeGoal(int bikeModeGoal) { + this.bikeModeGoal = bikeModeGoal; + } + + public Object getStepModeGoal() { + return stepModeGoal; + } + + public void setStepModeGoal(Object stepModeGoal) { + this.stepModeGoal = stepModeGoal; + } + + public Object getGymModeGoal() { + return gymModeGoal; + } + + public void setGymModeGoal(Object gymModeGoal) { + this.gymModeGoal = gymModeGoal; + } + + public Object getBeginerModeGoal() { + return beginerModeGoal; + } + + public void setBeginerModeGoal(Object beginerModeGoal) { + this.beginerModeGoal = beginerModeGoal; + } + + public int getJoinGroup() { + return joinGroup; + } + + public void setJoinGroup(int joinGroup) { + this.joinGroup = joinGroup; + } +} + diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMemberInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMemberInfo.java new file mode 100644 index 0000000..939f999 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMemberInfo.java @@ -0,0 +1,89 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Created by Admin on 8/21/2017. + */ + +public class SnsMemberInfo { + @SerializedName("user_id") + @Expose + private int userId; + @SerializedName("profile_image") + @Expose + private Object profileImage; + @SerializedName("username") + @Expose + private String username; + @SerializedName("nickname") + @Expose + private String nickname; + @SerializedName("gender") + @Expose + private String gender; + @SerializedName("birthday") + @Expose + private String birthday; + @SerializedName("join_date") + @Expose + private String joinDate; + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public Object getProfileImage() { + return profileImage; + } + + public void setProfileImage(Object profileImage) { + this.profileImage = profileImage; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getBirthday() { + return birthday; + } + + public void setBirthday(String birthday) { + this.birthday = birthday; + } + + public String getJoinDate() { + return joinDate; + } + + public void setJoinDate(String joinDate) { + this.joinDate = joinDate; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMyGroupInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMyGroupInfo.java new file mode 100644 index 0000000..445aafe --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsMyGroupInfo.java @@ -0,0 +1,44 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Created by sonlt on 8/21/17. + */ + +public class SnsMyGroupInfo { + @SerializedName("id") + @Expose + private int id; + @SerializedName("group_name") + @Expose + private String groupName; + @SerializedName("description") + @Expose + private String description; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchInfo.java new file mode 100644 index 0000000..e7dbdcd --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchInfo.java @@ -0,0 +1,133 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsSearchInfo { + @SerializedName("group_id") + @Expose + private int groupId; + @SerializedName("group_name") + @Expose + private String groupName; + @SerializedName("group_avatar") + @Expose + private Object groupAvatar; + @SerializedName("walk_mode_active") + @Expose + private int walkModeActive; + @SerializedName("run_mode_active") + @Expose + private int runModeActive; + @SerializedName("bike_mode_active") + @Expose + private int bikeModeActive; + @SerializedName("step_mode_active") + @Expose + private int stepModeActive; + @SerializedName("gym_mode_active") + @Expose + private int gymModeActive; + @SerializedName("beginer_mode_active") + @Expose + private int beginerModeActive; + @SerializedName("created_at") + @Expose + private String createdAt; + @SerializedName("num_search") + @Expose + private String numSearch; + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public Object getGroupAvatar() { + return groupAvatar; + } + + public void setGroupAvatar(Object groupAvatar) { + this.groupAvatar = groupAvatar; + } + + public int getWalkModeActive() { + return walkModeActive; + } + + public void setWalkModeActive(int walkModeActive) { + this.walkModeActive = walkModeActive; + } + + public int getRunModeActive() { + return runModeActive; + } + + public void setRunModeActive(int runModeActive) { + this.runModeActive = runModeActive; + } + + public int getBikeModeActive() { + return bikeModeActive; + } + + public void setBikeModeActive(int bikeModeActive) { + this.bikeModeActive = bikeModeActive; + } + + public int getStepModeActive() { + return stepModeActive; + } + + public void setStepModeActive(int stepModeActive) { + this.stepModeActive = stepModeActive; + } + + public int getGymModeActive() { + return gymModeActive; + } + + public void setGymModeActive(int gymModeActive) { + this.gymModeActive = gymModeActive; + } + + public int getBeginerModeActive() { + return beginerModeActive; + } + + public void setBeginerModeActive(int beginerModeActive) { + this.beginerModeActive = beginerModeActive; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public String getNumSearch() { + return numSearch; + } + + public void setNumSearch(String numSearch) { + this.numSearch = numSearch; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchResponse.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchResponse.java new file mode 100644 index 0000000..53b9fed --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsSearchResponse.java @@ -0,0 +1,46 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsSearchResponse { + @SerializedName("status") + @Expose + private Integer status; + @SerializedName("message") + @Expose + private String message; + @SerializedName("result") + @Expose + private List result = null; + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicInfo.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicInfo.java new file mode 100644 index 0000000..feca72d --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicInfo.java @@ -0,0 +1,122 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Created by Admin on 8/16/2017. + */ + +public class SnsTopicInfo { + @SerializedName("id") + @Expose + private int id; + @SerializedName("group_id") + @Expose + private int groupId; + @SerializedName("tweet_content") + @Expose + private String tweetContent; + @SerializedName("mode") + @Expose + private int mode; + @SerializedName("distance") + @Expose + private int distance; + @SerializedName("time") + @Expose + private String time; + @SerializedName("user_id") + @Expose + private String userId; + @SerializedName("username") + @Expose + private String username; + @SerializedName("profile_image") + @Expose + private Object profileImage; + @SerializedName("created_at") + @Expose + private String createdAt; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + public String getTweetContent() { + return tweetContent; + } + + public void setTweetContent(String tweetContent) { + this.tweetContent = tweetContent; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Object getProfileImage() { + return profileImage; + } + + public void setProfileImage(Object profileImage) { + this.profileImage = profileImage; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicResponse.java b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicResponse.java new file mode 100644 index 0000000..2bcce3a --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/model/structure/pojo/SnsTopicResponse.java @@ -0,0 +1,47 @@ +package com.dinhcv.lifelogpedometer.model.structure.pojo; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsTopicResponse { + @SerializedName("status") + @Expose + private Integer status; + @SerializedName("message") + @Expose + private String message; + @SerializedName("result") + @Expose + private List result = null; + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiService.java b/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiService.java new file mode 100644 index 0000000..0d62182 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiService.java @@ -0,0 +1,75 @@ +package com.dinhcv.lifelogpedometer.network; + +import com.dinhcv.lifelogpedometer.model.structure.pojo.RankingInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.ResultResponse; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsDetailInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMemberInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMyGroupInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchResponse; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicResponse; +import com.google.gson.JsonObject; + +import java.util.Map; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.HeaderMap; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.QueryMap; + +/** + * Created by Admin on 8/17/2017. + */ + +public interface ApiService { + @GET("/api/sns") + Call getSnsTopicList( + @HeaderMap Map headers + ); + + @POST("/api/sns/group/search") + Call getSnsSearchList( + @HeaderMap Map headers, + @Query("keyword") String keyword, + @Query("page") int page + ); + + @GET("/api/sns/group/detail/{group_id}") + Call> getSnsDetail( + @HeaderMap Map headers, + @Path("group_id") int groupId + ); + + @POST("/api/groups/newGroup") + Call createGroup( + @HeaderMap Map headers, + @QueryMap Map params + ); + + @GET("/api/groups/list") + Call> getSnsMyGroup( + @HeaderMap Map headers + ); + @GET("/api/sns/group/member/{group_id}") + Call> getSnsMember( + @HeaderMap Map headers, + @Path("group_id") int groupId + ); + + @POST("/api/sns/group/join") + Call joinSnsGroup( + @HeaderMap Map headers, + @Query("group_id") int groupId + ); + + @GET("/api/ranking/{mode}/{startDate}/{endDate}/{page}") + Call> getRankingList( + @HeaderMap Map headers, + @Path("mode") int mode, + @Path("startDate") String startDate, + @Path("endDate") String endDate, + @Path("page") int page + ); +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiUtils.java b/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiUtils.java new file mode 100644 index 0000000..0cf12b4 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/network/ApiUtils.java @@ -0,0 +1,13 @@ +package com.dinhcv.lifelogpedometer.network; + +/** + * Created by Admin on 8/17/2017. + */ + +public class ApiUtils { + public static final String BASE_URL = "http://clover.timesfun.jp:9001/"; + + public static ApiService getApiService() { + return RetrofitClient.getClient(BASE_URL).create(ApiService.class); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/network/RetrofitClient.java b/app/src/main/java/com/dinhcv/lifelogpedometer/network/RetrofitClient.java new file mode 100644 index 0000000..c87904d --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/network/RetrofitClient.java @@ -0,0 +1,22 @@ +package com.dinhcv.lifelogpedometer.network; + +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by Admin on 8/17/2017. + */ + +public class RetrofitClient { + private static Retrofit retrofit = null; + + public static Retrofit getClient(String baseUrl) { + if (retrofit==null) { + retrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + } + return retrofit; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/portal/APIResponse.java b/app/src/main/java/com/dinhcv/lifelogpedometer/portal/APIResponse.java new file mode 100644 index 0000000..e28a9b2 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/portal/APIResponse.java @@ -0,0 +1,22 @@ +package com.dinhcv.lifelogpedometer.portal; + +public class APIResponse { + private String key_c; + private String token; + private static APIResponse apiResponse; + + public static APIResponse getInstance() { + if (apiResponse == null) { + apiResponse = new APIResponse(); + } + return apiResponse; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/portal/LLAPIManager.java b/app/src/main/java/com/dinhcv/lifelogpedometer/portal/LLAPIManager.java new file mode 100644 index 0000000..e3ed856 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/portal/LLAPIManager.java @@ -0,0 +1,874 @@ +package com.dinhcv.lifelogpedometer.portal; + +import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.util.Base64; + +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.model.structure.RegisterInfo; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class LLAPIManager { + public static String URL_ROOT = "http://clover.timesfun.jp:9001/"; + //login info + public static String URL_LOGIN_INFO = "login"; + //register info + public static String URL_REGISTER_INFO = "register"; + //upload image info + public static String URL_UPLOAD_IMAGE_INFO = "upload-image"; + //Search zipcode + public static String URL_FORGET_PASS_INFO = "forgetPass"; + //history + public static String URL_HISTORE_INFO = "api/history"; + //history detail + public static String URL_HISTORE_DETAIL_INFO = "api/history/detail"; + // home + public static String URL_HOME_INFO = "api/home"; + //Search zipcode + public static String URL_FORGET_PASS_CONFIRM_INFO = "forgetPass/confirm"; + // Refesh Token + public static String URL_REFESH_TOKEN_INFO = "refreshToken"; + + + private static int deviationValue = 1; + + public static void login(final Context context, final String email, final String pass, final LLAPIManagerListener action) { + new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_LOGIN_INFO); + JSONObject jsonObject = new JSONObject(); + + try { + jsonObject.put("email", email); + jsonObject.put("password", pass); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json"); + Debug.normal("JSON STRING: %s", jsonObject.toString()); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1){ + JSONObject object = jsonObject.optJSONObject("result"); + JSONObject objUser = object.getJSONObject("user"); + String token = object.optString("token"); + // save data + Setting.setUserDataSharepre(context, Setting.TOKEN_SHAREPRE, token); + APIResponse.getInstance().setToken(token); + Debug.normal("Token: "+ token); + action.onSuccess(objUser); + }else { + action.onError(new Error(jsonObject.optString("message"))); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + }.execute(); + } + + public static void uploadImage(final Bitmap bitmap, final LLAPIManagerListener action) { + new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_UPLOAD_IMAGE_INFO); + JSONObject jsonObject = new JSONObject(); + byte[] bitmapByte = convertBitmapToByteArray(bitmap); + String imageBase64 = Base64.encodeToString(bitmapByte, Base64.DEFAULT); + String imageStr = imageBase64.replace("\n",""); + + String token = APIResponse.getInstance().getToken(); + try { + if (token != null && !token.isEmpty()) { + Debug.normal("Token is not null"); + jsonObject.put("token", token); + } + jsonObject.put("img", imageStr); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json; charset=utf-8"); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1){ + action.onSuccess(new JSONObject()); + }else { + action.onError(new Error(jsonObject.optString("message"))); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + }.execute(); + } + + public static void register(final RegisterInfo registerInfo, final LLAPIManagerListener action) { + new AsyncTask() { + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_REGISTER_INFO); + JSONObject jsonObject = new JSONObject(); + + String token = APIResponse.getInstance().getToken(); + try { + jsonObject.put("username", registerInfo.getUsername()); + jsonObject.put("password", registerInfo.getPassword()); + jsonObject.put("full_name", registerInfo.getFullName()); + jsonObject.put("nickname", registerInfo.getNickname()); + jsonObject.put("birthday", Utils.dateToStringFormatDayMonthYear(registerInfo.getBirthday())); + jsonObject.put("height", ""+registerInfo.getHeight()); + jsonObject.put("weight", ""+registerInfo.getWeight()); + jsonObject.put("fat_rate", ""+registerInfo.getFatRate()); + jsonObject.put("gender", ""+registerInfo.getGender()); + jsonObject.put("address", registerInfo.getAddress()); + jsonObject.put("desciption", ""); + jsonObject.put("receive_notification", "0"); + //jsonObject.put("phone", "+84986940999"); + jsonObject.put("share_data", "1"); + jsonObject.put("profile_image", ""+registerInfo.getProfileImage()); + jsonObject.put("delete_flag", "0"); + jsonObject.put("email", registerInfo.getEmail()); + jsonObject.put("physical_activity", "0"); + jsonObject.put("remember_me", "1"); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json; charset=utf-8"); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1){ + JSONObject object = jsonObject.optJSONObject("result"); + JSONObject objUser = object.getJSONObject("user"); + String token = object.optString("token"); + APIResponse.getInstance().setToken(token); + Debug.normal("Token: "+ token); + action.onSuccess(objUser); + }else { + action.onError(new Error(jsonObject.optString("message"))); + } + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }.execute(); + } + + private static byte[] convertBitmapToByteArray(Bitmap bitmap) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); + byte[] byteArray = byteArrayOutputStream.toByteArray(); + return byteArray; + } + + public static void forgetPass(final String email, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_FORGET_PASS_INFO); + JSONObject jsonObject = new JSONObject(); + try { + //Personal info + jsonObject.put("email", email); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json"); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static void forgetPassConfirm(final String email, final String codeConfirm, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_FORGET_PASS_CONFIRM_INFO); + JSONObject jsonObject = new JSONObject(); + try { + //Personal info + jsonObject.put("email", email); + jsonObject.put("code_confirm", codeConfirm); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json"); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static void history(final Date fromDate, final Date toDate, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + + String fromStr = Utils.dateToStringFormatYearMonthDay(fromDate); + String toStr = Utils.dateToStringFormatYearMonthDay(toDate); + Debug.normal("Token: "+ APIResponse.getInstance().getToken()); + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_HISTORE_INFO + "/"+ fromStr +"/"+ toStr); + Debug.normal("URL: "+baseUrl.toString()); + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .addHeader("token", APIResponse.getInstance().getToken()) + .get(); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static void historyDetail(final Date fromDate, final Date toDate, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + + String fromStr = Utils.dateToStringFormatDayMonthYear(fromDate); + String toStr = Utils.dateToStringFormatDayMonthYear(toDate); + Debug.normal("Token: "+ APIResponse.getInstance().getToken()); + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_HISTORE_DETAIL_INFO + "/"+ fromStr +"/"+ toStr); + Debug.normal("URL: "+baseUrl.toString()); + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .addHeader("token", APIResponse.getInstance().getToken()) + .get(); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static void homePage(final Date date, final Const.STEP_TYPE stepType, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + + String dateStr = Utils.dateToStringFormatDayMonthYear(date); + Debug.normal("Token: "+ APIResponse.getInstance().getToken()); + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_HOME_INFO + "/"+ stepType.value +"/"+ dateStr); + Debug.normal("URL: "+baseUrl.toString()); + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .addHeader("token", APIResponse.getInstance().getToken()) + .get(); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static void refreshToken(final Context context, final int userId, final LLAPIManagerListener action) { + new AsyncTask() { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... voids) { + HttpUrl baseUrl = HttpUrl.parse(URL_ROOT + URL_REFESH_TOKEN_INFO); + JSONObject jsonObject = new JSONObject(); + try { + //Personal info + jsonObject.put("userId", userId); + + Debug.warn("Json data: " + jsonObject.toString()); + } catch (JSONException e) { + Debug.normal("Error ", e.getMessage()); + } + + MediaType JSON + = MediaType.parse("application/json"); + RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); + + final Request.Builder request = new Request.Builder() + .url(baseUrl) + .header("User-Agent", Utils.getCustomUA()) + .header("Content-Type", "application/json") + .post(requestBody); + + OkHttpClient httpClient = new OkHttpClient.Builder() + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .connectTimeout(30, TimeUnit.SECONDS) + .build(); + + String jsonString = null; + try { + Response response = httpClient.newCall(request.build()).execute(); + if (response == null) { + action.onError(null); + Debug.error("Response is null"); + return null; + } + jsonString = getResponseData(response.body()); + + } catch (IOException e) { + Debug.normal("Error %s", e.getMessage()); + } + return jsonString; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + action.onError(null); + } + + @Override + protected void onPostExecute(String jsonString) { + super.onPostExecute(jsonString); + if ((jsonString == null) || (jsonString.isEmpty())) { + action.onError(null); + return; + } + Debug.normal("String body: "+jsonString); + + try { + JSONObject jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + JSONArray tokenArr = jsonObject.optJSONArray("result"); + String token = tokenArr.get(0).toString(); + Debug.normal("Refresh Token: "+ token); + // save data + Setting.setUserDataSharepre(context, Setting.TOKEN_SHAREPRE, token); + APIResponse.getInstance().setToken(token); + action.onSuccess(jsonString); + } else { + action.onError(new Error(jsonObject.getString("message"))); + } + } catch (JSONException e) { + action.onError(null); + } + } + }.execute(); + } + + public static Bitmap getBitmapFromAsset(Context context, String filePath) { + AssetManager assetManager = context.getAssets(); + InputStream istr; + Bitmap bitmap = null; + try { + istr = assetManager.open(filePath); + bitmap = BitmapFactory.decodeStream(istr); + } catch (IOException e) { + Debug.normal("error: %s", e.getMessage()); + } + return bitmap; + } + + public static String getResponseData(ResponseBody response) { + + String unzipString = ""; + try { + unzipString = response.string(); + Debug.normal("RESPONSE: "+unzipString); + } catch (IOException e) { + e.printStackTrace(); + } + return unzipString; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Const.java b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Const.java new file mode 100644 index 0000000..a753534 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Const.java @@ -0,0 +1,33 @@ +package com.dinhcv.lifelogpedometer.utils; + +public class Const { + + public static int STEP_GOAL = 10000; + public static int STEP_SIZE = 75; //cm + public static final String EMAIL = "email"; + + + public enum DATA_TYPE{ + ONE_DAY(1), + ONE_WEEK(2), + ONE_MONTH(3), + THREE_MONTH(4), + SIX_MONTH(5); + + public int value; + DATA_TYPE(int value){ + this.value = value; + } + } + + public enum STEP_TYPE{ + WALKING(1), + RUNNING(2), + BIKE(3); + + public int value; + STEP_TYPE(int value){ + this.value = value; + } + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/utils/DayAxisValueFormatter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/DayAxisValueFormatter.java new file mode 100644 index 0000000..02921b0 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/DayAxisValueFormatter.java @@ -0,0 +1,26 @@ +package com.dinhcv.lifelogpedometer.utils; + +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.formatter.IAxisValueFormatter; +import java.util.List; + +public class DayAxisValueFormatter implements IAxisValueFormatter { + + private List mDateList; + + public DayAxisValueFormatter(List dateList) { + mDateList = dateList; + } + + + @Override + public String getFormattedValue(float value, AxisBase axis) { + + int index = (int) value; + String date = mDateList.get(index); + + return date; + } + + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Debug.java b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Debug.java new file mode 100644 index 0000000..8e9fb82 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Debug.java @@ -0,0 +1,268 @@ +package com.dinhcv.lifelogpedometer.utils; + +import android.util.Log; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Locale; + +@SuppressWarnings("unused") +public class Debug +{ + /* + * define constants for debug mode + */ + private static final int DBG_LEVEL_DBG = 5; + private static final int DBG_LEVEL_NORMAL = 4; + private static final int DBG_LEVEL_WARN = 3; + private static final int DBG_LEVEL_ERROR = 2; + private static final int DBG_LEVEL_FATAL = 1; + + /* + * variables + */ + private static final int DEBUG_LEVEL = DBG_LEVEL_NORMAL; + private static final String TAG = "LifeLog"; + private static final double MB = 1.0 * 1024 * 1024; // MB + + /** + * Hide constructor + */ + private Debug(){ + } + + private static int getDebugLevel(){ + return DEBUG_LEVEL; + } + + /** + * Description : Trace fatal message + * + * @param fmt : text message + */ + public static void fatal(String fmt, Object... args) + { + if (getDebugLevel() >= DBG_LEVEL_FATAL) + { + final String stMsg = format("[FATAL]" + fmt, args); + final String stPoint = format(" at %s", getDebugPoint()); + + Log.e(TAG, "[FATAL]###########################################"); + Log.e(TAG, stMsg); + Log.e(TAG, stPoint); + Log.e(TAG, "[FATAL]###########################################"); + } + } + + /** + * Description : Trace error message + * + * @param args : text message + */ + public static void error(String fmt, Object... args) + { + if (getDebugLevel() >= DBG_LEVEL_ERROR) + { + final String stMsg = format("[ERR]" + fmt, args); + final String stPoint = format(" at %s", getDebugPoint()); + + Log.e(TAG, stMsg); + Log.e(TAG, stPoint); + } + } + + /** + * Description : Trace warning message + * + * @param args : text message + */ + public static void warn(String fmt, Object... args) + { + if (getDebugLevel() >= DBG_LEVEL_WARN) + { + final String stMsg = format("[WRN]" + fmt, args); + final String stPoint = format(" at %s", getDebugPoint()); + + Log.w(TAG, stMsg); + Log.w(TAG, stPoint); + } + } + + /** + * Description : Trace warning message + * + * @param args : text message + */ + public static void dbg(String fmt, Object... args) + { + if (getDebugLevel() >= DBG_LEVEL_DBG) + { + Log.v(TAG, format("[ d ]" + fmt, args)); + } + } + + /** + * Description : Trace normal message + * + * @param args : text message + */ + public static void normal(String fmt, Object... args) + { + if (getDebugLevel() >= DBG_LEVEL_NORMAL) + { + Log.v(TAG, format("[ - ]" + fmt, args)); + } + } + + /** + * Description : verify + * + * @param b : Condition assert + */ + @SuppressWarnings("unused") + public static void verify(boolean b) { + if (!(b)) { + final String stMsg = format("###### ASSERT FAILED ######"); + final String stPoint = format(" at %s", getDebugPoint()); + + Log.w(TAG, stMsg); + Log.w(TAG, stPoint); + } + } + + /** + * Description : verify + * + * @param b : Condition assert + */ + @SuppressWarnings("unused") + public static void verify(boolean b, String msg) { + if (!(b)) { + final String stMsg = format("###### ASSERT FAILED ######"); + final String stPoint = format(" at %s", getDebugPoint()); + Log.w(TAG, stMsg); + if (msg != null) { + Log.w(TAG, " msg: " + msg); + } + Log.w(TAG, stPoint); + } + } + + /** + * Print Stack trace when exception + * @param e Exception + */ + public static void printStackTrace( Exception e ){ + StringWriter sw = new StringWriter(); + e.printStackTrace( new PrintWriter(sw) ); + String msg = sw.toString(); + + if (getDebugLevel() >= DBG_LEVEL_ERROR) { + Log.e(TAG, msg); + } + } + + /** + * Is debug mode, true for debug mode + * @return DEBUG mode + */ + public static boolean isDebugEnable() { + return DEBUG_LEVEL >= DBG_LEVEL_DBG; + } + + /** + * Use to trace current line/file at debug log point + * + * @return The point with the Java's logging default format, so, you can + * double click on the tracing line in the LogCat tool + */ + private static String getDebugPoint() + { + final String fullClassName = Thread.currentThread().getStackTrace()[4].getClassName(); + final String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1); + final String methodName = Thread.currentThread().getStackTrace()[4].getMethodName(); + final int lineNumber = Thread.currentThread().getStackTrace()[4].getLineNumber(); + + // + return format("%s.%s(%s.java:%d)", fullClassName, methodName, className, lineNumber); + } + + /** + * Log current status of Heap + * + */ + @SuppressWarnings("unused") + public static void logHeap() { + final String tag = "HEAP"; + + + final Double allocated = android.os.Debug.getNativeHeapAllocatedSize() / MB; + final Double available = android.os.Debug.getNativeHeapSize() / MB; + final Double free = android.os.Debug.getNativeHeapFreeSize() / MB; + final Double memUsed = Runtime.getRuntime().totalMemory() / MB; + final Double memMax = Runtime.getRuntime().maxMemory() / MB; + final Double memFree = Runtime.getRuntime().freeMemory() / MB; + + Log.d(tag, format("Heap native: allocated %6.3f MB of %6.3f - free %6.3f MB", allocated, available, free)); + Log.d(tag, format("Memory : allocated %6.3f MB of %6.3f - free %6.3f MB", memUsed, memMax, memFree)); + } + + private static String format(String fmt, Object... args) + { + if ((args != null) && (args.length > 0)) { + return String.format(Locale.US, fmt, args); + } + else { + return fmt; + } + } + + /** + * Register a UnExceptionHandler to catch force-close error for thread + */ + public static void registerUnExceptionHandler() { + if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) { + Thread.setDefaultUncaughtExceptionHandler( new ExceptionHandler() ); + } + } + + /** + * Trace current stack + */ + @SuppressWarnings("unused") + public static void stackTrace() { + Log.w(TAG, "########### STACK TRACE START #############"); + for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) { + System.out.println(ste); + } + Log.w(TAG, "########### STACK TRACE END #############"); + } + + public static class ExceptionHandler implements UncaughtExceptionHandler { + private final UncaughtExceptionHandler defaultUEH; + + /* + * if any of the parameters is null, the respective functionality will + * not be used + */ + public ExceptionHandler() { + this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + e.printStackTrace(printWriter); + printWriter.close(); + + defaultUEH.uncaughtException(t, e); + } + } +} + +/******************************************************************************* + * End of file + ******************************************************************************/ diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Utils.java b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Utils.java new file mode 100644 index 0000000..d14a23d --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/utils/Utils.java @@ -0,0 +1,334 @@ +package com.dinhcv.lifelogpedometer.utils; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import com.dinhcv.lifelogpedometer.LifeLogApplication; + +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class Utils { + private Utils() { + + } + + /** + * Get color wrapper + * + * @param context + * @param id + * @return: + */ + public static int getColorWrapper(Context context, int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return context.getColor(id); + } else { + //noinspection deprecation + return context.getResources().getColor(id); + } + } + + /** + * Get drawable wrapper + * + * @param context + * @param id + * @return: + */ + public static Drawable getDrawableWrapper(Context context, int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return context.getDrawable(id); + } else { + //noinspection deprecation + return context.getResources().getDrawable(id); + } + } + + /** + * Convert value to string + * + * @param value + * @return + */ + public static String convert2String2Decimal(double value) { + String valueStr = null; + DecimalFormat dFormat = new DecimalFormat("####,###,##0.00"); + valueStr = dFormat.format(value); + return valueStr; + } + + /** + * Convert value to string + * + * @param value + * @return + */ + public static String convert2StringAroundNum(double value) { + String valueStr = null; + DecimalFormat dFormat = new DecimalFormat("####,###,###"); + valueStr = dFormat.format(value); + return valueStr; + } + + public static String convertDateToStringDialogSelect(Date input) { + //昭和yyyy年MM月dd日 + SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.JAPAN); + format.setTimeZone(TimeZone.getTimeZone("GMT+07:00")); + return format.format(input); + } + + /** + * * Convert date to string with format date month year + * + * @param date date + * @return date string + */ + public static String dateToStringFormatDayMonthYearJp(Date date) { + String dateStr = null; + if (date != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日", Locale.JAPAN); + dateStr = sdf.format(date); + } + return dateStr; + } + + /** + * * Convert date to string with format date month year + * + * @param date date + * @return date string + */ + public static String dateToStringFormatDayMonthYear(Date date) { + String dateStr = null; + if (date != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.JAPAN); + dateStr = sdf.format(date); + } + return dateStr; + } + + /** + * * Convert date to string with format date month year + * @param date date + * @return date string + */ + public static String dateToStringFormatYearMonthDay(Date date) { + String dateStr = null; + if ( date != null ) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.JAPAN); + dateStr = sdf.format(date); + } + Debug.normal("DATE format: "+dateStr); + return dateStr; + } + + public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) { + long diffInMillies = date2.getTime() - date1.getTime(); + return timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS); + } + + public static boolean checkMailFormat(String text) { + String regex = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + if (matcher.matches()) { + Debug.normal("String is Full width character"); + return true; + } else { + Debug.normal("String is not Full width character"); + return false; + } + + } + + public static long getToday() { + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + c.set(Calendar.HOUR_OF_DAY, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + return c.getTimeInMillis(); + } + + /** + * @return milliseconds since 1.1.1970 for tomorrow 0:00:01 local timezone + */ + public static long getTomorrow() { + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + c.set(Calendar.HOUR_OF_DAY, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 1); + c.set(Calendar.MILLISECOND, 0); + c.add(Calendar.DATE, 1); + return c.getTimeInMillis(); + } + + public static long getStandarDate(Date date) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + c.set(Calendar.HOUR_OF_DAY, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + return c.getTimeInMillis(); + } + + + public static Date getFromDate(Date date, Const.DATA_TYPE dataType ) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + if (dataType == Const.DATA_TYPE.ONE_DAY){ + c.add(Calendar.DAY_OF_YEAR, -1); + }else if (dataType == Const.DATA_TYPE.ONE_WEEK){ + c.add(Calendar.DAY_OF_YEAR, -7); + }else if (dataType == Const.DATA_TYPE.ONE_MONTH){ + c.add(Calendar.DAY_OF_YEAR, -30); + }else if (dataType == Const.DATA_TYPE.THREE_MONTH){ + c.add(Calendar.DAY_OF_YEAR, - 30 * 3); + }else if (dataType == Const.DATA_TYPE.SIX_MONTH){ + c.add(Calendar.DAY_OF_YEAR, - 30 * 6); + } + return c.getTime(); + } + + public static int getMonth(Date date) { + + int month = 0; + if (date != null) { + SimpleDateFormat sdf = new SimpleDateFormat("MM", Locale.JAPAN); + String dateStr = sdf.format(date); + if (dateStr != null) month = Integer.valueOf(dateStr); + } + Debug.normal("Month: " + month); + return month; + } + + public static int getDay(Date date) { + int month = 0; + if (date != null) { + SimpleDateFormat sdf = new SimpleDateFormat("dd", Locale.JAPAN); + String dateStr = sdf.format(date); + if (dateStr != null) month = Integer.valueOf(dateStr); + } + Debug.normal("Month: " + month); + return month; + } + + public static String userAgent = null; + + public static void setCustomUA(String ua) { + userAgent = ua; + } + + public static String getCustomUA() { + Context context = LifeLogApplication.context; + String packageName = context.getPackageName(); //{2} + String appVersion = "Android" + "." + "1.0.1"; //{3} + String osVersion = Build.VERSION.RELEASE; //{4} + String modelName = Build.MODEL; //{6} + String uaString = packageName + "/" + appVersion + "(Android " + osVersion + ";" + modelName + ")" + " " + userAgent; + return uaString; + } + + public static Date convertString2Date(String time) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date = null; + try { + date = df.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return date; + } + + public static String convertDate2DayString(Date date) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + return df.format(date); + } + + public static String convertDate2TimeString(Date date) { + DateFormat df = new SimpleDateFormat("HH:mm"); + return df.format(date); + } + + + public static String convertTimeStringFromString(int time){ + String timeCv = null; + String timeStr = String.valueOf(time); + int length = timeStr.length(); + switch (length){ + case 0: + timeCv = "00:00:00"; + break; + case 1: + timeCv = "00:00:0"+time; + break; + case 2: + timeCv = "00:00:"+time; + break; + case 3: + timeCv = "00:0"+timeStr.substring(0, 1)+":"+ timeStr.substring(1, timeStr.length()); + break; + case 4: + timeCv = "00:"+timeStr.substring(0, 2)+":"+ timeStr.substring(2, timeStr.length()); + break; + case 5: + timeCv = timeStr.substring(0, 1)+ ":"+timeStr.substring(1, 3)+":"+ timeStr.substring(3, timeStr.length()); + break; + case 6: + timeCv = timeStr.substring(0, 2)+":"+timeStr.substring(2, 4)+":"+ timeStr.substring(4, timeStr.length()); + break; + default: + timeCv = timeStr; + break; + } + + return timeCv; + } + + public static String convertSecond2HourMinSecString(int total){ + int hours = total / 3600; + int minutes = (total % 3600) / 60; + int seconds = total % 60; + + return String.format("%02d:%02d:%02d", hours, minutes, seconds); + } + + public static String formatInt2LengthDefault(int value){ + DecimalFormat dFormat = new DecimalFormat("00"); + String data = dFormat.format(value); + return data; + } + + public static String getWeekdayFromDate(Date date) { + SimpleDateFormat outFormat = new SimpleDateFormat("EEEE", Locale.JAPAN); + String goal = outFormat.format(date); + Debug.normal("WEEKDAY: " + goal); + return goal; + } + public static int parseString2Int(String input, int defaul) { + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + return defaul; + } + + } +} +/****************************************************************************** + * End of file + *****************************************************************************/ \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_beginer_user.png b/app/src/main/res/drawable-hdpi/ic_beginer_user.png new file mode 100644 index 0000000000000000000000000000000000000000..f9ad8972e80bd6a7ff38b5900f1db17dec81e7f3 GIT binary patch literal 2498 zcmV;z2|f0SP)3mnuQKAaqe6@kXB~`vNO7cTe{p_vD@lCb>Ag;fom|Jh*EU7K z{S(Fa-1DCIIq%nb-b1*}AG*!;#~lFfSio(Lz#SL(JPhDV&$5pgT_AYC<_Z!_X#Dr< z6uZ&u`CKf(yNRz7!NUv?0rFQsNW4L_Zdm}lLH4-sLX8G|N})MZ`Ed}45FXWtC3e!` z8wEt!EnxOW_G(5efB*p=Gx5rfPxF^Gl28aMp!3QON|Y0fvH~#Y`z(rwG8E_s5Y-y7 zE4wEAeeTn2q!=Eh;1i$#%+L5HbootcD;Ef50bq8Jy)!D%1%@Fz%^IB}6$ll&oAP~y z8({+cW0n#hcB8(~@9lt9asZ4V8&K$xAO}W2YXsvFirZP#_*i3unJpp!s+f_4My=Di za>*|#0HVB`&@-0adPf<7c!ZKpl)nx_kUcJim;&Z&Ml!{yjz>xt7fK4i*Mr;#z#yRa zT!h4*OZF@Za@+&~h@X#8b*UyU82}Hg;}8*AnKAfZ1*6!VpRAw}WY66iaU#Fi7?6OaHERF3yF3-$;wRas(k_PKVaz)BPVuhb2moILdzBm8G{aB? zZ=STCFYQ~t@7XQo(bT8*366r`C!qbzZfbVC^Nh%h^)?|G^$> z07QO;3j-1m|FD;4-f#exJGaOf9>32Aw$gCfFPwdMbM3*&ioRpar z>QC*XXfYtzwt$su`6?7VDPUG9l@}#eHgFHvtOi@U-=%Oa#U5_p5HVUAXg~IDac*E6 z0RLJ}GEk|8F*6!1F2`po_{g_83`Wx=H(Hgx+4iuMeZ39rh znxjPUYeo#CXpBakN8&($J>*6WfMyVUInPIownOhtq`klzmRdt9P=_tJCJ_QbGM)2Ul37=jQU;}RSK_hYCP&QYvW;L_OKXA}GSQZ)=Yy%(@Hw4(r zgfI~dsnZJ;W;Ko({X~dbjdr1vK7tsyWO=o0w7b!ll5$_a8FnE0(1Rt zcY)=ezi0r~`I$xaPKgX-PcXoSX7qtD_;!@Mc9qT?zs}D|B2UN^05+fH zD)~mv51P@r{Tn0}GUX{`oRyqsALbAX@k%(n{TNN>l2c^b2B2vLUo{UxpJ8S=M#-iX zEC(Z#`;#qbKamZmyG8=$5Pjiz3!jq27%^Q|bd**f&I&NIP`7NXW zwNqpW0E#gnKTVdO&!ubw@Z)c>w6AK2(Dv%7i6Hm<(sT^?)d$%C964?g#R<);mS+P{ z=r}7mKU%^erO>K14*&XenO$JZLmYq{S<@CD!YDdliBV$9lC)*~;&e6u7rVJ?G=)Tl z*$%lYFn__y>^M;9xJ)@e@tHwzy_u2H>#2R^w7qm_+X6(;3*Q{$|126jI)&<&W7#zL ze-3ih2qOT-%nF5$FFs}+1oMsC>SM#@LZ1}_1xDM8XY8k4M*s*2As_od2(h?BMz;%$ z`cSMmk|LMihI|}gLRY3d4fHBTC=|1|^W!oc12B1!KliZ^7)=1$e-fyA99jZ&ZG3;ON(=#9bT^C0WiF*Q2ohQ?x3hH4blFVjaa_eUO6;bP$ky{v&(2emZbU0>Czd zJ*m5~jTC|=I}9Y$r>Jg;Po>PdySa)L`oXB21i}z8=C7QT9c1z5{9nMp^-C2%M16`D ztNHC(LP-D!-_Jcz@Ug}a6cVC{w85J{rh2OdUGCqg| z!I+VPN4p@!SV`tD3V=5jaex%MWapXT+x(|={@;Et8%iN2?6K_BwQFd!Ypxvzd;T{A z9V9zH-TaLDP3N7bUB>{(0!Jz^z;X{jqve?k**yMl7n+2Lw6O#Pp|?ZNoTtu0tYPOO zUJo`oN4ZEfq!@vxFJ$NWoeQ~{6t>B|ff*y1)o2lK3X$a)fL-@;gc$3kL-f51*4%uD z!Cvh)FF4eUo!$~4LC+ddO!TL{$kefbgJJ>F+Ad^Qq{S}d8!uX?((yU$uER>UBLIHC zfI|fHE<0v!yE<*jPPn_r9=soFOGr2;Ic;J%rCTG`N4l0EXVT9^0m6;Jb zGKc%5C&($(uDasv3@#RMq)rk@OiIJx6A<&%B!m#Op5G1Jbqy9G{bB zWmo*IIR5{{9QLzDn-o$?qiOlyox6ab=5$@Q0XQ`~&HXLCVhupP_l~w0K)!kNz0W1r zHUMY7nr43=`iC_D`QAGPAm6Psj{DxqXX*}F{3)E;hU=m^txy`I@Mn!B@q_#->lduH}`XLn}KjKg8emMvSh zY}p!OX___;oCIF%;xiwxQ)M_~!H>1y>H}}Va$j&FI8t>$2ed!+gaHBH#Ot5n7?lB) z=>UBL&qXl(Dh3Y&ufWfoDgnB!1M~?Tp(`r|ALe@0N|gW|)WIkL`-4AnWjn!dxa%vb zy`*dK#+$%_SiTzk0DKbc4esCoT?DTJ=YXfF0BICB6njoI4*A=_bHF3fO0f*$^!ebRllbK2*4L=J$SQ=&*Mx2V!g-TQ(*YxDx8f35BAv=33wOIUG`#zPvqC0K&+DreX9(B z_!sACeDP)*9FjK@>!i$!KKGBP{~J&;*C>|m+;3u1cbr&fw#Q5mp&=tMFMI~P$i?hf zM1=;HEdwcCwh1D8v?@$4EYpc~Wf5XU%LXXakXXGkE>4S0zG}zX5K%E#5#OkWB^>LK}JC32H{+#9$68XUo}}} z2ZFsz0*LX01!m@*G6G650BD^+{9^)fzsd+`rXZYZk<(!Czm)>9r5we)Ffm3|tYCbR z-HmQp^U%4}cLW=e1Y_S90Q6K=K;gvMbhUxl=LG=Wk`<7XI8P}s5PP8jpd^Q^BL31@ z24fcyV%JK2s*Gjv2se>oFt#6ehu>7sfWqZ+85g=U{ZC;98$?38#5YhqCg$uNR zMHQ$EbkjUX3+voH`(}6167;^h}$}rY`rB?k!+b1O>&0Ac@%djx(tWp%utjU z0(BBn@*%Ha4>gQr~=ccx=+j!gxMXBYy8|ZgdonmlXxp zHe;Y6?UdE|EQ8?11}B0^zo*&hZQ5(Fbw0X|7hesJgxait3|o7{$JhfI51w;4sI!L-_OQhZh*B0lo0$VuQ%}5i`d3#g8SvUf@FfD^ zFW>C%29`Dm0yn?7o5{-R`S9t`xm^Jnx^%{^D)eek>wafTgWIsiz120izm=G}{G-ut zRWe}k;@PQYcirLMR*zxWdMpmJt6!!FQfi$%bs@ehAi8^v2hTAy_0IDLdZ=ntd2Rfy z;{+nElvQK;o|2W6U)WK@wrk-RbX88OyIrpDKILyUM0h-zg4+u# zK#+ug^3?goCjydJWe?B&;F<0YLk25llo|Z3xrIzJo%y5H1F#shDn)X!Vy;RuEqri! zIP?l0|Hj4O`!1e4`Ak=bAxZ31jjCfLzZ=-NJv?{vX%pk{_=>JLx2Plq@y~f^yKc2( z5VPRDHM=M#1@TXKAs5g5@ax@vrr5}&Ai}NLMUYkP+4tWZ`@9;69fRazC2(V3ef^=n zcCR6THxrLwdMTpYRxUBzU5;k&Z*AQSkBoh%T8Nr}n5pv5+cPRj66nx@UPC@*XI*2L?Aj=A%bQ&ZLG#Y7_c_sT(bi#V`R7sthD3ZDsJO>B` z2$rU(#wMDos{)xuN_lDZzaK`_j7Y*#l|){QKo9MB-g;y^fgVEx@@ zn+kf&M51Y4$@uKLm~D{M_24AI(66w){l=TMZBwPlD#)?eW5cb2;1`6MJF=FQ|KJ?3 zcIR8QBB|?VQ)X&pmKOn$6c9WQQY2zo5xqvks;ov*&SN2$se}asY$+oAc7om(Nb*|X0##r46Q;e>lIqohVAqtl62EaBvwl%$59E5_D&5?2%+YN86i`b= zaJG{+)~~q+#*SOsF}t4?l0_it|NI+RzaI!^>A1A2NPZmuwWoEvcORt4wZz$bK)D-$ zYRYwm#XqYc@`DE;$78_u^y*XWx@#2&J3cS)kM@=BR;_{*&m+#?%cv>w{H_Iiar)h^ zUV-oLFPV-lf#7sIGXqR(8<4pC-%h_8sXgoZw)G1;TfvTZzxY5DW~PB^Xn;})zzRsN zjEMo)e?V6^U#2(*Mvd3}6(YY1kl-Z2GB2||eR|!lBodHWUaA=M<<`%GGVL8XHE@YC z{e_~*%6q$BqHH%)QQGI@@2e5s+l52IdE1aA;Y_|`|+hjY~i(%5F<3m8?VcP4Zu)o{+ z=`j&qlR;BI;uY!DY9a8NI|6y^X8Lsy1QF$MI9ggLs&0?TbzdZ(3++c>n+a07*qoM6N<$ Ef^r1&&Hw-a literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c20f7c7ba52110da94f6d3a2bf00788614f28f GIT binary patch literal 2466 zcmV;T30?MyP)bh zEn!XFA8KmfaV!kn2hM@!LUW?Izqi_=`hD^$U}*2vRG+>rStyPkI5%1Yt@XXpDs@C+ z5HPfzlcjRCi7`y%kwwC6w88zLSx(j%pgKHxi z5G~_OYf@LTr9Gd^r4el5(W}(t$&)!(mtFq`TiJV)j>%18o=bb4Ek4S-7NP~wG%m1) z*;#m&(@aNa$KL&0^~8!8%6sO|I1}97d5(8JNGqaQIn8mRaBLV- zcH*B@P{>T1a8Mjodi--3`+P+C%$Y;`FP_gNmcNgnj}u_5=@65;tDH5o{)tye3TV;; zHnUQ|bwi;2H^_aZhe@iq%;eO!0Bz$Q7#tn|c^#iYld`IptzBlL$p5Knl*dCufIMZ& zBv5kfONVpjGzQa^{xb z^=F53LfVIc+X=2bGWi*~y%jHRY$>(~ZrJY8!i@0t-1p8_kF0@GvLs> zAzow;0_BWz1kKBQ>^kM);f_U{{{k;MGG#xLSYe>Ule#ExZw=Z{M&HuU7bnRYOfu;( zLRKnmK-y#II3B#uIW6hZ{5q8T2@^p-x`P~c}y#GOORaY1Ga#&>l;K9I%9@A z9kI1-7_(HYzWJh1T7r0!?zQsT&nPJzn}D(`bwr!_bkuStyZ$_DXd7^dK_l0Jyh-wE zD4&rtD`!iNqY}l?@8u`1sg^~DQ8NPOf(%QKo%-js_mk4h=Cu!qsRBsK*?^%)Y}xDA!3IMnw~&|DMAmfh8uxz9nLFx`jmybGkwTp~ylXp2CY{AA{oroj zl4L3{XoD{IBgn9onl;~_V`6K08THG@AGh0iZR1{h!dw43GFryg`rzoE>2S8rOu?s|I=dasY^$kYU+{i8Az9v=nY<30Ici;i5QsE4rX zIVeOR!c53BzJPWd_(0U;6(?_iwCbG@jQ3H#{?lxPMrE0yhICTy-X4NXZ88Zu1UPr1 zAmP(z|CFul{gy~TkY{WQg8|)lqGFt+isHK%$t0LBGFf#O=#Whb*gN9x?g0Zw-ZepP z(;-2^VQeKKi2V)^>%6>tAYh6!t@uJN=wosk`muKVe&+J`U*=`N*mY4*^S8AP5PM$8 z^KdVKfSa7ZG*Gnk4ejru@&xl_gunWk^(LaIUDwhhU;=;V*FtX(=o!D25}F|11qnr` z2ZSZkn?Tq6DK&liWTF%yuf2~~O9cdks*F<8p^+yij(0LLC6ssvQeLhgN^79@vF2mn z@Zy}YvyWH6aRs@Os|b*H=Lra<1~3mIGOvWv-GYuF-dxN(hqkd%5djgK7>s!k#EX_r zz+yibCh#W3(8GOA&7SvjUJc4^YE#6-NI-fhm^=Jmg5nd+XdCa%*|=RNsD<0w z4oejf7D$u0d7FT$-WnX4v10)<3J?VB3k=Oqr_?_W}rxrYTN_T;ymnhM%(zVAkme*R?5xI6Hh?WKw30P_!pM_CfK4-`oIR;TIkj)jQ3;eCj6i(jQQ&!P-UrOP^l_@;cv_*lSI8>?7si z5aLj*00wEdA`H7v;Xw37W0qpVQRphd z&=9!H!dAU?N4<32le}|y`nka*@v36NQS36yNKN9o4h5P22Q};0zi^a}fwbzwN?^{| zT!$KgNxT>8N?!X96KgV36DQt14w|A`xgi4N@4cdF7;w6`8rutX_vLJSaS~f~Y7k}c zY~`DGoGzGgb|up;n3VHUFKPNPE-&@kYm@6*I2Ja!zE}WvxW1YKU#nbSZbDGib$vaK gYq*AMxQ65LKS-+nRM(N&sQ>@~07*qoM6N<$f>l<&I{*Lx literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_notification.png b/app/src/main/res/drawable-hdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..991832a2d13c723eb169c271a487b6998e594ff6 GIT binary patch literal 576 zcmV-G0>Ax2ch1~Y2C~|Tm^7l$h z%D=)Yw9E6I{5I3{-cH)LGs^zz)6TZPH}jc!@Aux@u~?GvpMx>B0&YPOXaO!WWpcnL z`;I9(-UCihVTO=;$5QMN=MSO+z9k#mqrzs=|f zoy!y%1Vi8~IzUwyvQv(oCdOEi95&!b;c1D>P3c zvvk}*pR1q?WN_L91Va1q%D8|ZyntGI8ro>*v~voC#^aGm0k2>QG=q1+MJ_mPt#lLG zaLDK`ug?6Ubf=BeHmJ$FQEpO3bp>>)=0ea;TWxDHWRz}u))8tItZCXx^T`m()REba zPKuhF*yQAnB>D*{`<#4E8;>C0FKdS05L}>NkUyDdp-#@pKR})!e?lPSl_iwR8K8GD z@~Z?w^)eUMQ_abPI{9Pt6dB!&&muEu-BL$LZ;{0BC7=D+qh-0}^kDQ8#S=jpQZ%f;ghU-CHDxSX_)^6SU-Ofl`Y1->QcTS%>zgv!d4txI0 uQk!k}7_!Rh?y&+5L<1kX*SmU7`r>5$l#Qh;q3Jfr0Sun5elF{r5}E)QOgKUS literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_resume.png b/app/src/main/res/drawable-hdpi/ic_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..6384a4eeca9ea50549697355ded549f826a768a2 GIT binary patch literal 342 zcmV-c0jd6pP)duECyk?q-=ZJFbr9+h{0yEm`o;vNf-t}FsO(h|E*{62Cvv$IC2jh z9$OgvxbJS~-C34MBoc{=mQt!6$8n1m!1w(jAa3vsu2KR7LGaEDfFrIIZkH$l43KRY zhFw|!4e$-E>wri{ac{NV(sPI@)6oAnmJM>477C=|y z1+TERnv?)WHLh5vKaK4I@b6oQwuzZvqr4w7+9*LA=4j(I^?`==NJ)FBryZ+M54LDW oi?qXC>hU`L4-Sz?Bocko2Vp~E*YghGxBvhE07*qoM6N<$f^SuacK`qY literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_second.png b/app/src/main/res/drawable-hdpi/ic_second.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf9f8688e0a763dc53165c9e955d80f1209b0d9 GIT binary patch literal 2235 zcmV;s2t@aZP)NZIGlC+An1lSEwkp-5!jRAv$0pC5B>Wnjpcs%xuG5gSYvE(^( z&i~E#egFCYGZ_4zT$orKokM-Y3@{bK<1zn8kK=W*^PzF}!QOuW1_eUTV1TVTdmLS2 z<`fOYey6t!W3aoW`a+Nq1aIyQuP;tv^m`-S1H)n#M)MI2{--jdUYzB)A@3+5Hqe@;N5{ttZ^GiT8^p%gU|Mp?J0Nx$y`wPIo9KYE))b}r)R{QIz;4OBGZm@Y72x(LgBr7qJ^)GSI9TNq8kQD}hk>lY8Bcx6$|? z-|72Ut5IKVs;b~6iIcLCwMV$Ofr87|sIQ*O5F8qxR*FljR3IGr8wXmdtWFFhlX<5X zS0jON42}puMi#%rmg> z;1K54HrUvN62ro}C%&`4Kkn=q_;$7+asnh1E1%EK(*%KI?G3d&KT0WUGJ(w6>@TEM zfszANv6FL)P-!-SP)XzUA3Sz;-@243&`kGp0z{|?L{+TU?}yg<8eSZ^WFsfi;vz(4 zxwW{stlVT^|3Yk_YS>n4OvwgY_CI^J;p`r;WP00T?&pLNv=G}UVfY{08fp}%@k+-A z0y#0a7^4{ar(zqYOki>b?<=x$M_BhO$0u*~cr$7)Z zG7KMVD5;f20tzV88$iY+YB3rQ0pK*m@B?_fI7N~SeLYufKm)~KK-{BL#Lur?X%^i)rDG>2jEsy<^aJ3%8ns+z zF%>EFg?S)PaX^6riBlB#_JXjsu}endWDEdv*gIN&C00U0<4yzwu^@}k|0D?PQnl46 zD>0mr6wlV~0W7(^Bt>4r zU$!>dh;&Ts?gbzijh9eUu@LbOd26i zM51w+S#SgTJ$`A`N;ubG5ljTgGYhNRAyS2xNtKvnAS0ub!)lfM?Y5UI1x?{U48g+6 zHk6z7pi;_!BxzXR^sy0e(EajI!CE?H#S6&U~|GWMp(QSZ6B{WCKl% zm>^{M3vV9D?CFvR3bblC-ynRd`ka-Zy`x1~hbaUqiII`fiOT@kgIAiX1?3@R0-Tq*gM+N9=#r4ODd55e2w~p=CkFzmNipWnO*dN&mYJrEi}*6SL>03VEC34 z(@O(#fAY4zQ2VpS8fmrO{OT5L?;fz_%DH-BvvV(l1-%#ez5TUT(Fb*sfH?0@JhYV= zzE@$^XCi>Tk7Tm!+BpJow%QD0HqJGV4^}sJ|K0go+htJ;N&T#l4CFtP3(!<=0bRa^ zw;lrV-#Iq~!co@XXKT%ZzCu}UX5J0oZLMSHIdvc-Nz(fA=^7aI1u4@hx`)!O$#4eh zZRx+)xVQb__3gujvxzTzr!FnDqaQar(muM914V%?yS$*+X+eyilIMBybUk_)3g0|E zvnQqBMD@A@?M=29WHUYIg8e|4^+WO(sXVm;s>_W>QbZCQpIL=^n+XhsTGm%6{o(}C z{LZV*q7UpOnH{a3ydjRytg!Mqo&Y!?sf?PuAtFDZjMm;%$qr9!h+83hM=SrBKaKOV z0Wz#nE8c2tw6WhtxQ$N8^y#t=XL6Ly5F6+kn_8k`B=ym$mnf)clt(B}t*u1O6^%>l zUfA*-LSs#7$_$nY3<5E`xCtft{3EGxY>+DA^oz!Xye9eyocOS%u|me}3kb}H*Uw7K zY|^D|bv@gDHpP}1bw?oBGJeiQQuH@e#&d5sRbz!@hBm-BMT4O*540K;VD ze4?>J{o literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_spinner_expand.png b/app/src/main/res/drawable-hdpi/ic_spinner_expand.png new file mode 100644 index 0000000000000000000000000000000000000000..cdf29474bdc5e32408859a0a936e88d9225e0d15 GIT binary patch literal 419 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 M07*qoM6N<$f{CA4t^fc4 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_toggle_off.png b/app/src/main/res/drawable-hdpi/ic_toggle_off.png new file mode 100644 index 0000000000000000000000000000000000000000..22ac7a526e19923e0eb1a20db51494ed37c6b6e5 GIT binary patch literal 984 zcmV;}11J26P)n%(<0MJL=>y2OtXR@%KizIpchH97f7MdD9Vbke=CZh zC`*J$sEBaB(VG>yS*|%ZE46fb-km!a&)LZ|mEmr*VE5?+G;m+PVwjO1k{;&;X$(l^a=A|N9ICaEhEV4 z2Ah>L$pWq`GnOQ2LW>S;TEtSEzSjZ?3*=B>(1JoDoD^VyVxY3t0;X?+aAJEhuaK8( zJ`o?RednGW)0be#p4>$_N_VEGRc9P8DemfUXzxm3cdNwl<1-FZt6iXZ- zoV6FB6v6J5QC`{O9=iF`23<}UuNLcCyW#FjOD&djq47&$c47?bbI4wCR@~Tz@Rky7 zobu{6Ue_Y(lNTO-Y{%A@8{OCP(^;1MYYp)DXok03^rb@U*jky^(vhiOx z>NnJ&2#=WZs9U6xL;l+7kGk_UZD9LJ!AXA}bzE3bFm%I~v`CF1MU8ugh1@h1=yl`6 zg3;Uy51Jg1;g7KJ)=oZZ>a-3B#px)~OpIIhoE6cSAyvgfa&gOK?`Oj$x=?tH_gCC{ z;~=XV*|?=17q_?`iPj@BsZ%MV{zYIlJDfJo9LF?yPu+ZRGbnZII0nlFXSU73DE*w|0nPw0s?5sE$-3w7>|M2WjT^ zFpgJw{n5lH1Ru5j-|u2R-ky&dL4&?p3>pj?^wof`<9`Fx2Htd53pNx00000cS`sqppDX4w1dlxYDR` zW6;Dm)q<#qDDo(UVjE~mOJO>lwv3sf#TJX1&@tAecYV&8@Ba7PbN@jg%@>m9e2@W5 z^@K7CW)w_SfmHMV-ySTx`av!viG3nIznY>bT__yUr>aJLzJSlOAqX-M42N%$LiFMD zlf~X-^?y?^3U-_a$QewT6JDg0OXb-TkV&(+cyGbO1T*1vTRtYR)IKcT8JLIGtkxRpaMcsehiWUj44-S$X{aA zVw|4kmmWI|I^A%v1cTDTTrlK`8JNBi99q76;9jc}G?)TRM(r=izTv@`k_=!)o#nhr zvG7!B@$%_xj@AonC#+IS;8=wYq#|C@suRHoG&T>wXU8P$Fq@c|mJi=>mwWtTbM5By zNc3o(6QtTbwY?#U-_I*5Q!gdyd1mLr-)xsB%4 z1yWX(SOn2M_oB5EZXaDYr*gB)&`KU|YKI*qCZ;E86`k(!8f5R4)@LT;k}@r(VDV{o zA+&lWY5`PjRkKToM%{YtfL2F{QPJ*nLr1s$2~v5<+P`f>k)F#r_o}TEE*vPBxe#nA z>5FsjelKj>U}EOvtF|s1va8-g9oT7RTZ2{H{ijxVe0meB*x5n58{R^UhpvC*9tU%u}eNdHShj~PrMyHQ%ajI$v<-!W6w)DGKc#!NTvbo*+UL5+q8S4HU> z5!Zt{UpfV+E9W<;n_E5w2?475>rdSpjRb1S|NPW7JnDtM(O~kYZpJKx$#+Fd8MA=S zYd*}86f+Bl%ouDoCYl9Hj|c8qr_BOAoTHA0=;|LH4Df{;X-AV_x6n}VhsmHp3bZOt zA?cp9Ib7iJ`N18vTMD@ta%I_|kF#67b{EmvH$)Kv(c%QV727;x9Kz%~rCh51Cx+EK z;fN_0V@huM3F5>89-PU`Sr}2P6k^$5viv^(Bsg4dd}M5#Hx+?;5=F25(elT)5v`_x zAoimoe)SYZ>B6Cij?3QU3wQ%SK@S;<+zFxR1J*xHTtaYB>;L^P=3@6;)W|59s)`u} gGYY1vK&tsa0nEqWTTHl7!TSJoLy#jl{0sed& z6#FRPv@+W~=;JnxJk@slCSX`a+hx$Tkg0qV@I=`ejX(yhavfj^Nb@yilMzs%{eRF> zz}UZdy2aobmzy`1%RPxABT3lDacPp0@l9k6T;340r0UYKs z;SrAj**n^01^*!-_#BnqaRt7TN?_jhKhkDHTfZTYuVAyGpE^OnfQ#L<9c%%U5mVu+ zp`WxcjcVc)P|r7R0k16<;{&0uw*}h2kG&4!it>_WI=m4adQ%P+r!y8s>6;C<0mx z0=|Lj5Cn7x>2Ndz0U1HSjPphL2Ljpz0drCNfe!)>3Ibk+Fon|E`=3ScH$%xpbhvqw wH+AR@^O963#z##0apJhwKMy6A*ne!_0mRqpq7tR@y#N3J07*qoM6N<$f*a&se*gdg literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d34dab7df383eec8cf3bf483fffc5d85270586a7 GIT binary patch literal 1513 zcmV7!^o|xr1PDr z&^k1^Y!A|bb^W(T5%8eo{TkLi>z|)DU-p3AZ#|6#!QzfeCe4&cg@-dids0$4qjDW_ ztmEwbvco~Tuuesc;7;CO@ZK1hxC-*>U9haH2k2UxfwplJl%2eQ#0LdMM8%;`8t6N# zm+eD3m!3ob;E_N2<2F14swci@)d$xvlO3NG$!MwvnX>LK?nxYT=OSGmo;&#+6DTA2 z9IzrcbI_J7riM<)$zZfi2Kx24)2SC?w?OCApLYhfU)c$m2L_Y?k583)YReN+y68i7 z>EM7~jmryLGckXs42;FMB83WzFL{2s?|$L|j`8dGll$E`?V*B$ACz_146_YdhNi{p zgipl|RmXEa`M7iPSEi)Ph=TQNpmRI8v|G?*@VZczWuNS!y?Jz(qz;6MnA@P#M??=` z?fD;Y9tY*!wcOrJtD26>c$O0s67m>Mq1?K6&s?R#!hnow8p&IbNXH9A+zA?b%%mp| z(hR%tX$M8^<$@HXnf8KgOFSoNYjo)CSp^if)ynB+9pm$o2Zpf8KLOk6&t<_^^p9Y- zpd(+|u~eXX!Lhb#^!XXe?{l0X=KfPW;+AfDRaEi1^$)YhFG(L5!X}MAJn9idcV*oN zXza0^vH1-xw5GbA$#E1>+hYFB^N&Y9z#MiK3)T6@Pw-?f}*?G*1u@Q7uWfK*h93lv)^h6s!L(O_r`wMmot~d5I6U80EDDFP`_ID%& z*hatP3_a4E!st6Y(bxOMQ*o(aRskjNX$6)C$@#x`Kf)-Ui_1SSND4T9=@y+|m#W&Q zEs+AxU7?#p1*`v3&{mBS5?P;mUNwD?K6m4+z_A}H>sV8f~1bE=xZQ;0#ZRNn?{#Y9tV3g>M*HAGl4+FMy!}yc%7LuIBSh|Fm!lG-WUg`Q7PWEXI=(LtG)b{Z)d5`;@4(_S z!%)v~gUEe|$Q&V^USgu;24Dbn7k*so4OHB;BgOCrbe#Q$aJsQTJc=Y~Xh3ntVV?0v zT)BjO#7)%v{O0Z2NcNC6G^8yhQ`TM1+qgCQAq4IxMSAH#T1t|pUeEv>$eHH-fzFWv zZt6+KDngvbOC#)K*OUV9_gF=4uq9yt#oA7tR%j%%81S%HY_tdsy>`(gU>ltY7`zgr zMXBK~s2Z6Q>ItAaYXi#be+3F&vEi=Ncpd0mwWyJ1ysJ=q32h@Y0lSUD<8{dw9EhD> zgXTdu;{Uy%;o|i`0~YI8b+4F6^88(S#k68C`H-x&*R1#Ki|)1SUcdeU6Xd-{V^Y|y P00000NkvXXu0mjfIgjPE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_notification.png b/app/src/main/res/drawable-mdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..85956e39eb7cda4a7f1bf26e97c992d19f6ae508 GIT binary patch literal 406 zcmV;H0crk;P);lA$w6Y-NKLkt$;uAou1H>%Uw7>?4-vDto5HADbA3&T5#QfB>qyva= z1Mx;6?uPm#gIb1L{6__UfOs|#?*(FKN(=^tH6suQ{l^6VfVc&Sg-9_FWSArnZvx^b zs6oC!%m>8Ju~;&P6vH`yI2?#S1Mwapu7yUX8&p0Jiv{aQu^=6YPXqA;Af5@the4L0 zso9KXK|LwS5Ttn;5Pw4pXG0`);b;~Z5^I4ZH0k}p5)2_o>YR|opOcicfr_VNG5j46 ziy)~U9AAX#u7h}o%KvFt(%=Rj&( zupZ5VC~8~a1H`|fhJz{>K3dejD$pXDhheY+0C(^b literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_pause.png b/app/src/main/res/drawable-mdpi/ic_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..89a6735529f82407cbbaa05f6882527d058c2809 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzFHaZ8kcwMxuN~wBO1LHJ>s}PI z-<5N_jhW-2>Z0!lCbQi)G*;3o`mUH6Hu?9tw}n3ql)_ARzQ4l+)C>lDn0NeBRsOY% X*L`xuf#^+VGC`uAu6{1-oD!M<#|$e= literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_resume.png b/app/src/main/res/drawable-mdpi/ic_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..4552ae6db959d9cc4565b54c3c301be30520c40a GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJy`CmyncXojGI18J0_5#l*yBF+XFFU~6-mws7IX7Y&vSuR2yL6tc6k_c0bS zOmg1E%fqv#;gkgX5k`+4TrVV^HkL4GOgzVM>7<#NSrhXkh9wy@S*|>0UJ?mX!I#PW zOiZ}zGW$-xhQ#3D%R&m%WDVFAmi9-KmX_X|_`HF!yNS`eg?Sn;`z{5k8H*|oXf0-3 r+sD4f(I~-p6J!3AzNSD2eFlc4E|FO$m#FCiJ;LDW>gTe~DWM4fzD`mE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_dashclock.png b/app/src/main/res/drawable-xhdpi/ic_dashclock.png new file mode 100644 index 0000000000000000000000000000000000000000..5f58071af3069a566807e7f85766e618c90d3f8f GIT binary patch literal 1710 zcmV;f22uHmP)=|4w$f^wVFi&6qM{@rvQ)(W z2#byWWzX6K^ua5;@ z2b>5Tf)v%<8qlOp#M*#49dzs#EB+YZzaa*+0n>qRYsa@r3vg?|bQKQ#wx0?7 zTRVOTI1*R@d;(Yx%n>E|23!fN)G(*Z1Ma>Nu0o+Ie|A14@z-uV# zT;K}e<#cSRCO*FJJYX~M7vLkJD$j^)U1>TJ7guwg%(9T&Xs+t+_ zm@-2T_4yO%{qJjocoFbqY#pL*@8TEI0*eFu=2v0@54fGu7F9G=MI(L%&JdLo8?a2- zp_|5zbec8gYJ>ELqHr#DHEhzjMZnW())dEEqI9$Y zrvZ;BcQ}k|0BQ}2#)Jz*>1YE+M&yEQ@EMH~%&=X8& z35U`qOX#|GfI zl06s<_(1#MuhLYoHAEC#Y>kfiJ9GP>6x) z>yJ!W54=BEItc%-rZJ(1@;!M;#vKp*-GKo!Q(63Ct;=~<>sAiOH_qvN+@&f3UPYWj z+l!-V3o*km{@s@1A5H0cA-MQ^v=6k8=Ig6~o2XV3yNhz*E0lNFSEDVor<=xzk2_>v zTNtn{)w>`48@OM4eKzouB*j?8G@;tUfJal^fb+FJe+wNyl`0Ur4F$QEnd119nF}gQ zRnak>@FVbgU@c`T+o^VjO5{$e&&j0$_I4V0ZLoxK zO?8Yo4XN7gwCUx3bi9Vq<%D4~<>>#RRfx}4^lw&H(ibvMtd38G|ezZTd-az z)eM*!s7k}U&t&Ex7zM219AkJ*g@!TKrTXj#H?+$rJGsemb`mqBxrW!1Zx~~dFS(zJ zKv}pee9O3w$%Zjz`(nWBeXv2Yf^i*J8>Sz|`XK&ri&DWTba2GMgr7l-pS-wLiBid~ zv5;{c8HV|wR$scGD#zmQ;8ZEoO&TWS&~{%8sBS9>K)pi)mNTzm zIU`o1bU|8|!0dX8nVa*U`eH!2qeWLSGyZGLm@U2-kmn%zwu~7&$D%aFk6922@wtWg zyD^2$jC+km+;*P~Xs{4su|?c!G2r+(z{v$2;_Q3{;?`Ig(BhK;c=Pkm3=x_w&~(FfNsky_#g;5)z<)UgM2`2Qpns(|h=FrYRjaBf1YVG253RC8;< zmxiT*vqUww1~i&(jNlqVlp8n$tTLj46AjqPFaYl>C=m7B7_f_(n^`UD_5UnLZv`Vn zL3;z*EmFi4qTs+9us{?XxGo4$BMRCZ@R5Z9RidE10c$J_xKtFhH()+feEc~o`9TE- z28;@M7DO_5T-0-C!d-^qJ^D0T+tyY&4GRTL1t607*qoM6N<$ Ef-_YaZU6uP literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_down.png b/app/src/main/res/drawable-xhdpi/ic_down.png new file mode 100644 index 0000000000000000000000000000000000000000..bc910d87e1e53fa1b94803ab60a35e22291e4ee4 GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5Sk<>AFISn}W#)MQdFfcZGx;Tbp+842I%`@|Ezq@<)snzq^^M$8>J}rO# z+2Z}~z0Xx8`FZ(foM~+Pxk~KtnGW_DGuO}Bq;aBR$0e-;r&}5X1ely0I5-#;6<83Q z{cVimkIxs}-f2*=mpM0e@84Z(Zmnmw+mpB93^iU|DW9_d`f2S2lrEk6`qSu+8Wj`mz+FZrLB{> zjkBUtAC2bsaXBeXARR;sx~rJ^;LK#Wu5hx{Uj7=7WRkj z`f@IrxqhqvRNW;9H0a!0&HBaf zW=>c6<?)FK#IZ0z|dURz(Uv1 zGQ_~r%EZFTz(U)=$jZRr<3hHlC>nC}Q!>*kacgM!vo8{;K@wy`aDG}zd16s2LwR|* gUS?i)adKios$PCk`s{Z$Qb0uvp00i_>zopr0O~pr_y7O^ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3df639b489ff55f3413dd2d2ebceae705ffbd3b7 GIT binary patch literal 3379 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 a^fUw~z#qXaJFc?;0000>>jF;4&h literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_resume.png b/app/src/main/res/drawable-xhdpi/ic_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..652ac68d089a773a5cec709cc6e36dd284769d2b GIT binary patch literal 416 zcmV;R0bl-!P)qNBW?ke0&w8Pe~tHbk@~rcF_8i+{7+A1Mz; zsE@{I4@a4g$9WqhXj^1xo1|#lzv5#a-x-fq+Y3vas(t$;m!`wf|2$ zPIOexREb!1y{=yQdd0jV&inoq_BtL+Cm*ysa7|zOrdI0u(%f3LYVH){GCT1{`wY@W zPdwhar&s?$E^BeT&R%ve*Wmbd50a;Dnz{bhk6H1iTvrs6rUj z%`v-=@{}knTm0>{xd=DG5&0eVuIOvxE$VZTp?h|ll~sWZD? znP4~hx5Bk*g=zC&vL0vVo*DniX2X)dk2zku&wm+u;_Gzdy-G~k``E87x<8{LL762& z|3{P#%QkD_{kK>Be_`ADO|D+=0TUE`cz&RfONNK(_~aM9j*ElOPJmYro0|u39 ziEBhjN@7W>RdP`(kYX@0Ff`XSu+TNM3^A~@GBLI?Fw!6q|5!)T&*wc`k!(X!A-^|ZLP4APB+wZoHO3n&Nw##fZAem0@)gNik|#-agBJ7c z$E+~H7~^O^jpSd~>&ri()O8vHftO!vk@fA#7~+*(i)o1E`e?hL7)ev?aKjeevme!NH(}$dzF1H zXgiw(8XJN@mrL6x0@`rgsFLIxkJs488U}4=lR!O4HU$uajo(e$P7G)_MI3TJ+yiZA zlRyKaR9SDw4W^^ z?L@MJ<9AM7G$(0EQbn>O6UgVi>_mU=L7s0(I{CbIFLG$vBvO_5G)rVg+9W9qUZVd@ z@&d_4B>RwT;doy^lAjy|;hzVR4EKq6|IQhGXgoW_;jH@UB;T8G*d!!7iDX;(jP@jF zlbl7ei~MbBz-M%X=Cebf>k2IEgO>ZBNnEM1$LCH9c<)Zod^X5a9U`$BhDeJ^db>W` zFNX9riqWz`p1lGx?Ztq7r5kGf8+ok#;?eFxM`dFrN@UBEJiO9+&e*{_j!5=csd6;p zkk4noiDW#C<))tWzEY+Cc(^CP5ON>-hf9eA*oh z>y!t9S}QEwi+P+KE#L38ooF=&G+~|cAkZ+A4mi@?PI6?wxR(E;VVUwF&5LPH1GPIL|uRS9=(d$y2g_gkINuM}daN)b8B5LG+ z_KRV+(@?u-O}f}0R_11`C5heuC6KiLR^2e7c8z% zpcw(HmqF6z{tyNl8S?vXOK}!D4Hhq+D4dnvm!z}n@1F-Ke2%pFID~N~hwMj{)H|nv zOTmQV$aAz~vmQ_757lm!aTTY#@w~KI7Q#4pN9fPQl;T3Oz=r7LVF&m-4`t4j;`UVm z3V$)eW9PC6eQH!-r>ZSH21Z0DP_>UT*GUQJ!vPAvPd?+!5XKo5v0uBA{FpF-9t9(! z6KH;r(Mg7caH3m~{1NauTq;^sMBhdgxjUm++z3WQH`1a2gULiSI{&q)zLMKX_CM36z{3bCWcCwp$1OmN`&AUgN z#pv^P1y+KZ7zvj68{!C8(Rz)XWHH!h#lw$|UJ<{8^I;>|8I>98JfmhO4CTeS^>EY$SO@lA?_*jG=u2M?Eg)f+_yW?;N1GX^z>Y zt<>{W$gI^*i1l~G0xf=oZLd5ACh}~H1R4*f_$$9MUH^Z1KHDF(bY}v$j}f$=5BAhjV!qU`pNTes8mRANWv7lpf{b zzkDc5bZ)<&6n|;g8=sO;{~ThQ&+hIeH8Vr%UOOo!5kCsJ>N=kj9SZiUeR>` zYw9YulTT`5sl3iU&*KS~No=SMOe&4>5~Y4ELm|EQ3e0PYpCZfo=_yqE@%MFC9OF2p ze%%Ddcq_Pzse5DzXW#j9+5rW&-`K=(#qk}l)TiUX7Jnr-7eyZ_u^x7sKS^=N!!X6M z4N>UNdPJY2DSc9kyu$f@_0=g7i0`S`MsYk76#Dc!m=Rv#V@$f3 zqdcCg75a2Nm=Rv#Pp3$pzqBj;lmeiqf*IkR=|55=(2dF&c}~UrpwO>F!H#eW?`zUK z{cDwl!m<%Y=Pr!{!H#eWuTF9H8LvE+3Z=&vuL^MzM}iJ#F?g3V{>o!HOsSNEQ!8!2 zj&Mr9HwE%=kZynFad0T&Ev5dgLj_`Z#Xpt;fvzyh$K;ye>%2iAiv)TgVe)Xza#Q6o zbThgqmw`YLlz&Zv|6YwU2t?I-n}BBl)Sn(8^}Kh5jFFq2!k9pnHHF;S6wi zLUEu47W|$@ijK284s-z65zYv^8M`+DGJey{wmbUX)A(;qtgP<>_qPaW<)c{1Pg{Z#xm(&wL~CZm9_#aq8X&Uayo!- zS#E2&&-d91JAe_zr35q+t1A-dv#naD#b88n202dA2u~-_-=3C&ptw|}NQ1OAn@^3` zzzqrXmmTR>l*zMEJK>wR)z~5>LrhMn&;5+K zNTKh1vf9juE3@~xbOYqkHN^Zp9S9{s>f|SR3@CjV(Pueh9>vhXf@E6t_tI1ZXxt1nQ_4^woWVqN{>J-PkiO@V;|gp_DTc zHIu-fMm-SjAk8U>c9&Y7IOLg$=ySeF)S2Y%A`h#ahV8=ulc*^l{U#d*!{)sD-m6NS%G|oWRDy)vIg-2>Wx(>pOP8zc-fP(BLp1!W^4>^Q6^{vlev;GLQ(A?9-F{I+w+c~ivz0oqq=0E)` z%y^RW*^sw?_8@XJ1yrTKi>c zSlA|kWh*(G@(b7>+v-R4bGH54{f$eJ;px4PjUP4m15JAx1dndcl3;Y5qTvwhFn2H! z@8cXEz5OiH!5qjZZflF_PfdZ znO|My@$<}?uajWTloK;Cxa00QCLd9)D>5@TUk_3Jq`Ll4oJGH7)-;}#$7(J=bYwX2 zaK+IK)BaSsMG3Pe%TIgda>69p^41lXu*}1sOn$69&*ICwZRN~0o337|h@Y%}CEavo z@XUFqlGHV)Juo^|RPjBgSlIZ|e1_=UrALio+&X9JE9M*Az2o=4VD*2tv$|_SKdYwo z^47H#%>Tvk-mw1Gr-=7z$M@~%nBQ!5Zl3pyT%G?h={NlP7YDRI%(|v`sb%G}jc+F# z`Lvu-UgNTR*0yfQzc;-z z=l1dX#k00rv#J*#v|sn^O`HQ~KI`%Q2OG1_%@gr?G<(61^_GEWXDmr@4Pf-XT9YaA zN0jG3ziG4;V{N1`%m4Uqft#0x8qD&&_i=vFl3AzS4#sS&KKlPek?G{MO>^T|-voTV z!EIpkocI5hS!%PJ7Uq0ts-J%Jhjl1JLgV{6AMY1!nswOqU{pHe>Z?5KxcV#}%7=U} z7yqFA+URk7Vtr}7JlC<0scL`3|9IZLJH5&E&4y#|A25~X&*#!w!}@30yEowu`TufT zza`RI% z(<*Umn4jN&PEETh{4m<&t;uc GLK6VFQC=|s literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f3843a854665399202a3e8beb859f9163f7cb2e9 GIT binary patch literal 5685 zcmaLbXEYmb*!c0F#NMj0)hs2g*&=GIy|+?glp3-3-inHfEh$Q=O;Mw^qE^jXrDp8J zCf3v6Iscdc=Xr5o_uK2mea?Npp9EcPRSHrjQUCxzq4rWq|KFYZ-ytUYH_7GivU1(P$XJfZLO4}7wIa2W+)_NTi@ZDy9u4ZE zv&nY8c4GKvU5Z1tL-F_J&rPyE z_$A?@FuwbocPgb)Z==V;$0Em~$6_(z7-xKhiiA4(>g7sHcnu4SwRZ$~HY^!XY<1VU z@CvA&8F4BRUdPr>*Umfxc>A=ju>{&`$5ORPj#p z*IG3arbSMbOlBm{pPktA{pm=uFua7_SQJ&cSJk1*4S%N)fgKj6heyHY?Ov9tLn(eU$2_Tc#XWBWkJ(9B$JT+ma_01?Q z3LR<(=4t#q-*CHLz2<(K>YUEvhm4t=(PeQl6nu9z1B;Cfz(oSP>Kez{RwBSqS=^|* zvqZ-c)?Q%KkC82Ox<@6?@=QeAEF{I^+pXYDM3bEduyZK_*hxk~`HE8#%+6xsuhxMs z^vS2Z$N#K$U2)1U{7$Ic$Bs7^L*tv*Aw1+q%LV|4^D#Y<;=2!21zk+Pzp+jJO@`_~ zOMm*^|`@f zh1t+i=Tkc0)rtm(-|oNtT66>EOPB9j;Mpu59}(hxE7+vtLWD~<^IsaQI>B(|I*5J% zmMoG^TWm-&!GrG2D-p;lPb?zO|&Omq)(kR*#ka!VHuz1gbi?~mz zYt29AE4hUIu6#OQ#?_{On)vNa=a7+mY~$g?U@c+gflgjb%NMs?sn6bYlJKZ*YG<)u*o{_ZXmJ}c%wTx; zdK{tR50p{*1J>Q`qRanV6M9}w(YT6=m@E>N_b@{=u;Rt%BW^`RC;a4dB?kpL3}!=@ z>KbU+@WBzE{}4iCQcRUPj}x_?UtDw(sMPruM1>^N&&aqf!kPS10rObh-d#OGv7?MzD)@u!Bv#iRz~gR@6F(!c62+nG06 z732a&3U?m|ub`$rnVthQx-#fDM{NyzudDh8i_spohgS+4WkgsEH6aeQSg3^(e_@8O zrZHG3tqxr)VQX+%9(!5MJ{7B&aHyyd#*aq)=sjvo$v&cuQlJ z`h#AU^X7%SGB(_}F_TSv8QoKxfa^Wekt8+hz7(PS)qrbgI)*o1Zi0ZAv~Ia!bc3fL<1v3{pQC3N>>qeP2Fmo zA$?`Xe*w1RuN)kC^Ix|`P57)GJhELQ?Xb60UH&~`{ipvO7-H_|Bn#K#E?)VzkvWx9 zoy6tEmXYj15Qp;!Xbp2Adb=4rw$SPeQ-JpcD048E6TKgGH_sT6CX@E}hJJpWfrt>U zY7btj!Z71~JuLFYv=R1=#kWKzBvsHsgoPC~Nw5M{S#p%x_4epB>hr_kgEPTRKr~(A zGL8K`YLJul4oyAekADtN^$d0v5%!+^lgQpk^c3%1Qq)0bdn zZ)H~}1+CU51Y{+}bLxm#w`L69M7x)S-Z9r9^dzTO1%q&~1Rh7112MDXi|Q7=&{&Hl zxmb{>J*TzqjX|6}WOB_{e-p#HzLTyc4w!osMA{sPBV|T4v_*c zuY9UM8VIa%D%M@>;$aAzSl4P-zwI8}L*A$Fc$=}(Y9&!e*CU|^SyjaeWlXjZf&`+F zR^RiY?XSYVw!joOe_-YtGH_HRJm;a1Ox@r{#qUsTd`y1yy`9wjKcpd&j68f`#H6*=gsuPE$JZ|iY zB+&@T<1N3uh8*#%(|{r$mn~cULhFow;Pp9;8>rRUN}d&`ObP7u?ptJiW#>D7D44Q) zkix(B7#ar-{s`r1J1M1U{-#q>0%L!RvVCwREuZO4WITtXekpY=^Qn+I*Lr;@RQ z@SB*CFX?}b@I{mj)g%0u6ix5ESs|Tm&~=mBZ9f*13xV;VTNME8I|1O71J`Yhy)mnP zIE9{}*JB&A@;`_z92prT0-7)M*5I*OE&l9z;XRT#cf~%ymTr=;Bp75wHb8GD*rE0} z3}c%!!)R4=v}Qrr>rYtX4byslICOSL3dw3-uLIBhB7CbwV7SQ`N_<;jAwGuZe(;5s^Pjn36~NM8v4B+?-m+;4Y`YOvksO&W#5Y|bR0k~QGej&bdg?= z3;(WrKg4DLYiRBy!eP;T2<-P_=Gl+i?J43f5{rXDssfQUUdjua~M&-nX3P7LP`obVj2}4((Ny zqvAEJuaZBx*I2!XH%+0>Rc#ZhW{ZX%u@~0S6#kNLrxbHhI6Es^c-&j7^RZ@|UbFpa zolV(T(GtO;QU{By!Mm;xLXB=opiPL5$W6cByuy5xo!k%4mCwK?SdVm_+iMID7jqg` z?6RtCJ-ZVZ<6?J>AtX}`+pSH3W`quJxLm)k}k8Jm~I>+t1mbf}3nTov9}@3lF^hL~nA$fcf_p#CWxh<%%~T*04Zjb#J@ z8xAc;XTlP+5QNLgvoSRW56jIjs@~wm4}5b&Fl~0iEAcuBM$Y3>Zi$KnJjWee8oSjI(ZPG6PrPhU|Z~> zC5->9Anp4GC>4xT&XRRU@LRpl&MUL4VX_mt8JFd1w>(>;i%qyUIzPj*#j+<$1m?%( zfS!iRHdrDSw9s3`a-y4v#8n^f12yGI`}m6D7xP?RXA?VJJ)p+BT#L3#jl!#I%Az#t zJ_mTxyPzC@ykSNH4%W%jcJeD(23BRNX@*g3Eat`jtt#u|eAW-CppE3+c_PO|%=pgt$4K86qH$x`RaFN&ef*Y`D^NsWoqNusa3)Vvhc zA0DltUoxx-O!Q*x`qq^ztR?d}$pSW(JS2Yg& z2hEGIP7I7jgdELeWdB9&zkqcv9tpmL`smYBNLW~%7qg_FxM~SYSMvfQT;zXvns*rH z3TEj`;X7uie?7Zh{|Wcrw>&s2PeXI@Ao7efBQm}>D-X0f8imIE!+r)bhEHkRZw`vO5jhvLv#X;X z&yp|1PkD1K)wla?tDkOhalcziweTT4JrGJLe2=ld$g;g=dMMkWx84afe6wYp%z*W|UpMdos#FrU&vOaR2J< zuITRoaZBDQuQB)BH^GX<%xe z$?OP-NtJ1~l?$-dB#Iy57<<+01=_6=kPg= zdi50WkQ-LE5%xPAs-@@`!Jl$-pM;}Vn|$GAt83LXQr1}HY{8p!rF3yk>@mq1GK&^| z$)93*v{T&z34iUv2hTqGJVx=)3%FdKUB>OHx|t?!B@7Nfsn&eZJyEH{{!lO#RL9$0 zUr#v*F;XD~WX}Zpt@q$Us(mIW(XLzrq-Lzm-^f=?*xDbvH#naNBpB~T*9(CCQ~?o5 za>fHpBsiI&>=X{;1h-maRI5h%oAt^qMZ2Qo+>DrtY}n$FMk9a&OT4zY|7V9De~zP^ z?;k6Ko5_;$_uC|wZm;zOJjW_i&6G)5%G&|zUcnVMY;g*!vAk<`vr1U21kKK0oX$?(h;&R`Jd0)2OnYd69gX z9pKo=?(io%vyY}G9rnGGYf3zdwRobEaLGn_AyTiR(Y5hconFWH@ie+<>8$?|mmS~e zyjudI;5a`6>?_eGp1q?rb3dx((J8<>hG$g8<|=?+Er8;b^~p+O`(S%DA2ZU|eD>P% zyLx1ixK=2Vt#sjoqwdE?dp7cWNl)rhC^R6`hN3f4OFf)RHqoPe-?G4^w_4+*x+GAG z670Q|Y@$5lT2TpyK@yE}@faVzr2l?&d6N2Vwd!xZXv}3c_(c^PMntoLSElaI?EM&i z*-xwk2pzlKOBt<4pbDZ7qyHKc*w0|4AM&MdUncsWL*=Rw)$M}QMn|h*M@nm0EPVX{!luehc@zVznzz%YG83&}Jp%-dhZoWR zKe{8wUH^+F(~w}Y8REAw;yv@?c;-|#Vy|cK3ClpqGQXda+1w0Dl|RcKV0tZ7!)wZ1 zK{M|5rc5t0L0;wsi}`uaHL(5lo%m!rC({Aoh!y(^n~(ida)@UqRLTsLnU*_y^5dnX zQwH7`Smvj_Tkv~987zVI89(vD8+Z_4c>hcN6X+B%iV#JDqF5dm6B)FEw&oyU)KADW zS*2`6lA2@doc=#Dnxg`3O(J(@(tTU~sO$fdR^ZJG@b}oOABCa;(mAk#M zku^iMkdl2H%k_WinL4gJ-gC|!y=U&Z|N5ml^S;kH_wTIFJrjw93Kc3;s8FhM9H%un z3BH5myqLDj%Dml=~lGw_jrrlB_0H55y28fH=O5PStIL3J+A z1%+S;sLvC2xh{c4{Jm8+m{b!agMnZz*a9|#DIkkKvw_W_p0on|6b$PUbc0fOBK8su zu@j&V=nb;LFxO|s1$`dc>%e|HgJ{qMM@=tyUZP?68Y}|`z$-8( zhz1>T)b+i5SmED1q5K2&$e<9o|1!Jutb!Jx@P zgWrRu9-F_npn-?6*L@oF#JI^B4XO*K(cXiG4xhqB(eEC4JWSLh))=1#(WbGcX$BPv z4czHr&}?u@#vqQj*QZJCOf#rdXdIoi=L$d5L9!cI;(CZ@piTwx=&<_0he63Em_obO zO`sRJrHNN~=wji_G%-&6{;pHHtllR4EQSU&7jiPRrQa&gQS zo5y<{I(>JNtY@2sL1#?pJ>y-CA`@nS0?-!B<9xEa2fU*kvqC*BGk%dnD^k5|Z}uRG7%#Q{B}Vnt0oTrPgmnULxL`grDF!m9PekaxLvTqG8%Zvfi^2@s66bbB=kuM_1Kjh5AY);uV-= zP(dZ6C3Y#)Co_~sm}JmZpXShVoFQ3Pwq$ROnUoCs>C>Ra3iWN2jM>=~gPQv^htjI` zCF{ymIBKMsVo-(;b3Q2?RFn8dnXJ-H8e+OD*i40bCMm{_RrN{w0-38&$7RL%IVKsj zPQ#$C3h~o5dZ|%8XryA}PbDq_eTMd7nGw^)3Hx~ZV)I|<#3U!t zIkp-koBE&xS&EGYr70}M+if(cgW|=ezP1^Zqj(%B3Jr>%QEX_FK{1U}cUIVgDk*Um z1cQ<_ZlGq^WKa$MlO$P{s^q1EVp5@kLGx|g3#IVwcA2DBU0aVF9l^bSm_x5{T1IRZ w45$sJgWH@>{=^rb@~xY9LWK$yD%AheZ$h!!0*+fw$p8QV07*qoM6N<$g3ljP)c^nh literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_pause.png b/app/src/main/res/drawable-xxhdpi/ic_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..c457d4e920a03659056d42d4e7683d79a3dd5f58 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo>pfi@Ln>~)y|a;%K~ccf@wVap zgxwqVy$*Y_j)D29$g_jXJ|z};PgL=o1Vx#f&a4r<7XT0}Y}H jc(A1=S`%)y=cQ=&4+3Z86c)ZW1zG3m>gTe~DWM4fXfidH literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_resume.png b/app/src/main/res/drawable-xxhdpi/ic_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..14293ac203a0461cbd32dba0423fc717d67ec1a2 GIT binary patch literal 659 zcmV;E0&M+>P)29L|hcK6-3a51yNE;e#c0V6x|4dP?|2giW?DIL}3sG3#AfBL;Y|4 zQaa@d-MIQPlXKuQK`_WYdGEg5dGjn30000000000007|rJRk)|N~O|XwOW1I>2w~E z4Fi=*HG_aK8hZMj-D0sgN%jl^LR@OKRAbrd6YwYM z_4<)U#S)n`3HUoL4fHH@-uI8=RDM1WVqK=C$LZSO1z2-DI})rYNIv^BCQAVi{gp6U9KaRKSF^^5AmJOaGY zSG>+#+dD@B{`q;+>qgxBm%f8&$bi<-2K#lWn&gw6URybn{(NoK4t=VK*J<}N0dwgcu3DEfX7r# z0(el{CxD|090EA3!zh5`YJ37Xu*o5SBg;$zIJD0wfMY970ywzUB!HufO#(Q)+bDqJ t>rL1vBJ7C@QJ3`~BBN;`wVCmV?JxyC(-ls($>U#dYaA&!UwXraymK z2|s)y#c^KVP{w@0Hk2o#U83CpJm<>vsdbTXzN4ZepzbzWt-=}hX)|NubiV1`yv@J9xYXAEndE^(T|EoaO@!*44=?@@;b^qH zi*xNnppzJryxm;OkH}(R61@(>j7}P}D}aLRC7!;n><>AFIkoie*J#Hx zFfe6#x;TbZ+CequAO4gc-OPCLYvNDUr9XD_ zN+151Jo`ib?CmW=0c}5Xc@OI!UzGd#eRzl--;KDZx7V*bIO*+;mzD~BskfhA_fI&= zRr~AYl~WCOtN;AmTD|eqx3}M)F6U3UD!b;hNI-vs?5D@_eQc~ICci$+?o%jm@BjGw zxWB@Azj;ag8E*IHKKpjQ;YMWK|2vgh4-UEd?SCrtlzHuRN#=DI>&N_PmtDd6rSmU*Z~Xo4Ps(&phgXf-`^}ObG2i9C`{SjYvHS~PYt9$OUmM-^{yb2g z5qCJb+Wx+v&-;_X(f0p=^v&Ya4RzM?6^YOHZ~597ZuXC%lI3!>ZN|Ipdp3S=yc7MH zVX5+rd)C4K_e#tENO)GSQzm-h+sPyPKi`~U_uBvB_eRBXyAP(zWIvo;%3pK+t0~Y~ zPpkI56ZBcX$?5oY`=*yyL$X^%R^HI2>7}b%$e*5% zK-KO~ef}MN&Ro02KC6)Ba(CY(#^gD625xLAmCTz`7*1PfBpyz2c>aS$-rg|p^Ub6n z*;!i>R2-OyM@{BS}eUL(32YODhv2D-$zq10yQ~1EX(`yHPac=BH$)RpQp* zygJ$(s6i5BLvVgtNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~)E44$rjF6*2UngHY_ BT3`SG literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dashclock.png b/app/src/main/res/drawable-xxxhdpi/ic_dashclock.png new file mode 100644 index 0000000000000000000000000000000000000000..318bb55ba09c9c712bfc16a23aa6f677327cadda GIT binary patch literal 2828 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 VjLrYzXar3Hp4h|g9M|xSe*n?T)qwy2 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f3843a854665399202a3e8beb859f9163f7cb2e9 GIT binary patch literal 5685 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_pause.png b/app/src/main/res/drawable-xxxhdpi/ic_pause.png new file mode 100644 index 0000000000000000000000000000000000000000..c457d4e920a03659056d42d4e7683d79a3dd5f58 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo>pfi@Ln>~)y|a;%K~ccf@wVap zgxwqVy$*Y_j)D29$g_jXJ|z};PgL=o1Vx#f&a4r<7XT0}Y}H jc(A1=S`%)y=cQ=&4+3Z86c)ZW1zG3m>gTe~DWM4fXfidH literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_resume.png b/app/src/main/res/drawable-xxxhdpi/ic_resume.png new file mode 100644 index 0000000000000000000000000000000000000000..14293ac203a0461cbd32dba0423fc717d67ec1a2 GIT binary patch literal 659 zcmV;E0&M+>P)29L|hcK6-3a51yNE;e#c0V6x|4dP?|2giW?DIL}3sG3#AfBL;Y|4 zQaa@d-MIQPlXKuQK`_WYdGEg5dGjn30000000000007|rJRk)|N~O|XwOW1I>2w~E z4Fi=*HG_aK8hZMj-D0sgN%jl^LR@OKRAbrd6YwYM z_4<)U#S)n`3HUoL4fHH@-uI8=RDM1WVqK=C$LZSO1z2-DI})rYNIv^BCQAVi{gp6U9KaRKSF^^5AmJOaGY zSG>+#+dD@B{`q;+>qgxBm%f8&$bi<-2K#lWn&gw6URybn{(NoK4t=VK*J<}N0dwgcu3DEfX7r# z0(el{CxD|090EA3!zh5`YJ37Xu*o5SBg;$zIJD0wfMY970ywzUB!HufO#(Q)+bDqJ t>rLkRFalCn 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 Hu0mjf%Gqh_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/back_ic.PNG b/app/src/main/res/drawable/back_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..926635825b66b119ced508fec2b57543af406405 GIT binary patch literal 1996 zcmV;-2Q&DIP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2VqG>K~#8N?VUep zUsV*xGiL0VF=NII4#6o-c2P1ogidiXOCf_p5QKD);1GhK20Iw&kbp=73Jp3m;E;fb zfer>83^+7{t+7qpG{*MI=LfI+{NqP0bI-eujEs!9 z?l5Iwdhzbzb?P-2nE4G}brpAjjo;!9a0mG1j&wQ&zfuaGo}P9yGc#^!X{mRtt*yD8 zot+EE>gwu?b1q-L?53usN*zpxtKhM*F*i3i=eD-C-0A75%dz9*W4F1v*}LAQOP5Lk z-ag>*@$sJe_V@R5cm{vFx3}jO7Z)85(bx_6uHPPDI?Ah^tJEObffKmj^78VqRBaD< zbab?*SYF{_8uv%hw5LTy+X9}SpLa(`N5kZL;oh`|cC`fA1~7xn_V#u%*oUXj-M2qK zbzj_m+&iw_eB|Ey^1+2;`I|>C&iU@nQ^)U8jp(F>!B8JCgILM{_UqkqxBkNu_wMz- z-D@A-Ykcr~uEX_W?cm_RO-xK!s#zEC&-2_sQy0R0cYiwz zHL*8yR9136V3ZrOm0OQnQEcb|(2kH1$|*w51B}o0xdle|_ctCE0k?urdqTb$(I`P~ z4wz`c7vtVNel|3h5K=NOwQw&Cp)SNEl^KtmWGW>By$}Q2fTQ|JVhxa zV-gXomYnlG`0C_;i5*Vcc+C!#4 zQdF_NzMiV$IKa}R!dksCZ~>f~OCEf%l8T9-65T`?FwR{vOZCRW{q%eNM3PU%i8UBu zz|zFxr{Dikdo2eQ6bo0=_YSs!{?!=^xCtr_17_{2&McHeCrf}!JEXXn>9ZPOk~&iC zYZ0220vEvKDI`mn+4&VLCDTce#DrHV=adAuYWLxv|JE{|ot=$Uu^%w&RCV_Ck9uKI zNp2xFnn>`&e!yI)&Zt>PQK#?R5|vxEmwZQ^C9K`~0dt``qaZ{BaLI7#pOj^ziZgPc z^8@BWb*8b-M&c&MEJLx7NT@2RGa@S$z*30DjYEy|{hj1YXyK8L4HK>}l3+PW1uz$? zv)sawm0R_`t^Z!bh6~`=uidZhKcQ>UfPv>T)UBE4&3W6Tb`}lz%4hy{FgjHNWOD^u z`Ct?kQgI28rP-XC54MaVfE-hpH%ujy1~rW$tmEL)A)Cj+ZOr6KhHO5QlX4LjD;Xua z3yQewOf47DW;P8alSB$xn?6~pT~o`Z`SQWJlMN|0EhV~WB_B*MErn{9l{_Utmi#Xt z_(V=JI4`_pB(2F&lAkj}3jH<~a&BHkYKK(ili+{j086XN_(EnnAy7GgkAX}fwf5>Z z{gRSV>Z{7ATuS;_x{2z+#6Tu_l=C15e=99`n$$%ASgK1yJ=Q9YSyIx>ywM-&^8&NV z9%`~Avxtf7)F`cf@G5H-eGjEJ4HZjyi8kufD&Row_l?>yv9F@Xw7L?&zWU&{R19cR zofP|V@ZXxg*Ei8=P+1ulMf8Vqz8YcH*fcxa_O*O#gbjRe6)T71;C{e974y1kS2?x? znOIs1%UbQNsy^1UXN^l~1NoA+y}0Clp~Y zL-S36tF|+EXAWwEpmhKPT3Uhb2akFveQj$1Byq$2LN0+eA`)e|&B8Qal3rRQ9aJ~I znUtVqCXN*e-=-V=ZBq2Pb_%Y*v)yd$Hi{^Vjpe8}&Q&$P=Q=4H)e!|HEMTTA6*ZeG z$1E{%4)LRur1$yiJAa(_UTF$Gn7&F82>;ICIgj)CU8>Q(h6$V$(0V?25I+9QmmEq3 zqIo{;GVr%`;OzkS&-!Ab3{8O2wa95V+?F6kwf*PX1Fk?b^OH&dtl@Is7Tm#b6g=oU zn1X6-DIR(#)t2Li`%=cJx;+Kg4UoVler_@#)&XW$0Q@VFOzePceBN*Y_jiuSgIqH) zDGKMc=DXlJtNzaf_*BlPIHqOa8v6jt0c@ + + + + diff --git a/app/src/main/res/drawable/border_shadow.xml b/app/src/main/res/drawable/border_shadow.xml new file mode 100644 index 0000000..8bcba73 --- /dev/null +++ b/app/src/main/res/drawable/border_shadow.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_background.xml b/app/src/main/res/drawable/button_background.xml new file mode 100644 index 0000000..79db4d9 --- /dev/null +++ b/app/src/main/res/drawable/button_background.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_blue_bg.xml b/app/src/main/res/drawable/button_blue_bg.xml new file mode 100644 index 0000000..568e42d --- /dev/null +++ b/app/src/main/res/drawable/button_blue_bg.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_enabled.xml b/app/src/main/res/drawable/button_enabled.xml new file mode 100644 index 0000000..7a214d9 --- /dev/null +++ b/app/src/main/res/drawable/button_enabled.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_pressed.xml b/app/src/main/res/drawable/button_pressed.xml new file mode 100644 index 0000000..7c891f7 --- /dev/null +++ b/app/src/main/res/drawable/button_pressed.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/category.PNG b/app/src/main/res/drawable/category.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a41c186a290bbf99b75bc557814344af0ac0fd91 GIT binary patch literal 2891 zcmV-R3$*l!P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3gAgZK~z{r#aIb& zR@E7O+yDM8fA$p;0*Me5NLXSLvO&TY5&|)iML{uubu2B8XapBp+ahBHAtWGFNDJ*~ zL6qXuA~@<)WDyZCkb;S5sUuNZ?6qffcSw4NU{Is z-JbyLwL!|_cDwys;T6!|O@aSANC|Cla4^!+(hwIH_d~<~WP@jNDj zx(&gK4iC+#=}-)sNwc%)R2`a1M&MYtt{{RSbe&XYm{2q)&EYkZOk&eG59`6kd0pQF z(!YVy(o&o`bH)PL+1Y8e9i3P3=AO4OW=c71p)O9Y!o}(jS2W9l2uL*uiVG^H20P!G zLR$`kG!#S%NSha=raHI@ugS)2x{4_F2XUOr@m+dSKuRUgn>P=aE?vTvD_01v!)nn% zq-=J-vkygO<6$^VI5|E>F}Q#VkA&Z!1{(94eJ-}*Njp6mA|dAnWFvO*Jk3RuHBDMP zEsSP()23?*3JVLvrcIkH?+G~Zq~*=aMA_DX%S5{Ejn^fUm zfGME)PG_H8)}{AVn@UhVlYC^qMw3n1{Tuy0kVQpBXlZE)gu1iC2U4Qm-hp;>;$mkT zYU)-Yrd!N6NiQHxpE0*=;uR?fdQoGm3rKoZM56)oHv|D@?>ziB>U%bhMBy3K4EL1hTg~c2dAYu+*h;;!b zAe~+>D>f-UOD9}A+)^;dk01Y5s3qiIfBiKY_8-EgbsKQD`6H{pjUHaJemz1WBD~Zj zl`RXfm=vqBb%L=WRB<9mvBRO7q$$w=20chUz))MdfJ~sV&~yT{@q3euVS&8*nDhUR z;9@m3HR$N*2voFyId|?H)~{QKkp*Kgpl>?%?sz9aP5T<&L*GFeoRn2;kXCe7Jpm~S ztCpq_pi>EEXx&`XP4F(}AIC6{71EJvI^eW9nXfi$LmpbVLW&YlvV-rco9yiD05|$+ z=hUfFsH&>6$XzyPi;hLfoVl3$^jbW){u$g+yAo0SPKgMI5+)V}C6Z%f;@R?dR3!AM zaA<6m*k~xB^tyOHo_*bEF%i&B4>#eYr|tB(m(Bv=_7k@(F6VV+WhE|LxDfD?cyRXY z*>JhUJM?~!Zb+Iv3&WRHBY$Z%M%1i8-cz+GTDuCxt7gi1;?+h#gKJ1$XdG$*-L(h?n838ei$p>BuMfu(q9$Vhs?m&0mtAqtM{!5zmMF=6Xg6#sQ2Ccd=`(_4;XRx69> z;69YU^bg$p@;1zP?+B)U@ew9}b`q0Y525VfYbbtsGj89p2bIldkaxKiBQJl9(zC~q zSaBOvJ(Om8^U_66`oruGyMPd{&Y3d@7fImqcj)k8Ncb&pb2Bm_gxLfjvb2=Cr(%(MFB}6 zS$W8@E{7e73l?C)hpkBY)sqO$FGpI{5=2d&4bP;zFm}T>wm(N)*=!81dJ+!yM=W|0 zy_VI$o|%i(ikYame>rZ*z6)x`t?2gBs~G;pm*~5DFN~BzR(&KZ-r?1;LPr)joi6oJ zg^d*^swAaXGG5&HoCR{pqD2UG2k||XIV;W`8jB$->oB4D6GTpZ0CCf+P~LD1xz*3W z)2|qr3zot;dLo8D{xlZsKZV5G?tyaCG$^H0(X(U*CcW|wW}Ll*+c!7Bo<9>YRlmph zrWT|;_cs_Zsm#T2@~N9b#0HZm67dM@Q*GNtg%~hM0UG(sW7sfv<}9?GYeijkHNst_ z48B*?AcXWtMgE4Z7*>A@X2G3s&3Xv2|J;tK%KMR!T7mxeJ_^_P$w*(a5;v{gi157e zaNl|-l%lCfpZPdOHGPa8onN7%@gkh%RY;uvFm8Lh5!WxJr-OS?e0UJebwbIdu0Y|? zlbX0zNSB;tXhO6K5~HKBYUyGeIIs^lW@mB}BD*|D$SlOL9Xruu_b%wErLgs;WXmmq zRyYQIYHN`6@S|`Smmz#=C0r>vNKI!tJih_v++QL#s{q5+t-+WR2avJ+4^VPOBYELt zn6hsVlJ1+slO~kwJ7I)V6?qsrN>iBdE!rXLT0Xr4wPya@92;Ti6g zMs}%KhS*@p<;1XVg+3({*)tZyZYf9N=tAhdlQD4C&oHXK8DZOxqT9mfF?{POleXsoRd;2ah58zEue7SBdyPzJ!8*ok#Bax6%FXT0~4+i1>TgV&Dr0 zF#P0s6m5AO@tMUuZ|@fzg`L=NS$C*0VE+NNNH8JqW#1ynzGrUy2Ig4=!=j6IdJyR zLrh98!qbOA8J>sGfjQ{bhwn48;mXWL$e?V54IGN_K{-fF%|rLJOt^*&fO%sY`7#~u z^r5g1$$*wV7)JL5UO!B9XR39hDhgsmV|jijS>i;HTEKi7&;m$6l9Q4GSD8*q&~#Ff z7QzpO0d(tpb%^YD@CdVhd+#&~BO{7i#I2Z%Cc075Dj;b6GLcS@bzE#?h$Dt;2a%5> zR43vz;b+M`@nFEXpxolPpw0zlVv+uCYY|=xD7_5TL$C}9(?G5P)>YvufomylKFh*Z zQCj)V?`d*xkvoozm-Mn~K{g_nF5h=5H>i>dRg+TAY2EP|PAjy&FbhD7ibw$#C@)Cy zgq@x-toL?{Pp$v3$rY4`fnsB_GhAXO6W`>syf=6w6!9vQW(qkgAw2RJ35p0!4JF86 p&hH|t$Q+EKU&#w+O9Ana`42N=sQiDCYKZ^<002ovPDHLkV1jG1Qm6m` literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/corner_gray_page8_background.xml b/app/src/main/res/drawable/corner_gray_page8_background.xml new file mode 100644 index 0000000..9d99a77 --- /dev/null +++ b/app/src/main/res/drawable/corner_gray_page8_background.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/edittext_search_bg.xml b/app/src/main/res/drawable/edittext_search_bg.xml new file mode 100644 index 0000000..b987ba5 --- /dev/null +++ b/app/src/main/res/drawable/edittext_search_bg.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/goout_ic.PNG b/app/src/main/res/drawable/goout_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..27d2bfa4c00ae12f599221d1ae4c3cd9426b883a GIT binary patch literal 2881 zcmV-H3%>M;P)z1^@s6QL>-m00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3f4(PK~#8N?Og|G zRXr50d+)uq?uA9I;-o4S9L0$sDi$0lPMqKbC*oeXkSeIS75CmaaG|2&!oByluJiw2 zeqQO{@m|vVa&Ow40~bnP-c8>5a*~{xkdTlN;>QRc7%>Q*3@i=COhjV_V!KqNE+BH} z&P}1Ap;Vwi0m_geLs|kabpcVWS~VIwb}aSl*N=)7E5<;0wYNk?MbWKWx9G~1D-;nC z!9aKcM2;LeXxzAQ5N=3Cx^(Gi z(4avCrYA)^cI=?irArgqxiKD1eV8v1g$fm-EnBuE2?GB4@Zm!mK72S~GuOlL@>t>j)_nQkuo;-PI^yty_{rmSoIK+KEYt}3(T)40< zX6bydxj-~&(u7W&I6;{0vIObr)~%aPhUt2@xj+mYIFMpvV`VWA?Eu=URjb5tHkF;A z%me~f)^+RFDS_Z?{N%|K8Zcl00}+gw2s1Yrno`=gZy!~tP$4xbdFDw(-n@A!CMG7O z7>MsZfBszfEpq0}nOY>nEFjXSPcJO0mo8m$1O&c(`SN9|Q>PB$oxzY&&F?S^2+ZK+ z%aXwpQl^7p&e9YX7DlH}pQhixe+Lx^NJXDMeHaKCsmPcyBSl9? z)2C0Lf(nA~Wg9ncq;loTnGA**5&;u76gU-gh6-Xh&W;>8k^s2O#PFbv89?;t(Su&S zdZof!<+ewU9;NEltDCCic@G4vr3)7>RA#K|7v8;lCyuj-7W81o2kO&%AUb#MER-)d z=*Ep3)VOhD6T>yV1p@J_^XJdkwl^dM_uIE`G-u8nDpRIRpc(4+=iUJU(?fW8I2}87 z%nf0P>*Mj`$JD7)C$||Ls6X$3$d)Y|O`0@`UcY|rDiG*w<;s;*v0}wQ%yIK`?|^`r z8Xh<=2q8Fz`7FEv0@Bd4XHR9guR$TOP4M+ z!Drz<5I8#CxpPMw4zS)rUqJNVn>TL=OA!3u2x7i{`!+$TyL$Di@O$7{vt|t;Si$4v z$z33_X3Z+rY?#QsgO#^y*RIr|LkDWxwkZYJvj)SUQ@}AaWXKTe+qW-u>C%Pz_wP@8_wEfC`x;-o4j(>DEnBuEL<+*Llq*** z5k!zZdv>ugV=^GPIa8)g!WxUm0Kc}oK!73e3&0ABqa*%CFc|iYqD6}mLh$qD%O{wZ zB}*1ziU3eB*vZoV{riQ+?(tHi+P}L%s4@rcQ%H)6iTwES;}jVgsmchi+nWtU{`~pH z`VPmAEWzE{rcE2K8LQgA*+5`TA3S(4VFQ+>3l}a>`}XZs8R2z%|3E;|0W+}iVRpLt zAQj8ExvPX|Yoec9j7?GkVR zO5@O>LuHdJ69a)WHr$ucN|~H-05wAzHf$&pJ(3s*BoLy`#m}EVosELOElztQMvM@; zQGg{XF%a-vLF0uPg2@>NV78e#bEZtTYhobaD_F5&1xti848*r#5tu!Dwy+u~O9V_0 zkO*FyoFm~#B4mKTaT1$3Ob>WqH4XNI_riIES*5y6A|)8(!S{nbF1*k8yTNFG6IMGA z@N7ZkaKyzkefspEKX@-p*ozh|66SCf!qL%Z0@pP*9B42$e@A@nKp^J;rF&p4)%g@G zSdgkzsX_o=h2W2XE`;yv9AB+kwfx3qX$Jzc4EB6UtEuW|5b!xGsPB%L0((*X5^^$#z|7!AbOx%Y9XN2n9w1O0ONHPZl2D=?O%O

    M zf{(y7*r`;P8hOFpNa0PZ>$0W+A*|b73UEA+{mkdcTQ!^S8Zz*5MWNddiDG|U=prb zD8PjzMcvi&tpfsuwUD4LOJBc!6{V?l-&JQF5C~M*x^=584kD2r&LrKXMy&$^4BfC{ zgESCG@!h_CyY}jq)&YUA7-XTU5S;qD>oQpf1TpkAYwy{yRXr znYv}d%uj9%ED-2nK>rO>FctPzrcyG7uC#z8V4w1HnMB9>IHrAyU9VFc7RqupVKc6d1KMAu`+K zFc-JRh6$HvA|OiYZp>qsKKENLKs zAQA;}s}!yPKtWr6z4(#jL3DI9MMg%7 zd$biad^2*<6b7vF<5E*w2Evd@z(6n%hMTxu28boXWrioWZ!r)I1TRhTrGq7cC4wb_ fCBhIXhy&su^-|CdNkQkq00000NkvXXu0mjfR|Fyd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/home_ic.PNG b/app/src/main/res/drawable/home_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..429b647689b21a28084a0be1f853a1962f38add6 GIT binary patch literal 1488 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 Ef^r1&&Hw-a literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_date.png b/app/src/main/res/drawable/ic_date.png new file mode 100644 index 0000000000000000000000000000000000000000..148032cd2f833778a56a1bd82f48b054fc8e78e7 GIT binary patch literal 3524 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 I&=~2z0dQqAo&W#< literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_email.PNG b/app/src/main/res/drawable/ic_email.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4dffb90b29fb88beba64380050bc475adcb261d2 GIT binary patch literal 1468 zcmV;t1w;CYP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1yM;vK~#8N?VaCC zY#|WG_y7M3`UO1%L2p4&^cDm`5ClE-Rs=zBLC`}GoS3+FUDwfZ9CdU(5OweB9G#C} z$KyJ?t7Tq8cwjX|FJ>o}338A@FhNd`gLq(&Zfq#><>h5LK0aP{cX#KHQXc@H$H&LD zA-DnZ=;&w-;Lgs@1ga3|!NEZo#q#0Mb|S^z?Lje}5k&qV&;?&(F{0 z{QMl95u+fDDqSNW=llEnKD^L*DMS=(Fcse3-Y(zY z-)mr#Ktf@k@u^OEn3xLR-roLhX0KtAL7EB=4-X3fw2e)5<^%ou`dY58t~O$!QK5YY z5s+XI7CZpYHaOMEhY8Q^?js+>LR*DJKpLa4=$Y!|158n2QIJ!ee2A$kEDkcH&a<<# z-$l~A{(AsZ;mys>?~0UiiN#3lX1>@7&q3~S*mhq_&Vk7*2%2ga>NS&~;u&wIE zR0yk7crEp+1`>;%+o(<{6;_Lp*r@WYY_~z35bu1?gXm zCl+Gjs5-T}jerpfyA!XAURVdPK#Hi{ltwMDmp+O_5vz7`~f;5e)If_%4 z_>}V4?DF*VM5)d$(={U{rYJMlDOOW97+UnG( z!Y*SZrWj0}udlBZkwwdBR^d<}L+bRMHe0Re8H3pQqmPe|=m4l)pvlw<&gA^WoD)0q zLWRgZ5or1pYiEhqn}FnWgbD$Rolu{0{zc*xAhoR=KVWsb0LgKTtxl*99SxleO`RcP z5IAj)*$lm|3MAHfu2T#g_x(;ccEUlhl(V?p_V_?Z*-{UZ+fh>weq*^4&(F^r>1mYH z@!U3TB}neV!L4VU?j{`NfPNPiH`&T2^(rR1f)9$9R-_MlIX?7#YXloB^@xgow@aW zqfO1!TB36Xq%T$5q^EI`b#vO9Q@4x959tmXKw#G%t-ftLa8ODrJ*Ta)5I~yK1BFy5 zlH-_A$89JEWN0(M*rKX4rM;yAnzlCwnc|e#sP%2nfqhJcwmsu;>Tj$qZv9xBrCx6e zQW7GzVa~lrXycq~Qwo~u#SXWV+*EDq{UkQgsrSk$*Hn=?4Trk1x2>U2GArZi@>Z$pWP_Y4EDzDXLrk44kg2KK zb-O(7-9Vj}mzUlzJ!65iD^XIl$8~L+p7|1vfQiY%wp-=>YF-;4{B0+Ry06WDxBE`! zAV~L9FD9sVplsj!J_{iT5>}@Zo(_0E4rX?AKMO(T(+=8%ka<_j0~6#R!(oCP1mq9% Wcy?Ys{l!|E!-Wn>9OB{O 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_history.png b/app/src/main/res/drawable/ic_history.png new file mode 100644 index 0000000000000000000000000000000000000000..ee468aaa5e8e8d39bd1a713a9b7424c9642d682a GIT binary patch literal 2380 zcmeH}Yfw{16oB_$k^tdCVvG`kl7JwQ@d1Ja!O{qk5D*BDB3dfpQ4HD+aR{P-8XlG) z1Q@Ix1fdrLRbjOCf$~rr2!gah5>SWo5J3llBBE9W5$Pq^Y5mvf&yGL#?(Cg&_MF{w z&VDCb;LkHA(un{7W4<>x2%FLQVL-sXIUT#!V3VQPdwT)^6v_O6?#D9rV?S}bHv4S` z;6h&NOyDtW&5ZUA@&h2*1^{UW0Mm2WJPJUfJpf}u09=azFpV#axakFeK@*?5Ib?rN zRE$tK)nQNcY6OrJMA41Y1MLd{Q|h(&0gEO8WRAj6Ohs700M+7Lhy*IYX+-ccydDw2 zA}1&>9l`_1sTlAYrLYvx{iF&Z2jT$vN@buu`f;28csIhNTt7hcV7)q;FY{#ey>m2l z&6M5EGH)7#&mN0+V_CU8R;tk|rj`ARmlt?R5xWQ{vSrc+MOEmhhoI(LoYTGQw{W>M zb$h!Rf*`c8urRM+B@=h}-P_1o$tXpoRq)L2Ur*tgx-)Cf~ zL|aV)nUAKxAvdW(7~rU{;AAHZaAZFUQ&ez( zimc;QyWlZZYmNqKWzlv@L-!KN94EdM9jytpzXr|?Q86D10q=2Q76bk4B>X;e>8G)% zxC+=GlllK!p;*}GW@p&+iz-B8=Z_`%O2f&n(*X(xXZ1o}cvU}Gc%U%Jh->>DK9C$# zW&JIQ2|Vp@VAG@jvDMw`ZAd`bCNp_WBwY4M3gLaWZnu3jqE#py*jtrt$86(bojE|e z8oFPfm@|00)J<`L-Q1|)<%W9 z@UvYCVA&$sTvz8}7>1GZ@^U07C`jSpnh8YR_;07?t2a0WlNmN7hpX2+ICS^+Iu@Nc z;UE@^b6X~ugijB>1y`r@mThdBeB8k(?$sxABz&p8vZ<*_7!%WsR#pANw6$$jwzN3Y zA7+5JZ(bVp-D@~FK{ z&7zrX*R3~|7+O}iL+M^q9i?u(*PV=zH*%Ojz!>sH9v+wSdg9BeS5M6Q$K9|usCJf3 zq|tQ1@i2dca=l5wXC#ZnurQV^fXM)l?k=)0V!e7gK=Pkd09Yq$mG-3fYS*1qjadJB zZ%M{-9lE$M8fm#>C0WoKEm1AC({W8!>FJSU_q?ZO4??ooL^BpT>9|MswN2|;PSKnk zo9J)g>6scW2rE22+P4=+x8}*$`l=wEr6>s9N3U_UMmHoXs#SaSbR={EBJbhON?&S; zURCmFU46_M>`pO4;wU7W<&@nvLxYG;nR3P*v+8~2opyR>lMb0oNIZ6D)x|5;={`5K z=gwy8fXcDL_P6=G0tiatCEZ6{bS@ScaK`R&1wWdG9L$H`D<4m}gg$fE)DEziCb}bA zQ>3?BSHzkvVU>4AvwssqIx6u2T4+4r5u^!UC%T4(~kjeLEbb{nQ`Qdg>9yaqZavA|a>961IE0!-^X;i#^J;4U%t*khf+ zs*wVz$pn<>!)fUAf(~E@B#evl20=(ji1LpSLc;S8+J(Q$@?W$c2=JzBEseJ|)?=Ly N;BWEgp7#)@{|RLY4_p8M literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_left_arrow.png b/app/src/main/res/drawable/ic_left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c9ec649993f9ade2cc3438f844a07fb66df3518f GIT binary patch literal 470 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 R2;NCisVQqIl_D*J{||tthA{vD literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_map.png b/app/src/main/res/drawable/ic_map.png new file mode 100644 index 0000000000000000000000000000000000000000..f8b70389ab79613edaef1efe1a9f83877aad406e GIT binary patch literal 1968 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_right_arrow.png b/app/src/main/res/drawable/ic_right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..11af5565191c46c4854c78497ede99cb1488fa14 GIT binary patch literal 441 zcmV;q0Y?6bP)M_XN606{!%8P`k{SXEmAK|G<1JhKXB zOCTABq)FmjR9ged;t#f;mXPcq`D&eq4@)lIf8S-DOn+;ISnMIT-w+Q({MPgqC4^}V zVdFytEAsmEQ8&c!A;dT+#DI=GKK;lv#1K2gu|kN09`g3|M{gkxLqi--$9Q3&R#-3n jpW-P>seoF)4+HWC36l0R)+pIg00000NkvXXu0mjf-08Zn literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_sns.png b/app/src/main/res/drawable/ic_sns.png new file mode 100644 index 0000000000000000000000000000000000000000..d3f80d41baf9eb8a9aa476b9c6e57076d76ede96 GIT binary patch literal 1595 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I4M=vMPuB%foCO|{#S9EWB_ParFHODzD9DoT z=KY{7FBPg+xd2Cq|}>Ei8kw{P;4f4O(Um%6xTz Z;UO!ZeUPX1Dqum+;OXk;vd$@?2>@j0kLUmZ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_user.png b/app/src/main/res/drawable/ic_user.png new file mode 100644 index 0000000000000000000000000000000000000000..9bb0917c2b99bcddc01f23198a1b782bd75c4dd9 GIT binary patch literal 2588 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 + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/left_unselected_lev_bg.xml b/app/src/main/res/drawable/left_unselected_lev_bg.xml new file mode 100644 index 0000000..233494d --- /dev/null +++ b/app/src/main/res/drawable/left_unselected_lev_bg.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/list_ic.PNG b/app/src/main/res/drawable/list_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..5580e2aae608568247d53bf3aa6de4b3e7d96dfc GIT binary patch literal 786 zcmeAS@N?(olHy`uVBq!ia0vp^F+d#3!3HFcJZPQ(q!^2X+?^QKos)S9a~60+7BevL9R^{>Y zl$7i`6c#Bw`v3pfl-o&~OJA$yNvKqF?VD0^$FjQESUTfdvVnw%-B*bkhTU>G8`&zJ z@~~SRc)hG5*W2}>hD_^!8EN&&o-@y;rS6QG_O~wHZ+Y;}`|tPum~;O5dfWA3tBvNL z?~d4$8DvA=$5{!+B@xIMNZSdkcTU7*C|Bkh}~^mt@Qn-mQD5jyzO@z-qpK7^nR(pEei<{C1HrxHE2$^6h*1EXh*5)ng z%$pg!Ia@MU+Rkk>PC1j_2&CN3^Tj-R!!yTmV%Y=5W~J+|x30F${J3+Cq2l5I(+M`( z3trT=^8CKqk+$s7_S;<&tv#E=1QQMwSr-^?67e~@#qY%Rxyc#T#w8m!uDZ<<m@xq5r{dnR2mxeNU_!n`X}1OF}i`P84` u`PGCyQg2k(9}4>?&Nr=T>62|!{IvxpE=XGP)c}}|89ZJ6T-G@yGywnyiDPL1 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/login_button_selector.xml b/app/src/main/res/drawable/login_button_selector.xml new file mode 100644 index 0000000..ef9c9ac --- /dev/null +++ b/app/src/main/res/drawable/login_button_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/mid_selected_lev_bg.xml b/app/src/main/res/drawable/mid_selected_lev_bg.xml new file mode 100644 index 0000000..d7eb098 --- /dev/null +++ b/app/src/main/res/drawable/mid_selected_lev_bg.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/mid_unselected_lev_bg.xml b/app/src/main/res/drawable/mid_unselected_lev_bg.xml new file mode 100644 index 0000000..a214f53 --- /dev/null +++ b/app/src/main/res/drawable/mid_unselected_lev_bg.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/next_ic.PNG b/app/src/main/res/drawable/next_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d1d05d906429294b5739f9cc56908c359cc2bee7 GIT binary patch literal 2008 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/progress_circular.xml b/app/src/main/res/drawable/progress_circular.xml new file mode 100644 index 0000000..9a11efe --- /dev/null +++ b/app/src/main/res/drawable/progress_circular.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/right_selected_lev_bg.xml b/app/src/main/res/drawable/right_selected_lev_bg.xml new file mode 100644 index 0000000..5205548 --- /dev/null +++ b/app/src/main/res/drawable/right_selected_lev_bg.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/right_unselected_lev_bg.xml b/app/src/main/res/drawable/right_unselected_lev_bg.xml new file mode 100644 index 0000000..45f5ef7 --- /dev/null +++ b/app/src/main/res/drawable/right_unselected_lev_bg.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/round_shape.xml b/app/src/main/res/drawable/round_shape.xml new file mode 100644 index 0000000..9dfd969 --- /dev/null +++ b/app/src/main/res/drawable/round_shape.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_button.xml b/app/src/main/res/drawable/rounded_button.xml new file mode 100644 index 0000000..7dab18f --- /dev/null +++ b/app/src/main/res/drawable/rounded_button.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_button_selected.xml b/app/src/main/res/drawable/rounded_button_selected.xml new file mode 100644 index 0000000..f2b7d96 --- /dev/null +++ b/app/src/main/res/drawable/rounded_button_selected.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_edittext.xml b/app/src/main/res/drawable/rounded_edittext.xml new file mode 100644 index 0000000..b837fc8 --- /dev/null +++ b/app/src/main/res/drawable/rounded_edittext.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/seekbar_progress.xml b/app/src/main/res/drawable/seekbar_progress.xml new file mode 100644 index 0000000..3c4ffa1 --- /dev/null +++ b/app/src/main/res/drawable/seekbar_progress.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/seekbar_style.xml b/app/src/main/res/drawable/seekbar_style.xml new file mode 100644 index 0000000..3ea9016 --- /dev/null +++ b/app/src/main/res/drawable/seekbar_style.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_type_background.xml b/app/src/main/res/drawable/step_type_background.xml new file mode 100644 index 0000000..7f2266d --- /dev/null +++ b/app/src/main/res/drawable/step_type_background.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_type_enabled.xml b/app/src/main/res/drawable/step_type_enabled.xml new file mode 100644 index 0000000..5cc06f6 --- /dev/null +++ b/app/src/main/res/drawable/step_type_enabled.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/step_type_pressed.xml b/app/src/main/res/drawable/step_type_pressed.xml new file mode 100644 index 0000000..05372ee --- /dev/null +++ b/app/src/main/res/drawable/step_type_pressed.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_background.xml b/app/src/main/res/drawable/tab_background.xml new file mode 100644 index 0000000..949ce47 --- /dev/null +++ b/app/src/main/res/drawable/tab_background.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_background_selected.xml b/app/src/main/res/drawable/tab_background_selected.xml new file mode 100644 index 0000000..c3d1e1b --- /dev/null +++ b/app/src/main/res/drawable/tab_background_selected.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/drawable/tab_background_unselected.xml b/app/src/main/res/drawable/tab_background_unselected.xml new file mode 100644 index 0000000..d5b2a63 --- /dev/null +++ b/app/src/main/res/drawable/tab_background_unselected.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_color_selector.xml b/app/src/main/res/drawable/tab_color_selector.xml new file mode 100644 index 0000000..9be2e19 --- /dev/null +++ b/app/src/main/res/drawable/tab_color_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/table_background_row_even.xml b/app/src/main/res/drawable/table_background_row_even.xml new file mode 100644 index 0000000..02da526 --- /dev/null +++ b/app/src/main/res/drawable/table_background_row_even.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/table_background_row_even_selector.xml b/app/src/main/res/drawable/table_background_row_even_selector.xml new file mode 100644 index 0000000..7d0ef24 --- /dev/null +++ b/app/src/main/res/drawable/table_background_row_even_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/table_background_row_odd.xml b/app/src/main/res/drawable/table_background_row_odd.xml new file mode 100644 index 0000000..0e6adb9 --- /dev/null +++ b/app/src/main/res/drawable/table_background_row_odd.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/table_background_row_odd_selector.xml b/app/src/main/res/drawable/table_background_row_odd_selector.xml new file mode 100644 index 0000000..ae4a853 --- /dev/null +++ b/app/src/main/res/drawable/table_background_row_odd_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/toggle_on_off.xml b/app/src/main/res/drawable/toggle_on_off.xml new file mode 100644 index 0000000..2f18556 --- /dev/null +++ b/app/src/main/res/drawable/toggle_on_off.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/walking_ic.PNG b/app/src/main/res/drawable/walking_ic.PNG new file mode 100644 index 0000000000000000000000000000000000000000..9698a2ec9ead9c9c153f9fe0144b80a5ae5f414f GIT binary patch literal 3114 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 Eg7?b4#Q*>R literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/weather.PNG b/app/src/main/res/drawable/weather.PNG new file mode 100644 index 0000000000000000000000000000000000000000..7f7fecc6e83956bdbdc6e2ac4dbac8918c940193 GIT binary patch literal 1645 zcmV-z29o)SP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1_DV$K~#8N?VU|a zBry<%=l}l#6~%)h2p$wc@Z+EtK@bE%@Foa?2bqK5K@fVaVXHT0)2WYCrF)zV$by|t zr=C=*lXt4z*?d0l+Rsl0vj*gUr)W?TE2TlnLAkoR>ekoSSL)~N>?|2idrw(4AYkv> z+8Q6q!NEcI@$u39w$JD1XLoXP@?$lmUNrxC3IG9$dwYA``}_N^;Q~NH+i+#Dpu{)- z1~4g`L{Pvrpp)a{@G2q4E&0sK0V#-5`V@k^E z+uPeof{B4pGiK%~_@Mjy`yR~Q-5vFO_v_%b=ponF*R1E6LxHElK(J%*p0PgKakxN< z!9cvJ{dstJP*02-6o4RI%U0k@W1B0KF~F1pF?}WHX8HB?mE15{cuBZldU|?Ncj@ja zI5O_WNo$Ga2C^CyFc!eT$r>ICC++ymp#cJ$u#1a}{tRYu)TjytjLw}-xlm@a*`le} zY25`147&6u2MGEOg{8bYLkTddQpAr321sSh^**kT*x$=6lMAF__Zq z%_?snjlw4N7|Un4L$Mqz1fLvIm0o?^kZTT<-3&3cz zH_f3)H&xu(*S6Dq$7~8^YCsUA6pR@ZN%o<3)=Tb_WN(^487pH+3W+OG6hqNuA4-j} zY|qKwEP|rVKD0Da(-$>vH55ud)C{)fJwx)Q`jpIFn>CHpJZmTxiaq7G06~Z;Fd`^c z*@v20^}Hv}-eg0;Z|at%u15+n+<3B~V8d1U7o31qZMrHzz|K~z{k_&&v33-2TCp|( z1jI2>poRV{PsV+nnQs>QgR<-PvCYj>(7@VYN`aWZl5?}%inRyma5qlcC1kmQbYDK9ksjHMmf4m# z)~Zn8p%%$Jm`_`poHOK=E>JL$x8&d4GJ<|Rvn^eqP;mi`($p7wfeyz!8Wb3WCYuqU zXkbzkH5n)frWI>{lZdM+H~|yxX~o*X-=d`CL&?(Mv~`OqB>@ozh2L3wZ~9V@+@Mge z)ZFz}tUW-d6>CReTCsKnq!nxb{ex4;r4?&O`xPqNvK4C&1m9MyO@L{|+5w? zzmo2BTd_9hfRkxcb(_yQ4NL8@kT>IJR)gXxAGTuc0awzfcvXe#@L`sNrIwb}vs{-? zE7p#t(IWs-o`Tm)1G + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/statistics.xml b/app/src/main/res/layout-land/statistics.xml new file mode 100644 index 0000000..31a1594 --- /dev/null +++ b/app/src/main/res/layout-land/statistics.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +

  • 0jXhW&wHG4tw_sEx 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 literal 0 HcmV?d00001 diff --git a/app/src/androidTest/java/com/dinhcv/lifelogpedometer/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/dinhcv/lifelogpedometer/ExampleInstrumentedTest.java new file mode 100644 index 0000000..60d466e --- /dev/null +++ b/app/src/androidTest/java/com/dinhcv/lifelogpedometer/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.dinhcv.lifelogpedometer; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.dinhcv.lifelogpedometer", appContext.getPackageName()); + } +} diff --git a/app/src/dev/res/values/strings.xml b/app/src/dev/res/values/strings.xml new file mode 100644 index 0000000..5886c49 --- /dev/null +++ b/app/src/dev/res/values/strings.xml @@ -0,0 +1,4 @@ + + + lifelog + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f84901c --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/LifeLogApplication.java b/app/src/main/java/com/dinhcv/lifelogpedometer/LifeLogApplication.java new file mode 100644 index 0000000..7d65a95 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/LifeLogApplication.java @@ -0,0 +1,52 @@ +package com.dinhcv.lifelogpedometer; + +import android.app.Application; +import android.content.Context; +import android.webkit.WebView; + +import com.dinhcv.lifelogpedometer.model.DummyData; +import com.dinhcv.lifelogpedometer.model.database.orm.OrmDatabaseHelper; +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.util.Date; +import java.util.List; + + +public class LifeLogApplication extends Application { + + public List mSexList; + public List mProvinceList; + public static Context context; + + @Override + public void onCreate() { + super.onCreate(); + + context = LifeLogApplication.this; + // Add DB local + OrmDatabaseHelper.addOrmRecordClasses(new Class[]{ + + }); + + OrmDatabaseHelper.init(this); + + String ua = new WebView(this).getSettings().getUserAgentString(); + Utils.setCustomUA(ua); + } + + public List getSexList(){ + if (mSexList == null) { + mSexList = DummyData.getSexList(context); + } + return mSexList; + } + + public List getProvinceList(){ + if (mProvinceList == null) { + mProvinceList = DummyData.getProvinceList(context); + } + return mProvinceList; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/ActivityBase.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/ActivityBase.java new file mode 100644 index 0000000..060e13f --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/ActivityBase.java @@ -0,0 +1,92 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.MotionEvent; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +import com.dinhcv.lifelogpedometer.R; + + +abstract class ActivityBase extends AppCompatActivity { + + public void showAlerDialog(Context context, String message){ + AlertDialog.Builder alert = new AlertDialog.Builder(context); + + alert.setTitle(R.string.error_title); + alert.setMessage(message); + alert.setPositiveButton(R.string.ok, null); + alert.show(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + View v = getCurrentFocus(); + + if (v != null && + (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && + v instanceof EditText && + !v.getClass().getName().startsWith("android.webkit.")) { + int scrcoords[] = new int[2]; + v.getLocationOnScreen(scrcoords); + float x = ev.getRawX() + v.getLeft() - scrcoords[0]; + float y = ev.getRawY() + v.getTop() - scrcoords[1]; + + if (x < v.getLeft() || x > v.getRight() || y < v.getTop() || y > v.getBottom()) + hideKeyboard(this); + } + return super.dispatchTouchEvent(ev); + } + + public static void hideKeyboard(Activity activity) { + if (activity != null && activity.getWindow() != null && activity.getWindow().getDecorView() != null) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0); + } + } + + private static ProgressDialog progressDialog; + public static void showDialog(Context context){ + progressDialog = new ProgressDialog(context); + progressDialog.setMessage(context.getResources().getString(R.string.waite_some_minute)); + progressDialog.setCancelable(false); + progressDialog.show(); + } + + public static void hiddenDialog(){ + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + } + } + + public void gotoActivity(Class c) { + Intent intent = new Intent(this, c); + startActivity(intent); + } + + public void gotoActivity(Class c, Bundle b) { + Intent intent = new Intent(this, c); + intent.putExtras(b); + startActivity(intent); + } + + public void gotoActivityForResult(Class c, int requestCode) { + Intent intent = new Intent(this, c); + startActivityForResult(intent, requestCode); + } + + public void gotoActivityAndFinish(Class c) { + Intent intent = new Intent(this, c); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DateFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DateFragment.java new file mode 100644 index 0000000..ef76535 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DateFragment.java @@ -0,0 +1,337 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.DatePicker; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.NoticeAdapter; +import com.dinhcv.lifelogpedometer.customview.ExpandableListCustomView; +import com.dinhcv.lifelogpedometer.feature.Database; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.structure.history.HistoryInfo; +import com.dinhcv.lifelogpedometer.model.structure.home.NoticeInfo; +import com.dinhcv.lifelogpedometer.model.structure.home.TagetInfo; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import static com.dinhcv.lifelogpedometer.utils.Utils.getStandarDate; + +public class DateFragment extends FragmentBase implements SettingFragmentPresenter { + + private TextView tvDate; + private TextView tvStep; + private TextView tvRemain; + private TextView tvRateDone; + private ImageView ivBack; + private ImageView ivNext; + + private LinearLayout llBike; + private LinearLayout llWalking; + private LinearLayout llRunning; + + private Date mAnaDate; + private Calendar mCalendar; + + private int mAnaDay; + private int mAnaMonth; + private int mAnaYear; + private Context mContext; + + private Const.STEP_TYPE stepType; + private TagetInfo mTagetInfo = new TagetInfo(); + + private ExpandableListCustomView lvNotice; + private NoticeAdapter mNoticeAdapter; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle + savedInstanceState) { + // Inflate the layout for this fragment + View rootView = inflater.inflate(R.layout.fragment_date, container, false); + mContext = getActivity(); + initView(rootView); + initData(); + return rootView; + } + + + private void initView(View rootView) { + tvDate = (TextView) rootView.findViewById(R.id.tv_date); + tvStep = (TextView) rootView.findViewById(R.id.tv_step); + tvRemain = (TextView) rootView.findViewById(R.id.tv_remainingStep); + tvRateDone = (TextView) rootView.findViewById(R.id.tv_completeRate); + ivBack = (ImageView) rootView.findViewById(R.id.iv_back); + ivNext = (ImageView) rootView.findViewById(R.id.iv_next); + + llBike = (LinearLayout) rootView.findViewById(R.id.ll_bike); + llWalking = (LinearLayout) rootView.findViewById(R.id.ll_walking); + llRunning = (LinearLayout) rootView.findViewById(R.id.ll_running); + + lvNotice = (ExpandableListCustomView) rootView.findViewById(R.id.lv_notice); + + handleEvent(); + } + + private void handleEvent(){ + tvDate.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + handleAnaDatePicker(); + } + }); + + ivBack.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, -1); + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + getHomePage(mAnaDate, stepType); + } + }); + + ivNext.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, +1); + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + getHomePage(mAnaDate, stepType); + } + }); + + + llWalking.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + stepType = Const.STEP_TYPE.WALKING; + updateUiStepType(false, true, false); + // add data + getHomePage(mAnaDate, stepType); + } + }); + + llRunning.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + stepType = Const.STEP_TYPE.RUNNING; + updateUiStepType(false, false, true); + // add + getHomePage(mAnaDate, stepType); + } + }); + + llBike.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + stepType = Const.STEP_TYPE.BIKE; + updateUiStepType(true, false, false); + // add data + getHomePage(mAnaDate, stepType); + } + }); + + } + + private void updateUiStepType(boolean b1, boolean b2, boolean b3) { + llBike.setSelected(b1); + llWalking.setSelected(b2); + llRunning.setSelected(b3); + } + + /** + * Show date picker dialog + */ + private void handleAnaDatePicker() { + + new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + + mCalendar = Calendar.getInstance(); + mCalendar.set(year, monthOfYear, dayOfMonth); + mAnaYear = year; + mAnaMonth = monthOfYear; + mAnaDay = dayOfMonth; + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + + getHomePage(mAnaDate, stepType); + } + }, mAnaYear, mAnaMonth, mAnaDay).show(); + + } + + + /** + * init data for + */ + private void initData() { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(new Date()); + mAnaDate = mCalendar.getTime(); + mAnaYear = mCalendar.get(Calendar.YEAR); + mAnaMonth = mCalendar.get(Calendar.MONTH); + mAnaDay = mCalendar.get(Calendar.DAY_OF_MONTH); + + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); + + stepType = Const.STEP_TYPE.WALKING; + updateUiStepType(false, true, false); + getHomePage(mAnaDate, stepType); + } + + + private void getHomePage(Date date, Const.STEP_TYPE stepType){ + + showDialog(mContext); + LLAPIManager.homePage(date, stepType, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + Debug.error("Get data history error"); + hiddenDialog(); + showDialogNotData(); + } + + @Override + public void onSuccess(String json) { + Debug.error("Get data history success"); + hiddenDialog(); + loadDataDone(json); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.error("Get data history success"); + hiddenDialog(); + } + }); + } + + private void showDialogNotData(){ + showAlerDialog(mContext, getResources().getString(R.string.can_not_get_data)); + } + + private void loadDataDone(String jsonString) { + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + JSONObject jsonObject1 = jsonObject.optJSONObject("result"); + JSONObject targetInf = jsonObject1.getJSONObject("targetInf"); + JSONArray listNotice = jsonObject1.getJSONArray("listNotice"); + + if (targetInf != null){ + String target = targetInf.optString("target_step"); + Debug.normal("Target: "+ target); + mTagetInfo.setTaget(targetInf.optString("target_step")); + mTagetInfo.setSteps(targetInf.optString("num_step")); + mTagetInfo.setStepRemain(targetInf.optString("remaining_step")); + mTagetInfo.setCompletePercent(targetInf.optString("complete_percent")); + } + + if (listNotice != null && listNotice.length() > 0) { + List infoLists = new ArrayList<>(); + for (int i = 0; i < listNotice.length(); i++){ + NoticeInfo noticeInfo = new NoticeInfo(); + JSONObject ob = (JSONObject) listNotice.get(i); + noticeInfo.setId(ob.optInt("id")); + noticeInfo.setContent(ob.optString("notice_content")); + infoLists.add(noticeInfo); + } + + mTagetInfo.setNoticeList(infoLists); + } + + } + } catch (JSONException e) { + e.printStackTrace(); + mTagetInfo = new TagetInfo();; + } + + updateUI(); + } + + + private void updateUI(){ + + tvStep.setText(mTagetInfo.getSteps()); + tvRemain.setText(mTagetInfo.getStepRemain()); + tvRateDone.setText(getResources().getString(R.string.percent_unit, mTagetInfo.getCompletePercent())); + + List infoLists = mTagetInfo.getNoticeList(); + if (infoLists != null && infoLists.size() >0){ + mNoticeAdapter = new NoticeAdapter(mContext, infoLists); + lvNotice.setAdapter(mNoticeAdapter); + lvNotice.setExpanded(true); + } + + } + + private void addDataToObject(){ + + } + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + } + + + @Override + public void onSaveData() { + + } + + @Override + public void onInvalidate(boolean isInit) { + initData(); + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DialogBase.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DialogBase.java new file mode 100644 index 0000000..4ca0b5a --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/DialogBase.java @@ -0,0 +1,39 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.Context; +import android.support.v7.app.AppCompatDialog; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.utils.Debug; + + +public class DialogBase extends AppCompatDialog { + + public DialogBase(Context context) { + super(context); + } + + public DialogBase(Context context, int style) { + super(context, style); + } + + @Override + protected void onStart() { + super.onStart(); + // In order to not be too narrow, set the window size based on the screen resolution: + final int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels; + final int newScreenWidth = screenWidth * 100 / 100; + WindowManager.LayoutParams layout = getWindow().getAttributes(); + layout.width = Math.max(layout.width, newScreenWidth ); + + TextView textView = (TextView) findViewById(android.R.id.title); + + if(textView != null) { + Debug.normal("Set title dialog ----------------------------------"); + textView.setSingleLine(false); + textView.setGravity(Gravity.CENTER); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/FragmentBase.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/FragmentBase.java new file mode 100644 index 0000000..a112b5b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/FragmentBase.java @@ -0,0 +1,93 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.View; +import android.content.DialogInterface; +import android.os.Build; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; + +import com.dinhcv.lifelogpedometer.R; + +import butterknife.ButterKnife; +import butterknife.Unbinder; + +public abstract class FragmentBase extends Fragment { + + protected ActivityBase mActivity; + protected View mView; + protected Unbinder unbinder; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mActivity = (ActivityBase) getActivity(); + + } + + public void showAlerDialog(Context context, String message) { + android.app.AlertDialog.Builder alert = new android.app.AlertDialog.Builder(context); + + alert.setTitle(R.string.error_title); + alert.setMessage(message); + alert.setPositiveButton(R.string.ok, null); + alert.show(); + } + + private static ProgressDialog progressDialog; + private static ProgressDialog mLoadingDialog; + + public static void showDialog(Context context) { + if (progressDialog == null) { + progressDialog = new ProgressDialog(context); + } + } + + public static void hiddenDialog() { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + } + } + + public void showLoadingDialog() { + if (mLoadingDialog == null) { + mLoadingDialog = new ProgressDialog(getActivity()); + mLoadingDialog.setTitle(getString(R.string.waite_some_minute)); + } + if (mLoadingDialog.isShowing()) { +// mLoadingDialog.dismiss(); + return; + } + progressDialog.setCancelable(false); + mLoadingDialog.show(); + } + + public void dismissLoadingDialog() { + if (mLoadingDialog == null) { + return; + } + if (mLoadingDialog.isShowing()) { + mLoadingDialog.dismiss(); + } + } + + public AlertDialog.Builder getAlert(String title, String message) { + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + if (!title.isEmpty()) { + builder.setTitle(title); + } + if (!message.isEmpty()) { + builder.setMessage(message); + } + builder.setIcon(android.R.drawable.ic_dialog_alert); + + return builder; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryContentFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryContentFragment.java new file mode 100644 index 0000000..dbcfa30 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryContentFragment.java @@ -0,0 +1,637 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.structure.history.HistoryInfo; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.DayAxisValueFormatter; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +import static com.github.mikephil.charting.utils.ColorTemplate.rgb; + +public class HistoryContentFragment extends FragmentBase { + + @BindView(R.id.btn_left_date) + ImageButton btnLeftDate; + @BindView(R.id.btn_right_date) + ImageButton btnRightDate; + @BindView(R.id.tv_date) + TextView tvDate; + @BindView(R.id.tv_week_day) + TextView tvWeekDay; + private Button btnFace; + private Button btnTwitter; + private Button btnLine; + private Button btnEmail; + private Button btnOther; + @BindView(R.id.tv_steps) + TextView tvStep; + @BindView(R.id.tv_remainingStep) + TextView tvRemain; + @BindView(R.id.tv_stepRateDone) + TextView tvRateDone; + @BindView(R.id.tv_smallRemain) + TextView tvSmallRemain; + @BindView(R.id.tv_stepGoal) + TextView tvGoal; + + @BindView(R.id.tv_caloConsumned) + TextView tvCaloConsumned; + @BindView(R.id.tv_distance) + TextView tvDistance; + @BindView(R.id.tv_time) + TextView tvTime; + + @BindView(R.id.ll_bike) + LinearLayout llBike; + @BindView(R.id.ll_walking) + LinearLayout llWalking; + @BindView(R.id.ll_running) + LinearLayout llRunning; + @BindView(R.id.btn_oneDay) + Button btnOneDay; + @BindView(R.id.btn_oneWeek) + Button btnOneWeek; + @BindView(R.id.btn_oneMonth) + Button btnOneMonth; + @BindView(R.id.btn_threeMonth) + Button btnThreeMonth; + @BindView(R.id.btn_sixMonth) + Button btnSixMonth; + + // bar chart + private BarChart mBarChart; + private List dateList; + private String[] mParties; + private Integer[] mStep; + + private Date mAnaDate; + private Calendar mCalendar; + + private int mAnaDay; + private int mAnaMonth; + private int mAnaYear; + + private HistoryInfo mDataModWalking = new HistoryInfo(); + private HistoryInfo mDataModRunning = new HistoryInfo(); + private HistoryInfo mDataModBike = new HistoryInfo(); + private HistoryInfo mDataCurrent = new HistoryInfo(); + + private Const.DATA_TYPE dataType; + private Const.STEP_TYPE stepType; + + private Context mContext; + private View mRootView; + + private HistoryFragment mHistoryFragment; + + public void setRootFragment(HistoryFragment frag) { + this.mHistoryFragment = frag; + } + + @Override + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, + final Bundle savedInstanceState) { + mRootView = inflater.inflate(R.layout.fragment_history_content, null); + ButterKnife.bind(this, mRootView); + mContext = getActivity(); + initView(mRootView); + initData(); + + return mRootView; + } + + + private void initView(View view) { + btnFace = (Button) view.findViewById(R.id.btn_face); + btnTwitter = (Button) view.findViewById(R.id.btn_twitter); + btnLine = (Button) view.findViewById(R.id.btn_line); + btnEmail = (Button) view.findViewById(R.id.btn_email); + btnOther = (Button) view.findViewById(R.id.btn_other); + + mBarChart = (BarChart) view.findViewById(R.id.chart); + } + + + /** + * Show date picker dialog + */ + private void handleAnaDatePicker() { + + new DatePickerDialog(mContext, new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + + mCalendar = Calendar.getInstance(); + mCalendar.set(year, monthOfYear, dayOfMonth); + mAnaYear = year; + mAnaMonth = monthOfYear; + mAnaDay = dayOfMonth; + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date)); + mAnaDate = date; + getHistoryData(dataType, mAnaDate); + } + }, mAnaYear, mAnaMonth, mAnaDay).show(); + + } + + + /** + * init data for + */ + private void initData() { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(new Date()); + mAnaDate = mCalendar.getTime(); + mAnaYear = mCalendar.get(Calendar.YEAR); + mAnaMonth = mCalendar.get(Calendar.MONTH); + mAnaDay = mCalendar.get(Calendar.DAY_OF_MONTH); + + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); + tvWeekDay.setText(Utils.getWeekdayFromDate(mAnaDate)); + + dataType = Const.DATA_TYPE.ONE_DAY; + stepType = Const.STEP_TYPE.WALKING; + updateUiType(); + updateUiStepType(false, true, false); + + getHistoryData(dataType, mAnaDate); + } + + private void updateUiType() { + if (dataType == Const.DATA_TYPE.ONE_DAY) { + setButtonSelected(true, false, false, false, false); + } else if (dataType == Const.DATA_TYPE.ONE_WEEK) { + setButtonSelected(false, true, false, false, false); + } else if (dataType == Const.DATA_TYPE.ONE_MONTH) { + setButtonSelected(false, false, true, false, false); + } else if (dataType == Const.DATA_TYPE.THREE_MONTH){ + setButtonSelected(false, false, false, true, false); + } else if (dataType == Const.DATA_TYPE.SIX_MONTH){ + setButtonSelected(false, false, false, false, true); + } + } + + private void setButtonSelected(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5 ) { + btnOneDay.setSelected(b1); + btnOneWeek.setSelected(b2); + btnOneMonth.setSelected(b3); + btnThreeMonth.setSelected(b4); + btnSixMonth.setSelected(b5); + } + + private void updateUiStepType(boolean b1, boolean b2, boolean b3) { + llBike.setSelected(b1); + llWalking.setSelected(b2); + llRunning.setSelected(b3); + } + + private void getHistoryData(Const.DATA_TYPE dataType, Date toDate){ + + Date fromDate = Utils.getFromDate(mAnaDate, dataType); + + showDialog(mContext); + LLAPIManager.history(fromDate, toDate, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + Debug.error("Get data history error"); + hiddenDialog(); + showDialogNotData(); + } + + @Override + public void onSuccess(String json) { + Debug.error("Get data history success"); + hiddenDialog(); + loadDataDone(json); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.error("Get data history success"); + hiddenDialog(); + } + }); + } + + private void showDialogNotData(){ + showAlerDialog(mContext, getResources().getString(R.string.can_not_get_data)); + } + + private void loadDataDone(String jsonString) { + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + JSONObject jsonObject1 = jsonObject.optJSONObject("result"); + JSONObject jsonMod1 = jsonObject1.getJSONObject("mode_1"); + JSONObject jsonMod2 = jsonObject1.getJSONObject("mode_2"); + JSONObject jsonMod3 = jsonObject1.getJSONObject("mode_3"); + addDataModWalking(jsonMod1); + addDataModRunning(jsonMod2); + addDataModBike(jsonMod3); + + } + } catch (JSONException e) { + e.printStackTrace(); + mDataModWalking = new HistoryInfo(); + mDataModRunning = new HistoryInfo();; + mDataModBike = new HistoryInfo();; + } + + if (stepType == Const.STEP_TYPE.WALKING){ + mDataCurrent = mDataModWalking; + }else if (stepType == Const.STEP_TYPE.RUNNING){ + mDataCurrent = mDataModRunning; + }else { + mDataCurrent = mDataModBike; + } + + updateUI(); + } + + private void updateUI(){ + // get data server + tvGoal.setText(getResources().getString(R.string.step_unit, mDataCurrent.getTaget())); + tvStep.setText(getResources().getString(R.string.step_unit, mDataCurrent.getSteps())); + tvSmallRemain.setText(getResources().getString(R.string.step_unit_1, mDataCurrent.getStepRemain())); + tvRemain.setText(getResources().getString(R.string.step_unit, mDataCurrent.getStepRemain())); + tvRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(mDataCurrent.getCompletePercent()))); + tvCaloConsumned.setText(getResources().getString(R.string.kcal_unit, Utils.convert2String2Decimal(mDataCurrent.getKcal()))); + tvDistance.setText(getResources().getString(R.string.distance_unit, Utils.convert2String2Decimal(mDataCurrent.getDistance()))); + tvTime.setText(getResources().getString(R.string.time_unit, Utils.convertTimeStringFromString(mDataCurrent.getTime()))); + + // update bar + if (mDataCurrent.getDataChart() != null && mDataCurrent.getDataChart().size() == 24) { + updateBars(); + } + + } + + private void updateBars() { + dateList = new ArrayList<>(); + List stepList = new ArrayList<>(); + + stepList = mDataCurrent.getDataChart(); + for (int i = 0; i < 24; i++){ + dateList.add(String.valueOf(i)); + } + + mStep = stepList.toArray(new Integer[0]); + mParties = dateList.toArray(new String[0]); + + initGraph(); + } + + private void initGraph(){ + + mBarChart.setDrawBarShadow(false); + mBarChart.setDrawValueAboveBar(true); + + // if more than 60 entries are displayed in the chart, no values will be + // drawn + mBarChart.setMaxVisibleValueCount(60); + + mBarChart.getDescription().setEnabled(false); + // scaling can now only be done on x- and y-axis separately + mBarChart.setPinchZoom(false); + + mBarChart.setDrawGridBackground(false); + // mChart.setDrawYLabels(false); + + DayAxisValueFormatter xValueFormatter = new DayAxisValueFormatter(dateList); + + XAxis xAxis = mBarChart.getXAxis(); + xAxis.setLabelRotationAngle(0); + xAxis.setPosition(XAxis.XAxisPosition.TOP); + xAxis.setDrawGridLines(true); + xAxis.setLabelCount(10); + xAxis.setTextColor(Color.WHITE); + xAxis.setValueFormatter(xValueFormatter); + + + YAxis leftAxis = mBarChart.getAxisLeft(); + leftAxis.setDrawLabels(false); + leftAxis.setDrawGridLines(false); + leftAxis.setAxisMinimum(0f); + leftAxis.setAxisMaximum(10000f); + leftAxis.setDrawZeroLine(false); + + leftAxis.setEnabled(false); + mBarChart.setDrawValueAboveBar(false); + mBarChart.getAxisRight().setEnabled(false); + + // set auto scale min max + mBarChart.setAutoScaleMinMaxEnabled(true); + mBarChart.notifyDataSetChanged(); + + // Set enimate y + mBarChart.animateY(2000); + + setData(); + + mBarChart.getLegend().setEnabled(false); + } + + + private void setData() { + + ArrayList xVals = new ArrayList<>(); + for (int i = 0; i < mStep.length; i++) { + xVals.add(mParties[i % mStep.length]); + } + + ArrayList yVals1 = new ArrayList<>(); + for (int i = 0; i < mStep.length; i++) { + float val = (float) (mStep[i]*1); + yVals1.add(new BarEntry(i, val)); + } + + BarDataSet set1; + + if (mBarChart.getData() != null && mBarChart.getData().getDataSetCount() > 0) { + set1 = (BarDataSet)mBarChart.getData().getDataSetByIndex(0); + set1.setValues(yVals1); + mBarChart.getData().notifyDataChanged(); + mBarChart.notifyDataSetChanged(); + } else { + ArrayList colors = new ArrayList<>(); + + + int[] MATERIAL_COLORS = {rgb("#40CDEF")}; + + for (int c : MATERIAL_COLORS) + colors.add(c); + + set1 = new BarDataSet(yVals1, null); + + set1.setColors(colors); + + ArrayList dataSets = new ArrayList<>(); + dataSets.add(set1); + + BarData data = new BarData(dataSets); + data.setValueTextSize(10f); + + mBarChart.setData(data); + } + } + + private void addDataModWalking(JSONObject jsonObject){ + if (jsonObject == null) return; + mDataModWalking.setTaget(jsonObject.optInt("target")); + mDataModWalking.setSteps(jsonObject.optInt("steps")); + mDataModWalking.setStepRemain(jsonObject.optInt("step_remain")); + mDataModWalking.setCompletePercent(jsonObject.optDouble("complete_percent")); + mDataModWalking.setTime(jsonObject.optInt("time")); + mDataModWalking.setDistance(jsonObject.optInt("distance")); + mDataModWalking.setKcal(jsonObject.optInt("kcal")); + + JSONObject dataChart = jsonObject.optJSONObject("data_chart"); + ArrayList dataChartList = new ArrayList<>(); + dataChartList.add(dataChart.optInt("0")); + dataChartList.add(dataChart.optInt("1")); + dataChartList.add(dataChart.optInt("2")); + dataChartList.add(dataChart.optInt("3")); + dataChartList.add(dataChart.optInt("4")); + dataChartList.add(dataChart.optInt("5")); + dataChartList.add(dataChart.optInt("6")); + dataChartList.add(dataChart.optInt("7")); + dataChartList.add(dataChart.optInt("8")); + dataChartList.add(dataChart.optInt("9")); + dataChartList.add(dataChart.optInt("10")); + dataChartList.add(dataChart.optInt("11")); + dataChartList.add(dataChart.optInt("12")); + dataChartList.add(dataChart.optInt("13")); + dataChartList.add(dataChart.optInt("14")); + dataChartList.add(dataChart.optInt("15")); + dataChartList.add(dataChart.optInt("16")); + dataChartList.add(dataChart.optInt("17")); + dataChartList.add(dataChart.optInt("18")); + dataChartList.add(dataChart.optInt("19")); + dataChartList.add(dataChart.optInt("20")); + dataChartList.add(dataChart.optInt("21")); + dataChartList.add(dataChart.optInt("22")); + dataChartList.add(dataChart.optInt("23")); + + mDataModWalking.setDataChart(dataChartList); + } + + private void addDataModRunning(JSONObject jsonObject){ + if (jsonObject == null) return; + mDataModRunning.setTaget(jsonObject.optInt("target")); + mDataModRunning.setSteps(jsonObject.optInt("steps")); + mDataModRunning.setStepRemain(jsonObject.optInt("step_remain")); + mDataModRunning.setCompletePercent(jsonObject.optDouble("complete_percent")); + mDataModRunning.setTime(jsonObject.optInt("time")); + mDataModRunning.setDistance(jsonObject.optInt("distance")); + mDataModRunning.setKcal(jsonObject.optInt("kcal")); + + JSONObject dataChart = jsonObject.optJSONObject("data_chart"); + ArrayList dataChartList = new ArrayList<>(); + dataChartList.add(dataChart.optInt("0")); + dataChartList.add(dataChart.optInt("1")); + dataChartList.add(dataChart.optInt("2")); + dataChartList.add(dataChart.optInt("3")); + dataChartList.add(dataChart.optInt("4")); + dataChartList.add(dataChart.optInt("5")); + dataChartList.add(dataChart.optInt("6")); + dataChartList.add(dataChart.optInt("7")); + dataChartList.add(dataChart.optInt("8")); + dataChartList.add(dataChart.optInt("9")); + dataChartList.add(dataChart.optInt("10")); + dataChartList.add(dataChart.optInt("11")); + dataChartList.add(dataChart.optInt("12")); + dataChartList.add(dataChart.optInt("13")); + dataChartList.add(dataChart.optInt("14")); + dataChartList.add(dataChart.optInt("15")); + dataChartList.add(dataChart.optInt("16")); + dataChartList.add(dataChart.optInt("17")); + dataChartList.add(dataChart.optInt("18")); + dataChartList.add(dataChart.optInt("19")); + dataChartList.add(dataChart.optInt("20")); + dataChartList.add(dataChart.optInt("21")); + dataChartList.add(dataChart.optInt("22")); + dataChartList.add(dataChart.optInt("23")); + + mDataModRunning.setDataChart(dataChartList); + } + + private void addDataModBike(JSONObject jsonObject){ + if (jsonObject == null) return; + mDataModBike.setTaget(jsonObject.optInt("target")); + mDataModBike.setSteps(jsonObject.optInt("steps")); + mDataModBike.setStepRemain(jsonObject.optInt("step_remain")); + mDataModBike.setCompletePercent(jsonObject.optDouble("complete_percent")); + mDataModBike.setTime(jsonObject.optInt("time")); + mDataModBike.setDistance(jsonObject.optInt("distance")); + mDataModBike.setKcal(jsonObject.optInt("kcal")); + + JSONObject dataChart = jsonObject.optJSONObject("data_chart"); + ArrayList dataChartList = new ArrayList<>(); + dataChartList.add(dataChart.optInt("0")); + dataChartList.add(dataChart.optInt("1")); + dataChartList.add(dataChart.optInt("2")); + dataChartList.add(dataChart.optInt("3")); + dataChartList.add(dataChart.optInt("4")); + dataChartList.add(dataChart.optInt("5")); + dataChartList.add(dataChart.optInt("6")); + dataChartList.add(dataChart.optInt("7")); + dataChartList.add(dataChart.optInt("8")); + dataChartList.add(dataChart.optInt("9")); + dataChartList.add(dataChart.optInt("10")); + dataChartList.add(dataChart.optInt("11")); + dataChartList.add(dataChart.optInt("12")); + dataChartList.add(dataChart.optInt("13")); + dataChartList.add(dataChart.optInt("14")); + dataChartList.add(dataChart.optInt("15")); + dataChartList.add(dataChart.optInt("16")); + dataChartList.add(dataChart.optInt("17")); + dataChartList.add(dataChart.optInt("18")); + dataChartList.add(dataChart.optInt("19")); + dataChartList.add(dataChart.optInt("20")); + dataChartList.add(dataChart.optInt("21")); + dataChartList.add(dataChart.optInt("22")); + dataChartList.add(dataChart.optInt("23")); + + mDataModBike.setDataChart(dataChartList); + } + + @OnClick({R.id.btn_oneDay, R.id.btn_oneWeek, R.id.btn_oneMonth, R.id.btn_threeMonth, + R.id.btn_sixMonth, R.id.btn_left_date, R.id.btn_right_date, R.id.ll_bike, + R.id.ll_walking, R.id.ll_running, R.id.rl_stepView}) + public void onClick(View v){ + switch (v.getId()){ + case R.id.btn_left_date: + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, -1); + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date)); + mAnaDate = date; + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_right_date: + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, +1); + Date date1 = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date1)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date1)); + mAnaDate = date1; + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_oneDay: + dataType = Const.DATA_TYPE.ONE_DAY; + updateUiType(); + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_oneWeek: + dataType = Const.DATA_TYPE.ONE_WEEK; + updateUiType(); + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_oneMonth: + dataType = Const.DATA_TYPE.ONE_MONTH; + updateUiType(); + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_threeMonth: + dataType = Const.DATA_TYPE.THREE_MONTH; + updateUiType(); + getHistoryData(dataType, mAnaDate); + break; + + case R.id.btn_sixMonth: + dataType = Const.DATA_TYPE.SIX_MONTH; + updateUiType(); + getHistoryData(dataType, mAnaDate); + break; + + case R.id.tv_date: + handleAnaDatePicker(); + break; + + case R.id.ll_bike: + stepType = Const.STEP_TYPE.BIKE; + updateUiStepType(true, false, false); + // add data + mDataCurrent = mDataModBike; + updateUI(); + break; + + case R.id.ll_walking: + stepType = Const.STEP_TYPE.WALKING; + updateUiStepType(false, true, false); + // add data + mDataCurrent = mDataModWalking; + updateUI(); + break; + + case R.id.ll_running: + stepType = Const.STEP_TYPE.RUNNING; + updateUiStepType(false, false, true); + // add + mDataCurrent = mDataModRunning; + updateUI(); + break; + + case R.id.rl_stepView: + mHistoryFragment.showDetailFragment(); + break; + + default: + break; + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryDetailFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryDetailFragment.java new file mode 100644 index 0000000..f920529 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryDetailFragment.java @@ -0,0 +1,355 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.HistoryAdapter; +import com.dinhcv.lifelogpedometer.customview.ExpandableListCustomView; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.structure.history.HistoryInfo; +import com.dinhcv.lifelogpedometer.model.structure.history.HistoryItemInfo; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Callback; + + +public class HistoryDetailFragment extends FragmentBase { + private View mRootView; + + @BindView(R.id.btn_left_date) + ImageButton btnLeftDate; + @BindView(R.id.btn_right_date) + ImageButton btnRightDate; + @BindView(R.id.tv_date) + TextView tvDate; + @BindView(R.id.tv_week_day) + TextView tvWeekDay; + @BindView(R.id.ll_bike) + LinearLayout llBike; + @BindView(R.id.ll_walking) + LinearLayout llWalking; + @BindView(R.id.ll_running) + LinearLayout llRunning; + @BindView(R.id.lv_history) + ExpandableListCustomView lvHistory; + private HistoryAdapter mHistoreAdapter; + + + @BindView(R.id.btn_sixMonth) + Button btnSixMonth; + @BindView(R.id.btn_oneDay) + Button btnOneDay; + @BindView(R.id.btn_oneWeek) + Button btnOneWeek; + @BindView(R.id.btn_oneMonth) + Button btnOneMonth; + @BindView(R.id.btn_threeMonth) + Button btnThreeMonth; + + private Date mAnaDate; + private Calendar mCalendar; + + private int mAnaDay; + private int mAnaMonth; + private int mAnaYear; + private Context mContext; + private Const.DATA_TYPE dataType; + private Const.STEP_TYPE stepType; + + private List mDataModWalking = new ArrayList<>(); + private List mDataModRunning = new ArrayList<>(); + private List mDataModBike = new ArrayList<>(); + private List mDataCurrent = new ArrayList<>(); + + private HistoryFragment mHistoryFragment; + + public void setRootFragment(HistoryFragment frag) { + this.mHistoryFragment = frag; + } + + @Override + public View onCreateView(final LayoutInflater inflater,final ViewGroup container, + final Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_history_detail, null); + ButterKnife.bind(this, mRootView); + mContext = getActivity(); + initView(); + initData(); + + return mRootView; + } + + private void initView() { + + } + + /** + * init data for + */ + private void initData() { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(new Date()); + mAnaDate = mCalendar.getTime(); + mAnaYear = mCalendar.get(Calendar.YEAR); + mAnaMonth = mCalendar.get(Calendar.MONTH); + mAnaDay = mCalendar.get(Calendar.DAY_OF_MONTH); + + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); + tvWeekDay.setText(Utils.getWeekdayFromDate(mAnaDate)); + + dataType = Const.DATA_TYPE.ONE_DAY; + stepType = Const.STEP_TYPE.WALKING; + updateUiType(); + updateUiStepType(false, true, false); + + getHistoryDetail(dataType, mAnaDate); + } + + + /** + * Show date picker dialog + */ + private void handleAnaDatePicker() { + + new DatePickerDialog(mContext, new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + + mCalendar = Calendar.getInstance(); + mCalendar.set(year, monthOfYear, dayOfMonth); + mAnaYear = year; + mAnaMonth = monthOfYear; + mAnaDay = dayOfMonth; + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date)); + mAnaDate = date; + getHistoryDetail(dataType, mAnaDate); + } + }, mAnaYear, mAnaMonth, mAnaDay).show(); + + } + + private void updateUiType() { + if (dataType == Const.DATA_TYPE.ONE_DAY) { + setButtonSelected(true, false, false, false, false); + } else if (dataType == Const.DATA_TYPE.ONE_WEEK) { + setButtonSelected(false, true, false, false, false); + } else if (dataType == Const.DATA_TYPE.ONE_MONTH) { + setButtonSelected(false, false, true, false, false); + } else if (dataType == Const.DATA_TYPE.THREE_MONTH){ + setButtonSelected(false, false, false, true, false); + } else if (dataType == Const.DATA_TYPE.SIX_MONTH){ + setButtonSelected(false, false, false, false, true); + } + } + + private void setButtonSelected(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5 ) { + btnOneDay.setSelected(b1); + btnOneWeek.setSelected(b2); + btnOneMonth.setSelected(b3); + btnThreeMonth.setSelected(b4); + btnSixMonth.setSelected(b5); + } + + private void updateUiStepType(boolean b1, boolean b2, boolean b3) { + llBike.setSelected(b1); + llWalking.setSelected(b2); + llRunning.setSelected(b3); + } + + private void updateUI(){ + // get data server + if (mDataCurrent != null && mDataCurrent.size() >0){ + mHistoreAdapter = new HistoryAdapter(mContext, mDataCurrent); + lvHistory.setAdapter(mHistoreAdapter); + lvHistory.setExpanded(true); + } + } + + private void getHistoryDetail(Const.DATA_TYPE dataType, Date toDate){ + Date fromDate = Utils.getFromDate(mAnaDate, dataType); + + showDialog(mContext); + LLAPIManager.historyDetail(fromDate, toDate, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + Debug.error("Get data history error"); + hiddenDialog(); + showDialogNotData(); + } + + @Override + public void onSuccess(String json) { + Debug.error("Get data history success"); + hiddenDialog(); + loadDataDone(json); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.error("Get data history success"); + hiddenDialog(); + } + }); + } + + private void showDialogNotData(){ + showAlerDialog(mContext, getResources().getString(R.string.can_not_get_data)); + } + + private void loadDataDone(String jsonString) { + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(jsonString); + int status = jsonObject.optInt("status"); + if (status == 1) { + JSONObject jsonObject1 = jsonObject.optJSONObject("result"); + JSONObject jsonMod1 = jsonObject1.getJSONObject("mode_1"); + JSONObject jsonMod2 = jsonObject1.getJSONObject("mode_2"); + JSONObject jsonMod3 = jsonObject1.getJSONObject("mode_3"); + //addDataModWalking(jsonMod1); + //addDataModRunning(jsonMod2); + //addDataModBike(jsonMod3); + + } + } catch (JSONException e) { + e.printStackTrace(); + mDataModWalking.clear(); + mDataModRunning.clear();; + mDataModBike.clear();; + } + + if (stepType == Const.STEP_TYPE.WALKING){ + mDataCurrent = mDataModWalking; + }else if (stepType == Const.STEP_TYPE.RUNNING){ + mDataCurrent = mDataModRunning; + }else { + mDataCurrent = mDataModBike; + } + + updateUI(); + } + + @OnClick({R.id.tv_date, R.id.btn_left_date, R.id.btn_right_date, R.id.btn_oneDay, R.id.btn_oneWeek, + R.id.btn_oneMonth, R.id.btn_threeMonth, R.id.btn_sixMonth, R.id.ll_walking, R.id.ll_bike, + R.id.ll_running}) + public void onClick(View view){ + Date date; + switch (view.getId()){ + case R.id.tv_date: + handleAnaDatePicker(); + break; + case R.id.btn_left_date: + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, -1); + date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date)); + mAnaDate = date; + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_right_date: + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, +1); + date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + tvWeekDay.setText(Utils.getWeekdayFromDate(date)); + mAnaDate = date; + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_oneDay: + dataType = Const.DATA_TYPE.ONE_DAY; + updateUiType(); + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_oneWeek: + dataType = Const.DATA_TYPE.ONE_WEEK; + updateUiType(); + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_oneMonth: + dataType = Const.DATA_TYPE.ONE_MONTH; + updateUiType(); + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_threeMonth: + dataType = Const.DATA_TYPE.THREE_MONTH; + updateUiType(); + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.btn_sixMonth: + dataType = Const.DATA_TYPE.SIX_MONTH; + updateUiType(); + getHistoryDetail(dataType, mAnaDate); + break; + + case R.id.ll_walking: + stepType = Const.STEP_TYPE.WALKING; + updateUiStepType(false, true, false); + // add data + mDataCurrent = mDataModWalking; + updateUI(); + break; + + case R.id.ll_running: + stepType = Const.STEP_TYPE.RUNNING; + updateUiStepType(false, false, true); + // add + mDataCurrent = mDataModRunning; + updateUI(); + break; + + case R.id.ll_bike: + stepType = Const.STEP_TYPE.BIKE; + updateUiStepType(true, false, false); + // add data + mDataCurrent = mDataModBike; + updateUI(); + break; + + default: + break; + + } + } + + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryFragment.java new file mode 100644 index 0000000..cbfb454 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/HistoryFragment.java @@ -0,0 +1,123 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchInfo; + +public class HistoryFragment extends FragmentBase implements SettingFragmentPresenter { + public enum HistoryFragmentTag { + HISTORY_CONTENT, + HISTORY_DETAIL, + } + + private FragmentTransaction mFragmentTransaction; + private FragmentManager mFragmentManager; + + private View mRootView; + private FrameLayout mHistoryLayout; + private HistoryContentFragment mHistoryContentFragment; + private HistoryDetailFragment mHistoryDetailFragment; + + public static final String HISTORY_CONTENT_TAG = "history_content"; + public static final String HISTORY_DETAIL_TAG = "history_detail"; + + public HistoryFragmentTag mCurrentFragment = HistoryFragmentTag.HISTORY_CONTENT; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle + savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_history, container, false); + mFragmentManager = getFragmentManager(); + mFragmentTransaction = mFragmentManager.beginTransaction(); + + initView(); + initData(); + + return mRootView; + } + + /** + */ + private void initView() { + mHistoryLayout = (FrameLayout) mRootView.findViewById(R.id.layout_history); + + mHistoryContentFragment = new HistoryContentFragment(); + mHistoryContentFragment.setRootFragment(this); + mHistoryDetailFragment = new HistoryDetailFragment(); + mHistoryDetailFragment.setRootFragment(this); + + showContentFragment(); + } + + public void showContentFragment() { + mCurrentFragment = HistoryFragmentTag.HISTORY_CONTENT; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mHistoryLayout.getId(), mHistoryContentFragment, HISTORY_CONTENT_TAG); + mFragmentTransaction.commit(); + } + + public void showDetailFragment() { + mCurrentFragment = HistoryFragmentTag.HISTORY_DETAIL; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mHistoryLayout.getId(), mHistoryDetailFragment, HISTORY_DETAIL_TAG); + mFragmentTransaction.commit(); + } + + public void clickBackToHome(){ + switch (mCurrentFragment) { + case HISTORY_CONTENT: + break; + case HISTORY_DETAIL: + showContentFragment(); + break; + default: + break; + } + } + + /** + * Init data + */ + private void initData() { + + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + } + + /** + * Save data + */ + @Override + public void onSaveData() { + } + + @Override + public void onInvalidate(boolean isInit) { + initData(); + } + + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/InputConfirmCodeActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/InputConfirmCodeActivity.java new file mode 100644 index 0000000..f8d0642 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/InputConfirmCodeActivity.java @@ -0,0 +1,132 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import org.json.JSONObject; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +public class InputConfirmCodeActivity extends ActivityBase { + + @BindView(R.id.edt_confirmCode) + TextView edtConfirmCode; + @BindView(R.id.btn_confirm) + Button btnConfirm; + + private ProgressDialog progressDialog; + private String mEmail; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_input_confirm_code); + ButterKnife.bind(this); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); + Intent intent = getIntent(); + if (intent != null) { + mEmail = intent.getStringExtra(Const.EMAIL); + Debug.normal("Email request: "+mEmail); + if(mEmail == null){ + Debug.error("Email is null"); + return; + } + }else { + Debug.error("Email is null"); + return; + } + + } + + private void handleGetNewPass(String code){ + progressDialog = new ProgressDialog(InputConfirmCodeActivity.this); + progressDialog.setMessage(getResources().getString(R.string.waite_some_minute)); + progressDialog.setCancelable(false); + progressDialog.show(); + + LLAPIManager.forgetPassConfirm(mEmail, code, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + progressDialog.dismiss(); + Debug.error("Send confirm JSON result: ERROR " + error); + String err = getResources().getString(R.string.request_pass_error); + notifyErr(err); + } + + @Override + public void onSuccess(String json) { + Debug.warn("Send confirm JSON result: " + json.toString()); + progressDialog.dismiss(); + + confirmDone(); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.warn("Send confirm JSON object result: Success"); + progressDialog.dismiss(); + } + }); + } + + private void confirmDone(){ + AlertDialog.Builder alertDialog = new AlertDialog.Builder(InputConfirmCodeActivity.this); + alertDialog.setMessage(getResources().getString(R.string.password_have_send)); + alertDialog.setCancelable(false); + alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + alertDialog.show(); + } + + private void notifyErr(String err) { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(InputConfirmCodeActivity.this); + alertDialog.setMessage(err); + alertDialog.setCancelable(false); + alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + alertDialog.show(); + } + + @OnClick({R.id.btn_confirm}) + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_confirm: + // handle login + String code = edtConfirmCode.getText().toString(); + if (code.isEmpty()){ + showAlerDialog(InputConfirmCodeActivity.this, getResources().getString(R.string.please_input_confirm)); + return; + } + + handleGetNewPass(code); + break; + + default: + break; + } + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/LoginActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/LoginActivity.java new file mode 100644 index 0000000..98adad4 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/LoginActivity.java @@ -0,0 +1,208 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import org.json.JSONObject; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +public class LoginActivity extends ActivityBase { + + @BindView(R.id.edt_user) + TextView edtUser; + @BindView(R.id.edt_password) + TextView edtPassword; + @BindView(R.id.btn_login) + Button btnLogin; + @BindView(R.id.btn_register) + Button btnRegister; + @BindView(R.id.tv_forgetPass) + TextView tvForgetPass; + + + private ProgressDialog progressDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + ButterKnife.bind(this); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); + + initData(); + + } + + + private void initData() { + + } + + private boolean verifyData(String user, String pass) { + if (user.isEmpty()) { + showAlerDialog(LoginActivity.this, getResources().getString(R.string.account_is_null)); + return false; + } + + if (pass.isEmpty()) { + showAlerDialog(LoginActivity.this, getResources().getString(R.string.password_is_null)); + return false; + } + + return true; + } + + private void handleLogin() { + final String user = edtUser.getText().toString(); + String pass = edtPassword.getText().toString(); + + // verify + boolean isOk = verifyData(user, pass); + if (!isOk) { + return; + } + + progressDialog = new ProgressDialog(LoginActivity.this); + progressDialog.setMessage(getResources().getString(R.string.waite_some_minute)); + progressDialog.setCancelable(false); + progressDialog.show(); + + LLAPIManager.login(LoginActivity.this, user, pass, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + progressDialog.dismiss(); + Debug.error("Version JSON result: ERROR " + error); + String err = getResources().getString(R.string.login_error); + notifyErr(err); + } + + @Override + public void onSuccess(String json) { + Debug.warn("Version JSON result: " + json.toString()); + progressDialog.dismiss(); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.warn("Version JSON object result: Success"); + progressDialog.dismiss(); + + String email = object.optString("email"); + String username = object.optString("username"); + String pass = object.optString("password"); + int id = object.optInt("id"); + Debug.normal("Email: "+email +"\n"+ "Username: "+username); + // save data + Setting.setUserIdSharepre(LoginActivity.this, id); + Setting.setUserDataSharepre(LoginActivity.this, Setting.EMAIL_SHAREPRE, email); + Setting.setUserDataSharepre(LoginActivity.this, Setting.USER_SHAREPRE, username); + Setting.setUserDataSharepre(LoginActivity.this, Setting.PASS_SHAREPRE, pass); + loginDone(); + } + }); + } + + private void loginDone(){ + Intent intent = new Intent(LoginActivity.this, PedometerActivity.class); + startActivity(intent); + } + + private void handleSendConfirm(final String email){ + progressDialog = new ProgressDialog(LoginActivity.this); + progressDialog.setMessage(getResources().getString(R.string.waite_some_minute)); + progressDialog.setCancelable(false); + progressDialog.show(); + + LLAPIManager.forgetPass(email, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + progressDialog.dismiss(); + Debug.error("Send confirm JSON result: ERROR " + error); + String err = getResources().getString(R.string.request_pass_error); + notifyErr(err); + } + + @Override + public void onSuccess(String json) { + Debug.warn("Send confirm JSON result: " + json.toString()); + progressDialog.dismiss(); + + confirmDone(email); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.warn("Send confirm JSON object result: Success"); + progressDialog.dismiss(); + } + }); + } + + private void confirmDone(String email){ + Intent intent = new Intent(LoginActivity.this, InputConfirmCodeActivity.class); + intent.putExtra(Const.EMAIL, email ); + startActivity(intent); + } + + private void notifyErr(String err) { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(LoginActivity.this); + alertDialog.setMessage(err); + alertDialog.setCancelable(false); + alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + //finish(); + edtUser.setText(""); + edtPassword.setText(""); + } + }); + alertDialog.show(); + } + + @OnClick({R.id.btn_login, R.id.btn_register, R.id.tv_forgetPass}) + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_login: + // handle login + handleLogin(); + break; + case R.id.btn_register: + // hanle register + Intent intent = new Intent(LoginActivity.this, RegisterActivity.class); + startActivity(intent); + break; + + case R.id.tv_forgetPass: + // hanle register + String email = edtUser.getText().toString(); + if (email.isEmpty()){ + showAlerDialog(LoginActivity.this, getResources().getString(R.string.please_input_email)); + return; + } + + handleSendConfirm(email); + + break; + + default: + break; + } + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MainActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MainActivity.java new file mode 100644 index 0000000..f915ec2 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MainActivity.java @@ -0,0 +1,86 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; + +public class MainActivity extends AppCompatActivity implements SensorEventListener, StepListener { + private TextView tvSteps; + private Button btnStart; + private Button btnStop; + private StepDetector simpleStepDetector; + private SensorManager sensorManager; + private Sensor accel; + private static final String TEXT_NUM_STEPS = "Number of Steps: "; + private int numSteps; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + + // Get an instance of the SensorManager + sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); + accel = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + simpleStepDetector = new StepDetector(); + simpleStepDetector.registerListener(this); + + tvSteps = (TextView) findViewById(R.id.tv_steps); + btnStart = (Button) findViewById(R.id.btn_start); + btnStop = (Button) findViewById(R.id.btn_stop); + + + + btnStart.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + + numSteps = 0; + sensorManager.registerListener(MainActivity.this, accel, SensorManager.SENSOR_DELAY_FASTEST); + + } + }); + + + btnStop.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View arg0) { + + sensorManager.unregisterListener(MainActivity.this); + + } + }); + } + + + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { + simpleStepDetector.updateAccel( + event.timestamp, event.values[0], event.values[1], event.values[2]); + } + } + + @Override + public void step(long timeNs) { + numSteps++; + tvSteps.setText(TEXT_NUM_STEPS + numSteps); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MapFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MapFragment.java new file mode 100644 index 0000000..4a65791 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/MapFragment.java @@ -0,0 +1,83 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dinhcv.lifelogpedometer.R; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.OnMapReadyCallback; + +public class MapFragment extends Fragment implements SettingFragmentPresenter, OnMapReadyCallback { + private View mRootView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle + savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_map, container, false); + + initView(mRootView); + + initData(); + + return mRootView; + } + + /** + * init view + * + * @param rootView view + */ + private void initView(View rootView) { + + } + + /** + * Init data + */ + private void initData() { + + } + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof Activity) { + + } + } + + + /** + * Save data + */ + @Override + public void onSaveData() { + } + + @Override + public void onInvalidate(boolean isInit) { + initData(); + } + + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + + @Override + public void onMapReady(GoogleMap googleMap) { + Log.i("SonLT","Readdy"); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/PedometerActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/PedometerActivity.java new file mode 100644 index 0000000..c82f5d1 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/PedometerActivity.java @@ -0,0 +1,279 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.Manifest; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.content.PermissionChecker; +import android.support.v4.view.ViewPager; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.feature.SensorListener; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.util.ArrayList; +import java.util.List; + +public class PedometerActivity extends ActivityBase { + private Toolbar mToolBar; + private ViewPager mViewPager; + private int mCurrentTab = 0; + private TabLayout mTabLayout; + private TextView tvPageTitle; + private ImageView ivHome; + + private HistoryFragment mHistoryFragment; + private SnsFragment mSnsFragment; + + private int[] tabIcons = { + com.dinhcv.lifelogpedometer.R.drawable.ic_date, + R.drawable.ic_history, + R.drawable.ic_rank, + R.drawable.ic_map, + R.drawable.ic_sns + }; + + public enum TAB { + DATE_TAB(0), + HISTORY_TAB(1), + RANK_TAB(2), + MAP_TAB(3), + SNS_TAB(4); + + private final int index; + + TAB(int index) { + this.index = index; + } + + public int getValue() { + return index; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // start service + startService(new Intent(this, SensorListener.class)); + + setContentView(R.layout.activity_pedometer); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + + initView(); + + if (android.support.v4.BuildConfig.DEBUG && Build.VERSION.SDK_INT >= 23 && PermissionChecker + .checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != + PermissionChecker.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + } + } + + private void initView() { + + tvPageTitle = (TextView) findViewById(R.id.tv_pageTitle); + ivHome = (ImageView) findViewById(R.id.iv_home); + + mViewPager = (ViewPager) findViewById(R.id.viewpager); + mViewPager.setOffscreenPageLimit(5); + setupViewPager(mViewPager); + mTabLayout = (TabLayout) findViewById(R.id.tabs); + mTabLayout.setupWithViewPager(mViewPager); + //Set tab selected + TabLayout.Tab tab = mTabLayout.getTabAt(mCurrentTab); + if (tab != null) { + tab.select(); + } + + changeColorStatusBar(); + setupTabIcons(); + + //SonLT Add + ivHome.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (mCurrentTab){ + case 1: mHistoryFragment.clickBackToHome(); break; + case 4: mSnsFragment.handleToolbarClick(0); break; + default: break; + } + } + }); + } + + private void setupTabIcons() { + mTabLayout.getTabAt(0).setIcon(tabIcons[0]); + mTabLayout.getTabAt(1).setIcon(tabIcons[1]); + mTabLayout.getTabAt(2).setIcon(tabIcons[2]); + mTabLayout.getTabAt(3).setIcon(tabIcons[3]); + mTabLayout.getTabAt(4).setIcon(tabIcons[4]); + } + + + private void setTabView() { + + for (int i = 0; i < mTabLayout.getTabCount(); i++) { + TextView tv = (TextView) mTabLayout.getChildAt(0).findViewById(android.R.id.title); + //tv.setTextColor(Color.BLACK); + tv.setPadding(10, 10, 10, 15); + tv.setTextSize((float) 20.0); + //tv.setTypeface(null, Typeface.BOLD); + //tv.setBackgroundResource(R.drawable.icon); + tv.setHeight(100); + tv.setWidth(100); + } + + } + + private void changeColorStatusBar() { + if (android.os.Build.VERSION.SDK_INT >= 21) { + Window window = this.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.setStatusBarColor(Utils.getColorWrapper(this, R.color.white)); + } + } + +// @Override +// public boolean onCreateOptionsMenu(Menu menu) { +// getMenuInflater().inflate(R.menu.setting_menu, menu); +// return true; +// } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } + + /** + * Setup pager + * + * @param viewPager: view pager + */ + private void setupViewPager(ViewPager viewPager) { + ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); + adapter.addFragment(new DateFragment(), getString(R.string.date)); + mHistoryFragment = new HistoryFragment(); + adapter.addFragment(mHistoryFragment, getString(R.string.history)); + adapter.addFragment(new RankFragment(), getString(R.string.ranking)); + adapter.addFragment(new MapFragment(), getString(R.string.map)); + mSnsFragment = new SnsFragment(); + adapter.addFragment(mSnsFragment, getString(R.string.sns)); + viewPager.setAdapter(adapter); + } + + /** + * Class FragmentPagerAdapter + */ + class ViewPagerAdapter extends FragmentPagerAdapter { + private final List mFragmentList = new ArrayList<>(); + private final List mFragmentTitleList = new ArrayList<>(); + + public ViewPagerAdapter(FragmentManager manager) { + super(manager); + } + + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList.size(); + } + + private void addFragment(Fragment fragment, String title) { + mFragmentList.add(fragment); + mFragmentTitleList.add(title); + } + + @Override + public CharSequence getPageTitle(int position) { + return mFragmentTitleList.get(position); + } + } + + @Override + protected void onResume() { + super.onResume(); + mViewPager.addOnPageChangeListener(mPageChangeListener); + } + + @Override + protected void onPause() { + super.onPause(); + mViewPager.removeOnPageChangeListener(mPageChangeListener); + } + + private int mLastTab = 0; + private final ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager + .OnPageChangeListener + () { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + //Nothing here + } + + @Override + public void onPageSelected(int position) { + ViewPagerAdapter adapter = (ViewPagerAdapter) mViewPager.getAdapter(); + SettingFragmentPresenter presenter = (SettingFragmentPresenter) adapter.getItem + (position); + presenter.onInvalidate(false); + + switch (position) { + case 4: + tvPageTitle.setText(getString(R.string.sns_fragment)); + ivHome.setVisibility(View.VISIBLE); + break; + case 1: + tvPageTitle.setText(getString(R.string.today)); + ivHome.setVisibility(View.VISIBLE); + break; + default: + tvPageTitle.setText(getString(R.string.home)); + ivHome.setVisibility(View.GONE); + break; + } +// if (position == 1){ +// tvPageTitle.setText(getString(R.string.today)); +// ivHome.setVisibility(View.VISIBLE); +// }else { +// tvPageTitle.setText(getString(R.string.home)); +// ivHome.setVisibility(View.GONE); +// } + + mLastTab = position; + mCurrentTab = position; + } + + @Override + public void onPageScrollStateChanged(int state) { + //Nothing here + if (state == ViewPager.SCROLL_STATE_SETTLING) { + if (mLastTab >= 0) { + ViewPagerAdapter adapter = (ViewPagerAdapter) mViewPager.getAdapter(); + SettingFragmentPresenter presenter = (SettingFragmentPresenter) adapter + .getItem(mLastTab); + + Debug.normal("Save data in tab:" + mLastTab); + presenter.onSaveData(); + } + } + } + }; + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RankFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RankFragment.java new file mode 100644 index 0000000..db565eb --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RankFragment.java @@ -0,0 +1,402 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.RankingAdapter; +import com.dinhcv.lifelogpedometer.model.structure.pojo.RankingInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.ResultResponse; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicResponse; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class RankFragment extends FragmentBase implements SettingFragmentPresenter { + + private enum Mode { + WALK(1), + RUN(2), + BIKE(3), + ALL(0); + + private int mode; + + Mode(int mode) { + this.mode = mode; + } + + public int getValue() { + return mode; + } + + public Mode valueOf(int value) { + switch (mode) { + case 0: + return ALL; + case 1: + return WALK; + case 2: + return RUN; + case 3: + return BIKE; + default: + return ALL; + } + } + } + + private enum TypeJump { + DAILY(1), + WEEKLY(7), + MONTHLY(30), + YEARLY(365); + private int jump; + + TypeJump(int jump) { + this.jump = jump; + } + + public int getValue() { + return jump; + } + } + + @BindView(R.id.tv_start_date) + TextView mTvStartDate; + @BindView(R.id.tv_end_date) + TextView mTvEndDate; + @BindView(R.id.btn_back) + ImageButton mBtnBack; + @BindView(R.id.btn_next) + ImageView mBtnNext; + + @BindView(R.id.btn_daily) + Button mBtnDaily; + @BindView(R.id.btn_weekly) + Button mBtnWeekly; + @BindView(R.id.btn_monthly) + Button mBtnMonthly; + @BindView(R.id.btn_yearly) + Button mBtnYearly; + @BindView(R.id.btn_walk) + Button mBtnWalk; + @BindView(R.id.btn_run) + Button mBtnRun; + @BindView(R.id.btn_bike) + Button mBtnBike; + @BindView(R.id.btn_all) + Button mBtnAll; + + private ApiService mService; + + private Mode mCurrentMode = Mode.WALK; + private TypeJump mCurrentJump = TypeJump.DAILY; + private int mCurrentPage = 1; + + private View mRootView; + private List mRankList = new ArrayList<>(); + + private SwipeRefreshLayout mSwipeRefreshTopic; + private RecyclerView mRcvRank; + private RankingAdapter mAdapter; + private Date mStartDate = new Date(); + private Date mEndDate = new Date(); + + private static final DateFormat FORMAT_DATE = new SimpleDateFormat("yyyyMMdd"); + private static final String TAG = "RankFragment"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_rank, container, false); + ButterKnife.bind(this, mRootView); + mRcvRank = (RecyclerView) mRootView.findViewById(R.id.rcv_rank); + + initView(); + initData(); + + return mRootView; + } + + private void initView() { + mSwipeRefreshTopic = (SwipeRefreshLayout) mRootView.findViewById(R.id.swipe_ranking); + mSwipeRefreshTopic.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + handleLoadRankList(); + } + }); + + mAdapter = new RankingAdapter(getActivity(), mRankList); + RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this.getContext()); + mRcvRank.setLayoutManager(mLayoutManager); + mRcvRank.setAdapter(mAdapter); + + initButtonStatus(); + } + + private void initData() { + initStartDate(); + showDateData(); + handleLoadRankList(); + } + + private void showDateData() { + mTvStartDate.setText(Utils.dateToStringFormatDayMonthYearJp(mStartDate)); + mTvEndDate.setText(Utils.dateToStringFormatDayMonthYearJp(mEndDate)); + } + + @OnClick(R.id.btn_daily) + public void clickDaily() { + mCurrentJump = TypeJump.DAILY; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_weekly) + public void clickWeekly() { + mCurrentJump = TypeJump.WEEKLY; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_monthly) + public void clickMonthly() { + mCurrentJump = TypeJump.MONTHLY; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_yearly) + public void clickYearly() { + mCurrentJump = TypeJump.YEARLY; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_walk) + public void clickWalk() { + mCurrentMode = Mode.WALK; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_run) + public void clickRun() { + mCurrentMode = Mode.RUN; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_bike) + public void clickBike() { + mCurrentMode = Mode.BIKE; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_all) + public void clickAll() { + mCurrentMode = Mode.ALL; + initButtonStatus(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_back) + public void clickBack() { + mEndDate = mStartDate; + mStartDate = calDateByStep(mEndDate, -mCurrentJump.getValue()); + showDateData(); + handleLoadRankList(); + } + + @OnClick(R.id.btn_next) + public void clickNext() { + mStartDate = mEndDate; + mEndDate = calDateByStep(mStartDate, mCurrentJump.getValue()); + showDateData(); + handleLoadRankList(); + } + + private void initStartDate() { + mStartDate = calDateByStep(mEndDate, -mCurrentJump.getValue()); + } + + private void initButtonStatus() { + switch (mCurrentMode) { + case WALK: + showButtonStatusByMode(1); + break; + case RUN: + showButtonStatusByMode(2); + break; + case BIKE: + showButtonStatusByMode(3); + break; + case ALL: + showButtonStatusByMode(4); + break; + } + + switch (mCurrentJump) { + case DAILY: + showButtonStatusByTypeJump(1); + break; + case WEEKLY: + showButtonStatusByTypeJump(2); + break; + case MONTHLY: + showButtonStatusByTypeJump(3); + break; + case YEARLY: + showButtonStatusByTypeJump(4); + break; + } + } + + private void showButtonStatusByMode(int position) { + mBtnWalk.setEnabled(true); + mBtnRun.setEnabled(true); + mBtnBike.setEnabled(true); + mBtnAll.setEnabled(true); + + switch (position) { + case 1: + mBtnWalk.setEnabled(false); + break; + case 2: + mBtnRun.setEnabled(false); + break; + case 3: + mBtnBike.setEnabled(false); + break; + case 4: + mBtnAll.setEnabled(false); + ; + break; + } + } + + private void showButtonStatusByTypeJump(int position) { + mBtnDaily.setEnabled(true); + mBtnWeekly.setEnabled(true); + mBtnMonthly.setEnabled(true); + mBtnYearly.setEnabled(true); + + switch (position) { + case 1: + mBtnDaily.setEnabled(false); + break; + case 2: + mBtnWeekly.setEnabled(false); + break; + case 3: + mBtnMonthly.setEnabled(false); + break; + case 4: + mBtnYearly.setEnabled(false); + break; + } + } + + private Date calDateByStep(Date date, int numDay) { + Calendar myCal = new GregorianCalendar(); + myCal.setTime(date); + myCal.add(Calendar.DATE, numDay); + return myCal.getTime(); + } + + @Override + public void onSaveData() { + + } + + @Override + public void onInvalidate(boolean isInit) { + + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + + public void handleLoadRankList() { + mRankList.clear(); + mAdapter.clearData(); + mAdapter.notifyDataSetChanged(); + + String startDate = FORMAT_DATE.format(mStartDate); + String endDate = FORMAT_DATE.format(mEndDate); + getRankList(mCurrentMode.getValue(), startDate, endDate, mCurrentPage); + } + + public void getRankList(int mode, String startDate, String endDate, int page) { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map header = new HashMap<>(); + header.put("token", APIResponse.getInstance().getToken()); + + mService = ApiUtils.getApiService(); + mService.getRankingList(header, mode, startDate, endDate, page).enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) { + mRankList = response.body().getResult(); + mAdapter.updateData(mRankList); + mAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mRankList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RegisterActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RegisterActivity.java new file mode 100644 index 0000000..0280b13 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/RegisterActivity.java @@ -0,0 +1,547 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.AlertDialog; +import android.app.DatePickerDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.view.WindowManager; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.dinhcv.lifelogpedometer.LifeLogApplication; +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.customview.SimpleSelectBoxDialogBuilder; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.interfaces.OnSelectResultListener; +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.model.structure.RegisterInfo; +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import de.hdodenhof.circleimageview.CircleImageView; + +public class RegisterActivity extends ActivityBase { + + @BindView(R.id.edt_user) + EditText edtUsername; + @BindView(R.id.edt_name) + EditText edtName; + @BindView(R.id.edt_nickName) + EditText edtNickName; + @BindView(R.id.edt_email) + EditText edtEmail; + @BindView(R.id.edt_password) + EditText edtPassword; + @BindView(R.id.edt_confirmPass) + EditText edtConfirmPass; + @BindView(R.id.tv_sex) + TextView tvSex; + @BindView(R.id.tv_birthday) + TextView tvBirthday; + @BindView(R.id.edt_height) + EditText edtHeight; + @BindView(R.id.edt_weight) + EditText edtWeight; + @BindView(R.id.edt_bodyFat) + EditText edtBodyFat; + @BindView(R.id.tv_address) + TextView tvAddress; + @BindView(R.id.edt_comment) + EditText edtComment; + + @BindView(R.id.ll_low) + LinearLayout llLow; + @BindView(R.id.tv_low) + TextView tvLow; + @BindView(R.id.ll_mid) + LinearLayout llMid; + @BindView(R.id.tv_mid) + TextView tvMid; + @BindView(R.id.ll_hight) + LinearLayout llHight; + @BindView(R.id.tv_hight) + TextView tvHight; + @BindView(R.id.profile_image) + CircleImageView profileImage; + + private List sexList; + private List provinceList; + private LifeLogApplication mLifeLogApplication; + private SelectItemInfo sexInfo; + private SelectItemInfo provinceInfo; + + private Calendar mCalendar; + private int mDay; + private int mMonth; + private int mYear; + private Date mBirthDay; + + private int level = 0; + private static final int RESULT_LOAD_IMG = 99; + private RegisterInfo mRegisterInfo; + private String profileImagePath; + private ProgressDialog progressDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_register); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); + + ButterKnife.bind(this); + mLifeLogApplication = (LifeLogApplication) getApplication(); + + initData(); + + initView(); + + } + + private void initData() { + sexList = mLifeLogApplication.getSexList(); + provinceList = mLifeLogApplication.getProvinceList(); + + mCalendar = Calendar.getInstance(); + mDay = mCalendar.get(Calendar.DAY_OF_MONTH); + mMonth = mCalendar.get(Calendar.MONTH); + mYear = mCalendar.get(Calendar.YEAR); + } + + + private void initView() { + + + } + + private boolean checkData() { + String userName = edtUsername.getText().toString(); + String name = edtName.getText().toString(); + String nickName = edtNickName.getText().toString(); + String email = edtEmail.getText().toString(); + String pass = edtPassword.getText().toString(); + String confirmPass = edtConfirmPass.getText().toString(); + //sexInfo + //birthday + String height = edtHeight.getText().toString(); + String weight = edtWeight.getText().toString(); + String bodyFat = edtBodyFat.getText().toString(); + // address + String comment = edtComment.getText().toString(); + + + if (userName.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.username_null)); + return false; + } + + if (name.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.name_null)); + return false; + } + + if (nickName.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.nickname_null)); + return false; + } + + if (email.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.mail_null)); + return false; + } else { + if (!Utils.checkMailFormat(email)) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.mail_invalid)); + return false; + } + } + + if (pass.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.password_null)); + return false; + }else { + if (pass.length() < 6) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.password_less_6)); + return false; + } + } + + if (confirmPass.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.confirm_pass_null)); + return false; + } + + if (!pass.equals(confirmPass)) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.confirm_pass_wrong)); + return false; + } + + if (sexInfo == null) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.sex_not_select)); + return false; + } + + if (mBirthDay == null) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.birthday_not_select)); + return false; + } + + if (height.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.height_null)); + return false; + } + + if (weight.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.weight_null)); + return false; + } + + if (bodyFat.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.body_fat_percent_null)); + return false; + } + + if (provinceInfo == null) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.province_not_select)); + return false; + } + + if (level == 0) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.level_not_select)); + return false; + } + + if (comment.isEmpty()) { + showAlerDialog(RegisterActivity.this, getResources().getString(R.string.comment_null)); + return false; + } + + mRegisterInfo = new RegisterInfo(); + mRegisterInfo.setUsername(userName); + mRegisterInfo.setFullName(name); + mRegisterInfo.setNickname(nickName); + mRegisterInfo.setPassword(pass); + mRegisterInfo.setBirthday(mBirthDay); + mRegisterInfo.setHeight(Integer.valueOf(height)); + mRegisterInfo.setWeight(Integer.valueOf(weight)); + mRegisterInfo.setFatRate(Integer.valueOf(bodyFat)); + mRegisterInfo.setGender(sexInfo.getId()); + mRegisterInfo.setAddress(provinceInfo.getName()); + mRegisterInfo.setEmail(email); + mRegisterInfo.setProfileImage(profileImagePath); + + return true; + } + + private void handleRegister() { + progressDialog = new ProgressDialog(RegisterActivity.this); + progressDialog.setMessage(getResources().getString(R.string.uploading)); + progressDialog.setCancelable(false); + progressDialog.show(); + + LLAPIManager.register(mRegisterInfo, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + progressDialog.dismiss(); + Debug.error(" Can not upload data"); + if (error != null) { + String err = getResources().getString(R.string.register_err); + notifyErr(err); + } + } + + @Override + public void onSuccess(String json) { + progressDialog.dismiss(); + if (json != null) { + Debug.warn(" Upload data success success"); + Debug.warn("DATA JSON result: " + json.toString()); + registerDone(); + } else { + Debug.warn(" Upload data fail: response null"); + String err = getResources().getString(R.string.err_exception); + notifyErr(err); + } + } + + @Override + public void onSuccess(JSONObject object) { + Debug.warn("Version JSON object result: Success"); + progressDialog.dismiss(); + + String email = object.optString("email"); + String username = object.optString("username"); + String pass = object.optString("password"); + Debug.normal("Email: "+email +"\n"+ "Username: "+username); + // save data + Setting.setUserDataSharepre(RegisterActivity.this, Setting.EMAIL_SHAREPRE, email); + Setting.setUserDataSharepre(RegisterActivity.this, Setting.USER_SHAREPRE, username); + Setting.setUserDataSharepre(RegisterActivity.this, Setting.PASS_SHAREPRE, pass); + registerDone(); + } + }); + } + + private void hanleGetImagePath(Bitmap bitmap){ + progressDialog = new ProgressDialog(RegisterActivity.this); + progressDialog.setMessage(getResources().getString(R.string.uploading)); + progressDialog.setCancelable(false); + progressDialog.show(); + + LLAPIManager.uploadImage(bitmap, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + progressDialog.dismiss(); + Debug.error(" Can not upload data"); + if (error != null) { + String err = getResources().getString(R.string.register_err); + notifyErr(err); + } + } + + @Override + public void onSuccess(String json) { + if (json != null) { + Debug.warn(" Upload data success success"); + Debug.warn("DATA JSON result: " + json.toString()); + uploadImageDone(json); + } else { + progressDialog.dismiss(); + Debug.warn(" Upload data fail: response null"); + String err = getResources().getString(R.string.err_exception); + notifyErr(err); + } + } + + @Override + public void onSuccess(JSONObject array) { + progressDialog.dismiss(); + Debug.warn(" Upload data success array"); + } + }); + } + + private void registerDone(){ + Toast.makeText(RegisterActivity.this, R.string.register_success, Toast.LENGTH_SHORT).show(); + finish(); + } + + private void uploadImageDone(String path){ + profileImagePath = path; + } + + private void notifyErr(String err) { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(RegisterActivity.this); + alertDialog.setMessage(err); + alertDialog.setCancelable(false); + alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + alertDialog.show(); + } + + private void doSelectSex() { + String title = getResources().getString(R.string.sex); + new SimpleSelectBoxDialogBuilder().create(RegisterActivity.this, title, sexList, new OnSelectResultListener() { + @Override + public void onSelectedItem(SelectItemInfo selectItemInfo) { + if (selectItemInfo != null) { + Debug.normal("Item selected: " + selectItemInfo.getName()); + sexInfo = selectItemInfo; + tvSex.setText(sexInfo.getName()); + } else { + Debug.normal("Have not item selected"); + } + } + }).show(); + } + + private void doSelectProvince() { + String title = getResources().getString(R.string.prefecture); + new SimpleSelectBoxDialogBuilder().create(RegisterActivity.this, title, provinceList, new OnSelectResultListener() { + @Override + public void onSelectedItem(SelectItemInfo selectItemInfo) { + if (selectItemInfo != null) { + Debug.normal("Item selected: " + selectItemInfo.getName()); + provinceInfo = selectItemInfo; + tvAddress.setText(provinceInfo.getName()); + } else { + Debug.normal("Have not item selected"); + } + } + }).show(); + } + + private void hanleSelectDate() { + + DatePickerDialog datePicker = new DatePickerDialog(RegisterActivity.this, new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { + + mDay = dayOfMonth; + mMonth = month; + mYear = year; + mCalendar = Calendar.getInstance(); + mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); + mCalendar.set(Calendar.MONTH, month); + mCalendar.set(Calendar.YEAR, year); + mBirthDay = mCalendar.getTime(); + + String dateStr = Utils.convertDateToStringDialogSelect(mBirthDay); + tvBirthday.setText(dateStr); + } + }, mYear, mMonth, mDay); + datePicker.getDatePicker().setMaxDate(new Date().getTime()); + datePicker.show(); + } + + private void updateUILevel() { + if (level == 1) { + setLowButtonSelected(true); + setMidButtonSelected(false); + setHightButtonSelected(false); + } else if (level == 2) { + setLowButtonSelected(false); + setMidButtonSelected(true); + setHightButtonSelected(false); + } else if (level == 3) { + setLowButtonSelected(false); + setMidButtonSelected(false); + setHightButtonSelected(true); + } else { + setLowButtonSelected(false); + setMidButtonSelected(false); + setHightButtonSelected(false); + } + } + + private void setLowButtonSelected(boolean b) { + if (b) { + llLow.setBackgroundResource(R.drawable.left_selected_lev_bg); + tvLow.setTextColor(getResources().getColor(R.color.white)); + } else { + llLow.setBackgroundResource(R.drawable.left_unselected_lev_bg); + tvLow.setTextColor(getResources().getColor(R.color.black)); + } + } + + private void setMidButtonSelected(boolean b) { + if (b) { + llMid.setBackgroundResource(R.drawable.mid_selected_lev_bg); + tvMid.setTextColor(getResources().getColor(R.color.white)); + } else { + llMid.setBackgroundResource(R.drawable.mid_unselected_lev_bg); + tvMid.setTextColor(getResources().getColor(R.color.black)); + } + } + + private void setHightButtonSelected(boolean b) { + if (b) { + llHight.setBackgroundResource(R.drawable.right_selected_lev_bg); + tvHight.setTextColor(getResources().getColor(R.color.white)); + } else { + llHight.setBackgroundResource(R.drawable.right_unselected_lev_bg); + tvHight.setTextColor(getResources().getColor(R.color.black)); + } + } + + private void getImageBrower() { + Intent intent = new Intent(Intent.ACTION_PICK); + intent.setType("image/*"); + startActivityForResult(intent, RESULT_LOAD_IMG); + } + + + @OnClick({R.id.btn_register, R.id.rl_sex, R.id.rl_birthday, R.id.rl_address, R.id.ll_low, + R.id.ll_mid, R.id.ll_hight, R.id.profile_image}) + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_register: + if (checkData()) { + handleRegister(); + } + break; + + case R.id.rl_sex: + doSelectSex(); + break; + + + case R.id.rl_birthday: + hanleSelectDate(); + break; + + case R.id.rl_address: + doSelectProvince(); + break; + + case R.id.ll_low: + level = 1; + updateUILevel(); + break; + case R.id.ll_mid: + level = 2; + updateUILevel(); + break; + case R.id.ll_hight: + level = 3; + updateUILevel(); + break; + case R.id.profile_image: + getImageBrower(); + break; + + default: + break; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (resultCode == RESULT_OK) { + if (requestCode == RESULT_LOAD_IMG) { + try { + final Uri imageUri = data.getData(); + final InputStream imageStream = getContentResolver().openInputStream(imageUri); + final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream); + hanleGetImagePath(selectedImage); + profileImage.setImageBitmap(selectedImage); + } catch (FileNotFoundException e) { + e.printStackTrace(); + Toast.makeText(RegisterActivity.this, "Something went wrong", Toast.LENGTH_LONG).show(); + } + + } else { + Toast.makeText(RegisterActivity.this, "You haven't picked Image", Toast.LENGTH_LONG).show(); + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SensorFilter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SensorFilter.java new file mode 100644 index 0000000..0d7daf9 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SensorFilter.java @@ -0,0 +1,47 @@ +package com.dinhcv.lifelogpedometer.activity; + +public class SensorFilter { + + private SensorFilter() { + } + + public static float sum(float[] array) { + float retval = 0; + for (int i = 0; i < array.length; i++) { + retval += array[i]; + } + return retval; + } + + public static float[] cross(float[] arrayA, float[] arrayB) { + float[] retArray = new float[3]; + retArray[0] = arrayA[1] * arrayB[2] - arrayA[2] * arrayB[1]; + retArray[1] = arrayA[2] * arrayB[0] - arrayA[0] * arrayB[2]; + retArray[2] = arrayA[0] * arrayB[1] - arrayA[1] * arrayB[0]; + return retArray; + } + + public static float norm(float[] array) { + float retval = 0; + for (int i = 0; i < array.length; i++) { + retval += array[i] * array[i]; + } + return (float) Math.sqrt(retval); + } + + + public static float dot(float[] a, float[] b) { + float retval = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + return retval; + } + + public static float[] normalize(float[] a) { + float[] retval = new float[a.length]; + float norm = norm(a); + for (int i = 0; i < a.length; i++) { + retval[i] = a[i] / norm; + } + return retval; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SettingFragmentPresenter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SettingFragmentPresenter.java new file mode 100644 index 0000000..97e2504 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SettingFragmentPresenter.java @@ -0,0 +1,6 @@ +package com.dinhcv.lifelogpedometer.activity; + +interface SettingFragmentPresenter { + void onSaveData(); + void onInvalidate(boolean isInit); +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsCreateGroupFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsCreateGroupFragment.java new file mode 100644 index 0000000..4aaae1d --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsCreateGroupFragment.java @@ -0,0 +1,185 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ToggleButton; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.google.gson.JsonObject; + +import java.util.HashMap; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class SnsCreateGroupFragment extends FragmentBase { + private View mRootView; + @BindView(R.id.edt_name) + EditText mEdtName; + @BindView(R.id.toggle_walk) + ToggleButton mToggleWalk; + @BindView(R.id.toggle_bike) + ToggleButton mToggleBike; + @BindView(R.id.toggle_run) + ToggleButton mToggleRun; + @BindView(R.id.toggle_step) + ToggleButton mToggleStep; + @BindView(R.id.toggle_gym) + ToggleButton mToggleGym; + @BindView(R.id.toggle_beginner) + ToggleButton mToggleBeginner; + @BindView(R.id.edt_goal) + EditText mEdtGoal; + @BindView(R.id.edt_walk_goal) + EditText mEdtWalkGoal; + @BindView(R.id.edt_run_goal) + EditText mEdtRunGoal; + @BindView(R.id.edt_bike_goal) + EditText mEdtBikeGoal; + @BindView(R.id.btn_create_group) + Button mBtnCreateGroup; + + private String mName = ""; + private String mGoal = ""; + private int mWalkActive = 1; + private int mBikeActive = 1; + private int mRunActive = 1; + private int mStepActive = 1; + private int mGymActive = 1; + private int mBeginnerActive = 1; + private int mWalkGoal = 0; + private int mRunGoal = 0; + private int mBikeGoal = 0; + + private ApiService mService; + + public static final String TAG = "SnsCreateGroupFragment"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns_create_group, container, false); + ButterKnife.bind(this, mRootView); + + return mRootView; + } + + private void saveDate() { + mName = mEdtName.getText().toString().trim(); + mGoal = mEdtGoal.getText().toString().trim(); + mWalkActive = mToggleWalk.isChecked() ? 1 : 0; + mBikeActive = mToggleBike.isChecked() ? 1 : 0; + mRunActive = mToggleRun.isChecked() ? 1 : 0; + mStepActive = mToggleStep.isChecked() ? 1 : 0; + mGymActive = mToggleGym.isChecked() ? 1 : 0; + mBeginnerActive = mToggleBeginner.isChecked() ? 1 : 0; + mWalkGoal = Utils.parseString2Int(mEdtWalkGoal.getText().toString().trim(), 0); + mRunGoal = Utils.parseString2Int(mEdtRunGoal.getText().toString().trim(), 0); + mBikeGoal = Utils.parseString2Int(mEdtBikeGoal.getText().toString().trim(), 0); + } + + private boolean isValidInputData() { + if (mEdtName.getText().toString().isEmpty()) { + mEdtName.setError(getString(R.string.error_empty_text)); + return false; + } + if (mEdtGoal.getText().toString().isEmpty()) { + mEdtGoal.setError(getString(R.string.error_empty_text)); + return false; + } + return true; + } + + private void handleCreateGroup() { + showLoadingDialog(); + Map header = new HashMap<>(); + header.put("token", APIResponse.getInstance().getToken()); + + Map params = new HashMap<>(); + params.put("group_name", mName); + params.put("walk_mode_active", mWalkActive + ""); + params.put("run_mode_active", mRunActive + ""); + params.put("bike_mode_active", mBikeActive + ""); + params.put("step_mode_active", mStepActive + ""); + params.put("gym_mode_active", mGymActive + ""); + params.put("beginer_mode_active", mBeginnerActive + ""); + params.put("goal", mGoal); +// params.put("map_id", "0"); + params.put("walk_mode_goal", mWalkGoal + ""); + params.put("run_mode_goal", mRunGoal + ""); + params.put("bike_mode_goal", mBikeGoal + ""); + + mService = ApiUtils.getApiService(); + mService.createGroup(header, params).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + handleShowStatusAlert(true); + dismissLoadingDialog(); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i(TAG, "Fail 1" + statusCode); + handleShowStatusAlert(false); + dismissLoadingDialog(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.i(TAG, "Fail 2" + t); + handleShowStatusAlert(false); + dismissLoadingDialog(); + } + }); + } + + private void handleShowStatusAlert(boolean isSuccess) { + String title = getString(R.string.msg_create_group_title); + String message = ""; + if (isSuccess) { + message = getString(R.string.msg_create_group_success); + } else { + message = getString(R.string.msg_create_group_fail); + } + AlertDialog.Builder builder = getAlert(title, message); + builder.setPositiveButton(getString(R.string.msg_ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + //Do nothing + } + }).show(); + } + + @Override + public void onDetach() { + super.onDetach(); + Debug.normal("SonLT", "On DeAttack"); + } + + @OnClick(R.id.btn_create_group) + public void createGroup() { + saveDate(); + if (!isValidInputData()){ + return; + } + handleCreateGroup(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsDetailFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsDetailFragment.java new file mode 100644 index 0000000..a8d805b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsDetailFragment.java @@ -0,0 +1,403 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.SnsMemberAdapter; +import com.dinhcv.lifelogpedometer.adapter.SnsTopicAdapter; +import com.dinhcv.lifelogpedometer.model.structure.pojo.ResultResponse; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsDetailInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMemberInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMyGroupInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicResponse; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.google.gson.JsonObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created by Admin on 8/18/2017. + */ + +public class SnsDetailFragment extends FragmentBase { + private enum CurrentList { + TOPIC_LIST, + MEMBER_LIST, + } + + private ApiService mService; + private View mRootView; + + @BindView(R.id.rcv_topic) + RecyclerView mRcvRank; + @BindView(R.id.layout_pb_loading) + LinearLayout mLayoutPbLoading; + + @BindView(R.id.tv_title) + TextView mTvTitle; + @BindView(R.id.tv_goal) + TextView mTvGoal; + @BindView(R.id.imv_beginer_icon) + ImageView mImvBeginerIcon; + + @BindView(R.id.tv_run_active_mode) + TextView mTvRunAcivieMode; + @BindView(R.id.tv_walk_active_mode) + TextView mTvWalkAcivieMode; + @BindView(R.id.tv_bike_active_mode) + TextView mTvBikeAcivieMode; + @BindView(R.id.layout_run_active_mode) + LinearLayout mLayoutRunAcivieMode; + @BindView(R.id.layout_walk_active_mode) + LinearLayout mLayoutWalkAcivieMode; + @BindView(R.id.layout_bike_active_mode) + LinearLayout mLayoutBikeAcivieMode; + @BindView(R.id.tv_target_run) + TextView mTvTargetRun; + @BindView(R.id.tv_target_walk) + TextView mTvTargetWalk; + @BindView(R.id.tv_target_bike) + TextView mTvTargetBike; + + @BindView(R.id.btn_view_member) + TextView mBtnViewMember; + @BindView(R.id.btn_join_group) + TextView mBtnJoinGroup; + + SwipeRefreshLayout mSwipeRefreshTopic; + + private SnsTopicAdapter mTopicAdapter; + private SnsMemberAdapter mMemberAdapter; + private List mSnsTopicList = new ArrayList<>(); + private List mSnsMemberList = new ArrayList<>(); + + private List mSnsDetailList = new ArrayList<>(); + private List mSnsTopicGroupList = new ArrayList<>(); + private SnsSearchInfo mSnsSerchInfo; + private SnsDetailInfo mSnsDetailInfo; + + public static final String TAG = "SnsDetailFragment"; + + CurrentList mCurrentList = CurrentList.TOPIC_LIST; + + private SnsFragment mSnsFragment; + + public void setRootFragment(SnsFragment frag) { + this.mSnsFragment = frag; + } + + public void setInitData(SnsSearchInfo info) { + this.mSnsSerchInfo = info; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns_detail, container, false); + ButterKnife.bind(this, mRootView); + initView(); + getSnsDetail(); + return mRootView; + } + + private void initView() { + mTopicAdapter = new SnsTopicAdapter(getActivity(), mSnsTopicGroupList); + mMemberAdapter = new SnsMemberAdapter(getActivity(), mSnsMemberList); + + final RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); + mRcvRank.setLayoutManager(mLayoutManager); + mRcvRank.setAdapter(mTopicAdapter); + + mSwipeRefreshTopic = (SwipeRefreshLayout) mRootView.findViewById(R.id.swipe_topic); + mSwipeRefreshTopic.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + if (mCurrentList == CurrentList.MEMBER_LIST) { + if (mSnsSerchInfo == null) return; + mCurrentList = CurrentList.MEMBER_LIST; + mRcvRank.setAdapter(mMemberAdapter); + mMemberAdapter.clearData(); + mMemberAdapter.notifyDataSetChanged(); + getMemberList(mSnsSerchInfo.getGroupId()); + } else if (mCurrentList == CurrentList.TOPIC_LIST) { + mCurrentList = CurrentList.TOPIC_LIST; + mRcvRank.setAdapter(mTopicAdapter); + mTopicAdapter.clearData(); + mTopicAdapter.notifyDataSetChanged(); + getTopicList(); + } + } + }); + + mLayoutPbLoading.setVisibility(View.GONE); + + if (mCurrentList == CurrentList.TOPIC_LIST){ + //T.B.D + mBtnViewMember.setText("メンバーを見る"); + }else if (mCurrentList == CurrentList.MEMBER_LIST){ + mBtnViewMember.setText("ツイートを見る"); + } + } + + private void initData() { + if (mSnsDetailInfo == null) return; + mTvTitle.setText(mSnsDetailInfo.getGroupName()); + mTvGoal.setText(mSnsDetailInfo.getGoal()); + if (mSnsDetailInfo.getRunModeActive() == 1) { + mTvRunAcivieMode.setVisibility(View.VISIBLE); + mLayoutRunAcivieMode.setVisibility(View.VISIBLE); + mTvTargetRun.setText(mSnsDetailInfo.getRunModeGoal() + "m"); + } else { + mTvRunAcivieMode.setVisibility(View.GONE); + mLayoutRunAcivieMode.setVisibility(View.GONE); + } + if (mSnsDetailInfo.getWalkModeActive() == 1) { + mTvWalkAcivieMode.setVisibility(View.VISIBLE); + mLayoutWalkAcivieMode.setVisibility(View.VISIBLE); + mTvTargetWalk.setText(mSnsDetailInfo.getWalkModeGoal() + "m"); + } else { + mTvWalkAcivieMode.setVisibility(View.GONE); + mLayoutWalkAcivieMode.setVisibility(View.GONE); + } + if (mSnsDetailInfo.getBikeModeActive() == 1) { + mTvBikeAcivieMode.setVisibility(View.VISIBLE); + mLayoutBikeAcivieMode.setVisibility(View.VISIBLE); + mTvTargetBike.setText(mSnsDetailInfo.getBikeModeGoal() + "m"); + } else { + mTvBikeAcivieMode.setVisibility(View.GONE); + mLayoutBikeAcivieMode.setVisibility(View.GONE); + } + if (mSnsDetailInfo.getBeginerModeActive() == 1) { + mImvBeginerIcon.setVisibility(View.VISIBLE); + } else { + mImvBeginerIcon.setVisibility(View.INVISIBLE); + } + if (mSnsDetailInfo.getJoinGroup() == 1) { + //Member has been join group + mBtnJoinGroup.setVisibility(View.INVISIBLE); + mBtnJoinGroup.setClickable(false); + } else { + mBtnJoinGroup.setVisibility(View.VISIBLE); + mBtnJoinGroup.setClickable(true); + } + + } + + @OnClick(R.id.btn_view_member) + public void viewMember(){ + Debug.normal("SonLT", "View Member"); + if (mCurrentList == CurrentList.TOPIC_LIST) { + if (mSnsSerchInfo == null) return; + mBtnViewMember.setText(getString(R.string.sns_btn_view_member_title)); + mCurrentList = CurrentList.MEMBER_LIST; + mRcvRank.setAdapter(mMemberAdapter); + mMemberAdapter.clearData(); + mMemberAdapter.notifyDataSetChanged(); + getMemberList(mSnsSerchInfo.getGroupId()); + } else if (mCurrentList == CurrentList.MEMBER_LIST) { + mBtnViewMember.setText(getString(R.string.sns_btn_view_tweet_title)); + mCurrentList = CurrentList.TOPIC_LIST; + mRcvRank.setAdapter(mTopicAdapter); + mTopicAdapter.clearData(); + mTopicAdapter.notifyDataSetChanged(); + getTopicList(); + } + } + @OnClick(R.id.btn_join_group) + public void joinGroup(){ + Debug.normal("SonLT", "Join Group"); + if (mSnsDetailInfo.getJoinGroup() == 0) { + //Member has been join group + } else { + handleJoinGroup(); + } + } + + /** + * Init data + */ + private void getSnsDetail() { + mLayoutPbLoading.setVisibility(View.VISIBLE); + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + int groupId = mSnsSerchInfo.getGroupId(); + mService = ApiUtils.getApiService(); + mService.getSnsDetail(map, groupId).enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) { + mSnsDetailList = response.body().getResult(); + if (mSnsDetailList != null) { + if (mSnsDetailList.size() > 0) { + mSnsDetailInfo = mSnsDetailList.get(0); + initData(); + getTopicList(); + } + } + Debug.normal("SonLT", "getSnsDetail isSuccessful"); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Debug.normal("SonLT", "getSnsDetail isFailure"); + } + mLayoutPbLoading.setVisibility(View.GONE); + } + + @Override + public void onFailure(Call> call, Throwable t) { + Debug.normal("SonLT", "getSnsDetail onFailure"); + mLayoutPbLoading.setVisibility(View.GONE); + } + }); + } + + private void getTopicList() { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsTopicList(map).enqueue(new Callback() { + @Override + public void onResponse(retrofit2.Call call, retrofit2.Response response) { + if (response.isSuccessful()) { + mSnsTopicList = response.body().getResult(); + mSnsTopicGroupList.clear(); + for (SnsTopicInfo topic : mSnsTopicList) { + if (topic.getGroupId() != mSnsSerchInfo.getGroupId()) { + continue; + } + mSnsTopicGroupList.add(topic); + } + mTopicAdapter.updateData(mSnsTopicGroupList); + mTopicAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsTopicGroupList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(retrofit2.Call call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } + + private void getMemberList(int groupId) { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map header = new HashMap<>(); + header.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsMember(header, groupId).enqueue(new Callback>() { + @Override + public void onResponse(retrofit2.Call> call, retrofit2.Response> response) { + if (response.isSuccessful()) { + mSnsMemberList = response.body().getResult(); + mMemberAdapter.updateData(mSnsMemberList); + mMemberAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsTopicList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(retrofit2.Call> call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } + private void handleShowStatusAlert(boolean isSuccess) { + String title = getString(R.string.msg_join_group_title); + String message = ""; + if (isSuccess) { + message = getString(R.string.msg_create_group_success); + } else { + message = getString(R.string.msg_create_group_fail); + } + AlertDialog.Builder builder = getAlert(title, message); + builder.setPositiveButton(getString(R.string.msg_ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + //Do nothing + } + }).show(); + } + + private void handleJoinGroup(){ + showLoadingDialog(); + Map header = new HashMap<>(); + header.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.joinSnsGroup(header, mSnsSerchInfo.getGroupId()).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + handleShowStatusAlert(true); + dismissLoadingDialog(); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i(TAG, "Fail 1" + statusCode); + handleShowStatusAlert(false); + dismissLoadingDialog(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.i(TAG, "Fail 2" + t); + handleShowStatusAlert(false); + dismissLoadingDialog(); + } + }); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsFragment.java new file mode 100644 index 0000000..7911dcd --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsFragment.java @@ -0,0 +1,165 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchInfo; + +public class SnsFragment extends Fragment implements SettingFragmentPresenter { + public enum SnsFragmentTag { + SNS_TOPIC, + SNS_SEARCH, + SNS_DETAIL, + SNS_MY_GROUP, + SNS_CREATE_GROUP; + } + + private FragmentTransaction mFragmentTransaction; + private FragmentManager mFragmentManager; + + private View mRootView; + private FrameLayout mSmsLayout; + private SnsTopicFragment mSnsTopicFragment; + private SnsSearchFragment mSnsSearchFragment; + private SnsDetailFragment mSnsDetailFragment; + private SnsMyGroupFragment mSnsMyGroupFragment; + + public static final String SNS_TOPIC_TAG = "sns_topic"; + public static final String SNS_SEARCH_TAG = "sns_search"; + public static final String SNS_DETAIL_TAG = "sns_detail"; + public static final String SNS_CREATE_GROUP_TAG = "sns_detail"; + + public SnsFragmentTag mCurrentChildSnsFragment = SnsFragmentTag.SNS_TOPIC; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle + savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns, container, false); + mFragmentManager = getFragmentManager(); + mFragmentTransaction = mFragmentManager.beginTransaction(); + + initView(); + initData(); + + return mRootView; + } + + /** + */ + private void initView() { + mSmsLayout = (FrameLayout) mRootView.findViewById(R.id.layout_sns); + + mSnsTopicFragment = new SnsTopicFragment(); + mSnsTopicFragment.setRootFragment(this); + mSnsSearchFragment = new SnsSearchFragment(); + mSnsSearchFragment.setRootFragment(this); + mSnsDetailFragment = new SnsDetailFragment(); + mSnsDetailFragment.setRootFragment(this); + mSnsMyGroupFragment = new SnsMyGroupFragment(); + + showSnsTopicFragment(); + } + + public void handleToolbarClick(int i) { + // with i = 0 -> home icon is clicked + if (i == 0) { + Log.i("SonLT", "Home icon clicked"); + switch (mCurrentChildSnsFragment) { + case SNS_TOPIC: + break; + case SNS_SEARCH: + showSnsTopicFragment(); + break; + case SNS_DETAIL: + showSnsSearchFragment(); + break; + case SNS_CREATE_GROUP: + showSnsSearchFragment(); + break; + case SNS_MY_GROUP: + showSnsTopicFragment(); + break; + } + } + } + + public void showSnsTopicFragment() { + mCurrentChildSnsFragment = SnsFragmentTag.SNS_TOPIC; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mSmsLayout.getId(), mSnsTopicFragment, SNS_TOPIC_TAG); + mFragmentTransaction.commit(); + } + + public void showSnsSearchFragment() { + mCurrentChildSnsFragment = SnsFragmentTag.SNS_SEARCH; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mSmsLayout.getId(), mSnsSearchFragment, SNS_SEARCH_TAG); + mFragmentTransaction.commit(); + } + + public void showSnsDetailFragment(SnsSearchInfo info) { + if (info == null) return; + mCurrentChildSnsFragment = SnsFragmentTag.SNS_DETAIL; + mSnsDetailFragment.setInitData(info); + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mSmsLayout.getId(), mSnsDetailFragment, SNS_DETAIL_TAG); + mFragmentTransaction.commit(); + } + public void showSnsCreateGroupFragment() { + mCurrentChildSnsFragment = SnsFragmentTag.SNS_CREATE_GROUP; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mSmsLayout.getId(), new SnsCreateGroupFragment(), SNS_CREATE_GROUP_TAG); + mFragmentTransaction.commit(); + } + public void showSnsMyGroupFragment() { + mCurrentChildSnsFragment = SnsFragmentTag.SNS_MY_GROUP; + mFragmentTransaction = mFragmentManager.beginTransaction(); + mFragmentTransaction.replace(mSmsLayout.getId(), mSnsMyGroupFragment, SNS_CREATE_GROUP_TAG); + mFragmentTransaction.commit(); + } + + /** + * Init data + */ + private void initData() { + + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + } + + /** + * Save data + */ + @Override + public void onSaveData() { + } + + @Override + public void onInvalidate(boolean isInit) { + initData(); + } + + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsMyGroupFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsMyGroupFragment.java new file mode 100644 index 0000000..1453d4b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsMyGroupFragment.java @@ -0,0 +1,352 @@ +package com.dinhcv.lifelogpedometer.activity; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.SnsMemberAdapter; +import com.dinhcv.lifelogpedometer.adapter.SnsTopicAdapter; +import com.dinhcv.lifelogpedometer.model.structure.pojo.ResultResponse; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsDetailInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMemberInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMyGroupInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicResponse; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * A simple {@link Fragment} subclass. + */ +public class SnsMyGroupFragment extends FragmentBase { + private enum CurrentList { + TOPIC_LIST, + MEMBER_LIST, + } + + ApiService mService; + + View mRootView; + @BindView(R.id.spinner_my_group) + Spinner mSpinnerMyGroup; + @BindView(R.id.imv_spinner_my_group) + ImageView mImvSpinnerMyGroup; + + @BindView(R.id.tv_title) + TextView mTvTitle; + @BindView(R.id.tv_goal) + TextView mTvGoal; + + @BindView(R.id.tv_run_active_mode) + TextView mTvRunAcivieMode; + @BindView(R.id.tv_walk_active_mode) + TextView mTvWalkAcivieMode; + @BindView(R.id.tv_bike_active_mode) + TextView mTvBikeAcivieMode; + + SwipeRefreshLayout mSwipeRefreshTopic; + RecyclerView mRcvMemberList; + private SnsTopicAdapter mTopicAdapter; + private SnsMemberAdapter mMemberAdapter; + + private List mSnsTopicList = new ArrayList<>(); + private List mSnsMyGroupList = new ArrayList<>(); + private List mSnsMemberList = new ArrayList<>(); + + private SnsMyGroupInfo mSnsMyGroup; + + CurrentList mCurentList = CurrentList.TOPIC_LIST; + + public SnsMyGroupFragment() { + // Required empty public constructor + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns_my_group, container, false); + ButterKnife.bind(this, mRootView); + + initView(); + return mRootView; + } + + public void initView() { + mRcvMemberList = (RecyclerView) mRootView.findViewById(R.id.rcv_member); + mSpinnerMyGroup = (Spinner) mRootView.findViewById(R.id.spinner_my_group); + mSwipeRefreshTopic = (SwipeRefreshLayout) mRootView.findViewById(R.id.swipe_topic); + + mSwipeRefreshTopic.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + if (mCurentList == CurrentList.MEMBER_LIST) { + if (mSnsMyGroup == null) return; + mCurentList = CurrentList.MEMBER_LIST; + mRcvMemberList.setAdapter(mMemberAdapter); + mMemberAdapter.clearData(); + mMemberAdapter.notifyDataSetChanged(); + getMemberList(mSnsMyGroup); + } else if (mCurentList == CurrentList.TOPIC_LIST) { + mRcvMemberList.setAdapter(mTopicAdapter); + mTopicAdapter.clearData(); + mTopicAdapter.notifyDataSetChanged(); + getTopicList(); + } + } + }); + + mTopicAdapter = new SnsTopicAdapter(getActivity(), mSnsTopicList); + mMemberAdapter = new SnsMemberAdapter(getActivity(), mSnsMemberList); + + final RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); + + mRcvMemberList.setLayoutManager(mLayoutManager); + mRcvMemberList.setAdapter(mTopicAdapter); + + getMyGroupList(); + getTopicList(); + } + + @OnClick(R.id.imv_spinner_my_group) + public void showSpinnerMyGroup() { + mSpinnerMyGroup.performClick(); + } + + @OnClick(R.id.btn_show_member) + public void showGroupMember() { + if (mCurentList == CurrentList.TOPIC_LIST) { + if (mSnsMyGroup == null) return; + mCurentList = CurrentList.MEMBER_LIST; + mRcvMemberList.setAdapter(mMemberAdapter); + mMemberAdapter.clearData(); + mMemberAdapter.notifyDataSetChanged(); + getMemberList(mSnsMyGroup); + } else if (mCurentList == CurrentList.MEMBER_LIST) { + mCurentList = CurrentList.TOPIC_LIST; + mRcvMemberList.setAdapter(mTopicAdapter); + mTopicAdapter.clearData(); + mTopicAdapter.notifyDataSetChanged(); + getTopicList(); + } + } + + public void setDataSpinnerMyGroup() { + List list = new ArrayList<>(); + for (SnsMyGroupInfo info : mSnsMyGroupList) { + list.add(info.getGroupName()); + } + ArrayAdapter dataAdapter = new ArrayAdapter<>(getContext(), + android.R.layout.simple_spinner_item, list); + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mSpinnerMyGroup.setAdapter(dataAdapter); + mSpinnerMyGroup.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + getSnsGroupDetail(mSnsMyGroupList.get(position)); + //T.B.D + mCurentList = CurrentList.TOPIC_LIST; + mRcvMemberList.setAdapter(mTopicAdapter); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + } + + public void showDetailGroup(SnsDetailInfo detail) { + if (detail != null) { + mTvTitle.setText(detail.getGroupName()); + mTvGoal.setText(detail.getGoal()); + if (detail.getRunModeActive() == 1) { + mTvRunAcivieMode.setVisibility(View.VISIBLE); + } else { + mTvRunAcivieMode.setVisibility(View.GONE); + } + if (detail.getWalkModeActive() == 1) { + mTvWalkAcivieMode.setVisibility(View.VISIBLE); + } else { + mTvWalkAcivieMode.setVisibility(View.GONE); + } + if (detail.getBikeModeActive() == 1) { + mTvBikeAcivieMode.setVisibility(View.VISIBLE); + } else { + mTvBikeAcivieMode.setVisibility(View.GONE); + } + } else { + mTvTitle.setVisibility(View.INVISIBLE); + mTvGoal.setVisibility(View.INVISIBLE); + mTvRunAcivieMode.setVisibility(View.INVISIBLE); + mTvWalkAcivieMode.setVisibility(View.INVISIBLE); + mTvBikeAcivieMode.setVisibility(View.INVISIBLE); + } + } + + private void getMyGroupList() { + showLoadingDialog(); + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsMyGroup(map).enqueue(new Callback>() { + @Override + public void onResponse(retrofit2.Call> call, retrofit2.Response> response) { + if (response.isSuccessful()) { + mSnsMyGroupList = response.body().getResult(); + setDataSpinnerMyGroup(); + if (!mSnsMyGroupList.isEmpty()) { + mSnsMyGroup = mSnsMyGroupList.get(0); + getSnsGroupDetail(mSnsMyGroupList.get(0)); + } else { + dismissLoadingDialog(); + } + Log.i("SonLT", "Success" + mSnsTopicList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + dismissLoadingDialog(); + } + } + + @Override + public void onFailure(retrofit2.Call> call, Throwable t) { + Log.i("SonLT", "Success"); + dismissLoadingDialog(); + } + }); + } + + private void getSnsGroupDetail(SnsMyGroupInfo myGroup) { + showLoadingDialog(); + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + int groupId = myGroup.getId(); + mService = ApiUtils.getApiService(); + mService.getSnsDetail(map, groupId).enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) { + List mSnsDetailList = response.body().getResult(); + if (mSnsDetailList != null) { + if (mSnsDetailList.size() > 0) { + SnsDetailInfo detailInfo = mSnsDetailList.get(0); + showDetailGroup(detailInfo); + } + } + Debug.normal("SonLT", "getSnsDetail isSuccessful"); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Debug.normal("SonLT", "getSnsDetail isFailure"); + } + dismissLoadingDialog(); + } + + @Override + public void onFailure(Call> call, Throwable t) { + Debug.normal("SonLT", "getSnsDetail onFailure"); + dismissLoadingDialog(); + } + }); + } + + private void getTopicList() { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsTopicList(map).enqueue(new Callback() { + @Override + public void onResponse(retrofit2.Call call, retrofit2.Response response) { + if (response.isSuccessful()) { + mSnsTopicList = response.body().getResult(); + mTopicAdapter.updateData(mSnsTopicList); + mTopicAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsTopicList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(retrofit2.Call call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } + + private void getMemberList(SnsMyGroupInfo myGroup) { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map header = new HashMap<>(); + header.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsMember(header, myGroup.getId()).enqueue(new Callback>() { + @Override + public void onResponse(retrofit2.Call> call, retrofit2.Response> response) { + if (response.isSuccessful()) { + mSnsMemberList = response.body().getResult(); + mMemberAdapter.updateData(mSnsMemberList); + mMemberAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsTopicList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(retrofit2.Call> call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsSearchFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsSearchFragment.java new file mode 100644 index 0000000..47b6b71 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsSearchFragment.java @@ -0,0 +1,138 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.SnsSearchAdapter; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchResponse; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Callback; + +/** + * Created by Admin on 8/18/2017. + */ + +public class SnsSearchFragment extends Fragment { + private ApiService mService; + + private View mRootView; + + @BindView(R.id.rcv_search_result) + RecyclerView mRcvSearch; + SnsSearchAdapter mSearchAdapter; + List mSnsSearchList = new ArrayList<>(); + @BindView(R.id.edt_search_input) + EditText mEdtSearchInput; + @BindView(R.id.btn_search) + Button mBtnSearch; + @BindView(R.id.btn_create_group) + Button mBtnCreateGroup; + @BindView(R.id.pb_seaching) + ProgressBar mPbSearcher; + + private SnsFragment mSnsFragment; + + public void setRootFragment(SnsFragment frag) { + this.mSnsFragment = frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns_search, container, false); + ButterKnife.bind(this, mRootView); + initView(); + return mRootView; + } + + private void initView() { +// mRcvSearch = (RecyclerView) mRootView.findViewById(R.id.rcv_search_result); +// mPbSearcher =(ProgressBar) mRootView.findViewById(R.id.pb_seaching); +// mEdtSearchInput = (EditText) mRootView.findViewById(R.id.edt_search_input); +// mBtnSearch = (Button) m + + mSearchAdapter = new SnsSearchAdapter(getActivity(), mSnsSearchList); + final RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); + mRcvSearch.setLayoutManager(mLayoutManager); + mRcvSearch.setAdapter(mSearchAdapter); + mSearchAdapter.setOnItemClickListener(new SnsSearchAdapter.ItemClickListener() { + @Override + public void onItemClick(int position) { + Log.i("SonLT", "Item in adapter clicked " + position); + if ((mSnsFragment != null) && !mSnsSearchList.isEmpty()) { + mSnsFragment.showSnsDetailFragment(mSnsSearchList.get(position)); + } + } + }); + + mPbSearcher.setVisibility(View.GONE); + mBtnSearch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + handlerSearchAction(mEdtSearchInput.getText().toString(), 0); + } + }); + } + + @OnClick(R.id.btn_create_group) + public void createGroup(){ + mSnsFragment.showSnsCreateGroupFragment(); + } + + private void handlerSearchAction(String keyword, int page) { + mPbSearcher.setVisibility(View.VISIBLE); + mSearchAdapter.clearData(); + mSearchAdapter.notifyDataSetChanged(); + + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsSearchList(map, keyword, page).enqueue(new Callback() { + @Override + public void onResponse(retrofit2.Call call, retrofit2.Response response) { + if (response.isSuccessful()) { + mSnsSearchList = response.body().getResult(); + mSearchAdapter.updateData(mSnsSearchList); + mSearchAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsSearchList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + + mPbSearcher.setVisibility(View.GONE); + } + + @Override + public void onFailure(retrofit2.Call call, Throwable t) { + Log.i("SonLT", "Success"); + + mPbSearcher.setVisibility(View.GONE); + } + }); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsTopicFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsTopicFragment.java new file mode 100644 index 0000000..a4008d3 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/SnsTopicFragment.java @@ -0,0 +1,171 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.adapter.SnsTopicAdapter; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicResponse; +import com.dinhcv.lifelogpedometer.network.ApiService; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.portal.APIResponse; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import butterknife.ButterKnife; +import butterknife.OnClick; +import retrofit2.Callback; + +/** + * Created by Admin on 8/18/2017. + */ + +public class SnsTopicFragment extends FragmentBase { + private ApiService mService; + private View mRootView; + private RecyclerView mRcvRank; + private SnsTopicAdapter mMainAdapter; + private Button mBtnRecommendedGroup; + private List mSnsTopicList = new ArrayList<>(); + private SwipeRefreshLayout mSwipeRefreshTopic; + + private SnsFragment mSnsFragment; + + public void setRootFragment(SnsFragment frag) { + this.mSnsFragment = frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + mRootView = inflater.inflate(R.layout.fragment_sns_topic, container, false); + ButterKnife.bind(this, mRootView); + initView(); + initData(); + return mRootView; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + Log.i("SonLT FR", "onAttach"); + } + + @Override + public void onDetach() { + super.onDetach(); + Log.i("SonLT FR", "onAttach"); + } + + @Override + public void onPause() { + super.onPause(); + Log.i("SonLT FR", "onPause"); + } + + @Override + public void onResume() { + super.onResume(); + Log.i("SonLT FR", "onResume"); + } + + @Override + public void onStart() { + super.onStart(); + Log.i("SonLT FR", "onStart"); + } + + @Override + public void onStop() { + super.onStop(); + Log.i("SonLT FR", "onStop"); + } + + private void initView() { + mMainAdapter = new SnsTopicAdapter(getActivity(), mSnsTopicList); + final RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); + mRcvRank = (RecyclerView) mRootView.findViewById(R.id.rcv_topic); + mRcvRank.setLayoutManager(mLayoutManager); + mRcvRank.setAdapter(mMainAdapter); + + mBtnRecommendedGroup = (Button) mRootView.findViewById(R.id.btn_recommended_group); + mBtnRecommendedGroup.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mSnsFragment.showSnsSearchFragment(); + } + }); + + mSwipeRefreshTopic = (SwipeRefreshLayout) mRootView.findViewById(R.id.swipe_topic); + mSwipeRefreshTopic.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + getTopicList(); + } + }); + } + + @OnClick(R.id.btn_my_group) + public void showMyGroup(){ + mSnsFragment.showSnsMyGroupFragment(); + } + + /** + * Init data + */ + private void initData() { + if (mSnsTopicList.size() == 0) { + getTopicList(); + } else { + + } + } + + private void getTopicList() { + if (!mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(true); + } + Map map = new HashMap<>(); + map.put("token", APIResponse.getInstance().getToken()); + mService = ApiUtils.getApiService(); + mService.getSnsTopicList(map).enqueue(new Callback() { + @Override + public void onResponse(retrofit2.Call call, retrofit2.Response response) { + if (response.isSuccessful()) { + mSnsTopicList = response.body().getResult(); + mMainAdapter.updateData(mSnsTopicList); + mMainAdapter.notifyDataSetChanged(); + Log.i("SonLT", "Success" + mSnsTopicList.size()); + } else { + int statusCode = response.code(); + // handle request errors depending on status code + Log.i("SonLT", "Fail " + statusCode); + } + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + + @Override + public void onFailure(retrofit2.Call call, Throwable t) { + Log.i("SonLT", "Success"); + if (mSwipeRefreshTopic.isRefreshing()) { + mSwipeRefreshTopic.setRefreshing(false); + } + } + }); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepDetector.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepDetector.java new file mode 100644 index 0000000..5880211 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepDetector.java @@ -0,0 +1,65 @@ +package com.dinhcv.lifelogpedometer.activity; + +public class StepDetector { + + private static final int ACCEL_RING_SIZE = 50; + private static final int VEL_RING_SIZE = 10; + + // change this threshold according to your sensitivity preferences + private static final float STEP_THRESHOLD = 50f; + + private static final int STEP_DELAY_NS = 250000000; + + private int accelRingCounter = 0; + private float[] accelRingX = new float[ACCEL_RING_SIZE]; + private float[] accelRingY = new float[ACCEL_RING_SIZE]; + private float[] accelRingZ = new float[ACCEL_RING_SIZE]; + private int velRingCounter = 0; + private float[] velRing = new float[VEL_RING_SIZE]; + private long lastStepTimeNs = 0; + private float oldVelocityEstimate = 0; + + private StepListener listener; + + public void registerListener(StepListener listener) { + this.listener = listener; + } + + + public void updateAccel(long timeNs, float x, float y, float z) { + float[] currentAccel = new float[3]; + currentAccel[0] = x; + currentAccel[1] = y; + currentAccel[2] = z; + + // First step is to update our guess of where the global z vector is. + accelRingCounter++; + accelRingX[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[0]; + accelRingY[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[1]; + accelRingZ[accelRingCounter % ACCEL_RING_SIZE] = currentAccel[2]; + + float[] worldZ = new float[3]; + worldZ[0] = SensorFilter.sum(accelRingX) / Math.min(accelRingCounter, ACCEL_RING_SIZE); + worldZ[1] = SensorFilter.sum(accelRingY) / Math.min(accelRingCounter, ACCEL_RING_SIZE); + worldZ[2] = SensorFilter.sum(accelRingZ) / Math.min(accelRingCounter, ACCEL_RING_SIZE); + + float normalization_factor = SensorFilter.norm(worldZ); + + worldZ[0] = worldZ[0] / normalization_factor; + worldZ[1] = worldZ[1] / normalization_factor; + worldZ[2] = worldZ[2] / normalization_factor; + + float currentZ = SensorFilter.dot(worldZ, currentAccel) - normalization_factor; + velRingCounter++; + velRing[velRingCounter % VEL_RING_SIZE] = currentZ; + + float velocityEstimate = SensorFilter.sum(velRing); + + if (velocityEstimate > STEP_THRESHOLD && oldVelocityEstimate <= STEP_THRESHOLD + && (timeNs - lastStepTimeNs > STEP_DELAY_NS)) { + listener.step(timeNs); + lastStepTimeNs = timeNs; + } + oldVelocityEstimate = velocityEstimate; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepListener.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepListener.java new file mode 100644 index 0000000..980765a --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/StepListener.java @@ -0,0 +1,7 @@ +package com.dinhcv.lifelogpedometer.activity; + +public interface StepListener { + + public void step(long timeNs); + +} \ No newline at end of file diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/TopFragment.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/TopFragment.java new file mode 100644 index 0000000..2c47d9b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/TopFragment.java @@ -0,0 +1,379 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.DatePicker; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.feature.Database; +import com.dinhcv.lifelogpedometer.model.StepModel; +import com.dinhcv.lifelogpedometer.utils.Const; +import com.dinhcv.lifelogpedometer.utils.DayAxisValueFormatter; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; + +import com.github.mikephil.charting.charts.BarChart; +import com.github.mikephil.charting.data.BarData; +import com.github.mikephil.charting.data.BarDataSet; +import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.interfaces.datasets.IBarDataSet; + +import org.eazegraph.lib.charts.PieChart; +import org.eazegraph.lib.models.PieModel; + +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import static com.github.mikephil.charting.utils.ColorTemplate.rgb; + + +public class TopFragment extends FragmentBase implements SettingFragmentPresenter { + + private TextView stepsView; + private TextView tvDistance; + private TextView tvStepRemain; + private TextView tvStepRateDone; + private boolean showSteps = true; + private PieModel sliceGoal, sliceCurrent; + private PieChart pg; + private TextView tvDate; + private ImageView ivBack; + private ImageView ivNext; + private ImageView ivPlay; + + + private Date mAnaDate; + private Calendar mCalendar; + + private int mAnaDay; + private int mAnaMonth; + private int mAnaYear; + + private int todayOffset, total_start, since_boot; + public final static NumberFormat formatter = NumberFormat.getInstance(Locale.getDefault()); + public static int STEP_SIZE = 75; + private StepModel mStepModel; + private TextView tvSmallRemain; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, + final Bundle savedInstanceState) { + final View v = inflater.inflate(com.dinhcv.lifelogpedometer.R.layout.fragment_top, null); + stepsView = (TextView) v.findViewById(R.id.steps); + tvDistance = (TextView) v.findViewById(R.id.tv_distance); + tvStepRemain = (TextView) v.findViewById(R.id.tv_stepRemain); + tvStepRateDone = (TextView) v.findViewById(R.id.tv_stepRateDone); + tvSmallRemain = (TextView) v.findViewById(R.id.tv_smallRemain); + tvDate = (TextView) v.findViewById(R.id.tv_date); + ivBack = (ImageView) v.findViewById(R.id.iv_back); + ivNext = (ImageView) v.findViewById(R.id.iv_next); + ivPlay = (ImageView) v.findViewById(R.id.iv_play); + + mChart = (BarChart) v.findViewById(R.id.chart); + pg = (PieChart) v.findViewById(R.id.graph); + + // slice for the steps taken today + sliceCurrent = new PieModel("", 0, Color.parseColor("#6FE7F7")); + pg.addPieSlice(sliceCurrent); + + // slice for the "missing" steps until reaching the goal + sliceGoal = new PieModel("", Const.STEP_GOAL, Color.parseColor("#B7B8B6")); + pg.addPieSlice(sliceGoal); + pg.setDrawValueInPie(false); + pg.setUsePieRotation(false); + pg.startAnimation(); + pg.setAutoCenterInSlice(false); + + mCalendar = Calendar.getInstance(); + mCalendar.setTime(new Date()); + mAnaDate = mCalendar.getTime(); + mAnaYear = mCalendar.get(Calendar.YEAR); + mAnaMonth = mCalendar.get(Calendar.MONTH); + mAnaDay = mCalendar.get(Calendar.DAY_OF_MONTH); + + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(mAnaDate)); + + handleEvent(); + + return v; + } + + private void stepsDistanceChanged() { + updatePie(); + updateBars(); + } + + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + inflater.inflate(R.menu.main, menu); + } + + + private void updatePie() { + // todayOffset might still be Integer.MIN_VALUE on first start + int steps_today = Math.max(todayOffset + since_boot, 0); + sliceCurrent.setValue(steps_today); + if (Const.STEP_GOAL - steps_today > 0) { + // goal not reached yet + if (pg.getData().size() == 1) { + pg.addPieSlice(sliceGoal); + } + sliceGoal.setValue(Const.STEP_GOAL - steps_today); + } else { + // goal reached + pg.clearChart(); + pg.addPieSlice(sliceCurrent); + } + pg.update(); + + stepsView.setText(formatter.format(steps_today)); + int remain = Const.STEP_GOAL - steps_today; + tvStepRemain.setText(String.valueOf(remain)); + tvStepRateDone.setText(getResources().getString(R.string.percent_unit, Utils.convert2String2Decimal(steps_today *100/ Const.STEP_GOAL))); + tvSmallRemain.setText(getResources().getString(R.string.pie_text_content3a, remain)); + + double distance_today = steps_today * STEP_SIZE; + distance_today /= 100000; + tvDistance.setText(Utils.convert2String2Decimal(distance_today)); + + } + + /** + * Updates the bar graph to show the steps/distance of the last week. Should + * be called when switching from step count to distance. + */ + private void updateBars() { + + dateList = new ArrayList<>(); + List stepList = new ArrayList<>(); + + Database db = Database.getInstance(getActivity()); + List> last = db.getLastEntries(8, mAnaDate); + db.close(); + for (int i = last.size() - 1; i > 0; i--) { + Pair current = last.get(i); + int step = current.second; + Date date = new Date(current.first); + stepList.add(step); + dateList.add(String.valueOf(Utils.getDay(date))); + } + + mStep = stepList.toArray(new Integer[0]); + mParties = dateList.toArray(new String[0]); + + initGraph(); + } + + private BarChart mChart; + + private List dateList; + private String[] mParties; + private Integer[] mStep; + + private void initGraph(){ + + mChart.setDrawBarShadow(false); + mChart.setDrawValueAboveBar(true); + + // if more than 60 entries are displayed in the chart, no values will be + // drawn + mChart.setMaxVisibleValueCount(60); + + mChart.getDescription().setEnabled(false); + // scaling can now only be done on x- and y-axis separately + mChart.setPinchZoom(false); + + mChart.setDrawGridBackground(false); + // mChart.setDrawYLabels(false); + + DayAxisValueFormatter xValueFormatter = new DayAxisValueFormatter(dateList); + + XAxis xAxis = mChart.getXAxis(); + xAxis.setLabelRotationAngle(0); + xAxis.setPosition(XAxis.XAxisPosition.TOP); + xAxis.setDrawGridLines(true); + xAxis.setLabelCount(10); + xAxis.setTextColor(Color.WHITE); + xAxis.setValueFormatter(xValueFormatter); + + + YAxis leftAxis = mChart.getAxisLeft(); + leftAxis.setDrawLabels(false); + leftAxis.setDrawGridLines(false); + leftAxis.setAxisMinimum(0f); + leftAxis.setAxisMaximum(10000f); + leftAxis.setDrawZeroLine(false); + + leftAxis.setEnabled(false); + mChart.setDrawValueAboveBar(false); + mChart.getAxisRight().setEnabled(false); + + // set auto scale min max + mChart.setAutoScaleMinMaxEnabled(true); + mChart.notifyDataSetChanged(); + + // Set enimate y + mChart.animateY(2000); + + setData(); + + mChart.getLegend().setEnabled(false); + } + + + private void setData() { + + ArrayList xVals = new ArrayList<>(); + for (int i = 0; i < mStep.length; i++) { + xVals.add(mParties[i % mStep.length]); + } + + ArrayList yVals1 = new ArrayList<>(); + for (int i = 0; i < mStep.length; i++) { + float val = (float) (mStep[i]*1); + yVals1.add(new BarEntry(i, val)); + } + + BarDataSet set1; + + if (mChart.getData() != null && mChart.getData().getDataSetCount() > 0) { + set1 = (BarDataSet)mChart.getData().getDataSetByIndex(0); + set1.setValues(yVals1); + mChart.getData().notifyDataChanged(); + mChart.notifyDataSetChanged(); + } else { + ArrayList colors = new ArrayList<>(); + + + int[] MATERIAL_COLORS = {rgb("#40CDEF")}; + + for (int c : MATERIAL_COLORS) + colors.add(c); + + set1 = new BarDataSet(yVals1, null); + + set1.setColors(colors); + + ArrayList dataSets = new ArrayList<>(); + dataSets.add(set1); + + BarData data = new BarData(dataSets); + data.setValueTextSize(10f); + + mChart.setData(data); + } + } + + + + private void handleEvent(){ + tvDate.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + handleAnaDatePicker(); + } + }); + + ivBack.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, -1); + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + } + }); + + ivNext.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mCalendar = Calendar.getInstance(); + mCalendar.setTime(mAnaDate); + mCalendar.add(Calendar.DAY_OF_MONTH, +1); + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + } + }); + + + } + + + /** + * Show date picker dialog + */ + private void handleAnaDatePicker() { + + new DatePickerDialog(getActivity(), new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + + mCalendar = Calendar.getInstance(); + mCalendar.set(year, monthOfYear, dayOfMonth); + mAnaYear = year; + mAnaMonth = monthOfYear; + mAnaDay = dayOfMonth; + Date date = mCalendar.getTime(); + tvDate.setText(Utils.dateToStringFormatDayMonthYearJp(date)); + mAnaDate = date; + } + }, mAnaYear, mAnaMonth, mAnaDay).show(); + + } + + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + } + + private void initData() { + + } + + @Override + public void onSaveData() { + + } + + @Override + public void onInvalidate(boolean isInit) { + initData(); + } + + @Override + public void onViewStateRestored(@Nullable Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + + initData(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/activity/WelcomeActivity.java b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/WelcomeActivity.java new file mode 100644 index 0000000..f01d670 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/activity/WelcomeActivity.java @@ -0,0 +1,104 @@ +package com.dinhcv.lifelogpedometer.activity; + +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.support.v7.app.AlertDialog; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.interfaces.LLAPIManagerListener; +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.portal.LLAPIManager; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import org.json.JSONArray; +import org.json.JSONObject; + + +public class WelcomeActivity extends ActivityBase implements Runnable { + private boolean isRefresh = false; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_welcome); + checkRefreshToken(); + } + + private void checkRefreshToken(){ + int id = Setting.getUserIdSharepre(WelcomeActivity.this); + Debug.normal("String id: "+ id); + if (id != 0){ + handleRefreshToken(id); + }else { + refeshDone(); + } + } + + + private void handleRefreshToken(int id) { + + LLAPIManager.refreshToken(WelcomeActivity.this, id, new LLAPIManagerListener() { + @Override + public void onError(Error error) { + Debug.error("Version JSON result: ERROR " + error); + String err = getResources().getString(R.string.login_error); + isRefresh = false; + refeshDone(); + } + + @Override + public void onSuccess(String json) { + Debug.warn("Version JSON result: " + json.toString()); + isRefresh = true; + refeshDone(); + } + + @Override + public void onSuccess(JSONObject object) { + Debug.warn("Version JSON object result: Success"); + isRefresh = true; + refeshDone(); + } + }); + } + + private void refeshDone(){ + Handler handler = new Handler(); + handler.postDelayed(WelcomeActivity.this, 2000); + } + + private void notifyErr(String err){ + AlertDialog.Builder alertDialog = new AlertDialog.Builder(WelcomeActivity.this); + alertDialog.setMessage(err); + alertDialog.setCancelable(false); + alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + AlertDialog alert = alertDialog.create(); + alert.show(); + } + + @Override + public void run() { + // go to main screen + if ( isRefresh) { + gotoActivity(PedometerActivity.class); + } else { +// Bundle bundle = new Bundle(); +// bundle.putString(Const.URL, url); + gotoActivity(LoginActivity.class); + } + finish(); + } + + @Override + protected void onResume() { + super.onResume(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/HistoryAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/HistoryAdapter.java new file mode 100644 index 0000000..61cae45 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/HistoryAdapter.java @@ -0,0 +1,107 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.history.HistoryItemInfo; +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.util.ArrayList; +import java.util.List; + + +public class HistoryAdapter extends BaseAdapter{ + private List mHistoryItemList = new ArrayList<>(); + private Context mActivity; + + public HistoryAdapter(Context activity, List historyItemInfos){ + mHistoryItemList.clear(); + mHistoryItemList.addAll(historyItemInfos); + mActivity = activity; + + } + + public void changeDataList(List list) { + Debug.normal("Change data of adapter size = " + list.size()); + mHistoryItemList.clear(); + mHistoryItemList.addAll(list); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mHistoryItemList.size(); + } + + @Override + public Object getItem(int postion) { + return postion; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int position, View cvView, ViewGroup viewGroup) { + final HistoryAdapter.ViewHolder viewHolder; + final HistoryItemInfo historyItemInfo = mHistoryItemList.get(position); + Debug.normal("Add view: " + position); + + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + cvView = inflater.inflate(R.layout.dialog_city_list_row, null, false); + viewHolder = new HistoryAdapter.ViewHolder(); + viewHolder.tvDate = (TextView) cvView.findViewById(R.id.tv_date); + viewHolder.tvStep = (TextView) cvView.findViewById(R.id.tv_subStep); + viewHolder.imgType = (ImageView) cvView.findViewById(R.id.img_type); + viewHolder.tvSubStep = (TextView) cvView.findViewById(R.id.tv_deviceId); + viewHolder.tvDistance = (TextView) cvView.findViewById(R.id.tv_distance); + viewHolder.tvKalo = (TextView) cvView.findViewById(R.id.tv_kalo); + viewHolder.tvTime = (TextView) cvView.findViewById(R.id.tv_time); + + if (historyItemInfo != null){ + + //viewHolder.tvDate.setText(String.valueOf(historyItemInfo.getDate())); + viewHolder.tvStep.setText(String.valueOf(historyItemInfo.getSteps())); + if (historyItemInfo.getSubStep() > 0) { + viewHolder.imgType.setImageResource(R.drawable.ic_up); + }else { + viewHolder.imgType.setImageResource(R.drawable.ic_down); + } + viewHolder.tvSubStep.setText(String.valueOf(historyItemInfo.getSubStep())); + viewHolder.tvDistance.setText(Utils.convert2String2Decimal(historyItemInfo.getDistance())); + viewHolder.tvKalo.setText(Utils.convert2String2Decimal(historyItemInfo.getKcal())); + viewHolder.tvTime.setText(Utils.convertTimeStringFromString(historyItemInfo.getTime())); + + cvView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + } + + return cvView; + } + + class ViewHolder { + TextView tvDate; + TextView tvStep; + ImageView imgType; + TextView tvSubStep; + TextView tvDistance; + TextView tvKalo; + TextView tvTime; + } + + + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/NoticeAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/NoticeAdapter.java new file mode 100644 index 0000000..9d4f2ea --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/NoticeAdapter.java @@ -0,0 +1,67 @@ +package com.dinhcv.lifelogpedometer.adapter; + + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.home.NoticeInfo; + +import java.util.List; + +public class NoticeAdapter extends BaseAdapter { + private Context context; + private List listNotice; + + public NoticeAdapter(Context context, List list) { + this.context = context; + this.listNotice = list; + } + + @Override + public int getCount() { + return listNotice.size(); + } + + @Override + public Object getItem(int position) { + return listNotice.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(final int position, final View convertView, ViewGroup parent) { + final ViewHolder viewHolder; + View view = convertView; + if (view == null) { + viewHolder = new ViewHolder(); + view = LayoutInflater.from(context).inflate(R.layout.notice_list_item, null); + viewHolder.tvContent = (TextView) view.findViewById(R.id.tv_content); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); + } + + + final NoticeInfo noticeInfo = listNotice.get(position); + if (noticeInfo != null) { + viewHolder.tvContent.setText(noticeInfo.getContent()); + } + + return view; + } + + private class ViewHolder { + TextView tvContent; + } + +} + diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/RankingAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/RankingAdapter.java new file mode 100644 index 0000000..06749e6 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/RankingAdapter.java @@ -0,0 +1,102 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.app.Activity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.pojo.RankingInfo; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.squareup.picasso.Picasso; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Admin on 8/17/2017. + */ + +public class RankingAdapter extends RecyclerView.Adapter { + private List mRankingInfoList = new ArrayList<>(); + private Activity mActivity; + + public class MyViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.tv_position) + TextView mTvPosition; + @BindView(R.id.imv_user_icon) + ImageView mImvUserIcon; + @BindView(R.id.tv_time) + TextView mTvTime; + @BindView(R.id.tv_steps) + TextView mTvSteps; + @BindView(R.id.tv_distance) + TextView mTvDistance; + @BindView(R.id.imv_position) + ImageView mImvPosition; + + public MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + + public RankingAdapter(Activity activity, List list) { + mActivity = activity; + mRankingInfoList.clear(); + mRankingInfoList.addAll(list); + } + + public void updateData(List list) { + mRankingInfoList.clear(); + mRankingInfoList.addAll(list); + } + + public void clearData() { + mRankingInfoList.clear(); + } + + @Override + public RankingAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_rank_row, parent, false); + + return new RankingAdapter.MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(RankingAdapter.MyViewHolder holder, int position) { + RankingInfo rankingInfo = mRankingInfoList.get(position); + holder.mTvPosition.setText(rankingInfo.getRank()+""); + holder.mTvTime.setText(Utils.convertSecond2HourMinSecString(rankingInfo.getTime())); + holder.mTvSteps.setText(rankingInfo.getSteps() + " 歩"); + holder.mTvDistance.setText(rankingInfo.getDistance() + " km"); + if (rankingInfo.getProfileImage() != null && !rankingInfo.getProfileImage().toString().isEmpty()) { + Picasso.with(mActivity).load(ApiUtils.BASE_URL + rankingInfo.getProfileImage().toString()).into( + holder.mImvUserIcon); + } + switch (rankingInfo.getRank()) { + case 1: + holder.mImvPosition.setBackground(Utils.getDrawableWrapper(mActivity, R.drawable.ic_first)); + break; + case 2: + holder.mImvPosition.setBackground(Utils.getDrawableWrapper(mActivity, R.drawable.ic_second)); + break; + case 3: + holder.mImvPosition.setBackground(Utils.getDrawableWrapper(mActivity, R.drawable.ic_third)); + break; + } + } + + @Override + public int getItemCount() { + return mRankingInfoList.size(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SelectBoxListAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SelectBoxListAdapter.java new file mode 100644 index 0000000..57461fb --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SelectBoxListAdapter.java @@ -0,0 +1,100 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.app.Dialog; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.interfaces.OnSelectResultListener; +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; +import com.dinhcv.lifelogpedometer.utils.Debug; + +import java.util.ArrayList; +import java.util.List; + +public class SelectBoxListAdapter extends BaseAdapter{ + + List mSelectItemInfoList = new ArrayList<>(); + private Context mActivity; + private OnSelectResultListener mListener; + private Dialog mDialog; + + public SelectBoxListAdapter(List selectItemInfos, Context activity, Dialog dialog, OnSelectResultListener listener){ + mSelectItemInfoList.clear(); + mSelectItemInfoList.addAll(selectItemInfos); + mActivity = activity; + + mListener = listener; + mDialog = dialog; + } + + public void changeDataList(List list) { + Debug.normal("Change data of adapter size = " + list.size()); + mSelectItemInfoList.clear(); + mSelectItemInfoList.addAll(list); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mSelectItemInfoList.size(); + } + + @Override + public Object getItem(int postion) { + return postion; + } + + @Override + public long getItemId(int i) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup viewGroup) { + final SelectBoxListAdapter.ViewHolder viewHolder; + final SelectItemInfo selectItemInfo = mSelectItemInfoList.get(position); + Debug.normal("Add view: " + position); + + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.dialog_city_list_row, null, false); + viewHolder = new SelectBoxListAdapter.ViewHolder(); + viewHolder.llRow = (LinearLayout) convertView.findViewById(R.id.ll_row); + viewHolder.tvId = (TextView) convertView.findViewById(R.id.tv_deviceId); + viewHolder.tvName = (TextView) convertView.findViewById(R.id.tv_name); + + if (selectItemInfo != null){ + + //set other background by odd/even + convertView.setBackgroundResource((position % 2 == 0) ? + R.drawable.table_background_row_even_selector : + R.drawable.table_background_row_odd_selector); + viewHolder.tvId.setText(String.valueOf(selectItemInfo.getId())); + viewHolder.tvName.setText(selectItemInfo.getName()); + + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mListener != null) { + mListener.onSelectedItem(selectItemInfo); + } + mDialog.dismiss(); + } + }); + } + + return convertView; + } + + class ViewHolder { + LinearLayout llRow; + TextView tvId; + TextView tvName; + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsMemberAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsMemberAdapter.java new file mode 100644 index 0000000..6fb5438 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsMemberAdapter.java @@ -0,0 +1,79 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.app.Activity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsMemberInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.squareup.picasso.Picasso; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsMemberAdapter extends RecyclerView.Adapter { + private List mSnsMemberList = new ArrayList<>(); + private Activity mActivity; + + public class MyViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.imv_user_icon) ImageView mImvUserIcon; + @BindView(R.id.tv_username) TextView mTvUserName; + + public MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + public SnsMemberAdapter(Activity activity, List list) { + mActivity = activity; + + mSnsMemberList.clear(); + mSnsMemberList.addAll(list); + } + + public void updateData(List list) { + mSnsMemberList.clear(); + mSnsMemberList.addAll(list); + } + public void clearData() { + mSnsMemberList.clear(); + } + + @Override + public SnsMemberAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_sns_member_row, parent, false); + + return new SnsMemberAdapter.MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(SnsMemberAdapter.MyViewHolder holder, int position) { + SnsMemberInfo member = mSnsMemberList.get(position); + if (member.getProfileImage() != null && !member.getProfileImage().toString().isEmpty()){ + Picasso.with(mActivity).load(ApiUtils.BASE_URL+member.getProfileImage().toString()).into( + holder.mImvUserIcon); + } + holder.mTvUserName.setText(member.getUsername()); + } + + @Override + public int getItemCount() { + return mSnsMemberList.size(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsSearchAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsSearchAdapter.java new file mode 100644 index 0000000..23157d1 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsSearchAdapter.java @@ -0,0 +1,91 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.app.Activity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.activity.SnsFragment; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsSearchInfo; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsSearchAdapter extends RecyclerView.Adapter { + private List mSnsSearchList = new ArrayList<>(); + private ItemClickListener mItemClickListener; + private Activity mActivity; + + public class MyViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.imv_user_icon) ImageView mImvUserIcon; + @BindView(R.id.tv_title) TextView mTvTitle; + View mRootView; + + public MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + mRootView = view; + } + } + + public SnsSearchAdapter(Activity activity, List list) { + mActivity = activity; + + mSnsSearchList.clear(); + mSnsSearchList.addAll(list); + } + + public void updateData(List list) { + mSnsSearchList.clear(); + mSnsSearchList.addAll(list); + } + public void clearData(){ + mSnsSearchList.clear(); + } + public void setOnItemClickListener(ItemClickListener listener){ + this.mItemClickListener = listener; + } + + @Override + public SnsSearchAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_sns_search_row, parent, false); + + return new SnsSearchAdapter.MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(SnsSearchAdapter.MyViewHolder holder, final int position) { + SnsSearchInfo search = mSnsSearchList.get(position); + holder.mTvTitle.setText(search.getGroupName()); + holder.mRootView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(mItemClickListener != null){ + mItemClickListener.onItemClick(position); + } + } + }); + } + + @Override + public int getItemCount() { + return mSnsSearchList.size(); + } + + public interface ItemClickListener{ + void onItemClick(int position); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsTopicAdapter.java b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsTopicAdapter.java new file mode 100644 index 0000000..023b4d4 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/adapter/SnsTopicAdapter.java @@ -0,0 +1,90 @@ +package com.dinhcv.lifelogpedometer.adapter; + +import android.app.Activity; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.activity.SnsFragment; +import com.dinhcv.lifelogpedometer.model.structure.pojo.SnsTopicInfo; +import com.dinhcv.lifelogpedometer.network.ApiUtils; +import com.dinhcv.lifelogpedometer.utils.Utils; +import com.squareup.picasso.Picasso; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Admin on 8/17/2017. + */ + +public class SnsTopicAdapter extends RecyclerView.Adapter { + private List mSnsTopicList = new ArrayList<>(); + private Activity mActivity; + + public class MyViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.imv_user_icon) ImageView mImvUserIcon; + @BindView(R.id.tv_start_date) TextView mTvCreateDate; + @BindView(R.id.tv_start_time) TextView mTvCreateTime; + @BindView(R.id.tv_user_name) TextView mTvUsername; + @BindView(R.id.tv_message) TextView mTvMessage; + @BindView(R.id.tv_distance) TextView mTvDistance; + @BindView(R.id.tv_duration) TextView mTvTime; + + public MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + public SnsTopicAdapter(Activity activity, List list) { + mActivity = activity; + + mSnsTopicList.clear(); + mSnsTopicList.addAll(list); + } + + public void updateData(List list) { + mSnsTopicList.clear(); + mSnsTopicList.addAll(list); + } + + public void clearData() { + mSnsTopicList.clear(); + } + @Override + public SnsTopicAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_sns_topic_row, parent, false); + + return new SnsTopicAdapter.MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(SnsTopicAdapter.MyViewHolder holder, int position) { + SnsTopicInfo topic = mSnsTopicList.get(position); + Date date = Utils.convertString2Date(topic.getCreatedAt()); + if (topic.getProfileImage() != null && !topic.getProfileImage().toString().isEmpty()){ + Picasso.with(mActivity).load(ApiUtils.BASE_URL+topic.getProfileImage().toString()).into( + holder.mImvUserIcon); + } + holder.mTvCreateDate.setText(Utils.convertDate2DayString(date)+""); + holder.mTvCreateTime.setText(Utils.convertDate2TimeString(date)+""); + holder.mTvUsername.setText(topic.getUsername()+""); + holder.mTvMessage.setText(topic.getTweetContent()+""); + holder.mTvDistance.setText(topic.getDistance()+"m"); + holder.mTvTime.setText(topic.getTime()+""); + } + + @Override + public int getItemCount() { + return mSnsTopicList.size(); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/customview/ExpandableListCustomView.java b/app/src/main/java/com/dinhcv/lifelogpedometer/customview/ExpandableListCustomView.java new file mode 100644 index 0000000..1d3dc5b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/customview/ExpandableListCustomView.java @@ -0,0 +1,40 @@ +package com.dinhcv.lifelogpedometer.customview; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.widget.ListView; + +public class ExpandableListCustomView extends ListView { + + boolean expanded = false; + + public ExpandableListCustomView(Context context) { + super(context); + } + + public ExpandableListCustomView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ExpandableListCustomView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public boolean isExpanded() { + return expanded; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + + ViewGroup.LayoutParams params = getLayoutParams(); + params.height = getMeasuredHeight(); + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/customview/SimpleSelectBoxDialogBuilder.java b/app/src/main/java/com/dinhcv/lifelogpedometer/customview/SimpleSelectBoxDialogBuilder.java new file mode 100644 index 0000000..1aa6aa5 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/customview/SimpleSelectBoxDialogBuilder.java @@ -0,0 +1,71 @@ +package com.dinhcv.lifelogpedometer.customview; + +import android.app.Dialog; +import android.content.Context; +import android.view.View; +import android.widget.ListView; +import android.widget.TextView; + +import com.dinhcv.lifelogpedometer.R; +import com.dinhcv.lifelogpedometer.activity.DialogBase; +import com.dinhcv.lifelogpedometer.adapter.SelectBoxListAdapter; +import com.dinhcv.lifelogpedometer.interfaces.OnSelectResultListener; +import com.dinhcv.lifelogpedometer.model.structure.SelectItemInfo; + +import java.util.List; + + +public class SimpleSelectBoxDialogBuilder +{ + + private ListView lvOccupation; + + private Dialog mDialog = null; + private List mCityInfoList; + private Context mContext; + private OnSelectResultListener listener; + private String mTitle; + + + public Dialog create(Context cnt, String title, List selectItemInfos, OnSelectResultListener onSelectResult) + { + mCityInfoList = selectItemInfos; + mContext = cnt; + listener = onSelectResult; + mTitle = title; + + //create the actual dialog + mDialog = new DialogBase(cnt); + + //override layout + mDialog.setContentView(R.layout.dialog_city_simple_list); + + + initView(); + initData(); + + return mDialog; + } + + private void initView() { + + lvOccupation = (ListView) mDialog.findViewById(R.id.lv_deviceList); + TextView title = (TextView) mDialog.findViewById(R.id.tv_nameDefault); + + title.setText(mTitle); + mDialog.findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mDialog.dismiss(); + } + }); + } + + private void initData(){ + + SelectBoxListAdapter mCityAdapter = new SelectBoxListAdapter(mCityInfoList, mContext, mDialog, listener); + lvOccupation.setAdapter(mCityAdapter); + mCityAdapter.notifyDataSetChanged(); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/AppUpdatedReceiver.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/AppUpdatedReceiver.java new file mode 100644 index 0000000..31c7116 --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/AppUpdatedReceiver.java @@ -0,0 +1,14 @@ +package com.dinhcv.lifelogpedometer.feature; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.support.v4.BuildConfig; + +public class AppUpdatedReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, final Intent intent) { + context.startService(new Intent(context, SensorListener.class)); + } + +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/BootReceiver.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/BootReceiver.java new file mode 100644 index 0000000..0e7743b --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/BootReceiver.java @@ -0,0 +1,32 @@ +package com.dinhcv.lifelogpedometer.feature; + + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.support.v4.BuildConfig; + +import com.dinhcv.lifelogpedometer.model.Shareprefer.Setting; +import com.dinhcv.lifelogpedometer.utils.Const; + + +public class BootReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, final Intent intent) { + Database db = Database.getInstance(context); + + if (!Setting.getPedometerCorrectShutdown(context, false)) { + int steps = db.getCurrentSteps(); + db.addToLastEntry(steps); + } + db.removeNegativeEntries(); + db.saveCurrentSteps(0); + db.close(); + + Setting.removePedometer(context, Setting.CORRECTSHUTDOWN); + + context.startService(new Intent(context, SensorListener.class)); + } +} diff --git a/app/src/main/java/com/dinhcv/lifelogpedometer/feature/Database.java b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/Database.java new file mode 100644 index 0000000..aff5dfb --- /dev/null +++ b/app/src/main/java/com/dinhcv/lifelogpedometer/feature/Database.java @@ -0,0 +1,399 @@ +package com.dinhcv.lifelogpedometer.feature; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.v4.BuildConfig; +import android.util.Pair; + +import com.dinhcv.lifelogpedometer.utils.Debug; +import com.dinhcv.lifelogpedometer.utils.Utils; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class Database extends SQLiteOpenHelper { + + private final static String DB_NAME = "steps"; + private final static int DB_VERSION = 2; + + private static Database instance; + private static final AtomicInteger openCounter = new AtomicInteger(); + + private Database(final Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + public static synchronized Database getInstance(final Context c) { + if (instance == null) { + instance = new Database(c.getApplicationContext()); + } + openCounter.incrementAndGet(); + return instance; + } + + @Override + public void close() { + if (openCounter.decrementAndGet() == 0) { + super.close(); + } + } + + @Override + public void onCreate(final SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + DB_NAME + " (date INTEGER, steps INTEGER)"); + } + + @Override + public void onUpgrade(final SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion == 1) { + // drop PRIMARY KEY constraint + db.execSQL("CREATE TABLE " + DB_NAME + "2 (date INTEGER, steps INTEGER)"); + db.execSQL("INSERT INTO " + DB_NAME + "2 (date, steps) SELECT date, steps FROM " + + DB_NAME); + db.execSQL("DROP TABLE " + DB_NAME); + db.execSQL("ALTER TABLE " + DB_NAME + "2 RENAME TO " + DB_NAME + ""); + } + } + + /** + * Query the 'steps' table. Remember to close the cursor! + * + * @param columns the colums + * @param selection the selection + * @param selectionArgs the selction arguments + * @param groupBy the group by statement + * @param having the having statement + * @param orderBy the order by statement + * @return the cursor + */ + public Cursor query(final String[] columns, final String selection, + final String[] selectionArgs, final String groupBy, final String having, + final String orderBy, final String limit) { + return getReadableDatabase() + .query(DB_NAME, columns, selection, selectionArgs, groupBy, having, orderBy, limit); + } + + public void insertNewDay(long date, int steps) { + getWritableDatabase().beginTransaction(); + try { + Cursor c = getReadableDatabase().query(DB_NAME, new String[]{"date"}, "date = ?", + new String[]{String.valueOf(date)}, null, null, null); + if (c.getCount() == 0 && steps >= 0) { + + // add 'steps' to yesterdays count + addToLastEntry(steps); + + // add today + ContentValues values = new ContentValues(); + values.put("date", date); + // use the negative steps as offset + values.put("steps", -steps); + getWritableDatabase().insert(DB_NAME, null, values); + } + c.close(); + getWritableDatabase().setTransactionSuccessful(); + } finally { + getWritableDatabase().endTransaction(); + } + } + + /** + * Adds the given number of steps to the last entry in the database + * + * @param steps the number of steps to add. Must be > 0 + */ + public void addToLastEntry(int steps) { + if (steps > 0) { + getWritableDatabase().execSQL("UPDATE " + DB_NAME + " SET steps = steps + " + steps + + " WHERE date = (SELECT MAX(date) FROM " + DB_NAME + ")"); + } + } + + /** + * Inserts a new entry in the database, if there is no entry for the given + * date yet. Use this method for restoring data from a backup. + *