Exercises can now be added and deleted to and from Sets.

Spinner now saves the last pressed entry.
This commit is contained in:
Christopher Beckmann 2017-09-07 02:04:21 +02:00
commit 65d8a6fe10
24 changed files with 1084 additions and 201 deletions

View file

@ -69,10 +69,10 @@
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.tutorial.TutorialActivity"
android:theme="@style/AppTheme.NoActionBar" />
@ -86,7 +86,6 @@
android:name=".activities.TimerActivity"
android:label="@string/activity_title_break_reminder"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.ManageExerciseSetsActivity"
android:label="@string/activity_title_manage_exercise_sets"
@ -96,7 +95,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.secuso.privacyfriendlybreakreminder.activities.TimerActivity" />
</activity>
<activity
android:name=".activities.ExerciseActivity"
android:label="@string/activity_title_exercise"
@ -105,7 +103,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.secuso.privacyfriendlybreakreminder.activities.TimerActivity" />
</activity>
<activity
android:name=".activities.EditExerciseSetActivity"
android:label="@string/activity_title_edit_exercise_set"
@ -116,6 +113,14 @@
android:value="org.secuso.privacyfriendlybreakreminder.activities.ManageExerciseSetsActivity" />
</activity>
<activity android:name=".activities.ChooseExerciseActivity"
android:label="@string/activity_title_choose_exercises"
android:parentActivityName=".activities.EditExerciseSetActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.secuso.privacyfriendlybreakreminder.activities.EditExerciseSetActivity" />>
</activity>
</application>
</manifest>

View file

@ -35,9 +35,9 @@ public class AboutActivity extends AppCompatActivity {
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle(R.string.about);
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setTitle(R.string.about);
actionBar.setDisplayHomeAsUpEnabled(true);
}
}

View file

@ -0,0 +1,122 @@
package org.secuso.privacyfriendlybreakreminder.activities;
import android.content.Intent;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.util.SortedList;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import org.secuso.privacyfriendlybreakreminder.R;
import org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseAdapter;
import org.secuso.privacyfriendlybreakreminder.activities.layout.FlowLayout;
import org.secuso.privacyfriendlybreakreminder.database.SQLiteHelper;
import org.secuso.privacyfriendlybreakreminder.database.data.Exercise;
import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseSections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseAdapter.ID_COMPARATOR;
public class ChooseExerciseActivity extends AppCompatActivity {
private static final String TAG = ChooseExerciseActivity.class.getSimpleName();
public static final String EXTRA_SELECTED_EXERCISES = TAG+".EXTRA_SELECTED_EXERCISES";
FlowLayout filterButtonLayout;
RecyclerView exerciseList;
ExerciseAdapter exerciseAdapter;
SQLiteHelper databaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_exercise);
initResources();
ActionBar ab = getSupportActionBar();
if(ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
}
int[] chosenExercises = getIntent().getIntArrayExtra(EXTRA_SELECTED_EXERCISES);
List<Integer> chosenExercisesList = new ArrayList<>();
for(int i : chosenExercises) chosenExercisesList.add(i);
exerciseAdapter.add(databaseHelper.getExerciseList(ExerciseLocale.getLocale()));
exerciseAdapter.setCheckedItems(chosenExercisesList);
}
private void initResources() {
databaseHelper = new SQLiteHelper(this);
filterButtonLayout = (FlowLayout) findViewById(R.id.layout_filter_buttons);
exerciseList = (RecyclerView) findViewById(R.id.exercise_list);
exerciseAdapter = new ExerciseAdapter(this, ID_COMPARATOR);
exerciseAdapter.showCheckboxes(true);
GridLayoutManager gridLayout = new GridLayoutManager(this, 3);
exerciseList.setLayoutManager(gridLayout);
exerciseList.setAdapter(exerciseAdapter);
filterButtonLayout.removeAllViews();
for(ExerciseSections section : ExerciseSections.getSectionList()) {
// TODO: Add Buttons for every section we have
//View view = LayoutInflater.from(this).inflate(R.layout.layout_section_filter_button, null, false);
//TextView image = (TextView) view.findViewById(R.id.button_text);
//filterButtonLayout.addView(view);
}
}
public void onClick(View v) {
// TODO get onclicklistener to call this method so we can filter the list
//exerciseAdapter.replaceAll(databaseHelper.getExerciseListBySections());
exerciseList.scrollToPosition(0);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
sendDataBack();
super.onBackPressed();
}
private void sendDataBack() {
Intent result = new Intent();
List<Integer> selectedIdList = exerciseAdapter.getCheckedIds();
int[] selectedIds = new int[selectedIdList.size()];
for(int i = 0; i < selectedIds.length; ++i) {
selectedIds[i] = selectedIdList.get(i);
}
result.putExtra(EXTRA_SELECTED_EXERCISES, selectedIds);
setResult(RESULT_OK, result);
}
}

View file

