From f05d1dea285877b29f7de442bec1f83b090a44ef Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Wed, 13 Mar 2024 18:17:42 -0700 Subject: [PATCH 01/11] Fixing Bug for Recurring options in Pending List --- .../cse110/successorator/MainActivity.java | 4 + .../ui/CreateGoalDialogFragment.java | 20 +--- .../ui/CreatePendingGoalDialogFragment.java | 96 +++++++++++++++++++ .../fragment_dialog_create_pending_goal.xml | 79 +++++++++++++++ 4 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java create mode 100644 app/src/main/res/layout/fragment_dialog_create_pending_goal.xml diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java b/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java index ac971ce..4cf5f0a 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java @@ -22,6 +22,7 @@ import edu.ucsd.cse110.successorator.databinding.TutorialTextBinding; import edu.ucsd.cse110.successorator.lib.domain.AppMode; import edu.ucsd.cse110.successorator.ui.CreateGoalDialogFragment; +import edu.ucsd.cse110.successorator.ui.CreatePendingGoalDialogFragment; import edu.ucsd.cse110.successorator.ui.CreateRecurringGoalDialogFragment; import edu.ucsd.cse110.successorator.ui.GoalListAdapter; @@ -106,6 +107,9 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (mainViewModel.getCurrentMode().getValue() == AppMode.RECURRING) { var dialogFragment = CreateRecurringGoalDialogFragment.newInstance(); dialogFragment.show(getSupportFragmentManager(), "CreateRecurringGoalDialogFragment"); + } else if (mainViewModel.getCurrentMode().getValue() == AppMode.PENDING) { + var dialogFragment = CreatePendingGoalDialogFragment.newInstance(); + dialogFragment.show(getSupportFragmentManager(), "CreatePendingGoalDialogFragment"); } else { var dialogFragment = CreateGoalDialogFragment.newInstance(); dialogFragment.show(getSupportFragmentManager(), "CreateGoalDialogFragment"); diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java index 40ec144..f51bdc2 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java @@ -3,20 +3,16 @@ import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; +import android.view.inputmethod.EditorInfo; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; -import android.view.View; -import android.view.inputmethod.EditorInfo; -import android.widget.Button; -import android.widget.TextView; - import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreateGoalBinding; -import edu.ucsd.cse110.successorator.lib.domain.AppMode; import edu.ucsd.cse110.successorator.lib.domain.Context; @@ -51,7 +47,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @NonNull @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){ + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { this.view = FragmentDialogCreateGoalBinding.inflate(getLayoutInflater()); @@ -74,20 +70,14 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){ TextView.OnEditorActionListener editListener = (v, actionId, event) -> { //actionId determined in corresponding xml file. //Unnecessary now but futureproofs for multiple textboxes with the same listener. - if(actionId == EditorInfo.IME_ACTION_DONE){ + if (actionId == EditorInfo.IME_ACTION_DONE) { String content = view.goalInput.getText().toString(); if (context == null) { return false; } - //If on pending view logic to make pending goal - if (mainViewModel.getCurrentMode().getValue() == AppMode.PENDING) { - mainViewModel.addPendingGoal(content, context); - } else { - mainViewModel.addGoal(content, context); - } - + mainViewModel.addGoal(content, context); //Lambda functions allow for usage of this. in interface declaration. //Interestingly, without it dismiss() appears to call the correct function regardless. this.dismiss(); diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java new file mode 100644 index 0000000..3475024 --- /dev/null +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java @@ -0,0 +1,96 @@ +package edu.ucsd.cse110.successorator.ui; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.inputmethod.EditorInfo; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.lifecycle.ViewModelProvider; + +import edu.ucsd.cse110.successorator.MainViewModel; +import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreatePendingGoalBinding; +import edu.ucsd.cse110.successorator.lib.domain.Context; + + +public class CreatePendingGoalDialogFragment extends DialogFragment { + private FragmentDialogCreatePendingGoalBinding view; + //Not this most flexible name but the least ambiguous. + private MainViewModel mainViewModel; + + private Context context; + + public CreatePendingGoalDialogFragment() { + // Required empty public constructor + } + + public static CreatePendingGoalDialogFragment newInstance() { + var fragment = new CreatePendingGoalDialogFragment(); + //In case args needed in future. + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + var modelOwner = requireActivity(); + var modelFactory = ViewModelProvider.Factory.from(MainViewModel.initializer); + var modelProvider = new ViewModelProvider(modelOwner, modelFactory); + this.mainViewModel = modelProvider.get(MainViewModel.class); + } + + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + this.view = FragmentDialogCreatePendingGoalBinding.inflate(getLayoutInflater()); + + + // Create listener for context buttons + this.view.contextRadio.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == this.view.homeButton.getId()) { + this.context = Context.HOME; + } else if (checkedId == this.view.workButton.getId()) { + this.context = Context.WORK; + } else if (checkedId == this.view.schoolButton.getId()) { + this.context = Context.SCHOOL; + } else if (checkedId == this.view.errandsButton.getId()) { + this.context = Context.ERRANDS; + } + }); + + //Create listener for enter key. + //Interface containing method called anytime enter key is pressed. + //https://youtu.be/DivBp_9ZeK0?si=8Laea7bnST0mfmtm + TextView.OnEditorActionListener editListener = (v, actionId, event) -> { + //actionId determined in corresponding xml file. + //Unnecessary now but futureproofs for multiple textboxes with the same listener. + if (actionId == EditorInfo.IME_ACTION_DONE) { + String content = view.goalInput.getText().toString(); + + if (context == null) { + return false; + } + + //Add pending goal to the view model. + mainViewModel.addPendingGoal(content, context); + + //Lambda functions allow for usage of this. in interface declaration. + //Interestingly, without it dismiss() appears to call the correct function regardless. + this.dismiss(); + } + return false; + }; + //Give goal input textbox an enter listener. + this.view.goalInput.setOnEditorActionListener(editListener); + + return new AlertDialog.Builder(getActivity()) + .setView(view.getRoot()) + .create(); + } +} diff --git a/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml b/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml new file mode 100644 index 0000000..0e8c653 --- /dev/null +++ b/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From e1c9c9d2f599c5305a0d86663c7711a59f80df95 Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Wed, 13 Mar 2024 20:42:55 -0700 Subject: [PATCH 02/11] Added Recurrence String to show Day of Week --- .../cse110/successorator/MainViewModel.java | 26 ++++++++++++++++++- .../successorator/ui/GoalListAdapter.java | 19 ++++++-------- .../successorator/lib/util/TimeUtils.java | 25 ++++++++++++++++-- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java index e608ea6..1174cdd 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java @@ -5,6 +5,7 @@ import static edu.ucsd.cse110.successorator.lib.domain.AppMode.PENDING; import static edu.ucsd.cse110.successorator.lib.domain.AppMode.TODAY; import static edu.ucsd.cse110.successorator.lib.domain.AppMode.TOMORROW; +import static edu.ucsd.cse110.successorator.lib.util.TimeUtils.nthDayofWeek; import androidx.lifecycle.ViewModel; import androidx.lifecycle.viewmodel.ViewModelInitializer; @@ -433,7 +434,8 @@ public boolean addRecurringGoal(String contents, int year, int month, int day, R if (currentTime == null) return false; var selectedDate = (Calendar) currentTime.clone(); // Set at 12:00 PM to avoid 2am edge cases - selectedDate.set(year, month, day, 12, 0, 0); + // Decremented month by 1 because it is zero indexed + selectedDate.set(year, month - 1, day, 12, 0, 0); // Is this a bug? It seems like we are checking if selected date is equal to itself // if (selectedDate.get(Calendar.DAY_OF_MONTH) == day && selectedDate.get(Calendar.YEAR) == year && selectedDate.get(Calendar.MONTH) == month) { // return false; @@ -469,6 +471,28 @@ public void addRecurringGoalDateless(String contents, RecurrenceType recurrenceT handleRecurringGoalGeneration(recurringGoal, currentTime); } + // Method that adds date text when a recurring goal will reoccur + public String getGoalContent(Goal goal) { + if (currentMode.getValue() == AppMode.RECURRING) { + var startDate = TimeUtils.localize(goal.startDate(), dateConverter); + + switch (goal.recurrenceType()) { + case DAILY: + return goal.content() + ", Daily"; + case WEEKLY: + return goal.content() + ", Weekly on " + startDate.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US); + case MONTHLY: + return goal.content() + ", Monthly on " + nthDayofWeek(startDate); + case YEARLY: + return goal.content() + ", Yearly on " + (startDate.get(Calendar.MONTH) + 1) + "/" + startDate.get(Calendar.DAY_OF_MONTH); + default: + return goal.content(); + } + } else { + return goal.content(); + } + } + // Public for testing // Only call from a context where it won't recurse into LiveData updates public void handleRecurringGoalGeneration(Goal recurringGoal, Calendar currentDate) { diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/GoalListAdapter.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/GoalListAdapter.java index a20ce4d..6e2045e 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/GoalListAdapter.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/GoalListAdapter.java @@ -1,13 +1,11 @@ package edu.ucsd.cse110.successorator.ui; -import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Paint; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; import android.widget.ArrayAdapter; import androidx.annotation.NonNull; @@ -17,11 +15,12 @@ import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.ListItemGoalBinding; -import edu.ucsd.cse110.successorator.lib.domain.Goal; import edu.ucsd.cse110.successorator.lib.domain.Context; +import edu.ucsd.cse110.successorator.lib.domain.Goal; public class GoalListAdapter extends ArrayAdapter { private MainViewModel mainViewModel; + public GoalListAdapter(@NonNull android.content.Context context, @NonNull List goals, MainViewModel mainViewModel) { super(context, 0, new ArrayList<>(goals)); this.mainViewModel = mainViewModel; @@ -45,12 +44,11 @@ public View getView(int position, View convertView, ViewGroup parent) { Strike through reference: https://stackoverflow.com/questions/3881553/is-there-an-easy-way-to-strike-through-text-in-an-app-widget/6739637 */ - binding.goalText.setText(goal.content()); + binding.goalText.setText(mainViewModel.getGoalContent(goal)); if (goal.completed()) { binding.goalText.setPaintFlags(binding.goalText.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); binding.background.setBackgroundColor(Color.LTGRAY); - } - else { + } else { binding.goalText.setPaintFlags(binding.goalText.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG)); binding.background.setBackgroundColor(Color.WHITE); } @@ -58,21 +56,20 @@ public View getView(int position, View convertView, ViewGroup parent) { /* Logic for color of the list context icon */ - if (goal.context()==Context.HOME) { + if (goal.context() == Context.HOME) { binding.imageView.setColorFilter(Color.parseColor("#faf04d")); } - if (goal.context()==Context.WORK) { + if (goal.context() == Context.WORK) { binding.imageView.setColorFilter(Color.parseColor("#31c7f8")); } - if (goal.context()==Context.SCHOOL) { + if (goal.context() == Context.SCHOOL) { binding.imageView.setColorFilter(Color.parseColor("#c95bf9")); } - if (goal.context()==Context.ERRANDS) { + if (goal.context() == Context.ERRANDS) { binding.imageView.setColorFilter(Color.parseColor("#a2cb84")); } - return binding.getRoot(); } diff --git a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/util/TimeUtils.java b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/util/TimeUtils.java index f04a0ef..cbd83f7 100644 --- a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/util/TimeUtils.java +++ b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/util/TimeUtils.java @@ -1,8 +1,8 @@ package edu.ucsd.cse110.successorator.lib.util; -import java.sql.Time; import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.TimeZone; import edu.ucsd.cse110.successorator.lib.domain.RecurrenceType; @@ -106,7 +106,7 @@ public static int nextGoalRecurrenceIndex(Calendar nowLocalized, Calendar startT while (low < high) { int mid = (low + high) / 2; Calendar midRecurrence = nthRecurrence(startTime, recurrenceType, mid); - if (midRecurrence.before(nowLocalized) || (midRecurrence.get(Calendar.DAY_OF_YEAR) == nowLocalized.get(Calendar.DAY_OF_YEAR) && midRecurrence.get(Calendar.YEAR) == nowLocalized.get(Calendar.YEAR))) { + if (midRecurrence.before(nowLocalized) || (midRecurrence.get(Calendar.DAY_OF_YEAR) == nowLocalized.get(Calendar.DAY_OF_YEAR) && midRecurrence.get(Calendar.YEAR) == nowLocalized.get(Calendar.YEAR))) { low = mid + 1; } else { high = mid; @@ -164,4 +164,25 @@ public static long getStartTime() { return calendar.getTimeInMillis(); } + + // Generated by Chat-GPT, checked for correctness + public static String nthDayofWeek(Calendar calendar) { + String dayOfWeekString = calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US); + int occurrence = (calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH)); + String ordinalIndicator; + switch (occurrence) { + case 1: + ordinalIndicator = "st"; + break; + case 2: + ordinalIndicator = "nd"; + break; + case 3: + ordinalIndicator = "rd"; + break; + default: + ordinalIndicator = "th"; + } + return occurrence + ordinalIndicator + " " + dayOfWeekString; + } } From e8710df4b989325ff6e3b35fd0808cc709585bee Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Wed, 13 Mar 2024 21:11:55 -0700 Subject: [PATCH 03/11] Today and Tomorrow Recurring Goals show in Recurring List --- .../ui/CreateGoalDialogFragment.java | 24 +++++++++++++++++-- .../ui/CreateRecurringGoalDialogFragment.java | 14 +++++------ .../layout/fragment_dialog_create_goal.xml | 4 +--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java index f51bdc2..2e183c9 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java @@ -14,12 +14,15 @@ import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreateGoalBinding; import edu.ucsd.cse110.successorator.lib.domain.Context; +import edu.ucsd.cse110.successorator.lib.domain.RecurrenceType; public class CreateGoalDialogFragment extends DialogFragment { private FragmentDialogCreateGoalBinding view; //Not this most flexible name but the least ambiguous. private MainViewModel mainViewModel; + private RecurrenceType recurrenceType = RecurrenceType.NONE; + private Context context; @@ -64,6 +67,19 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { } }); + // Create listener for recurrence buttons + this.view.recurrenceRadio.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == this.view.DailyRecurringGoalButton.getId()) { + this.recurrenceType = RecurrenceType.DAILY; + } else if (checkedId == this.view.WeeklyRecurringGoalButton.getId()) { + this.recurrenceType = RecurrenceType.WEEKLY; + } else if (checkedId == this.view.MonthlyRecurringGoalButton.getId()) { + this.recurrenceType = RecurrenceType.MONTHLY; + } else if (checkedId == this.view.YearlyRecurringGoalButton.getId()) { + this.recurrenceType = RecurrenceType.YEARLY; + } + }); + //Create listener for enter key. //Interface containing method called anytime enter key is pressed. //https://youtu.be/DivBp_9ZeK0?si=8Laea7bnST0mfmtm @@ -76,8 +92,12 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { if (context == null) { return false; } - - mainViewModel.addGoal(content, context); + if (this.recurrenceType != recurrenceType.NONE) { + mainViewModel.addRecurringGoalDateless(content, this.recurrenceType, context); + } else { + mainViewModel.addGoal(content, context); + } + //Lambda functions allow for usage of this. in interface declaration. //Interestingly, without it dismiss() appears to call the correct function regardless. this.dismiss(); diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java index 0545057..524985e 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java @@ -3,15 +3,14 @@ import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; +import android.view.inputmethod.EditorInfo; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; -import android.view.inputmethod.EditorInfo; -import android.widget.TextView; - import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreateRecurringGoalBinding; import edu.ucsd.cse110.successorator.lib.domain.Context; @@ -50,12 +49,11 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @NonNull @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){ + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { this.view = FragmentDialogCreateRecurringGoalBinding.inflate(getLayoutInflater()); - - // Create listener for context buttons + // Create listener for recurrence buttons this.view.recurrenceRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { if (checkedId == this.view.dailyRecurringGoalButton.getId()) { this.recurrenceType = RecurrenceType.DAILY; @@ -90,10 +88,10 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){ String[] parts = view.recurringDatePicker.getText().toString().split("/"); if (parts.length == 3) { - if(actionId == EditorInfo.IME_ACTION_DONE){ + if (actionId == EditorInfo.IME_ACTION_DONE) { String content = view.goalInput.getText().toString(); //Context is defaulted to HOME, Needs US3 to be implemented. - mainViewModel.addRecurringGoal(content,Integer.parseInt(parts[2]), Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), + mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), recurrenceType, context); //Lambda functions allow for usage of this. in interface declaration. diff --git a/app/src/main/res/layout/fragment_dialog_create_goal.xml b/app/src/main/res/layout/fragment_dialog_create_goal.xml index d74f836..8c53d4a 100644 --- a/app/src/main/res/layout/fragment_dialog_create_goal.xml +++ b/app/src/main/res/layout/fragment_dialog_create_goal.xml @@ -1,7 +1,6 @@ @@ -77,9 +76,8 @@ - Date: Wed, 13 Mar 2024 21:23:17 -0700 Subject: [PATCH 04/11] Added Test for NthDayofWeek --- .../successorator/lib/util/TimeUtilsTest.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/src/test/java/edu/ucsd/cse110/successorator/lib/util/TimeUtilsTest.java b/lib/src/test/java/edu/ucsd/cse110/successorator/lib/util/TimeUtilsTest.java index 4daced6..0fbf517 100644 --- a/lib/src/test/java/edu/ucsd/cse110/successorator/lib/util/TimeUtilsTest.java +++ b/lib/src/test/java/edu/ucsd/cse110/successorator/lib/util/TimeUtilsTest.java @@ -1,12 +1,16 @@ package edu.ucsd.cse110.successorator.lib.util; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static edu.ucsd.cse110.successorator.lib.util.TimeUtils.nthDayofWeek; import org.junit.Test; import java.util.Calendar; +import java.util.Locale; -import edu.ucsd.cse110.successorator.lib.domain.AppMode; import edu.ucsd.cse110.successorator.lib.domain.RecurrenceType; public class TimeUtilsTest { @@ -185,7 +189,6 @@ public void nthRecurrence() { assertEquals(recurrence.get(Calendar.DAY_OF_MONTH), 31); - calendar = Calendar.getInstance(); calendar.set(year, month, day, hour, 0, 0); calendar.setTimeZone(TimeUtils.GMT); @@ -267,7 +270,6 @@ public void nextGoalRecurrenceIndex() { assertEquals(TimeUtils.nextGoalRecurrenceIndex(now, start, RecurrenceType.MONTHLY), 6); - // Test 4: Recurrence is Yearly } @@ -293,4 +295,34 @@ public void twoAMNormalized() { assertEquals(normalized.get(Calendar.DAY_OF_YEAR), test.get(Calendar.DAY_OF_YEAR)); } + + // Test Generated with GPT4, Check for correctness + @Test + public void testNthDayOfWeekForVariousDates() { + Calendar calendar = Calendar.getInstance(Locale.US); + + // Test for the first Monday of a month + calendar.set(2024, Calendar.MARCH, 4); // Assuming March 4, 2024 is the first Monday + assertEquals("1st Monday", nthDayofWeek(calendar)); + + // Test for the second Tuesday of a month + calendar.set(2024, Calendar.APRIL, 9); // Assuming April 9, 2024 is the second Tuesday + assertEquals("2nd Tuesday", nthDayofWeek(calendar)); + + // Test for the third Wednesday of a month + calendar.set(2024, Calendar.MAY, 15); // Assuming May 15, 2024 is the third Wednesday + assertEquals("3rd Wednesday", nthDayofWeek(calendar)); + + // Test for the fourth Thursday of a month + calendar.set(2024, Calendar.JUNE, 27); // Assuming June 27, 2024 is the fourth Thursday + assertEquals("4th Thursday", nthDayofWeek(calendar)); + + // Test for the fifth Friday of a month + calendar.set(2024, Calendar.AUGUST, 30); // Assuming August 30, 2024 is the fifth Friday + assertEquals("5th Friday", nthDayofWeek(calendar)); + + // Test for the last Saturday of a month (could be 4th or 5th) + calendar.set(2024, Calendar.FEBRUARY, 24); // Assuming February 24, 2024 is the last Saturday + assertEquals("4th Saturday", nthDayofWeek(calendar)); + } } \ No newline at end of file From 5f8e792cc3057f1391858eb70cc7c256a49d6252 Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Wed, 13 Mar 2024 22:14:04 -0700 Subject: [PATCH 05/11] Made Test for Recurring Goal String UI, DOESN'T WORK PLEASE HELP --- .../cse110/successorator/MainViewModel.java | 5 -- .../successorator/MainViewModelTest.java | 46 ++++++++++++++----- .../lib/domain/MockGoalRepository.java | 15 +++++- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java index 1174cdd..1209640 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java @@ -585,8 +585,3 @@ public void deleteRecurringGoal(int goalId) { } } - -// public AppMode getCurrentMode() { -// return currentMode.getValue(); -// } -//} \ No newline at end of file diff --git a/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java b/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java index 20da789..331b390 100644 --- a/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java +++ b/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java @@ -1,6 +1,10 @@ package edu.ucsd.cse110.successorator; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import org.junit.After; import org.junit.Before; @@ -160,6 +164,28 @@ public void advance24HoursGoalVisibility() { assertCompleteCount(0); } + @Test + public void testGetGoalContent() { + goalRepository = null; + goalRepository = MockGoalRepository.createWithAllRecurranceTypeTestGoals(); + mainViewModel = new MainViewModel(goalRepository, dateOffset, dateTicker, localizedCalendar); + + System.out.println(goalRepository.goals.get(0).getValue().toString()); + mainViewModel.activateTodayView(); + assertEquals("Goal 1", mainViewModel.getGoalContent(goalRepository.)); + assertEquals("Goal 2", mainViewModel.getGoalContent(goalRepository.findGoal(2))); + assertEquals("Goal 3", mainViewModel.getGoalContent(goalRepository.findGoal(3))); + assertEquals("Goal 4", mainViewModel.getGoalContent(goalRepository.findGoal(4))); + assertEquals("Goal 5", mainViewModel.getGoalContent(goalRepository.findGoal(5))); + + mainViewModel.activateRecurringView(); + assertEquals("Goal 1", mainViewModel.getGoalContent(goalRepository.goals.get(0).getValue())); + assertEquals("Goal 2, Daily", mainViewModel.getGoalContent(goalRepository.goals.get(1).getValue())); + assertEquals("Goal 3, Weekly", mainViewModel.getGoalContent(goalRepository.goals.get(2).getValue())); + assertEquals("Goal 4, Monthly", mainViewModel.getGoalContent(goalRepository.goals.get(3).getValue())); + assertEquals("Goal 5, Yearly", mainViewModel.getGoalContent(goalRepository.goals.get(4).getValue())); + } + @Test public void testCalendarStreings() { // Verify that the current date string is correct @@ -391,7 +417,7 @@ public void ScenarioBasedSystemTests2() { //Step 1 //Sets up time to be March 7th, 2024 - dateTicker.setValue(TimeUtils.getStartTime()+TimeUtils.DAY_LENGTH*28); + dateTicker.setValue(TimeUtils.getStartTime() + TimeUtils.DAY_LENGTH * 28); mainViewModel = new MainViewModel(goalRepository, dateOffset, dateTicker, localizedCalendar); //Steps 2 to 5 @@ -410,14 +436,14 @@ public void ScenarioBasedSystemTests2() { mainViewModel.activateTodayView(); var displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()=="10km run") { + if (displayedGoals.get(i).content() == "10km run") { assertTrue(mainViewModel.pressGoal(displayedGoals.get(i).id())); } } mainViewModel.activateTomorrowView(); displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()==" ") { + if (displayedGoals.get(i).content() == " ") { assertTrue(mainViewModel.pressGoal(displayedGoals.get(i).id())); break; } @@ -426,7 +452,7 @@ public void ScenarioBasedSystemTests2() { //Step 7, trying to complete a goal that shouldn't be displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()=="push buttons on keyboard") { + if (displayedGoals.get(i).content() == "push buttons on keyboard") { assertFalse(mainViewModel.pressGoal(displayedGoals.get(i).id())); break; } @@ -436,7 +462,7 @@ public void ScenarioBasedSystemTests2() { mainViewModel.activateTodayView(); displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()=="push buttons on keyboard") { + if (displayedGoals.get(i).content() == "push buttons on keyboard") { assertTrue(mainViewModel.pressGoal(displayedGoals.get(i).id())); break; } @@ -444,7 +470,7 @@ public void ScenarioBasedSystemTests2() { mainViewModel.activateTomorrowView(); displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()=="push buttons on keyboard") { + if (displayedGoals.get(i).content() == "push buttons on keyboard") { assertTrue(mainViewModel.pressGoal(displayedGoals.get(i).id())); break; } @@ -464,7 +490,7 @@ public void ScenarioBasedSystemTests2() { mainViewModel.activateTomorrowView(); displayedGoals = mainViewModel.getGoalsToDisplay().getValue(); for (int i = 0; i < displayedGoals.size(); i++) { - if (displayedGoals.get(i).content()=="push buttons on keyboard") { + if (displayedGoals.get(i).content() == "push buttons on keyboard") { assertFalse(displayedGoals.get(i).completed()); break; } @@ -491,7 +517,6 @@ public void ScenarioBasedSystemTests3() { assertIncompleteCount(4); - //WIP logic to filter by context } @@ -760,6 +785,7 @@ public void MS2_US6Scenario2() { mainViewModel.activateRecurringView(); assertIncompleteCount(1); } + @Test public void MS2_US6Scenario3() { goalRepository = MockGoalRepository.createWithEmptyGoals(); @@ -1031,6 +1057,4 @@ public void MS2_US8Scenario4() { } - - } \ No newline at end of file diff --git a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java index bf91ed0..3f513f8 100644 --- a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java +++ b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java @@ -1,6 +1,5 @@ package edu.ucsd.cse110.successorator.lib.domain; -import java.sql.Time; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -39,6 +38,14 @@ public class MockGoalRepository implements GoalRepository { new Goal(3, "Goal 1", 3, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4 + TimeUtils.DAY_LENGTH, false, false, RecurrenceType.NONE, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4 + TimeUtils.DAY_LENGTH, 2, null, 1, true) ); + private final static List ALL_RECURRENCE_TEST_GOALS = List.of( + new Goal(1, "Goal 1", 1, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, false, RecurrenceType.NONE, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, 1, null, true), + new Goal(2, "Goal 2", 2, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.DAILY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 0, 2, null, false), + new Goal(3, "Goal 3", 3, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.WEEKLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 1, 3, null, false), + new Goal(4, "Goal 4", 4, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.MONTHLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 2, 4, null, false), + new Goal(5, "Goal 5", 5, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.YEARLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 3, null, null, false) + ); + public static MockGoalRepository createWithDefaultGoals() { return new MockGoalRepository(DEFAULT_GOALS_SIMPLE_CASE); } @@ -51,12 +58,16 @@ public static MockGoalRepository createWithRecurringTestGoals() { return new MockGoalRepository(RECCURING_TEST_GOALS); } + public static MockGoalRepository createWithAllRecurranceTypeTestGoals() { + return new MockGoalRepository(ALL_RECURRENCE_TEST_GOALS); + } + public static MockGoalRepository createWithEmptyGoals() { return new MockGoalRepository(new ArrayList<>()); } public MockGoalRepository(List goals) { - this.goals = new ArrayList<>(); + this.goals = new ArrayList<>(); for (Goal goal : goals) { var subject = new SimpleSubject(); subject.setValue(goal); From acc5ad08db76b9bb895f80c2900ead517cac2cd9 Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Thu, 14 Mar 2024 15:09:39 -0700 Subject: [PATCH 06/11] Fixed test for UI String on recurring goal --- .../successorator/MainViewModelTest.java | 20 +++++++++---------- .../lib/domain/MockGoalRepository.java | 12 +++++------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java b/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java index 331b390..7d9a48e 100644 --- a/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java +++ b/app/src/test/java/edu/ucsd/cse110/successorator/MainViewModelTest.java @@ -166,24 +166,22 @@ public void advance24HoursGoalVisibility() { @Test public void testGetGoalContent() { - goalRepository = null; - goalRepository = MockGoalRepository.createWithAllRecurranceTypeTestGoals(); + goalRepository = MockGoalRepository.createWithAllRecurrenceTypeTestGoals(); mainViewModel = new MainViewModel(goalRepository, dateOffset, dateTicker, localizedCalendar); - System.out.println(goalRepository.goals.get(0).getValue().toString()); mainViewModel.activateTodayView(); - assertEquals("Goal 1", mainViewModel.getGoalContent(goalRepository.)); - assertEquals("Goal 2", mainViewModel.getGoalContent(goalRepository.findGoal(2))); - assertEquals("Goal 3", mainViewModel.getGoalContent(goalRepository.findGoal(3))); - assertEquals("Goal 4", mainViewModel.getGoalContent(goalRepository.findGoal(4))); - assertEquals("Goal 5", mainViewModel.getGoalContent(goalRepository.findGoal(5))); + assertEquals("Goal 1", mainViewModel.getGoalContent(goalRepository.goals.get(0).getValue())); + assertEquals("Goal 2", mainViewModel.getGoalContent(goalRepository.goals.get(1).getValue())); + assertEquals("Goal 3", mainViewModel.getGoalContent(goalRepository.goals.get(2).getValue())); + assertEquals("Goal 4", mainViewModel.getGoalContent(goalRepository.goals.get(3).getValue())); + assertEquals("Goal 5", mainViewModel.getGoalContent(goalRepository.goals.get(4).getValue())); mainViewModel.activateRecurringView(); assertEquals("Goal 1", mainViewModel.getGoalContent(goalRepository.goals.get(0).getValue())); assertEquals("Goal 2, Daily", mainViewModel.getGoalContent(goalRepository.goals.get(1).getValue())); - assertEquals("Goal 3, Weekly", mainViewModel.getGoalContent(goalRepository.goals.get(2).getValue())); - assertEquals("Goal 4, Monthly", mainViewModel.getGoalContent(goalRepository.goals.get(3).getValue())); - assertEquals("Goal 5, Yearly", mainViewModel.getGoalContent(goalRepository.goals.get(4).getValue())); + assertEquals("Goal 3, Weekly on Wednesday", mainViewModel.getGoalContent(goalRepository.goals.get(2).getValue())); + assertEquals("Goal 4, Monthly on 1st Wednesday", mainViewModel.getGoalContent(goalRepository.goals.get(3).getValue())); + assertEquals("Goal 5, Yearly on 2/7", mainViewModel.getGoalContent(goalRepository.goals.get(4).getValue())); } @Test diff --git a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java index 3f513f8..5245d28 100644 --- a/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java +++ b/lib/src/main/java/edu/ucsd/cse110/successorator/lib/domain/MockGoalRepository.java @@ -39,11 +39,11 @@ public class MockGoalRepository implements GoalRepository { ); private final static List ALL_RECURRENCE_TEST_GOALS = List.of( - new Goal(1, "Goal 1", 1, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, false, RecurrenceType.NONE, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, 1, null, true), - new Goal(2, "Goal 2", 2, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.DAILY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 0, 2, null, false), - new Goal(3, "Goal 3", 3, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.WEEKLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 1, 3, null, false), - new Goal(4, "Goal 4", 4, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.MONTHLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 2, 4, null, false), - new Goal(5, "Goal 5", 5, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.YEARLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, 3, null, null, false) + new Goal(1, "Goal 1", 1, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, false, RecurrenceType.NONE, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, null, null, false), + new Goal(2, "Goal 2", 2, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.DAILY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, null, null, false), + new Goal(3, "Goal 3", 3, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.WEEKLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, null, null, false), + new Goal(4, "Goal 4", 4, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.MONTHLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, null, null, false), + new Goal(5, "Goal 5", 5, false, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, false, true, RecurrenceType.YEARLY, Context.HOME, TimeUtils.START_TIME - TimeUtils.HOUR_LENGTH * 4, null, null, null, false) ); public static MockGoalRepository createWithDefaultGoals() { @@ -58,7 +58,7 @@ public static MockGoalRepository createWithRecurringTestGoals() { return new MockGoalRepository(RECCURING_TEST_GOALS); } - public static MockGoalRepository createWithAllRecurranceTypeTestGoals() { + public static MockGoalRepository createWithAllRecurrenceTypeTestGoals() { return new MockGoalRepository(ALL_RECURRENCE_TEST_GOALS); } From 5252994b39e6d0159615b07879441916198e6521 Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Thu, 14 Mar 2024 15:26:55 -0700 Subject: [PATCH 07/11] Fixed Merge Conflict --- .../ui/CreateRecurringGoalDialogFragment.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java index 4b55150..736794f 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java @@ -10,9 +10,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; -import android.view.inputmethod.EditorInfo; -import android.widget.TextView; -import android.widget.Toast; + import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreateRecurringGoalBinding; import edu.ucsd.cse110.successorator.lib.domain.Context; @@ -94,8 +92,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { if (actionId == EditorInfo.IME_ACTION_DONE) { String content = view.goalInput.getText().toString(); //Context is defaulted to HOME, Needs US3 to be implemented. - mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), - boolean success = mainViewModel.addRecurringGoal(content,Integer.parseInt(parts[2]), Integer.parseInt(parts[0]) - 1, Integer.parseInt(parts[1]), recurrenceType, context); + boolean success = mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]) - 1, Integer.parseInt(parts[1]), recurrenceType, context); if (!success) { // Display a popup telling the user to correct their date or select a context // https://stackoverflow.com/questions/2115758/how-do-i-display-an-alert-dialog-on-android From 49627dfa9e3310a947af4f79a237323b8c31a9cb Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Thu, 14 Mar 2024 16:00:31 -0700 Subject: [PATCH 08/11] Fixing error caused by merge conflict --- .../successorator/ui/CreateRecurringGoalDialogFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java index 736794f..5602334 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.view.inputmethod.EditorInfo; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -91,7 +92,6 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { if (parts.length == 3) { if (actionId == EditorInfo.IME_ACTION_DONE) { String content = view.goalInput.getText().toString(); - //Context is defaulted to HOME, Needs US3 to be implemented. boolean success = mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]) - 1, Integer.parseInt(parts[1]), recurrenceType, context); if (!success) { // Display a popup telling the user to correct their date or select a context From d4672ed7e30436fff24d48403375dc6c0dbc430b Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Thu, 14 Mar 2024 16:08:53 -0700 Subject: [PATCH 09/11] Fixing decrement issue --- .../main/java/edu/ucsd/cse110/successorator/MainViewModel.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java index a35ba55..2e73a87 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/MainViewModel.java @@ -436,8 +436,7 @@ public boolean addRecurringGoal(String contents, int year, int month, int day, R if (currentTime == null) return false; var selectedDate = (Calendar) currentTime.clone(); // Set at 12:00 PM to avoid 2am edge cases - // Decremented month by 1 because it is zero indexed - selectedDate.set(year, month - 1, day, 12, 0, 0); + selectedDate.set(year, month, day, 12, 0, 0); // Is this a bug? It seems like we are checking if selected date is equal to itself if (selectedDate.get(Calendar.DAY_OF_MONTH) != day || selectedDate.get(Calendar.YEAR) != year && selectedDate.get(Calendar.MONTH) != month) { return false; From b13236f4e8e19cc5e30ed96d595063cf8d406d86 Mon Sep 17 00:00:00 2001 From: JGonzaga7 Date: Thu, 14 Mar 2024 16:24:32 -0700 Subject: [PATCH 10/11] Fixing .class merge error (hopefully) --- .../successorator/ui/CreateRecurringGoalDialogFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java index 5602334..2920936 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateRecurringGoalDialogFragment.java @@ -92,7 +92,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { if (parts.length == 3) { if (actionId == EditorInfo.IME_ACTION_DONE) { String content = view.goalInput.getText().toString(); - boolean success = mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]) - 1, Integer.parseInt(parts[1]), recurrenceType, context); + boolean success = (boolean) mainViewModel.addRecurringGoal(content, Integer.parseInt(parts[2]), Integer.parseInt(parts[0]) - 1, Integer.parseInt(parts[1]), recurrenceType, context); if (!success) { // Display a popup telling the user to correct their date or select a context // https://stackoverflow.com/questions/2115758/how-do-i-display-an-alert-dialog-on-android From 835af42b794dfd667712dfa979f0b12744ab8108 Mon Sep 17 00:00:00 2001 From: wizard1238 <49770335+wizard1238@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:54:53 -0700 Subject: [PATCH 11/11] reverted redundant bug fix --- .../cse110/successorator/MainActivity.java | 4 - .../ui/CreateGoalDialogFragment.java | 18 ++-- .../ui/CreatePendingGoalDialogFragment.java | 96 ------------------- .../fragment_dialog_create_pending_goal.xml | 79 --------------- 4 files changed, 11 insertions(+), 186 deletions(-) delete mode 100644 app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java delete mode 100644 app/src/main/res/layout/fragment_dialog_create_pending_goal.xml diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java b/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java index 162a07a..ec6b542 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/MainActivity.java @@ -23,7 +23,6 @@ import edu.ucsd.cse110.successorator.databinding.TutorialTextBinding; import edu.ucsd.cse110.successorator.lib.domain.AppMode; import edu.ucsd.cse110.successorator.ui.CreateGoalDialogFragment; -import edu.ucsd.cse110.successorator.ui.CreatePendingGoalDialogFragment; import edu.ucsd.cse110.successorator.ui.CreateRecurringGoalDialogFragment; import edu.ucsd.cse110.successorator.ui.GoalListAdapter; @@ -121,9 +120,6 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (mainViewModel.getCurrentMode().getValue() == AppMode.RECURRING) { var dialogFragment = CreateRecurringGoalDialogFragment.newInstance(); dialogFragment.show(getSupportFragmentManager(), "CreateRecurringGoalDialogFragment"); - } else if (mainViewModel.getCurrentMode().getValue() == AppMode.PENDING) { - var dialogFragment = CreatePendingGoalDialogFragment.newInstance(); - dialogFragment.show(getSupportFragmentManager(), "CreatePendingGoalDialogFragment"); } else { var dialogFragment = CreateGoalDialogFragment.newInstance(); dialogFragment.show(getSupportFragmentManager(), "CreateGoalDialogFragment"); diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java index 1b06a95..e985e99 100644 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java +++ b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreateGoalDialogFragment.java @@ -3,16 +3,18 @@ import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; -import android.view.inputmethod.EditorInfo; -import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProvider; import android.view.inputmethod.EditorInfo; import android.widget.TextView; + + import edu.ucsd.cse110.successorator.MainViewModel; import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreateGoalBinding; +import edu.ucsd.cse110.successorator.lib.domain.AppMode; import edu.ucsd.cse110.successorator.lib.domain.Context; import edu.ucsd.cse110.successorator.lib.domain.RecurrenceType; @@ -50,7 +52,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @NonNull @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){ this.view = FragmentDialogCreateGoalBinding.inflate(getLayoutInflater()); // Hook up button labels to the view model @@ -91,7 +93,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { TextView.OnEditorActionListener editListener = (v, actionId, event) -> { //actionId determined in corresponding xml file. //Unnecessary now but futureproofs for multiple textboxes with the same listener. - if (actionId == EditorInfo.IME_ACTION_DONE) { + if(actionId == EditorInfo.IME_ACTION_DONE){ String content = view.goalInput.getText().toString(); if (context == null) { @@ -101,12 +103,14 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { .show(); return false; } - if (this.recurrenceType != recurrenceType.NONE) { - mainViewModel.addRecurringGoalDateless(content, this.recurrenceType, context); + + //If on pending view logic to make pending goal + if (mainViewModel.getCurrentMode().getValue() == AppMode.PENDING) { + mainViewModel.addPendingGoal(content, context); } else { mainViewModel.addGoal(content, context); } - + //Lambda functions allow for usage of this. in interface declaration. //Interestingly, without it dismiss() appears to call the correct function regardless. this.dismiss(); diff --git a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java b/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java deleted file mode 100644 index 3475024..0000000 --- a/app/src/main/java/edu/ucsd/cse110/successorator/ui/CreatePendingGoalDialogFragment.java +++ /dev/null @@ -1,96 +0,0 @@ -package edu.ucsd.cse110.successorator.ui; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.os.Bundle; -import android.view.inputmethod.EditorInfo; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.DialogFragment; -import androidx.lifecycle.ViewModelProvider; - -import edu.ucsd.cse110.successorator.MainViewModel; -import edu.ucsd.cse110.successorator.databinding.FragmentDialogCreatePendingGoalBinding; -import edu.ucsd.cse110.successorator.lib.domain.Context; - - -public class CreatePendingGoalDialogFragment extends DialogFragment { - private FragmentDialogCreatePendingGoalBinding view; - //Not this most flexible name but the least ambiguous. - private MainViewModel mainViewModel; - - private Context context; - - public CreatePendingGoalDialogFragment() { - // Required empty public constructor - } - - public static CreatePendingGoalDialogFragment newInstance() { - var fragment = new CreatePendingGoalDialogFragment(); - //In case args needed in future. - Bundle args = new Bundle(); - fragment.setArguments(args); - return fragment; - } - - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - var modelOwner = requireActivity(); - var modelFactory = ViewModelProvider.Factory.from(MainViewModel.initializer); - var modelProvider = new ViewModelProvider(modelOwner, modelFactory); - this.mainViewModel = modelProvider.get(MainViewModel.class); - } - - - @NonNull - @Override - public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { - this.view = FragmentDialogCreatePendingGoalBinding.inflate(getLayoutInflater()); - - - // Create listener for context buttons - this.view.contextRadio.setOnCheckedChangeListener((group, checkedId) -> { - if (checkedId == this.view.homeButton.getId()) { - this.context = Context.HOME; - } else if (checkedId == this.view.workButton.getId()) { - this.context = Context.WORK; - } else if (checkedId == this.view.schoolButton.getId()) { - this.context = Context.SCHOOL; - } else if (checkedId == this.view.errandsButton.getId()) { - this.context = Context.ERRANDS; - } - }); - - //Create listener for enter key. - //Interface containing method called anytime enter key is pressed. - //https://youtu.be/DivBp_9ZeK0?si=8Laea7bnST0mfmtm - TextView.OnEditorActionListener editListener = (v, actionId, event) -> { - //actionId determined in corresponding xml file. - //Unnecessary now but futureproofs for multiple textboxes with the same listener. - if (actionId == EditorInfo.IME_ACTION_DONE) { - String content = view.goalInput.getText().toString(); - - if (context == null) { - return false; - } - - //Add pending goal to the view model. - mainViewModel.addPendingGoal(content, context); - - //Lambda functions allow for usage of this. in interface declaration. - //Interestingly, without it dismiss() appears to call the correct function regardless. - this.dismiss(); - } - return false; - }; - //Give goal input textbox an enter listener. - this.view.goalInput.setOnEditorActionListener(editListener); - - return new AlertDialog.Builder(getActivity()) - .setView(view.getRoot()) - .create(); - } -} diff --git a/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml b/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml deleted file mode 100644 index 0e8c653..0000000 --- a/app/src/main/res/layout/fragment_dialog_create_pending_goal.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file