From e8f04a218ea28d8443f23ac30315ea5e77a4d5e9 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Fri, 7 Apr 2017 11:07:40 -0600 Subject: [PATCH 1/8] Added isDue field support --- Habitica/assets/migrations/Habitica/35.sql | 3 ++- Habitica/assets/migrations/Habitica/37.sql | 1 + .../com/habitrpg/android/habitica/HabitDatabase.java | 2 +- .../android/habitica/NotificationPublisher.java | 2 +- .../habitrpg/android/habitica/models/tasks/Task.java | 10 ++++++++-- 5 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 Habitica/assets/migrations/Habitica/37.sql diff --git a/Habitica/assets/migrations/Habitica/35.sql b/Habitica/assets/migrations/Habitica/35.sql index 34786fcee..993400ee6 100644 --- a/Habitica/assets/migrations/Habitica/35.sql +++ b/Habitica/assets/migrations/Habitica/35.sql @@ -1 +1,2 @@ -ALTER TABLE Preferences ADD COLUMN dailyDueDefaultView bool; \ No newline at end of file +ALTER TABLE Preferences ADD COLUMN dailyDueDefaultView bool; + diff --git a/Habitica/assets/migrations/Habitica/37.sql b/Habitica/assets/migrations/Habitica/37.sql new file mode 100644 index 000000000..ef6218a57 --- /dev/null +++ b/Habitica/assets/migrations/Habitica/37.sql @@ -0,0 +1 @@ +ALTER TABLE Task ADD COLUMN isDue BOOLEAN; \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java index 56ed150b8..51c56ecae 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java @@ -7,7 +7,7 @@ public class HabitDatabase { public static final String NAME = "Habitica"; - public static final int VERSION = 36; + public static final int VERSION = 37; public HabitDatabase() { super(); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/NotificationPublisher.java b/Habitica/src/main/java/com/habitrpg/android/habitica/NotificationPublisher.java index dacd96fc0..fdc01b633 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/NotificationPublisher.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/NotificationPublisher.java @@ -42,7 +42,7 @@ public class NotificationPublisher extends BroadcastReceiver { .queryList(); show_notification = false; for (Task task : dailies) { - if (task.isDue(0)) { + if (task.checkIfDue(0)) { show_notification = true; break; } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java index 4324e6f80..e2d0da4ea 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java @@ -107,6 +107,9 @@ public class Task extends BaseModel { @SerializedName("_id") String id; + @Column + public Boolean isDue; + /** * @return the id */ @@ -568,7 +571,7 @@ public class Task extends BaseModel { return R.color.best_10; } - public Boolean isDue(int offset) { + public Boolean checkIfDue(int offset) { if (this.getCompleted()) { return true; } @@ -608,7 +611,10 @@ public class Task extends BaseModel { } public Boolean isDisplayedActive(int offset) { - return this.isDue(offset) && !this.completed; + if (this.isDue != null) { + return this.isDue; + } + return this.checkIfDue(offset) && !this.completed; } public Boolean isChecklistDisplayActive(int offset) { From e8a3b769a4a405f1feb38cd2304caa148bc48a1c Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Fri, 7 Apr 2017 13:38:55 -0600 Subject: [PATCH 2/8] Add remote config parser --- .../habitica/helpers/RemoteConfigManager.java | 122 ++++++++++++++++++ .../habitica/ui/activities/MainActivity.java | 3 + 2 files changed, 125 insertions(+) create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java new file mode 100644 index 000000000..c3af931a9 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java @@ -0,0 +1,122 @@ +package com.habitrpg.android.habitica.helpers; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Environment; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; + +import bolts.Bolts; + +/** + * Created by keith holliday on 4/7/2017. + */ + +public class RemoteConfigManager { + + private static RemoteConfigManager instance; + private Context context; + private static Boolean enableRepeatbles = false; + + private RemoteConfigManager(Context context) { + this.context = context; + new DownloadFileFromURL().execute("https://s3.amazonaws.com/habitica-assets/mobileApp/endpoint/config-ios.json"); + } + + public static RemoteConfigManager getInstance(Context context) { + if (instance == null) { + instance = new RemoteConfigManager(context); + } + return instance; + } + + public static Boolean repeatablesAreEnabled () { + return enableRepeatbles; + } + + class DownloadFileFromURL extends AsyncTask { + private String filename = "config.json"; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(String ...fileUrl) { + int count; + try { + URL url = new URL(fileUrl[0]); + URLConnection conection = url.openConnection(); + conection.connect(); + + int lenghtOfFile = conection.getContentLength(); + + InputStream input = new BufferedInputStream(url.openStream(), + 8192); + + OutputStream output = context.openFileOutput(filename, Context.MODE_PRIVATE); + + byte data[] = new byte[1024]; + + long total = 0; + + while ((count = input.read(data)) != -1) { + total += count; + publishProgress("" + (int) ((total * 100) / lenghtOfFile)); + output.write(data, 0, count); + } + + output.flush(); + + output.close(); + input.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + @Override + protected void onPostExecute(String file_url) { + File file = new File(context.getFilesDir(), filename); + StringBuilder text = new StringBuilder(); + + try { + BufferedReader br = new BufferedReader(new FileReader(file)); + String line; + + while ((line = br.readLine()) != null) { + text.append(line); + text.append('\n'); + } + br.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + + try { + JSONObject obj = new JSONObject(text.toString()); + enableRepeatbles = obj.getBoolean("enableRepeatbles"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + } +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java index a507cfd4e..a57c608e6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java @@ -78,6 +78,7 @@ import com.habitrpg.android.habitica.events.commands.UnlockPathCommand; import com.habitrpg.android.habitica.events.commands.UpdateUserCommand; import com.habitrpg.android.habitica.helpers.AmplitudeManager; import com.habitrpg.android.habitica.helpers.LanguageHelper; +import com.habitrpg.android.habitica.helpers.RemoteConfigManager; import com.habitrpg.android.habitica.helpers.SoundManager; import com.habitrpg.android.habitica.helpers.TaskAlarmManager; import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager; @@ -257,6 +258,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + RemoteConfigManager remoteConfigManager = RemoteConfigManager.getInstance(this); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); LanguageHelper languageHelper = new LanguageHelper(sharedPreferences.getString("language", "en")); Locale.setDefault(languageHelper.getLocale()); From 20cedc2e0c23b957016e62a43a11be2579a80461 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Fri, 7 Apr 2017 14:03:11 -0600 Subject: [PATCH 3/8] Began adding repeatables layout --- Habitica/res/layout/activity_task_form.xml | 91 +++++++++++++--------- Habitica/res/layout/tasks_duedate.xml | 36 +++++++++ Habitica/res/values/strings.xml | 2 + 3 files changed, 92 insertions(+), 37 deletions(-) create mode 100644 Habitica/res/layout/tasks_duedate.xml diff --git a/Habitica/res/layout/activity_task_form.xml b/Habitica/res/layout/activity_task_form.xml index e4a4273fe..a68c12a43 100644 --- a/Habitica/res/layout/activity_task_form.xml +++ b/Habitica/res/layout/activity_task_form.xml @@ -33,21 +33,22 @@ android:focusable="true" android:focusableInTouchMode="true" /> - - - - - + android:layout_height="match_parent" + app:hintTextAppearance="@style/TextAppearance.AppCompat"> + + + + + + + + + + + + + + + + + android:orientation="vertical"> - - - + + + + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginTop="20dp" + android:id="@+id/task_tags_wrapper"> + + + + + + + + + + + + \ No newline at end of file diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index cda78452a..31943442f 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -78,6 +78,8 @@ Report a Bug Source Code + Repeat Every + Connection Error You are not connected to the internet. From 47af28546b0845f1f097bff7976155838ca62cec Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Mon, 10 Apr 2017 14:23:42 -0600 Subject: [PATCH 4/8] Added initial repeatabls UI --- Habitica/res/layout/activity_task_form.xml | 75 ++++-- Habitica/res/layout/tasks_startdate.xml | 23 ++ Habitica/res/values/strings.xml | 10 + Habitica/res/values/values.xml | 12 + .../ui/activities/TaskFormActivity.java | 231 ++++++++++++++++++ gradle.properties | 3 + 6 files changed, 334 insertions(+), 20 deletions(-) create mode 100644 Habitica/res/layout/tasks_startdate.xml create mode 100644 gradle.properties diff --git a/Habitica/res/layout/activity_task_form.xml b/Habitica/res/layout/activity_task_form.xml index a68c12a43..6ab5c2fcc 100644 --- a/Habitica/res/layout/activity_task_form.xml +++ b/Habitica/res/layout/activity_task_form.xml @@ -231,6 +231,7 @@ @@ -257,21 +258,7 @@ android:layout_marginTop="20dp" android:orientation="vertical"> - - - + @@ -294,7 +281,34 @@ android:layout_marginTop="20dp" android:orientation="vertical"> - + + + + + + + + android:text="@string/repeatables_on_title" + android:id="@+id/repeatables_on_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + + + @@ -325,8 +352,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:is="@id+/summary" - android:textAppearance="?android:attr/textAppearanceLarge" /> + android:id="@+id/summaryTitle" + android:text="@string/repeatables_summary_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + diff --git a/Habitica/res/layout/tasks_startdate.xml b/Habitica/res/layout/tasks_startdate.xml new file mode 100644 index 000000000..7423d86e6 --- /dev/null +++ b/Habitica/res/layout/tasks_startdate.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index 31943442f..86d49d168 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -118,6 +118,16 @@ On Certain Days of the Week Every X Days + Summary + Repeats + Repeats On + Daily + Weekly + Monthly + Yearly + Day of Month + Day of Week + Monday Tuesday Wednesday diff --git a/Habitica/res/values/values.xml b/Habitica/res/values/values.xml index 5b9a18efe..8619ffcc2 100644 --- a/Habitica/res/values/values.xml +++ b/Habitica/res/values/values.xml @@ -19,6 +19,18 @@ @string/frequency_daily + + @string/repeatables_frequency_daily + @string/repeatables_frequency_weekly + @string/repeatables_frequency_monthly + @string/repeatables_frequency_yearly + + + + @string/repeatables_frequency_day_of_month + @string/repeatables_frequency_day_of_week + + @string/monday @string/tuesday diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java index 3fa63ec30..6afdaec17 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java @@ -1,10 +1,35 @@ package com.habitrpg.android.habitica.ui.activities; + +import com.habitrpg.android.habitica.R; +import com.habitrpg.android.habitica.components.AppComponent; +import com.habitrpg.android.habitica.events.TaskSaveEvent; +import com.habitrpg.android.habitica.events.commands.DeleteTaskCommand; +import com.habitrpg.android.habitica.helpers.FirstDayOfTheWeekHelper; +import com.habitrpg.android.habitica.helpers.RemindersManager; +import com.habitrpg.android.habitica.helpers.RemoteConfigManager; +import com.habitrpg.android.habitica.helpers.TaskFilterHelper; +import com.habitrpg.android.habitica.helpers.TaskAlarmManager; +import com.habitrpg.android.habitica.ui.WrapContentRecyclerViewLayoutManager; +import com.habitrpg.android.habitica.ui.adapter.tasks.CheckListAdapter; +import com.habitrpg.android.habitica.ui.adapter.tasks.RemindersAdapter; +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser; +import com.habitrpg.android.habitica.ui.helpers.SimpleItemTouchHelperCallback; +import com.habitrpg.android.habitica.ui.helpers.ViewHelper; +import com.raizlabs.android.dbflow.sql.builder.Condition; +import com.raizlabs.android.dbflow.sql.language.Select; + +import net.pherth.android.emoji_library.EmojiEditText; +import net.pherth.android.emoji_library.EmojiPopup; + +import org.greenrobot.eventbus.EventBus; + import android.app.DatePickerDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.support.annotation.Nullable; @@ -17,10 +42,12 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.text.TextUtils; +import android.util.TypedValue; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -28,9 +55,11 @@ import android.widget.Button; import android.widget.CheckBox; import android.widget.DatePicker; import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.NumberPicker; +import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TableRow; import android.widget.TextView; @@ -138,6 +167,9 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem @BindView(R.id.task_weekdays_wrapper) LinearLayout weekdayWrapper; + @BindView(R.id.frequency_title) + TextView frequencyTitleTextView; + @BindView(R.id.task_frequency_spinner) Spinner dailyFrequencySpinner; @@ -178,10 +210,31 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem @BindView(R.id.duedate_checkbox) CheckBox dueDateCheckBox; + @BindView(R.id.startdate_text_title) + TextView startDateTitleTextView; @BindView(R.id.startdate_text_edittext) EditText startDatePickerText; + @BindView (R.id.repeatables_startdate_text_edittext) + EditText repeatablesStartDatePickerText; DateEditTextListener startDateListener; + @BindView(R.id.repeatables) + LinearLayout repeatablesLayout; + + @BindView(R.id.repeatables_on_title) + TextView reapeatablesOnTextView; + @BindView(R.id.task_repeatables_on_spinner) + Spinner repeatablesOnSpinner; + + @BindView(R.id.task_repeatables_every_x_spinner) + NumberPicker repeatablesEveryXSpinner; + + @BindView(R.id.task_repeatables_frequency_container) + LinearLayout repeatablesFrequencyContainer; + + @BindView(R.id.summary) + TextView summaryTextView; + @BindView(R.id.duedate_text_edittext) EditText dueDatePickerText; DateEditTextListener dueDateListener; @@ -192,6 +245,9 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem @BindView(R.id.task_tags_checklist) LinearLayout tagsContainerLinearLayout; + @BindView(R.id.task_repeatables_frequency_spinner) + Spinner repeatablesFrequencySpinner; + @Inject TaskFilterHelper taskFilterHelper; @@ -404,6 +460,8 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem emojiToggle2.setOnClickListener(new emojiClickListener(newCheckListEditText)); } + enableRepeatables(); + Observable.defer(() -> Observable.just(new Select().from(Tag.class) .where(Condition.column("user_id").eq(this.userId)) .queryList()) @@ -420,7 +478,170 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem ); } + // @TODO: abstract business logic to Presenter and only modify view? + private void enableRepeatables() + { + if (!RemoteConfigManager.repeatablesAreEnabled()){ + return; + } + if (!taskType.equals("daily")) { + repeatablesLayout.setVisibility(View.INVISIBLE); + ViewGroup.LayoutParams repeatablesLayoutParams = repeatablesLayout.getLayoutParams(); + repeatablesLayoutParams.height = 0; + repeatablesLayout.setLayoutParams(repeatablesLayoutParams); + return; + }; + + startDateLayout.setVisibility(View.INVISIBLE); + + ViewGroup.LayoutParams startDateLayoutParams = startDateLayout.getLayoutParams(); + startDateLayoutParams.height = 0; + startDateLayout.setLayoutParams(startDateLayoutParams); + + ViewGroup.LayoutParams startDatePickerTextParams = startDatePickerText.getLayoutParams(); + startDatePickerTextParams.height = 0; + startDatePickerText.setLayoutParams(startDatePickerTextParams); + + ViewGroup.LayoutParams startDateTitleTextViewParams = startDateTitleTextView.getLayoutParams(); + startDateTitleTextViewParams.height = 0; + startDateTitleTextView.setLayoutParams(startDateTitleTextViewParams); + + weekdayWrapper.setVisibility(View.INVISIBLE); + ViewGroup.LayoutParams weekdayWrapperParams = weekdayWrapper.getLayoutParams(); + weekdayWrapperParams.height = 0; + weekdayWrapper.setLayoutParams(weekdayWrapperParams); + + ViewGroup.LayoutParams frequencyTitleTextViewParams = frequencyTitleTextView.getLayoutParams(); + frequencyTitleTextViewParams.height = 0; + frequencyTitleTextView.setLayoutParams(frequencyTitleTextViewParams); + + ViewGroup.LayoutParams dailyFrequencySpinnerParams = dailyFrequencySpinner.getLayoutParams(); + dailyFrequencySpinnerParams.height = 0; + dailyFrequencySpinner.setLayoutParams(dailyFrequencySpinnerParams); + + startDateListener = new DateEditTextListener(repeatablesStartDatePickerText); + + ArrayAdapter frequencyAdapter = ArrayAdapter.createFromResource(this, + R.array.repeatables_frequencies, android.R.layout.simple_spinner_item); + frequencyAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + this.repeatablesFrequencySpinner.setAdapter(frequencyAdapter); + this.repeatablesFrequencySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + generateSummary(); + Resources r = getResources(); + + // @TODO: remove magic numbers + + if (position == 2) { + ViewGroup.LayoutParams repeatablesOnSpinnerParams = repeatablesOnSpinner.getLayoutParams(); + repeatablesOnSpinnerParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 72, r.getDisplayMetrics()); + repeatablesOnSpinner.setLayoutParams(repeatablesOnSpinnerParams); + + ViewGroup.LayoutParams repeatablesOnTitleParams = reapeatablesOnTextView.getLayoutParams(); + repeatablesOnTitleParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, r.getDisplayMetrics()); + reapeatablesOnTextView.setLayoutParams(repeatablesOnTitleParams); + + return; + } + + if (position == 1) { + ViewGroup.LayoutParams repeatablesFrequencyContainerParams = repeatablesFrequencyContainer.getLayoutParams(); + repeatablesFrequencyContainerParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 172, r.getDisplayMetrics()); + repeatablesFrequencyContainer.setLayoutParams(repeatablesFrequencyContainerParams); + return; + } + + ViewGroup.LayoutParams repeatablesOnSpinnerParams = repeatablesOnSpinner.getLayoutParams(); + repeatablesOnSpinnerParams.height = 0; + repeatablesOnSpinner.setLayoutParams(repeatablesOnSpinnerParams); + + ViewGroup.LayoutParams repeatablesOnTitleParams = reapeatablesOnTextView.getLayoutParams(); + repeatablesOnTitleParams.height = 0; + reapeatablesOnTextView.setLayoutParams(repeatablesOnTitleParams); + + ViewGroup.LayoutParams repeatablesFrequencyContainerParams = repeatablesFrequencyContainer.getLayoutParams(); + repeatablesFrequencyContainerParams.height = 0; + repeatablesFrequencyContainer.setLayoutParams(repeatablesFrequencyContainerParams); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + ArrayAdapter repeatablesOnAdapter = ArrayAdapter.createFromResource(this, + R.array.repeatables_on, android.R.layout.simple_spinner_item); + repeatablesOnAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + this.repeatablesOnSpinner.setAdapter(repeatablesOnAdapter); + this.repeatablesOnSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + generateSummary(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + + setEveryXSpinner(repeatablesEveryXSpinner); + repeatablesEveryXSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + generateSummary(); + } + }); + + String[] weekdays = getResources().getStringArray(R.array.weekdays); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + String dayOfTheWeek = sharedPreferences.getString("FirstDayOfTheWeek", + Integer.toString(Calendar.getInstance().getFirstDayOfWeek())); + firstDayOfTheWeekHelper = + FirstDayOfTheWeekHelper.newInstance(Integer.parseInt(dayOfTheWeek)); + ArrayList weekdaysTemp = new ArrayList<>(Arrays.asList(weekdays)); + Collections.rotate(weekdaysTemp, firstDayOfTheWeekHelper.getDailyTaskFormOffset()); + weekdays = weekdaysTemp.toArray(new String[1]); + + for (int i = 0; i < 7; i++) { + View weekdayRow = getLayoutInflater().inflate(R.layout.row_checklist, repeatablesFrequencyContainer, false); + CheckBox checkbox = (CheckBox) weekdayRow.findViewById(R.id.checkbox); + checkbox.setText(weekdays[i]); + checkbox.setChecked(true); + frequencyContainer.addView(weekdayRow); + } + + generateSummary(); + } + + private void generateSummary () { + String frequency = repeatablesFrequencySpinner.getSelectedItem().toString(); + String everyX = String.valueOf(repeatablesEveryXSpinner.getValue()); + String frequencyQualifier = ""; + + switch (frequency) { + case "Daily": + frequencyQualifier = "day(s)"; + break; + case "Weekly": + frequencyQualifier = "week(s)"; + break; + case "Monthly": + frequencyQualifier = "month(s)"; + break; + case "Yearly": + frequencyQualifier = "year(s)"; + break; + } + + String weekdays = ""; + + String summary = "Repeats " + frequency + " every " + everyX + " " + frequencyQualifier + " on " + weekdays; + summaryTextView.setText(summary); + } @Override protected void injectActivity(AppComponent component) { @@ -564,6 +785,16 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem } } + private void setEveryXSpinner(NumberPicker frequencyPicker) { +// View dayRow = getLayoutInflater().inflate(R.layout.row_number_picker, this.frequencyContainer, false); +// frequencyPicker = (NumberPicker) dayRow.findViewById(R.id.numberPicker); + frequencyPicker.setMinValue(1); + frequencyPicker.setMaxValue(366); +// TextView tv = (TextView) dayRow.findViewById(R.id.label); +// tv.setText(getResources().getString(R.string.frequency_daily)); +// this.frequencyContainer.addView(dayRow); + } + private void setDailyFrequencyViews() { this.frequencyContainer.removeAllViews(); if (this.dailyFrequencySpinner.getSelectedItemPosition() == 0) { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..3fcfe5803 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.configureondemand=true +org.gradle.daemon=true +org.gradle.jvmargs=-Xmx2048m \ No newline at end of file From c60724db89033a4463c4f8bc0d2bf0d464171c81 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Tue, 11 Apr 2017 11:08:21 -0600 Subject: [PATCH 5/8] Finished repeatables UI and read values to task --- .../android/habitica/models/tasks/Task.java | 5 + .../ui/activities/TaskFormActivity.java | 120 +++++++++++++++--- 2 files changed, 104 insertions(+), 21 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java index e2d0da4ea..e83cbc931 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java @@ -110,6 +110,11 @@ public class Task extends BaseModel { @Column public Boolean isDue; + // These do need to be local columns because all logic is stored in + // is due for now + public List daysOfMonth = new ArrayList<>(); + public List weeksOfMonth = new ArrayList<>(); + /** * @return the id */ diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java index 6afdaec17..946c59984 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java @@ -42,6 +42,7 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.text.TextUtils; +import android.util.Log; import android.util.TypedValue; import android.view.KeyEvent; import android.view.Menu; @@ -259,6 +260,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem private Task task; private String allocationMode; private List weekdayCheckboxes = new ArrayList<>(); + private List repeatablesWeekDayCheckboxes = new ArrayList<>(); private NumberPicker frequencyPicker; private List tags; private CheckListAdapter checklistAdapter; @@ -542,28 +544,24 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem ViewGroup.LayoutParams repeatablesOnTitleParams = reapeatablesOnTextView.getLayoutParams(); repeatablesOnTitleParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, r.getDisplayMetrics()); reapeatablesOnTextView.setLayoutParams(repeatablesOnTitleParams); - - return; - } - - if (position == 1) { + }else if (position == 1) { ViewGroup.LayoutParams repeatablesFrequencyContainerParams = repeatablesFrequencyContainer.getLayoutParams(); - repeatablesFrequencyContainerParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 172, r.getDisplayMetrics()); + repeatablesFrequencyContainerParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 220, r.getDisplayMetrics()); repeatablesFrequencyContainer.setLayoutParams(repeatablesFrequencyContainerParams); return; + } else { + ViewGroup.LayoutParams repeatablesOnSpinnerParams = repeatablesOnSpinner.getLayoutParams(); + repeatablesOnSpinnerParams.height = 0; + repeatablesOnSpinner.setLayoutParams(repeatablesOnSpinnerParams); + + ViewGroup.LayoutParams repeatablesOnTitleParams = reapeatablesOnTextView.getLayoutParams(); + repeatablesOnTitleParams.height = 0; + reapeatablesOnTextView.setLayoutParams(repeatablesOnTitleParams); + + ViewGroup.LayoutParams repeatablesFrequencyContainerParams = repeatablesFrequencyContainer.getLayoutParams(); + repeatablesFrequencyContainerParams.height = 0; + repeatablesFrequencyContainer.setLayoutParams(repeatablesFrequencyContainerParams); } - - ViewGroup.LayoutParams repeatablesOnSpinnerParams = repeatablesOnSpinner.getLayoutParams(); - repeatablesOnSpinnerParams.height = 0; - repeatablesOnSpinner.setLayoutParams(repeatablesOnSpinnerParams); - - ViewGroup.LayoutParams repeatablesOnTitleParams = reapeatablesOnTextView.getLayoutParams(); - repeatablesOnTitleParams.height = 0; - reapeatablesOnTextView.setLayoutParams(repeatablesOnTitleParams); - - ViewGroup.LayoutParams repeatablesFrequencyContainerParams = repeatablesFrequencyContainer.getLayoutParams(); - repeatablesFrequencyContainerParams.height = 0; - repeatablesFrequencyContainer.setLayoutParams(repeatablesFrequencyContainerParams); } @Override @@ -596,6 +594,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem } }); + this.repeatablesFrequencyContainer.removeAllViews(); String[] weekdays = getResources().getStringArray(R.array.weekdays); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); String dayOfTheWeek = sharedPreferences.getString("FirstDayOfTheWeek", @@ -607,11 +606,18 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem weekdays = weekdaysTemp.toArray(new String[1]); for (int i = 0; i < 7; i++) { - View weekdayRow = getLayoutInflater().inflate(R.layout.row_checklist, repeatablesFrequencyContainer, false); + View weekdayRow = getLayoutInflater().inflate(R.layout.row_checklist, this.repeatablesFrequencyContainer, false); CheckBox checkbox = (CheckBox) weekdayRow.findViewById(R.id.checkbox); checkbox.setText(weekdays[i]); checkbox.setChecked(true); - frequencyContainer.addView(weekdayRow); + checkbox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + generateSummary(); + } + }); + repeatablesWeekDayCheckboxes.add(checkbox); + repeatablesFrequencyContainer.addView(weekdayRow); } generateSummary(); @@ -638,8 +644,49 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem } String weekdays = ""; + List weekdayStrings = new ArrayList<>(); + int offset = firstDayOfTheWeekHelper.getDailyTaskFormOffset(); + if (this.repeatablesWeekDayCheckboxes.get(offset).isChecked()) { + weekdayStrings.add("Monday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 1) % 7).isChecked()) { + weekdayStrings.add("Tuesday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 2) % 7).isChecked()) { + weekdayStrings.add("Wednesday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 3) % 7).isChecked()) { + weekdayStrings.add("Thursday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 4) % 7).isChecked()) { + weekdayStrings.add("Friday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 5) % 7).isChecked()) { + weekdayStrings.add("Saturday"); + } + if (this.repeatablesWeekDayCheckboxes.get((offset + 6) % 7).isChecked()) { + weekdayStrings.add("Sunday"); + } + weekdays = " on " + TextUtils.join(", ", weekdayStrings); + if (!frequency.equals("Weekly")) { + weekdays = ""; + } - String summary = "Repeats " + frequency + " every " + everyX + " " + frequencyQualifier + " on " + weekdays; + if (frequency.equals("Monthly")) { + weekdays = ""; + Calendar calendar = startDateListener.getCalendar(); + String monthlyFreq = repeatablesOnSpinner.getSelectedItem().toString(); + if (monthlyFreq.equals("Day of Month")) { + Integer date = calendar.get(Calendar.DATE); + weekdays = " on the " + date.toString(); + } else { + Integer week = calendar.get(Calendar.WEEK_OF_MONTH); + String dayLongName = calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault()); + weekdays = " on the " + week.toString() + " week on " + dayLongName; + } + } + + String summary = "Repeats " + frequency + " every " + everyX + " " + frequencyQualifier + weekdays; summaryTextView.setText(summary); } @@ -1027,6 +1074,11 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem if (this.dailyFrequencySpinner.getSelectedItemPosition() == 0) { task.setFrequency("weekly"); + String frequency = this.repeatablesFrequencySpinner.getSelectedItem().toString(); + if (frequency != null && RemoteConfigManager.repeatablesAreEnabled()) { + task.setFrequency(frequency.toLowerCase()); + } + Days repeat = task.getRepeat(); if (repeat == null) { repeat = new Days(); @@ -1041,6 +1093,32 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem repeat.setF(this.weekdayCheckboxes.get((offset + 4) % 7).isChecked()); repeat.setS(this.weekdayCheckboxes.get((offset + 5) % 7).isChecked()); repeat.setSu(this.weekdayCheckboxes.get((offset + 6) % 7).isChecked()); + + if (RemoteConfigManager.repeatablesAreEnabled()) { + repeat.setM(this.repeatablesWeekDayCheckboxes.get(offset).isChecked()); + repeat.setT(this.repeatablesWeekDayCheckboxes.get((offset + 1) % 7).isChecked()); + repeat.setW(this.repeatablesWeekDayCheckboxes.get((offset + 2) % 7).isChecked()); + repeat.setTh(this.repeatablesWeekDayCheckboxes.get((offset + 3) % 7).isChecked()); + repeat.setF(this.repeatablesWeekDayCheckboxes.get((offset + 4) % 7).isChecked()); + repeat.setS(this.repeatablesWeekDayCheckboxes.get((offset + 5) % 7).isChecked()); + repeat.setSu(this.repeatablesWeekDayCheckboxes.get((offset + 6) % 7).isChecked()); + } + + if (frequency.equals("monthly")) { + Calendar calendar = startDateListener.getCalendar(); + String monthlyFreq = repeatablesOnSpinner.getSelectedItem().toString(); + if (monthlyFreq.equals("Day of Month")) { + Integer date = calendar.get(Calendar.DATE); + task.daysOfMonth = new ArrayList<>(); + task.daysOfMonth.add(date); + task.weeksOfMonth = new ArrayList<>(); + } else { + Integer week = calendar.get(Calendar.WEEK_OF_MONTH); + task.weeksOfMonth = new ArrayList<>(); + task.weeksOfMonth.add(week); + task.daysOfMonth = new ArrayList<>(); + } + } } else { task.setFrequency("daily"); task.setEveryX(this.frequencyPicker.getValue()); From 2ca3c4db1f07f2a4511aa86291f4b3e5cedae54f Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Tue, 2 May 2017 10:02:13 -0600 Subject: [PATCH 6/8] Added shared preferences --- .../habitica/helpers/RemoteConfigManager.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java index c3af931a9..e12b3e6c4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/RemoteConfigManager.java @@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.helpers; import android.content.Context; import android.os.AsyncTask; import android.os.Environment; +import android.support.v7.preference.PreferenceManager; import android.util.Log; import org.json.JSONException; @@ -30,9 +31,11 @@ public class RemoteConfigManager { private static RemoteConfigManager instance; private Context context; private static Boolean enableRepeatbles = false; + private String REMOTE_STRING_KEY = "remote-string"; private RemoteConfigManager(Context context) { this.context = context; + loadFromPreferences(); new DownloadFileFromURL().execute("https://s3.amazonaws.com/habitica-assets/mobileApp/endpoint/config-ios.json"); } @@ -47,6 +50,22 @@ public class RemoteConfigManager { return enableRepeatbles; } + private void loadFromPreferences () { + String storedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + .getString(REMOTE_STRING_KEY, ""); + + if (storedPreferences.isEmpty()) { + return; + } + + try { + JSONObject obj = new JSONObject(storedPreferences); + enableRepeatbles = obj.getBoolean("enableRepeatbles"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + class DownloadFileFromURL extends AsyncTask { private String filename = "config.json"; @@ -110,6 +129,9 @@ public class RemoteConfigManager { e.printStackTrace(); } + PreferenceManager.getDefaultSharedPreferences(context) + .edit().putString(REMOTE_STRING_KEY, text.toString()).apply(); + try { JSONObject obj = new JSONObject(text.toString()); enableRepeatbles = obj.getBoolean("enableRepeatbles"); From 8af1982d2b96e4346fd88ff8935ee83b0f64c9df Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Tue, 2 May 2017 10:06:34 -0600 Subject: [PATCH 7/8] Added is completed check --- .../java/com/habitrpg/android/habitica/models/tasks/Task.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java index e83cbc931..62d2728ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.java @@ -616,7 +616,7 @@ public class Task extends BaseModel { } public Boolean isDisplayedActive(int offset) { - if (this.isDue != null) { + if (this.isDue != null && !this.completed) { return this.isDue; } return this.checkIfDue(offset) && !this.completed; From a516d7428224c98bdfab3ca5e49e2f26d3915c05 Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Tue, 2 May 2017 10:47:25 -0600 Subject: [PATCH 8/8] Added string resource --- Habitica/res/values/strings.xml | 1 + .../android/habitica/ui/activities/TaskFormActivity.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index 86d49d168..29c27abe5 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -581,4 +581,5 @@ Reload Content Set Dailies default to ‘due’ tab With this option set, the Dailies tasks will default to ‘due’ instead of ‘all’ + "Repeats %1$s every %2$s %3$s %4$s" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java index 946c59984..0a00f24b6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.java @@ -686,7 +686,7 @@ public class TaskFormActivity extends BaseActivity implements AdapterView.OnItem } } - String summary = "Repeats " + frequency + " every " + everyX + " " + frequencyQualifier + weekdays; + String summary = getResources().getString(R.string.repeat_summary, frequency, everyX, frequencyQualifier, weekdays); summaryTextView.setText(summary); }