@ -23,32 +23,43 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import org.secuso.privacyfriendlybreakreminder.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseAdapter;
import org.secuso.privacyfriendlybreakreminder.database.data.Exercise;
import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.R;
import org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseSetAdapter;
import org.secuso.privacyfriendlybreakreminder.database.SQLiteHelper;
import org.secuso.privacyfriendlybreakreminder.database.data.ExerciseSet;
import java.util.ArrayList;
import java.util.List;
import static org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseAdapter.ID_COMPARATOR;
public class EditExerciseSetActivity extends AppCompatActivity implements android.support.v4.app.LoaderManager.LoaderCallbacks<ExerciseSet> {
// extras
public static final String EXTRA_EXERCISE_SET_ID = "EXTRA_EXERCISE_SET_ID";
public static final String EXTRA_EXERCISE_SET_NAME = "EXTRA_EXERCISE_SET_NAME";
private static final int PICK_EXERCISE_REQUEST = 1; // The request code
// UI
private TextView exerciseSetNameText;
private RecyclerView exerciseList;
private ProgressBar loadingSpinner;
private ExerciseSetAdapter exerciseSetAdapter;
private ExerciseAdapter mAdapter;
private ActionBar actionBar;
private Toolbar toolbar;
// exercise set information
private long exerciseSetId = -1L;
private String exerciseSetName = "";
private boolean nameChanged = false;
private boolean modificationsDone = false;
private SQLiteHelper mDbHelper;
//methods
@ -72,13 +83,13 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
}
private void initResources() {
mDbHelper = new SQLiteHelper(this);
toolbar = (Toolbar) findViewById(R.id.toolbar);
exerciseSetNameText = (TextView) findViewById(R.id.exercise_set_name);
exerciseList = (RecyclerView) findViewById(R.id.exercise_list);
exerciseSetAdapter = new ExerciseSetAdapter(this, null);
exerciseList.setAdapter(exerciseSetAdapter);
//exerciseList.setLayoutManager(new GridLayoutManager(this, 2));
exerciseList.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new ExerciseAdapter(this, ID_COMPARATOR);
exerciseList.setAdapter(mAdapter);
exerciseList.setLayoutManager(new GridLayoutManager(this, 3));
loadingSpinner = (ProgressBar) findViewById(R.id.loading_spinner);
exerciseSetNameText.setText(exerciseSetName);
@ -91,7 +102,7 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
@Override
public void afterTextChanged(Editable editable) {
modificationsDone = true;
nameChanged = true;
}
});
@ -117,9 +128,7 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
return new AsyncTaskLoader<ExerciseSet>(this) {
@Override
public ExerciseSet loadInBackground() {
SQLiteHelper helper = new SQLiteHelper(getContext());
return helper.getExerciseListForSet((int)exerciseSetId, ExerciseLocale.getLocale());
return mDbHelper.getExerciseListForSet((int)exerciseSetId, ExerciseLocale.getLocale());
}
@Override
@ -142,7 +151,12 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
}
});
exerciseSetAdapter.updateData(set);
if(set != null) {
mAdapter.replaceAll(set.getExercises());
}
// load data only once
getSupportLoaderManager().destroyLoader(0);
}
@Override
@ -159,22 +173,40 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if(modificationsDone) {
if(modificationsDone()) {
showDiscardDialog();
} else {
super.onBackPressed();
}
return true;
case R.id.save:
saveChanges();
super.onBackPressed();
if(TextUtils.getTrimmedLength(exerciseSetNameText.getText()) == 0) {
Toast.makeText(this, R.string.activity_edit_no_empty_name, Toast.LENGTH_SHORT).show();
} else {
saveChanges();
super.onBackPressed();
}
return true;
}
return super.onOptionsItemSelected(item);
}
private void saveChanges() {
ExerciseSet set = exerciseSetAdapter.getExerciseSet();
List<Exercise> set = mAdapter.getExercises();
if(modificationsDone) {
mDbHelper.clearExercisesFromSet((int) exerciseSetId);
for (Exercise e : set) {
mDbHelper.addExerciseToExerciseSet((int) exerciseSetId, e.getId());
}
}
if(nameChanged) {
ExerciseSet exerciseSet = new ExerciseSet();
exerciseSet.setId(exerciseSetId);
exerciseSet.setName(exerciseSetNameText.getText().toString());
mDbHelper.updateExerciseSet(exerciseSet);
}
// TODO: save changes to database
// man könnte den unterschied, der gespeichert werden muss rausfinden, indem man nur die änderungen speichert..
@ -191,13 +223,17 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
@Override
public void onBackPressed() {
if(modificationsDone) {
if(modificationsDone()) {
showDiscardDialog();
} else {
super.onBackPressed();
}
}
private boolean modificationsDone() {
return nameChanged || modificationsDone;
}
private void showDiscardDialog() {
new AlertDialog.Builder(this)
.setPositiveButton(R.string.keep_editing, new DialogInterface.OnClickListener() {
@ -215,4 +251,83 @@ public class EditExerciseSetActivity extends AppCompatActivity implements androi
.setMessage(R.string.dialog_discard_confirmation)
.create().show();
}
public void onClick(View view) {
switch(view.getId()) {
case R.id.add_button:
Intent i = new Intent(this, ChooseExerciseActivity.class);
i.putExtra(ChooseExerciseActivity.EXTRA_SELECTED_EXERCISES , getSelectedExerciseIds());
startActivityForResult(i, PICK_EXERCISE_REQUEST);
break;
}
}
private int[] getSelectedExerciseIds() {
List<Exercise> set = mAdapter.getExercises();
int[] result = new int[set.size()];
for(int i = 0; i < set.size(); ++i) {
result[i] = set.get(i).getId();
}
return result;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == PICK_EXERCISE_REQUEST) {
if(resultCode == RESULT_OK) {
int[] result = data.getIntArrayExtra(ChooseExerciseActivity.EXTRA_SELECTED_EXERCISES);
List<Exercise> oldList = mAdapter.getExercises();
// did we make any changes?
boolean needToUpdate = false;
if(result.length != oldList.size()) {
modificationsDone = true;
needToUpdate = true;
}
if(!needToUpdate) {
for (int id : result) {
boolean found = false;
for (Exercise e : oldList) {
if (e.getId() == id) {
found = true;
break;
}
}
if (!found) {
modificationsDone = true;
needToUpdate = true;
break;
}
}
}
if(needToUpdate) {
List<Exercise> allExercises = mDbHelper.getExerciseList(ExerciseLocale.getLocale());
List<Exercise> newList = new ArrayList<>();
for (int id : result) {
for (Exercise e : allExercises) {
if (e.getId() == id) {
newList.add(e);
break;
}
}
}
mAdapter.replaceAll(newList);
}
}
}
}
}

View file

@ -32,7 +32,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import org.secuso.privacyfriendlybreakreminder.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.R;
import org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseSetListAdapter;
import org.secuso.privacyfriendlybreakreminder.activities.helper.BaseActivity;

View file

@ -14,15 +14,13 @@ import android.graphics.drawable.ColorDrawable;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.ColorRes;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
@ -30,7 +28,7 @@ import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import org.secuso.privacyfriendlybreakreminder.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.exercises.ExerciseLocale;
import org.secuso.privacyfriendlybreakreminder.R;
import org.secuso.privacyfriendlybreakreminder.activities.adapter.ExerciseSetSpinnerAdapter;
import org.secuso.privacyfriendlybreakreminder.activities.helper.BaseActivity;
@ -62,6 +60,7 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
// animation
private int mShortAnimationDuration;
private boolean currentStatusIsPickerVisible = false;
private static final String[] SECONDS_MINUTES = new String[60];
private static final String[] HOURS = new String[24];
@ -105,11 +104,9 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
boolean isRunning = intent.getBooleanExtra("isRunning", false);
boolean isPaused = intent.getBooleanExtra("isPaused", false);
if(mTimerService != null) {
updateUI();
} else {
updateUI(isRunning, isPaused, initialDuration, millisUntilDone);
}
Log.d(TAG, millisUntilDone + "/" + initialDuration + " (" + (isRunning ? "Running" : "") + (isPaused ? "Paused" : "") + (!isRunning && !isPaused ? "Stopped" : "") + ")");
updateUI(isRunning, isPaused, initialDuration, millisUntilDone);
}
};
@ -175,7 +172,7 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
}
private void initResources() {
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
exerciseSetAdapter = new ExerciseSetSpinnerAdapter(this, R.layout.layout_exercise_set, new LinkedList<ExerciseSet>());
@ -186,6 +183,14 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
resetButton = (ImageButton) findViewById(R.id.button_reset);
exerciseSetSpinner = (Spinner) findViewById(R.id.spinner_choose_exercise_set);
exerciseSetSpinner.setAdapter(exerciseSetAdapter);
exerciseSetSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
pref.edit().putLong("DEFAULT_EXERCISE_SET", id).apply();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
secondsPicker = (NumberPicker) findViewById(R.id.seconds_picker);
minutesPicker = (NumberPicker) findViewById(R.id.minutes_picker);
hoursPicker = (NumberPicker) findViewById(R.id.hours_picker);
@ -240,14 +245,13 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
handlePlayPressed();
break;
case R.id.button_reset:
mTimerService.stopAndResetTimer();
if(mTimerService != null)
mTimerService.stopAndResetTimer();
break;
//case R.id.button_chooseExercise:
// startActivity(new Intent(this, ManageExerciseSetsActivity.class));
// break;
}
updateUI();
}
private void handlePlayPressed() {
@ -262,7 +266,7 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
long duration = getCurrentSetDuration();
saveCurrentSetDuration();
mTimerService.startTimer(duration);
progressBar.setMax((int)duration);
progressBar.setMax((int) duration);
}
}
}
@ -289,68 +293,80 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
}
}
private void updateUI(boolean running, boolean isPaused, long initialDuration, long remainingDuration) {
private synchronized void updateUI(boolean running, boolean isPaused, long initialDuration, long remainingDuration) {
updatePlayButton(running);
progressBar.setMax((int) initialDuration);
updateProgress(remainingDuration);
showPicker(!running && !isPaused);
}
private void showPicker(boolean showPicker) {
if(showPicker && pickerLayout.getVisibility() != View.VISIBLE) {
pickerLayout.setAlpha(0f);
pickerLayout.setVisibility(View.VISIBLE);
pickerLayout.animate()
.alpha(1f)
.setStartDelay(mShortAnimationDuration)
.setDuration(mShortAnimationDuration)
.setListener(null);
private synchronized void showPicker(final boolean showPicker) {
if(showPicker != currentStatusIsPickerVisible) {
timerText.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
timerText.setVisibility(View.INVISIBLE);
}
});
pickerLayout.clearAnimation();
timerText.clearAnimation();
progressBar.clearAnimation();
progressBar.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
progressBar.setVisibility(View.INVISIBLE);
}
});
currentStatusIsPickerVisible = showPicker;
} else if(!showPicker && pickerLayout.getVisibility() == View.VISIBLE) {
pickerLayout.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
pickerLayout.setVisibility(View.INVISIBLE);
}
});
if (showPicker) {
pickerLayout.setAlpha(0f);
pickerLayout.setVisibility(View.VISIBLE);
pickerLayout.animate()
.alpha(1f)
//.setStartDelay(mShortAnimationDuration)
.setDuration(mShortAnimationDuration)
.setListener(null);
timerText.setAlpha(0f);
timerText.setVisibility(View.VISIBLE);
timerText.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setListener(null);
timerText.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
if(currentStatusIsPickerVisible)
timerText.setVisibility(View.INVISIBLE);
}
});
progressBar.setAlpha(0f);
progressBar.setVisibility(View.VISIBLE);
progressBar.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setStartDelay(mShortAnimationDuration)
.setListener(null);
progressBar.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
if(currentStatusIsPickerVisible)
progressBar.setVisibility(View.INVISIBLE);
}
});
} else {
pickerLayout.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
if(!currentStatusIsPickerVisible)
pickerLayout.setVisibility(View.INVISIBLE);
}
});
timerText.setAlpha(0f);
timerText.setVisibility(View.VISIBLE);
timerText.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
.setListener(null);
progressBar.setAlpha(0f);
progressBar.setVisibility(View.VISIBLE);
progressBar.animate()
.alpha(1f)
.setDuration(mShortAnimationDuration)
//.setStartDelay(mShortAnimationDuration)
.setListener(null);
}
}
}
@ -400,6 +416,18 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap
@Override
public void onLoadFinished(Loader<List<ExerciseSet>> loader, List<ExerciseSet> data) {
exerciseSetAdapter.updateData(data);
long defaultId = PreferenceManager.getDefaultSharedPreferences(this).getLong("DEFAULT_EXERCISE_SET", 0L);
for(int i = 0; i < data.size(); ++i) {
ExerciseSet e = data.get(i);
if(e.getId() == defaultId) {
exerciseSetSpinner.setSelection(i);
break;
}
}
}
@Override

