From 0d42da010ce4551a3f1fdce078b6c0b8999675d9 Mon Sep 17 00:00:00 2001 From: Christopher Beckmann Date: Fri, 8 Sep 2017 17:05:48 +0200 Subject: [PATCH] Exercises can now be done. A Notification will be displayed when the timer is done. The Exercise Dialog is added. --- app/src/main/AndroidManifest.xml | 97 ++-- .../activities/AboutActivity.java | 39 +- .../activities/ExerciseActivity.java | 414 +++++++++++++++++- .../ManageExerciseSetsActivity.java | 4 +- .../activities/TimerActivity.java | 4 + .../activities/adapter/ExerciseAdapter.java | 18 +- .../adapter/ExerciseSetAdapter.java | 25 +- .../adapter/ExerciseSetSpinnerAdapter.java | 13 +- .../activities/helper/BaseActivity.java | 8 +- .../activities/old/BreakReminder.java | 7 +- .../{ => old}/SettingsActivity.java | 2 +- .../database/data/Exercise.java | 18 + .../dialog/ExerciseDialog.java | 62 +++ .../service/TimerService.java | 47 +- .../main/res/drawable/bg_splash_screen.xml | 2 +- app/src/main/res/layout/about.xml | 120 ----- app/src/main/res/layout/activity_about.xml | 145 ++++++ app/src/main/res/layout/activity_exercise.xml | 67 ++- app/src/main/res/layout/activity_help.xml | 12 +- .../layout/activity_manage_exercise_set.xml | 8 +- app/src/main/res/layout/activity_timer.xml | 25 +- app/src/main/res/layout/dialog_exercise.xml | 100 +++++ app/src/main/res/layout/layout_exercise.xml | 81 ---- app/src/main/res/layout/nav_header.xml | 2 +- app/src/main/res/layout/tutorial_slide1.xml | 2 +- app/src/main/res/layout/tutorial_slide2.xml | 2 +- app/src/main/res/layout/tutorial_slide3.xml | 2 +- .../main/res/menu/menu_activity_exercise.xml | 11 + app/src/main/res/menu/nav_drawer.xml | 4 +- .../{ic_drawer_logo.png => ic_app.png} | Bin .../{splash_icon.png => ic_splash.png} | Bin .../{ic_drawer_logo.png => ic_app.png} | Bin .../{splash_icon.png => ic_splash.png} | Bin .../{ic_drawer_logo.png => ic_app.png} | Bin .../{splash_icon.png => ic_splash.png} | Bin .../{ic_drawer_logo.png => ic_app.png} | Bin .../{splash_icon.png => ic_splash.png} | Bin .../{ic_drawer_logo.png => ic_app.png} | Bin .../{splash_icon.png => ic_splash.png} | Bin app/src/main/res/values-de/strings.xml | 3 +- app/src/main/res/values-fr/strings.xml | 3 +- app/src/main/res/values-ru/strings.xml | 3 +- app/src/main/res/values/strings.xml | 15 +- app/src/main/res/xml/pref_headers.xml | 4 +- 44 files changed, 999 insertions(+), 370 deletions(-) rename app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/{ => old}/SettingsActivity.java (99%) create mode 100644 app/src/main/java/org/secuso/privacyfriendlybreakreminder/dialog/ExerciseDialog.java delete mode 100644 app/src/main/res/layout/about.xml create mode 100644 app/src/main/res/layout/activity_about.xml create mode 100644 app/src/main/res/layout/dialog_exercise.xml delete mode 100644 app/src/main/res/layout/layout_exercise.xml create mode 100644 app/src/main/res/menu/menu_activity_exercise.xml rename app/src/main/res/mipmap-hdpi/{ic_drawer_logo.png => ic_app.png} (100%) rename app/src/main/res/mipmap-hdpi/{splash_icon.png => ic_splash.png} (100%) rename app/src/main/res/mipmap-mdpi/{ic_drawer_logo.png => ic_app.png} (100%) rename app/src/main/res/mipmap-mdpi/{splash_icon.png => ic_splash.png} (100%) rename app/src/main/res/mipmap-xhdpi/{ic_drawer_logo.png => ic_app.png} (100%) rename app/src/main/res/mipmap-xhdpi/{splash_icon.png => ic_splash.png} (100%) rename app/src/main/res/mipmap-xxhdpi/{ic_drawer_logo.png => ic_app.png} (100%) rename app/src/main/res/mipmap-xxhdpi/{splash_icon.png => ic_splash.png} (100%) rename app/src/main/res/mipmap-xxxhdpi/{ic_drawer_logo.png => ic_app.png} (100%) rename app/src/main/res/mipmap-xxxhdpi/{splash_icon.png => ic_splash.png} (100%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index db8df51..757ca78 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ - + - - - - - - @@ -32,24 +21,10 @@ android:name="android.support.PARENT_ACTIVITY" android:value="org.secuso.privacyfriendlybreakreminder.activities.old.BreakReminder" /> + - - - - - + android:theme="@style/SplashTheme" + android:screenOrientation="portrait"> @@ -75,30 +50,35 @@ - - + android:theme="@style/AppTheme.NoActionBar" + android:parentActivityName=".activities.TimerActivity" + android:screenOrientation="portrait"> + + + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait" /> + + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait"> + android:label="" + android:parentActivityName=".activities.TimerActivity" + android:screenOrientation="portrait"> @@ -107,20 +87,49 @@ android:name=".activities.EditExerciseSetActivity" android:label="@string/activity_title_edit_exercise_set" android:parentActivityName=".activities.ManageExerciseSetsActivity" - android:theme="@style/AppTheme.NoActionBar"> + android:theme="@style/AppTheme.NoActionBar" + android:screenOrientation="portrait"> - + android:parentActivityName=".activities.EditExerciseSetActivity" + android:screenOrientation="portrait"> > - + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/AboutActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/AboutActivity.java index 099f31b..98f1791 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/AboutActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/AboutActivity.java @@ -1,6 +1,7 @@ package org.secuso.privacyfriendlybreakreminder.activities; import android.os.Bundle; +import android.os.Handler; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.text.method.LinkMovementMethod; @@ -12,12 +13,17 @@ import org.secuso.privacyfriendlybreakreminder.R; public class AboutActivity extends AppCompatActivity { + Handler mHandler; + View mainContent; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.about); + setContentView(R.layout.activity_about); - View mainContent = findViewById(R.id.main_content); + mHandler = new Handler(); + + mainContent = findViewById(R.id.main_content); if (mainContent != null) { mainContent.setAlpha(0); mainContent.animate().alpha(1).setDuration(250); @@ -26,11 +32,14 @@ public class AboutActivity extends AppCompatActivity { overridePendingTransition(0, 0); setupActionBar(); - TextView t1 = (TextView) findViewById(R.id.git); + TextView t1 = (TextView) findViewById(R.id.githubURL); t1.setMovementMethod(LinkMovementMethod.getInstance()); - TextView t2 = (TextView) findViewById(R.id.url); + TextView t2 = (TextView) findViewById(R.id.secusoWebsite); t2.setMovementMethod(LinkMovementMethod.getInstance()); + + TextView authors = (TextView) findViewById(R.id.textFieldAuthorNames); + authors.setText(getString(R.string.about_author_contributors, getString(R.string.about_author_names))); } private void setupActionBar() { @@ -47,9 +56,29 @@ public class AboutActivity extends AppCompatActivity { switch (item.getItemId()) { // Respond to the action bar's Up/Home button case android.R.id.home: - finish(); + exitActivity(); return true; } return super.onOptionsItemSelected(item); } + + @Override + public void onBackPressed() { + exitActivity(); + } + + private void exitActivity() { + if (mainContent != null) { + mainContent.setAlpha(1); + mainContent.animate().alpha(0).setDuration(125); + } + + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + finish(); + overridePendingTransition(0, 0); + } + }, 70); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ExerciseActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ExerciseActivity.java index 92073dc..dcf8b2a 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ExerciseActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ExerciseActivity.java @@ -1,14 +1,69 @@ package org.secuso.privacyfriendlybreakreminder.activities; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.CountDownTimer; +import android.preference.PreferenceManager; +import android.support.v4.content.AsyncTaskLoader; +import android.support.v4.content.Loader; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; import org.secuso.privacyfriendlybreakreminder.R; +import org.secuso.privacyfriendlybreakreminder.database.SQLiteHelper; +import org.secuso.privacyfriendlybreakreminder.database.data.Exercise; +import org.secuso.privacyfriendlybreakreminder.database.data.ExerciseSet; +import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseLocale; -public class ExerciseActivity extends AppCompatActivity { +import java.util.Locale; +import static android.support.design.R.id.center_horizontal; +import static android.support.design.R.id.center_vertical; + +public class ExerciseActivity extends AppCompatActivity implements android.support.v4.app.LoaderManager.LoaderCallbacks{ + + private static final String TAG = ExerciseActivity.class.getSimpleName(); + + // UI + private TextView breakTimerText; private ImageView playButton; + private ProgressBar progressBar; + private TextView timerText; + private TextView executionText; + private TextView descriptionText; + private ImageView exerciseImage; + private TextView sectionText; + + // exerciseSet info + private long exerciseSetId; + private ExerciseSet set; + private int currentExercise = 0; + private int currentExercisePart = 0; + + // timer + private long exerciseTime = 20 * 1000; // TODO - get from exercise? + private long pauseDuration = 5 * 60 * 1000; // TODO 5 minutes - get from settings + private CountDownTimer exerciseTimer; + private CountDownTimer breakTimer; + private boolean isBreakTimerRunning; + private boolean isExerciseTimerRunning; + private long remainingBreakDuration; + private long remainingExerciseDuration; + + // database + private SQLiteHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { @@ -16,12 +71,121 @@ public class ExerciseActivity extends AppCompatActivity { setContentView(R.layout.activity_exercise); initResources(); + + ActionBar ab = getSupportActionBar(); + if(ab != null) { + ab.setDisplayHomeAsUpEnabled(true); + ab.setHomeAsUpIndicator(R.drawable.ic_close_white); + } + + exerciseSetId = PreferenceManager.getDefaultSharedPreferences(this).getLong("DEFAULT_EXERCISE_SET", 0L); + pauseDuration = PreferenceManager.getDefaultSharedPreferences(this).getLong("DEFAULT_PAUSE_DURATION", 0L); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + getSupportLoaderManager().initLoader(0, null, this); } private void initResources() { + dbHelper = new SQLiteHelper(this); playButton = (ImageView) findViewById(R.id.button_playPause); + progressBar = (ProgressBar) findViewById(R.id.progressBar); + timerText = (TextView) findViewById(R.id.timerText); + executionText = (TextView) findViewById(R.id.execution); + descriptionText = (TextView) findViewById(R.id.description); + exerciseImage = (ImageView) findViewById(R.id.exercise_image); + sectionText = (TextView) findViewById(R.id.section); } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + showConfirmationDialog(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_activity_exercise, menu); + + MenuItem timerItem = menu.findItem(R.id.break_timer); + breakTimerText = (TextView) MenuItemCompat.getActionView(timerItem); + breakTimerText.setTextColor(Color.WHITE); + breakTimerText.setTextSize(20); + breakTimerText.setGravity(center_vertical); + breakTimerText.setText("00:00"); + breakTimerText.setPadding(16, 0, 16, 0); + //breakTimerText.set(10, 0, 10, 0); + + return true; + } + + @Override + public void onBackPressed() { + showConfirmationDialog(); + } + + private void showConfirmationDialog() { + new AlertDialog.Builder(this) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + ExerciseActivity.this.finish(); + ExerciseActivity.this.startActivity(new Intent(ExerciseActivity.this, TimerActivity.class)); + ExerciseActivity.this.overridePendingTransition(0, 0); + } + }) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }) + .setMessage(R.string.dialog_leave_break_confirmation) + .create().show(); + } + + @Override + public Loader onCreateLoader(int id, final Bundle args) { + return new AsyncTaskLoader(this) { + @Override + public ExerciseSet loadInBackground() { + return dbHelper.getExerciseListForSet((int)exerciseSetId, ExerciseLocale.getLocale()); + } + + @Override + protected void onStartLoading() { + forceLoad(); + } + + @Override + protected void onReset() {} + }; + } + + @Override + public void onLoadFinished(Loader loader, ExerciseSet set) { + this.set = set; + + if(set.size() > 0) { + setExercise(0); + } else { + // TODO IF THERE ARE NO EXERCISES ONLY SHOW TIMER : showTimer(); + } + // load data only once + getSupportLoaderManager().destroyLoader(0); + + pauseDuration = PreferenceManager.getDefaultSharedPreferences(ExerciseActivity.this).getLong("PAUSE TIME", 5 * 60 * 1000); + startBreakTimer(); + } + + @Override + public void onLoaderReset(Loader loader) {} + + private void updatePlayButton(boolean isRunning) { if(isRunning) { playButton.setImageResource(R.drawable.ic_pause_black_48dp); @@ -29,4 +193,252 @@ public class ExerciseActivity extends AppCompatActivity { playButton.setImageResource(R.drawable.ic_play_arrow_black); } } + + private void updateProgress(long remainingDuration) { + progressBar.setMax((int)exerciseTime); + progressBar.setProgress(progressBar.getMax() - (int) remainingDuration); + + int secondsUntilFinished = (int) Math.ceil(remainingDuration / 1000.0); + int minutesUntilFinished = secondsUntilFinished / 60; + int seconds = secondsUntilFinished % 60; + int minutes = minutesUntilFinished % 60; + + String time = String.format(Locale.US, "%02d:%02d", minutes, seconds); + timerText.setText(time); + } + + public void onClick(View view) { + switch(view.getId()) { + case R.id.progressBarLayout: + case R.id.button_playPause: + handlePlayPauseClicked(); + break; + case R.id.button_next: + handleSkipClicked(); + break; + case R.id.button_prev: + handlePrevClicked(); + break; + default: + } + } + + private boolean next() { + return nextExercisePart() || nextExercise(); + } + + private boolean nextExercise() { + if(set != null) { + setExercise((currentExercise + 1)); + return true; + } + return false; + } + private boolean previousExercise() { + if(set != null) { + setExercise(currentExercise - 1); + return true; + } + return false; + } + + private void setExercise(int number) { + if(set != null) { + if(set.size() != 0) { + + // TODO: stop if we reach the end or loop around + boolean loopAround = true; + + if(number < 0) { + currentExercise = loopAround ? + (number + set.size()) : + 0; + + } else if(number >= set.size()) { + currentExercise = loopAround ? + (number % set.size()) : + (set.size() -1); + + } else { + currentExercise = number; + } + + currentExercisePart = 0; + showExercise(set.get(currentExercise), currentExercisePart); + } + } + } + + private boolean nextExercisePart() { + if(set != null) { + if(set.size() != 0) { + int[] images = set.get(currentExercise).getImageResIds(this); + + currentExercisePart = (currentExercisePart + 1); + + if(currentExercisePart >= images.length) { + currentExercisePart = 0; + return false; + } + + showExercise(set.get(currentExercise), currentExercisePart); + return true; + } + } + return false; + } + + private void showExercise(Exercise e, int image) { + int[] images = e.getImageResIds(this); + + if (image < 0 || image >= images.length) { + image = 0; + } + + executionText.setText(e.getExecution()); + descriptionText.setText(e.getDescription()); + sectionText.setText(e.getSection()); + exerciseImage.setImageResource(e.getImageResIds(this)[image]); + + // TODO: continuous play? + // if() + startExerciseTimer(); + // else + //resetExerciseTimer(); + } + + private void handlePrevClicked() { + previousExercise(); + } + + private void handleSkipClicked() { + nextExercise(); + } + + private void handlePlayPauseClicked() { + if(isExercisePaused()) { + resumeExerciseTimer(); + updatePlayButton(true); + } + else if(isExerciseTimerRunning){ + pauseExerciseTimer(); + updatePlayButton(false); + } else { + startExerciseTimer(); + updatePlayButton(true); + } + } + + // timer + public CountDownTimer createBreakTimer(long duration) { + return new CountDownTimer(duration, 100) { + @Override + public void onTick(long millisUntilFinished) { + remainingBreakDuration = millisUntilFinished; + updateBreakTimer(remainingBreakDuration); + } + + @Override + public void onFinish() { + remainingBreakDuration = 0; + isBreakTimerRunning = false; + updateBreakTimer(remainingBreakDuration); + // TODO: show dialog to end the exercises? + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + }; + } + + private void updateBreakTimer(long remainingBreakDuration) { + int secondsUntilFinished = (int) Math.ceil(remainingBreakDuration / 1000.0); + int minutesUntilFinished = secondsUntilFinished / 60; + int seconds = secondsUntilFinished % 60; + int minutes = minutesUntilFinished % 60; + + String time = String.format(Locale.US, "%02d:%02d", minutes, seconds); + time = getString(R.string.remaining_time) + " " + time; + if(breakTimerText != null) { + breakTimerText.setText(time); + } + } + + public CountDownTimer createExerciseTimer(long duration) { + return new CountDownTimer(duration, 25) { + @Override + public void onTick(long millisUntilFinished) { + remainingExerciseDuration = millisUntilFinished; + updateProgress(millisUntilFinished); + } + + @Override + public void onFinish() { + remainingExerciseDuration = 0; + isExerciseTimerRunning = false; + updatePlayButton(false); + updateProgress(0L); + next(); + } + }; + } + + public void startBreakTimer() { + breakTimer = createBreakTimer(pauseDuration); + breakTimer.start(); + isBreakTimerRunning = true; + } + + public void startExerciseTimer() { + if(exerciseTimer != null) { + exerciseTimer.cancel(); + } + exerciseTimer = createExerciseTimer(exerciseTime); + exerciseTimer.start(); + isExerciseTimerRunning = true; + updateProgress(exerciseTime); + updatePlayButton(true); + } + + private void pauseBreakTimer() { + if(isBreakTimerRunning) { + breakTimer.cancel(); + isBreakTimerRunning = false; + } + } + + private void pauseExerciseTimer() { + if(isExerciseTimerRunning) { + exerciseTimer.cancel(); + isExerciseTimerRunning = false; + } + } + + public void resumeBreakTimer() { + if(!isBreakTimerRunning & remainingBreakDuration > 0) { + breakTimer = createExerciseTimer(remainingBreakDuration); + breakTimer.start(); + isBreakTimerRunning = true; + } + } + + public void resumeExerciseTimer() { + if(!isExerciseTimerRunning & remainingExerciseDuration > 0) { + exerciseTimer = createExerciseTimer(remainingExerciseDuration); + exerciseTimer.start(); + isExerciseTimerRunning = true; + } + } + + public boolean isExercisePaused() { + return !isExerciseTimerRunning && remainingExerciseDuration > 0; + // return !isRunning && initialDuration != 0 && remainingDuration > 0 && remainingDuration != initialDuration; + } + + private void resetExerciseTimer() { + exerciseTimer.cancel(); + isExerciseTimerRunning = false; + remainingExerciseDuration = 0; + + updatePlayButton(false); + updateProgress(0L); + } } diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ManageExerciseSetsActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ManageExerciseSetsActivity.java index 5e02a4a..7b0a15e 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ManageExerciseSetsActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/ManageExerciseSetsActivity.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -46,6 +47,7 @@ import static android.view.View.VISIBLE; public class ManageExerciseSetsActivity extends BaseActivity implements android.support.v4.app.LoaderManager.LoaderCallbacks> { + private static final String TAG = ManageExerciseSetsActivity.class.getSimpleName(); private RecyclerView exerciseSetList; private ProgressBar loadingSpinner; private TextView noExerciseSetsText; @@ -192,7 +194,7 @@ public class ManageExerciseSetsActivity extends BaseActivity implements android. enableDeleteMode(); return true; default: - Toast.makeText(this, "option selected", Toast.LENGTH_SHORT).show(); + Log.d(TAG, "Default option selected?"); return super.onOptionsItemSelected(item); } } diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/TimerActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/TimerActivity.java index de34ddf..8a258b2 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/TimerActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/TimerActivity.java @@ -237,6 +237,10 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap //animation.start(); } + @Override + protected void onDestroy() { + super.onDestroy(); + } public void onClick(View view) { switch(view.getId()) { diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseAdapter.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseAdapter.java index f308167..4427066 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseAdapter.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseAdapter.java @@ -3,6 +3,7 @@ package org.secuso.privacyfriendlybreakreminder.activities.adapter; import android.content.Context; import android.support.annotation.NonNull; import android.support.constraint.ConstraintLayout; +import android.support.v7.app.AlertDialog; import android.support.v7.util.SortedList; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -18,6 +19,7 @@ import org.secuso.privacyfriendlybreakreminder.R; import org.secuso.privacyfriendlybreakreminder.activities.ChooseExerciseActivity; import org.secuso.privacyfriendlybreakreminder.database.data.Exercise; import org.secuso.privacyfriendlybreakreminder.database.data.ExerciseSet; +import org.secuso.privacyfriendlybreakreminder.dialog.ExerciseDialog; import java.util.ArrayList; import java.util.Comparator; @@ -99,18 +101,10 @@ public class ExerciseAdapter extends RecyclerView.Adapter 1) { - imageID = imageIDSplit[0]; - } - final View.OnClickListener infoClick = new View.OnClickListener() { @Override public void onClick(View v) { - Toast.makeText(mContext, "Show Details Of the Exercise Now.", Toast.LENGTH_SHORT).show(); - // TODO: show Fragement ? Dialog? Something with the Information of the Exercise! + ExerciseDialog.showExerciseDialog(mContext, exercise); } }; @@ -127,11 +121,7 @@ public class ExerciseAdapter extends RecyclerView.Adapter { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_exercise, parent, false); + View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.dialog_exercise, parent, false); return new ExerciseViewHolder(itemView); } @@ -44,19 +43,7 @@ public class ExerciseSetAdapter extends RecyclerView.Adapter { ExerciseViewHolder vh = (ExerciseViewHolder) holder; - String imageID = exercise.getImageID(); - String[] imageIDSplit = imageID.split(","); - - if(imageIDSplit.length > 1) { - imageID = imageIDSplit[0]; // only take the first image as a display image - } - - int imageResID = mContext.getResources().getIdentifier( - "exercise_" + imageID, - "drawable", - mContext.getPackageName()); - vh.image.setImageResource(imageResID); - vh.name.setText(exercise.getName()); + vh.image.setImageResource(exercise.getImageResIds(mContext)[0]); vh.executionText.setText(exercise.getExecution()); vh.descriptionText.setText(exercise.getDescription()); vh.section.setText(exercise.getSection()); @@ -91,7 +78,6 @@ public class ExerciseSetAdapter extends RecyclerView.Adapter { public class ExerciseViewHolder extends ViewHolder { ImageView image; - TextView name; TextView executionText; TextView descriptionText; TextView section; @@ -99,11 +85,10 @@ public class ExerciseSetAdapter extends RecyclerView.Adapter { public ExerciseViewHolder(View itemView) { super(itemView); - name = (TextView) itemView.findViewById(R.id.exercise_name); image = (ImageView) itemView.findViewById(R.id.exercise_image); - executionText = (TextView) itemView.findViewById(R.id.exercise_execution); - descriptionText = (TextView) itemView.findViewById(R.id.exercise_description); - section = (TextView) itemView.findViewById(R.id.exercise_section); + executionText = (TextView) itemView.findViewById(R.id.execution); + descriptionText = (TextView) itemView.findViewById(R.id.description); + section = (TextView) itemView.findViewById(R.id.section); } } } diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseSetSpinnerAdapter.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseSetSpinnerAdapter.java index 93a46e6..83a2f8d 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseSetSpinnerAdapter.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/adapter/ExerciseSetSpinnerAdapter.java @@ -73,19 +73,8 @@ public class ExerciseSetSpinnerAdapter extends ArrayAdapter { View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_round_exercise_image, null, false); ImageView image = (ImageView) view.findViewById(R.id.exercise_image); - String imageID = set.get(i).getImageID(); - String[] imageIDSplit = imageID.split(","); + image.setImageResource(set.get(i).getImageResIds(getContext())[0]); - if(imageIDSplit.length > 1) { - imageID = imageIDSplit[0]; // only take the first image as a display image - } - - int imageResID = getContext().getResources().getIdentifier( - "exercise_" + imageID, - "drawable", - getContext().getPackageName()); - - image.setImageResource(imageResID); exerciseList.addView(view); } diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/helper/BaseActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/helper/BaseActivity.java index c447937..c00e4d5 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/helper/BaseActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/helper/BaseActivity.java @@ -21,7 +21,7 @@ import org.secuso.privacyfriendlybreakreminder.R; import org.secuso.privacyfriendlybreakreminder.activities.AboutActivity; import org.secuso.privacyfriendlybreakreminder.activities.HelpActivity; import org.secuso.privacyfriendlybreakreminder.activities.ManageExerciseSetsActivity; -import org.secuso.privacyfriendlybreakreminder.activities.SettingsActivity; +import org.secuso.privacyfriendlybreakreminder.activities.old.SettingsActivity; import org.secuso.privacyfriendlybreakreminder.activities.TimerActivity; import org.secuso.privacyfriendlybreakreminder.activities.tutorial.TutorialActivity; @@ -148,7 +148,7 @@ public abstract class BaseActivity extends AppCompatActivity implements OnNaviga break; case R.id.nav_tutorial: intent = new Intent(this, TutorialActivity.class); - startActivity(intent); + createBackStack(intent); break; case R.id.nav_about: intent = new Intent(this, AboutActivity.class); @@ -158,12 +158,12 @@ public abstract class BaseActivity extends AppCompatActivity implements OnNaviga intent = new Intent(this, HelpActivity.class); createBackStack(intent); break; - case R.id.nav_settings: + /*case R.id.nav_settings: intent = new Intent(this, SettingsActivity.class); intent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.GeneralPreferenceFragment.class.getName() ); intent.putExtra( PreferenceActivity.EXTRA_NO_HEADERS, true ); createBackStack(intent); - break; + break;*/ default: } overridePendingTransition(0,0); diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/BreakReminder.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/BreakReminder.java index 2f7fa54..03bdd52 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/BreakReminder.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/BreakReminder.java @@ -39,7 +39,6 @@ import android.widget.TextView; import org.secuso.privacyfriendlybreakreminder.R; import org.secuso.privacyfriendlybreakreminder.activities.AboutActivity; import org.secuso.privacyfriendlybreakreminder.activities.HelpActivity; -import org.secuso.privacyfriendlybreakreminder.activities.SettingsActivity; import org.secuso.privacyfriendlybreakreminder.widget.*; import java.util.Locale; @@ -304,7 +303,7 @@ public class BreakReminder extends AppCompatActivity // Handle navigation view item clicks here. int id = item.getItemId(); - if (id == R.id.nav_settings) { + /*if (id == R.id.nav_settings) { // Handle the profile action Intent intent = new Intent(this, SettingsActivity.class); this.startActivity(intent); @@ -320,7 +319,7 @@ public class BreakReminder extends AppCompatActivity // Show about page Intent intent = new Intent(this, AboutActivity.class); this.startActivity(intent); - } + }*/ DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); @@ -539,7 +538,7 @@ public class BreakReminder extends AppCompatActivity AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setView(i.inflate(R.layout.first_dialog, null)); - builder.setIcon(R.mipmap.ic_drawer_logo); + builder.setIcon(R.mipmap.ic_app); builder.setTitle(getActivity().getString(R.string.app_name_long)); builder.setPositiveButton(getActivity().getString(R.string.dialog_positive), null); diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/SettingsActivity.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/SettingsActivity.java similarity index 99% rename from app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/SettingsActivity.java rename to app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/SettingsActivity.java index 5465567..c018374 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/SettingsActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/activities/old/SettingsActivity.java @@ -1,5 +1,5 @@ -package org.secuso.privacyfriendlybreakreminder.activities; +package org.secuso.privacyfriendlybreakreminder.activities.old; import android.annotation.TargetApi; diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/database/data/Exercise.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/database/data/Exercise.java index ff5c0b2..6a078c5 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/database/data/Exercise.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/database/data/Exercise.java @@ -1,6 +1,10 @@ package org.secuso.privacyfriendlybreakreminder.database.data; +import android.content.Context; +import android.support.annotation.DrawableRes; +import android.support.annotation.IdRes; + public class Exercise { private int id; private int localId; @@ -46,6 +50,20 @@ public class Exercise { public void setImageID(String imageID) { this.imageID = imageID; } + public @DrawableRes int[] getImageResIds(Context context) { + String[] imageIDSplit = imageID.split(","); + + int[] result = new int[imageIDSplit.length]; + + for(int i = 0; i < result.length; ++i) { + result[i] = context.getResources().getIdentifier( + "exercise_" + imageIDSplit[i], + "drawable", + context.getPackageName()); + } + + return result; + } public String getSection() { return section; diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/dialog/ExerciseDialog.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/dialog/ExerciseDialog.java new file mode 100644 index 0000000..73da30b --- /dev/null +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/dialog/ExerciseDialog.java @@ -0,0 +1,62 @@ +package org.secuso.privacyfriendlybreakreminder.dialog; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v4.app.FragmentActivity; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.secuso.privacyfriendlybreakreminder.R; +import org.secuso.privacyfriendlybreakreminder.database.data.Exercise; + +/** + * Use {@link ExerciseDialog#showExerciseDialog(Context, Exercise)} to show the dialog. + */ +public final class ExerciseDialog { + + /** + * Use {@link ExerciseDialog#showExerciseDialog(Context, Exercise)} to show the dialog. + */ + private ExerciseDialog() {} + + + public static void showExerciseDialog(@NonNull final Context context,@NonNull final Exercise e) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(FragmentActivity.LAYOUT_INFLATER_SERVICE); + View v = inflater.inflate(R.layout.dialog_exercise, null); + + final TextView executionText = (TextView) v.findViewById(R.id.execution); + final TextView descriptionText = (TextView) v.findViewById(R.id.description); + final ImageView exerciseImage = (ImageView) v.findViewById(R.id.exercise_image); + final TextView sectionText = (TextView) v.findViewById(R.id.section); + + if(executionText != null) + executionText.setText(e.getExecution()); + if(descriptionText != null) + descriptionText.setText(e.getDescription()); + if(sectionText != null) + sectionText.setText(e.getSection()); + if(exerciseImage != null) { + exerciseImage.setOnClickListener(new View.OnClickListener() { + int currentlyShownExercise = 0; + @Override + public void onClick(View v) { + int[] resIds = e.getImageResIds(context); + + if(resIds.length > 0) { + currentlyShownExercise = (currentlyShownExercise + 1) % resIds.length; + exerciseImage.setImageResource(resIds[currentlyShownExercise]); + } + } + }); + exerciseImage.setImageResource(e.getImageResIds(context)[0]); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setView(v); + builder.show(); + } + +} diff --git a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/service/TimerService.java b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/service/TimerService.java index 96123a8..451147e 100644 --- a/app/src/main/java/org/secuso/privacyfriendlybreakreminder/service/TimerService.java +++ b/app/src/main/java/org/secuso/privacyfriendlybreakreminder/service/TimerService.java @@ -14,11 +14,13 @@ import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; import android.os.RemoteException; +import android.provider.Settings; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.support.v7.app.NotificationCompat; import org.secuso.privacyfriendlybreakreminder.R; +import org.secuso.privacyfriendlybreakreminder.activities.ExerciseActivity; import org.secuso.privacyfriendlybreakreminder.activities.TimerActivity; import java.io.FileDescriptor; @@ -49,6 +51,20 @@ public class TimerService extends Service { @Override public void onReceive(Context context, Intent intent) { + if(intent.getBooleanExtra("done" ,false)) { + lastTime = 0; + onTimerDone(); + return; + } + + // reset lastTime if we are starting a new timer + long initialMillis = intent.getLongExtra("initialMillis", 0); + long remainingMillis = intent.getLongExtra("onTickMillis", 0); + + if(initialMillis == remainingMillis) { + lastTime = 0; + } + // limit the notification updates int remainingSeconds = intent.getIntExtra("countdown_seconds", 0); @@ -56,13 +72,34 @@ public class TimerService extends Service { lastTime = remainingSeconds; updateNotification(); - } else if(intent.getBooleanExtra("done" ,false)) { - lastTime = 0; - updateNotification(); } } }; + private void onTimerDone() { + + // send a notification with sound and vibration + stopForeground(false); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + builder.setContentTitle(getString(R.string.app_name)) + .setContentText("Take a break now! Click here to do your chosen exercises.") + .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, ExerciseActivity.class), FLAG_UPDATE_CURRENT)) + .setColor(ContextCompat.getColor(this, R.color.colorAccent)) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setWhen(0) + .setAutoCancel(true) + .setSmallIcon(R.mipmap.ic_launcher) + .setDefaults(Notification.DEFAULT_LIGHTS) + .setVibrate(new long[] { 0, 1000, 1000, 1000, 1000, 1000, 1000 }) + .setSound(Settings.System.DEFAULT_NOTIFICATION_URI) + .setOnlyAlertOnce(false); + notificationManager.notify(NOTIFICATION_ID, builder.build()); + + // TODO: show decider activity?! + // maybe rather show a dialog + } + @Override public void onCreate() { super.onCreate(); @@ -155,14 +192,12 @@ public class TimerService extends Service { @Override public void onFinish() { - - mTimer.cancel(); isRunning = false; remainingDuration = 0; Intent broadcast = buildBroadcast(); broadcast.putExtra("done", true); - sendBroadcast(broadcast); + TimerService.this.sendBroadcast(broadcast); remainingDuration = initialDuration; diff --git a/app/src/main/res/drawable/bg_splash_screen.xml b/app/src/main/res/drawable/bg_splash_screen.xml index 5ee60fc..831014f 100644 --- a/app/src/main/res/drawable/bg_splash_screen.xml +++ b/app/src/main/res/drawable/bg_splash_screen.xml @@ -5,7 +5,7 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/about.xml b/app/src/main/res/layout/about.xml deleted file mode 100644 index 9c52abd..0000000 --- a/app/src/main/res/layout/about.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..ece63f5 --- /dev/null +++ b/app/src/main/res/layout/activity_about.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_exercise.xml b/app/src/main/res/layout/activity_exercise.xml index d398027..b302f42 100644 --- a/app/src/main/res/layout/activity_exercise.xml +++ b/app/src/main/res/layout/activity_exercise.xml @@ -2,6 +2,7 @@ @@ -25,11 +26,53 @@ app:layout_constraintRight_toRightOf="parent" app:srcCompat="@drawable/ic_play_arrow_black" /> + + + + + android:layout_marginTop="8dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@+id/progressBarLayout" + app:srcCompat="@drawable/exercise_0" /> + tools:context=".activities.HelpActivity"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_manage_exercise_set.xml b/app/src/main/res/layout/activity_manage_exercise_set.xml index ff54d8b..307f4c8 100644 --- a/app/src/main/res/layout/activity_manage_exercise_set.xml +++ b/app/src/main/res/layout/activity_manage_exercise_set.xml @@ -9,9 +9,6 @@ tools:openDrawer="start"> - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_exercise.xml b/app/src/main/res/layout/layout_exercise.xml deleted file mode 100644 index 6f86842..0000000 --- a/app/src/main/res/layout/layout_exercise.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/nav_header.xml b/app/src/main/res/layout/nav_header.xml index 8121887..e7efb16 100644 --- a/app/src/main/res/layout/nav_header.xml +++ b/app/src/main/res/layout/nav_header.xml @@ -22,7 +22,7 @@ android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@mipmap/ic_drawer_logo"/> + android:src="@mipmap/ic_app"/> + android:background="@mipmap/ic_splash" /> + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/nav_drawer.xml b/app/src/main/res/menu/nav_drawer.xml index 7f90ced..90ca8f3 100644 --- a/app/src/main/res/menu/nav_drawer.xml +++ b/app/src/main/res/menu/nav_drawer.xml @@ -18,10 +18,10 @@ android:id="@+id/nav_tutorial" android:icon="@drawable/ic_menu_tutorial" android:title="@string/title_activity_tutorial" /> - + android:title="@string/title_activity_settings" /> --> Übungen wurden erfolgreich erstellt! Wählen Sie die zu trainierenden Körperbereiche aus Haftungsausschluss - und Mitwirkende + %s und Mitwirkende Sie können in den Pausen trainieren, müssen dies aber nicht! Erstellen Sie einfach ein Profil, ohne Übungen hinzuzufügen. Der \'Privacy friendly break reminder\' hilft Ihnen, regelmäßiger Pausen zu nehmen und währenddessen zu trainieren! Alternativ können die Profile und die dazugehörigen Übungen in den Profil-Einstellungen bearbeitet werden @@ -119,5 +119,4 @@ Interaktive Uhr Beim Klicken auf \'Next\' wird eine andere Übung aus der aktuellen Körperregion ausgewählt. Zugleich wird die Uhr wieder auf die letzte volle Minute gesetzt. Somit geht keine Zeit für die Übungen verloren. Bedienungsanleitung - Sergej Alexeev, Jannik Schildknecht und Mitwirkende \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9ab0792..15b1864 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -102,7 +102,7 @@ Exercices créé avec succès! Désistement Sélectionnez les parties du corps pour l\'entrainement - et contributeurs + %s et contributeurs Vous pouvez faire de l\'entrainement dans les pauses, mais vous n\'etes pas forcé! Il suffit de créer un nouveau profil et de ne pas sélectionnez d\'exercices pour faire une pause simple sans exercise. Le \'privacy friendly break reminder\' vous aide à faire des pauses plus régulièrement et se mettre en forme avec des exercise pour toute le corps! Alternative, les profils et ces exercices peuvent être modifiés dans le paramètres du profils @@ -119,6 +119,5 @@ Horloge interactive En appuyant sur l\'horloge à chaque étape de cette application, l\'horloge peut être démarré et arrêté . En cliquant sur le bouton \'next\', l\'application va choisir un nouvel exercice dans la région du corps actuel. Dans le même temps l\'horloge sera remise à zéro sur la minute d\'avant, que le temps sera dépenser pleinement sur les exercices. - Sergej Alexeev, Jannik Schildknecht et contributeurs \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d5566fd..a56e8cb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -101,7 +101,7 @@ Дисклеймер Выберите части тела, которые вы хотите тренировать - и соучастники + %s и соучастники Basic Rest Activity Circle Рекомендация Помодоро @@ -118,5 +118,4 @@ При нажатии на кнопку \'Next\', приложение будет выбрать новое упражнение в текущей области тела. В то же время часы будут сброшены на следующую полную минуту, чтобы провестить время полностью на упражнениях. Интерактивные часы При нажатии на часы возможно их запустить или остановить. - Sergej Alexeev, Jannik Schildknecht и соучастники \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a60e82..e530cf3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,10 +73,10 @@ About Privacy Friendly Break Reminder - Version 1.0 - Authors: - Sergej Alexeev, Jannik Schildknecht and contributors. - and contributors. + Version + Authors: + Christopher Beckmann, Sergej Alexeev, Jannik Schildknecht + %s and contributors. In affiliation with More Information can be found on: Github-Repo @@ -302,6 +302,13 @@ Legs Choose Exercises Please specify a name. + Help + About + Do you really want to cancel your break? + Yes + No + Exercise + Time remaining: diff --git a/app/src/main/res/xml/pref_headers.xml b/app/src/main/res/xml/pref_headers.xml index ea23f02..f8ba6ff 100644 --- a/app/src/main/res/xml/pref_headers.xml +++ b/app/src/main/res/xml/pref_headers.xml @@ -3,12 +3,12 @@