View file

@ -0,0 +1,230 @@
package org.secuso.privacyfriendlybreakreminder.activities.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.constraint.ConstraintLayout;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
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 java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Christopher Beckmann on 06.09.2017.
*/
public class ExerciseAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<Integer> checkedIds = new ArrayList<>();
private boolean mShowCheckboxes = false;
public static final Comparator<Exercise> ID_COMPARATOR = new Comparator<Exercise>() {
@Override
public int compare(Exercise a, Exercise b) {
return (a.getId() < b.getId()) ? -1 : ((a.getId() == b.getId()) ? 0 : 1);
}
};
private final LayoutInflater mInflater;
private final Comparator<Exercise> mComparator;
private final SortedList<Exercise> mSortedList = new SortedList<>(Exercise.class, new SortedList.Callback<Exercise>() {
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public int compare(Exercise a, Exercise b) {
return mComparator.compare(a, b);
}
@Override
public boolean areContentsTheSame(Exercise oldItem, Exercise newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(Exercise item1, Exercise item2) {
return item1.getId() == item2.getId();
}
});
public ExerciseAdapter(Context context, Comparator<Exercise> comparator) {
this.mContext = context;
this.mComparator = comparator;
this.mInflater = LayoutInflater.from(context);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.layout_exercise_grid_item, parent, false);
return new ExerciseAdapter.ExerciseViewHolder(itemView);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Exercise exercise = mSortedList.get(position);
final ExerciseViewHolder vh = (ExerciseViewHolder) holder;
String imageID = exercise.getImageID();
String[] imageIDSplit = imageID.split(",");
if(imageIDSplit.length > 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!
}
};
final View.OnClickListener checkClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(vh.checkbox.isChecked()) {
checkedIds.remove(checkedIds.indexOf(exercise.getId()));
} else {
checkedIds.add(exercise.getId());
}
vh.checkbox.setChecked(!vh.checkbox.isChecked());
}
};
int imageResID = mContext.getResources().getIdentifier(
"exercise_" + imageID,
"drawable",
mContext.getPackageName());
vh.image.setImageResource(imageResID);
if(checkedIds != null)
vh.checkbox.setChecked(checkedIds.contains(exercise.getId()));
vh.checkbox.setClickable(false);
vh.checkbox.setVisibility(mShowCheckboxes ? View.VISIBLE : View.GONE);
vh.layout.setOnClickListener(mShowCheckboxes ? checkClick : infoClick);
vh.layout.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
infoClick.onClick(v);
return true;
}
});
vh.infoButton.setOnClickListener(infoClick);
}
@Override
public int getItemCount() {
return mSortedList.size();
}
public void replaceAll(@NonNull List<Exercise> exercises) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final Exercise ex = mSortedList.get(i);
if (!exercises.contains(ex)) {
mSortedList.remove(ex);
}
}
mSortedList.addAll(exercises);
mSortedList.endBatchedUpdates();
}
public List<Integer> getCheckedIds() {
return checkedIds;
}
public void add(Exercise model) {
mSortedList.add(model);
}
public void remove(Exercise model) {
mSortedList.remove(model);
}
public void add(List<Exercise> models) {
mSortedList.addAll(models);
}
public void remove(List<Exercise> models) {
mSortedList.beginBatchedUpdates();
for (Exercise model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
public void setCheckedItems(@NonNull List<Integer> checkedItems) {
this.checkedIds = checkedItems;
}
public List<Exercise> getExercises() {
List<Exercise> result = new LinkedList<>();
for (int i = 0; i < mSortedList.size(); ++i) {
Exercise e = mSortedList.get(i);
result.add(e);
}
return result;
}
public class ExerciseViewHolder extends RecyclerView.ViewHolder {
ImageView image;
CheckBox checkbox;
ImageButton infoButton;
ConstraintLayout layout;
public ExerciseViewHolder(View itemView) {
super(itemView);
layout = (ConstraintLayout) itemView.findViewById(R.id.exercise_layout);
checkbox = (CheckBox) itemView.findViewById(R.id.exercise_checkbox);
image = (ImageView) itemView.findViewById(R.id.exercise_image);
infoButton = (ImageButton) itemView.findViewById(R.id.exercise_info_button);
}
}
public void showCheckboxes(boolean show) {
mShowCheckboxes = show;
}
}

View file

@ -11,14 +11,14 @@ import android.widget.ImageView;
import android.widget.TextView;
import org.secuso.privacyfriendlybreakreminder.R;
import org.secuso.privacyfriendlybreakreminder.activities.ManageExerciseSetsActivity;
import org.secuso.privacyfriendlybreakreminder.activities.helper.CursorRecyclerViewAdapter;
import org.secuso.privacyfriendlybreakreminder.database.columns.ExerciseColumns;
import org.secuso.privacyfriendlybreakreminder.database.data.Exercise;
import org.secuso.privacyfriendlybreakreminder.database.data.ExerciseSet;
/**
* Created by Christopher Beckmann on 30.08.2017.
* This adapter provides the {@link Exercise}s of one {@link ExerciseSet}.
* Use {@link ExerciseSetAdapter#add(Exercise)} and {@link ExerciseSetAdapter#remove(Exercise)} to manage the {@link Exercise}s.
* @author Christopher Beckmann
* @see android.support.v7.widget.RecyclerView.Adapter
*/
public class ExerciseSetAdapter extends RecyclerView.Adapter<ViewHolder> {

View file

@ -3,6 +3,7 @@ package org.secuso.privacyfriendlybreakreminder.activities.adapter;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
@ -93,6 +94,7 @@ public class ExerciseSetSpinnerAdapter extends ArrayAdapter<ExerciseSet> {
} else {
noExercisesText.setVisibility(View.GONE);
}
noExercisesText.setTextColor(ContextCompat.getColor(getContext(), R.color.black));
//LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE);
//View row = inflater.inflate(resource, parent, false);

View file

@ -0,0 +1,166 @@
package org.secuso.privacyfriendlybreakreminder.activities.layout;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import org.secuso.privacyfriendlybreakreminder.R;
public class FlowLayout extends ViewGroup {
private int mHorizontalSpacing;
private int mVerticalSpacing;
private Paint mPaint;
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
try {
mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
} finally {
a.recycle();
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xffff0000);
mPaint.setStrokeWidth(2.0f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
boolean growHeight = widthMode != MeasureSpec.UNSPECIFIED;
int width = 0;
int height = getPaddingTop();
int currentWidth = getPaddingLeft();
int currentHeight = 0;
boolean breakLine = false;
boolean newLine = false;
int spacing = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
spacing = mHorizontalSpacing;
if (lp.horizontalSpacing >= 0) {
spacing = lp.horizontalSpacing;
}
if (growHeight && (breakLine || currentWidth + child.getMeasuredWidth() > widthSize)) {
height += currentHeight + mVerticalSpacing;
currentHeight = 0;
width = Math.max(width, currentWidth - spacing);
currentWidth = getPaddingLeft();
newLine = true;
} else {
newLine = false;
}
lp.x = currentWidth;
lp.y = height;
currentWidth += child.getMeasuredWidth() + spacing;
currentHeight = Math.max(currentHeight, child.getMeasuredHeight());
breakLine = lp.breakLine;
}
if (!newLine) {
height += currentHeight;
width = Math.max(width, currentWidth - spacing);
}
width += getPaddingRight();
height += getPaddingBottom();
setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean more = super.drawChild(canvas, child, drawingTime);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.horizontalSpacing > 0) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y - 4.0f, x, y + 4.0f, mPaint);
canvas.drawLine(x, y, x + lp.horizontalSpacing, y, mPaint);
canvas.drawLine(x + lp.horizontalSpacing, y - 4.0f, x + lp.horizontalSpacing, y + 4.0f, mPaint);
}
if (lp.breakLine) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y, x, y + 6.0f, mPaint);
canvas.drawLine(x, y + 6.0f, x + 6.0f, y + 6.0f, mPaint);
}
return more;
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p.width, p.height);
}
public static class LayoutParams extends ViewGroup.LayoutParams {
int x;
int y;
public int horizontalSpacing;
public boolean breakLine;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout_LayoutParams);
try {
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, -1);
breakLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_breakLine, false);
} finally {
a.recycle();
}
}
public LayoutParams(int w, int h) {
super(w, h);
}
}
}

View file

@ -6,6 +6,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.util.Log;
import org.secuso.privacyfriendlybreakreminder.database.columns.ExerciseSetColumns;
@ -72,13 +73,29 @@ public class SQLiteHelper extends SQLiteOpenHelper {
database.close();
}
public void updateExerciseSet(ExerciseSet exerciseSet) {
SQLiteDatabase database = getReadableDatabase();
database.update(ExerciseSetColumns.TABLE_NAME, ExerciseSetColumns.getValues(exerciseSet), ExerciseSetColumns._ID + " = ?", new String[]{String.valueOf(exerciseSet.getId())});
database.close();
}
public synchronized long addExerciseSet(String name) {
SQLiteDatabase database = getReadableDatabase();
ContentValues cv = new ContentValues();
cv.put(ExerciseSetColumns.NAME, name);
return database.insert(ExerciseSetColumns.TABLE_NAME, null, cv);
long id = database.insert(ExerciseSetColumns.TABLE_NAME, null, cv);
database.close();
return id;
}
public void clearExercisesFromSet(int exerciseSetId) {
SQLiteDatabase database = getReadableDatabase();
database.delete("exercise_set_exercises", ExerciseSetColumns._ID + " = ?", new String[]{String.valueOf(exerciseSetId)});
database.close();
}
public synchronized void addExerciseToExerciseSet(int exerciseSetId, int exerciseId) {
@ -131,14 +148,17 @@ public class SQLiteHelper extends SQLiteOpenHelper {
}
c.moveToNext();
}
c.close();
}
close();
return result;
}
public synchronized Cursor getExerciseCursor(String language) {
SQLiteDatabase database = getReadableDatabase();
return database.rawQuery(buildQuery(false), new String[]{language});
return database.rawQuery(buildQuery(0), new String[]{language});
}
public synchronized List<Exercise> getExerciseList(String language) {
@ -196,6 +216,8 @@ public class SQLiteHelper extends SQLiteOpenHelper {
c.close();
}
close();
return result;
}
@ -214,41 +236,45 @@ public class SQLiteHelper extends SQLiteOpenHelper {
c.close();
}
close();
return result;
}
private String buildQuery(boolean addSectionCheck) {
return buildQuery(addSectionCheck, "");
}
public synchronized List<Exercise> getExercisesFromSection(String language, String section) { // TODO: Rename after old activities are deleted
public synchronized List<Exercise> getExerciseListBySections(String language, @NonNull List<String> sections) {
SQLiteDatabase database = getReadableDatabase();
Cursor c = database.rawQuery(buildQuery(true), new String[]{language, "%"+section+"%"});
String[] argValues = new String[sections.size() + 1];
argValues[0] = language;
for(int i = 1; i < argValues.length; ++i) {
argValues[i] = "%"+sections.get(i - 1)+"%";
}
Cursor c = database.rawQuery(buildQuery(sections.size()), argValues);
return buildExerciseList(c);
}
public synchronized List<Exercise> getExercisesFromSection(String language, String section) { // TODO: REMOVE after old activities are deleted
SQLiteDatabase database = getReadableDatabase();
Cursor c = database.rawQuery(buildQuery(1), new String[]{language, "%"+section+"%"});
return buildExerciseList(c);
}
/**
* SELECT
* E._id,
* E.section,
* E.image_id,
* L.local_id,
* L.language,
* L.exercise_id,
* L.name,
* L.description,
* L.execution
* SELECT *
* FROM exercises E LEFT OUTER JOIN exercises_local L
* ON E._id = L.exercise_id
* WHERE L.language = "de" [AND E.section LIKE %?%]
* WHERE L.language = "de" [AND E.section LIKE ?]
* ORDER BY E._id ASC
*
* @return the sql query without the ; at the end.
*/
private String buildQuery(boolean addSectionCheck, String customWhereClause) {
private String buildQuery(int sectionCheck) {
StringBuilder sqlQuery = new StringBuilder();
sqlQuery.append("SELECT ");
@ -279,12 +305,23 @@ public class SQLiteHelper extends SQLiteOpenHelper {
sqlQuery.append(ExerciseLocalColumns.LANGUAGE);
sqlQuery.append(" = ? ");
if(addSectionCheck) {
sqlQuery.append("AND E.");
if(sectionCheck > 0) {
sqlQuery.append("AND ( ");
}
for(int i = 0; i < sectionCheck; ++i) {
sqlQuery.append("E.");
sqlQuery.append(ExerciseColumns.SECTION);
sqlQuery.append(" LIKE ? ");
if(i + 1 == sectionCheck) {
sqlQuery.append(") ");
} else {
sqlQuery.append("OR ");
}
}
sqlQuery.append("ORDER BY E.");
sqlQuery.append(ExerciseColumns._ID);
sqlQuery.append(" ASC");
@ -364,5 +401,4 @@ public class SQLiteHelper extends SQLiteOpenHelper {
}
}
}
}

View file

@ -56,4 +56,7 @@ public class ExerciseSet {
return exercises.size();
}
public List<Exercise> getExercises() {
return exercises;
}
}

View file

@ -1,4 +1,4 @@
package org.secuso.privacyfriendlybreakreminder;
package org.secuso.privacyfriendlybreakreminder.exercises;
import java.util.Arrays;
import java.util.HashSet;
@ -8,7 +8,9 @@ import java.util.Locale;
* This class saves the available languages for the exercises.
* @author Christopher Beckmann
*/
public class ExerciseLocale {
public final class ExerciseLocale {
private ExerciseLocale() {}
private static final HashSet<String> AVAILABLE_LOCALE = new HashSet<>();

View file

@ -0,0 +1,36 @@
package org.secuso.privacyfriendlybreakreminder.exercises;
import android.content.Context;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import org.secuso.privacyfriendlybreakreminder.R;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Created by Christopher Beckmann on 06.09.2017.
*/
public enum ExerciseSections {
Head(R.string.exercise_section_head),
Neck(R.string.exercise_section_neck),
Arms(R.string.exercise_section_arms),
Torso(R.string.exercise_section_torso),
Spinal(R.string.exercise_section_spinal),
Pelvis(R.string.exercise_section_pelvis),
Legs(R.string.exercise_section_legs);
private final @StringRes int nameResId;
ExerciseSections(@StringRes int resId) {
this.nameResId = resId;
}
public String getLocalName(Context context) {
return context.getString(nameResId);
}
public static List<ExerciseSections> getSectionList() { return Arrays.asList( Head, Neck, Arms, Torso, Spinal, Pelvis, Legs ); }
}

View file

@ -28,12 +28,17 @@ import java.util.Timer;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
public class TimerService extends Service {
public static final String TAG = TimerService.class.getSimpleName();
public static final String NOTIFICATION_BROADCAST = TAG + ".NOTIFICATION_BROADCAST";
public static final String TIMER_BROADCAST = TAG + ".TIMER_BROADCAST";
private static final int UPDATE_INTERVAL = 25;
private static final int NOTIFICATION_ID = 31337;
private TimerServiceBinder mBinder = new TimerServiceBinder();
private CountDownTimer mTimer;
private NotificationManager notificationManager;
private boolean isRunning = false;
private long remainingDuration = 0;
@ -43,14 +48,17 @@ public class TimerService extends Service {
int lastTime = 0;
@Override
public void onReceive(Context context, Intent intent) {
if((int) remainingDuration / 1000 != lastTime) {
lastTime = (int) remainingDuration / 1000;
updateNotification();
}
if(intent.getBooleanExtra("done" ,false)) {
// limit the notification updates
int remainingSeconds = intent.getIntExtra("countdown_seconds", 0);
if(remainingSeconds != lastTime) {
lastTime = remainingSeconds;
updateNotification();
} else if(intent.getBooleanExtra("done" ,false)) {
lastTime = 0;
updateNotification();
}
}
};
@ -72,10 +80,19 @@ public class TimerService extends Service {
public synchronized void startTimer(long duration) {
if(!isRunning) {
initialDuration = duration;
mTimer = createTimer(duration);
mTimer.start();
isRunning = true;
sendBroadcast(buildBroadcast());
if(duration > 0) {
mTimer = createTimer(duration);
mTimer.start();
isRunning = true;
sendBroadcast(buildBroadcast());
} else {
remainingDuration = initialDuration;
Intent broadcast = buildBroadcast();
broadcast.putExtra("done", true);
sendBroadcast(broadcast);
}
}
}
@ -83,6 +100,7 @@ public class TimerService extends Service {
if(isRunning) {
mTimer.cancel();
isRunning = false;
sendBroadcast(buildBroadcast());
}
}
@ -92,6 +110,7 @@ public class TimerService extends Service {
mTimer = createTimer(remainingDuration);
mTimer.start();
isRunning = true;
sendBroadcast(buildBroadcast());
}
}
@ -103,6 +122,7 @@ public class TimerService extends Service {
mTimer.start();
}
remainingDuration = initialDuration;
sendBroadcast(buildBroadcast());
}
@ -110,10 +130,11 @@ public class TimerService extends Service {
if(isRunning) mTimer.cancel();
isRunning = false;
remainingDuration = initialDuration;
sendBroadcast(buildBroadcast());
}
public synchronized boolean isPaused() { return !isRunning && remainingDuration > 0 && remainingDuration != initialDuration; }
public synchronized boolean isPaused() { return !isRunning && initialDuration != 0 && remainingDuration > 0 && remainingDuration != initialDuration; }
public synchronized boolean isRunning() {
return isRunning;
@ -122,24 +143,29 @@ public class TimerService extends Service {
private CountDownTimer createTimer(long duration) {
remainingDuration = duration;
return new CountDownTimer(duration, 10) {
return new CountDownTimer(duration, UPDATE_INTERVAL) {
@Override
public void onTick(long millisUntilFinished) {
synchronized (TimerService.this) {
if(isRunning) {
remainingDuration = millisUntilFinished;
sendBroadcast(buildBroadcast());
}
sendBroadcast(buildBroadcast());
}
@Override
public void onFinish() {
mTimer.cancel();
isRunning = false;
remainingDuration = 0;
Intent broadcast = buildBroadcast();
broadcast.putExtra("done", true);
sendBroadcast(buildBroadcast());
sendBroadcast(broadcast);
remainingDuration = initialDuration;
stopAndResetTimer();
}
};
}
@ -153,6 +179,7 @@ public class TimerService extends Service {
broadcast.putExtra("countdown_seconds", secondsUntilFinished);
broadcast.putExtra("isRunning", isRunning());
broadcast.putExtra("isPaused", isPaused());
return (broadcast);
}
@ -160,15 +187,11 @@ public class TimerService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
setAsForegroundService();
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
return START_STICKY;
}
private void setAsForegroundService() {
startForeground(31337, buildNotification());
}
private Notification buildNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle(getString(R.string.app_name));
@ -187,13 +210,18 @@ public class TimerService extends Service {
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setWhen(0);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setOngoing(isRunning() || isPaused());
return builder.build();
}
private void updateNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(31337, buildNotification());
if(isRunning() || isPaused())
startForeground(NOTIFICATION_ID, buildNotification());
else
stopForeground(false);
notificationManager.notify(NOTIFICATION_ID, buildNotification());
}
@Override

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape
android:innerRadiusRatio="4"
android:shape="ring"
android:useLevel="false"
android:thicknessRatio="12">
<solid android:color="@color/middlegrey"/>
</shape>
</item>
<item android:id="@android:id/progress">
<shape
android:innerRadiusRatio="4"
android:useLevel="true"
android:shape="ring"
android:thicknessRatio="12">
<solid android:color="@color/lightblue"/>
<corners android:radius="2dp"/>
</shape>
</item>
</layer-list>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.secuso.privacyfriendlybreakreminder.activities.ChooseExerciseActivity">
<org.secuso.privacyfriendlybreakreminder.activities.layout.FlowLayout
android:id="@+id/layout_filter_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="@+id/exercise_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_filter_buttons"
app:layout_constraintVertical_bias="0.0"
android:layout_marginLeft="8dp"
android:layout_marginRight="4dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp" />
</android.support.constraint.ConstraintLayout>

View file

@ -44,39 +44,52 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="org.secuso.privacyfriendlybreakreminder.activities.ManageExerciseSetsActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/exercise_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintVertical_bias="0.0">
<android.support.design.widget.FloatingActionButton
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:clickable="true"
android:onClick="onClick"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:srcCompat="@drawable/ic_edit_white_24dp" />
</android.support.v7.widget.RecyclerView>
<android.support.v7.widget.RecyclerView
android:id="@+id/exercise_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="4dp"
app:layout_constraintVertical_bias="0.0">
<ProgressBar
android:id="@+id/loading_spinner"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
</android.support.v7.widget.RecyclerView>
<ProgressBar
android:id="@+id/loading_spinner"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
</android.support.constraint.ConstraintLayout>

View file

@ -48,7 +48,7 @@
android:layout_marginTop="8dp"
app:layout_constraintHorizontal_bias="0.0"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
android:layout_marginEnd="8dp"/>
<!-- <android.support.design.widget.FloatingActionButton
android:id="@+id/button_chooseExercise"
@ -99,7 +99,8 @@
android:layout_height="135dp"
android:clickable="false"
android:focusable="false"
android:theme="@style/AppTheme.NumberPicker" />
android:theme="@style/AppTheme.NumberPicker"
android:descendantFocusability="blocksDescendants" />
<TextView
android:layout_width="wrap_content"
@ -114,7 +115,8 @@
android:id="@+id/minutes_picker"
android:layout_width="wrap_content"
android:layout_height="135dp"
android:theme="@style/AppTheme.NumberPicker" />
android:theme="@style/AppTheme.NumberPicker"
android:descendantFocusability="blocksDescendants" />
<TextView
android:layout_width="wrap_content"
@ -130,7 +132,8 @@
android:layout_width="wrap_content"
android:layout_height="135dp"
android:clipChildren="false"
android:theme="@style/AppTheme.NumberPicker" />
android:theme="@style/AppTheme.NumberPicker"
android:descendantFocusability="blocksDescendants" />
</LinearLayout>
@ -185,7 +188,7 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" />
android:layout_marginBottom="8dp"/>
<ImageButton
android:id="@+id/button_playPause"

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/exercise_layout"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
android:padding="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/exercise_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ImageButton
android:id="@+id/exercise_info_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:padding="4dp"
android:background="?android:selectableItemBackgroundBorderless"
android:hapticFeedbackEnabled="true"
app:layout_constraintRight_toRightOf="@+id/exercise_image"
app:layout_constraintTop_toTopOf="@+id/exercise_image"
app:srcCompat="@drawable/ic_about" />
<CheckBox
android:id="@+id/exercise_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintBottom_toBottomOf="@+id/exercise_image"
app:layout_constraintRight_toRightOf="@+id/exercise_image" />
</android.support.constraint.ConstraintLayout>

View file

@ -76,6 +76,7 @@
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:text="This set contains no exercises."
android:textColor="@color/black"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
</declare-styleable>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_breakLine" format="boolean" />
<attr name="layout_horizontalSpacing" format="dimension" />
</declare-styleable>
</resources>

View file

@ -293,6 +293,15 @@
</string>
<string name="action_settings">Settings</string>
<string name="activity_edit_exercise_set_name_hint">Enter a name …</string>
<string name="exercise_section_head">Head</string>
<string name="exercise_section_neck">Neck</string>
<string name="exercise_section_arms">Arms</string>
<string name="exercise_section_torso">Torso</string>
<string name="exercise_section_spinal">Spinal Column</string>
<string name="exercise_section_pelvis">Pelvis</string>
<string name="exercise_section_legs">Legs</string>
<string name="activity_title_choose_exercises">Choose Exercises</string>
<string name="activity_edit_no_empty_name">Please specify a name.</string>
</resources>