commit ecd4120b0a82f3f5be0f1caa6223a461c07b53a7 Author: Rapturate Date: Mon Feb 23 09:50:15 2026 -0500 Gitea Migration diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..37db34f --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +MIT License + +Copyright (c) 2026 rapturate + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8da1a4 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# To_Do_List + +A console To Do List, written in Java, for a software development class. Shows my functional understanding of Java and organizational skills for code \ No newline at end of file diff --git a/To_Do_List_Console.jar b/To_Do_List_Console.jar new file mode 100644 index 0000000..b4250d3 Binary files /dev/null and b/To_Do_List_Console.jar differ diff --git a/bin/list.txt b/bin/list.txt new file mode 100644 index 0000000..5eab067 --- /dev/null +++ b/bin/list.txt @@ -0,0 +1,6 @@ +Health, Doctors Appointment, 10/31/2025, 2 +Health, Dentist Appointment, 10/31/2025, 3 +School, School Visit, 11/22/2025, 3 +Rover, Sadie, 11/22/1995, 4 +Rover, Sadie and Finn, 09/10/2025, 4 +na, Dog Sit, 12/31/1969, 10 diff --git a/src/Item.java b/src/Item.java new file mode 100644 index 0000000..02dc2ef --- /dev/null +++ b/src/Item.java @@ -0,0 +1,224 @@ + + + + + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Item { + private String category = " "; + private String name; + private Date dueDate; + private int priority = 10; + + //Constructors + /** + * Initializes an {@code Item} object. + *

+ * Usage: + * {@snippet : + * Item item = new Item("Jump up and down"); + * } + * @param String The name of the item to do. + * @return {@code void} + */ + public Item(String name){ + this.name = name; + } + + public Item(String name, String category, String dateString, int priority){ + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + + this.name = name; + this.category = category; + try { + this.dueDate = formatter.parse(dateString); + } catch (ParseException e){ + System.out.println("Date formatting failed."); + e.printStackTrace(); + } + this.priority = priority; + + } + //Setters + + // Method Signature: setCategoty(String) -> void + // Purpose: sets the category name + // Example: Item.setCategory("Health") + + /** + * Sets the {@code String category} field. + *

+ * Usage: + * {@snippet : + * item.setCategory("Health"); + * } + * @param String The String for {@code Private String category}. + * @return {@code void} + */ + public void setCategory(String category){ + this.category = category; + } + + // Method Signature: setName(String) -> void + // Purpose: sets the name of the event + // Example: Item.setName("Workout") + + /** + * Sets the {@code private String name} field. + *

+ * Usage: + * {@snippet : + * item.setName("Field Work"); + * } + * @param String The String for {@code Private String name}. + * @return {@code void} + */ + public void setName(String name){ + this.name = name; + } + + // Method Signature: setDueDate(String) -> void + // Purpose: sets the date. This class takes in a String, converts it into a Date and puts it into dueDate. + // Default: if the date is input incorrectly, it defaults to 12/31/1969. + // Example: Item.setCategory(dateString) + + /** + * Sets the {@code private Date dueDate} field. + *

+ * The date MUST be formatted as MM/DD/YYYY. + *

+ * Usage: + * {@snippet : + * item.setDueDate("MM/DD/YYYY"); + * } + * @param String The String that will be formatted for {@code Private Date dueDate}. + * @return {@code void} + */ + public void setDueDate(String dateString){ + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + Date date = new Date(0); + try { + date = formatter.parse(dateString); + } catch (ParseException e){ + System.out.println("Bad Date format."); + } + + this.dueDate = date; + } + + // Method Signature: setPriority(int) -> void + // Purpose: sets the priority on a scale of 1-10. 10 being the least important and 1 being the most. + // Example: Item.setPriority(1) + + /** + * Sets the {@code private int priority} field. + *

+ * Usage: + * {@snippet : + * item.setPriority(10); + * } + * @param int The integer for {@code Private String priority}. + * @return {@code void} + */ + public void setPriority(int priority){ + this.priority = priority; + } + + + //Getters + + /** + * Gets the String stored in {@code private String category} field. + *

+ * Usage: + * {@snippet : + * String category = item.getCategory(); + * } + * @return {@code String} + */ + public String getCategory() { + return this.category; + } + + /** + * Gets the String stored in {@code private String name} field. + *

+ * Usage: + * {@snippet : + * String name = item.getName(); + * } + * @return {@code String} + */ + public String getName() { + return this.name; + } + + /** + * Gets the {@code Date} object stored in {@code private int dueDate} field. + *

+ * Usage: + * {@snippet : + * Date dueDate = item.getDueDate(); + * } + * @return {@code Date} + */ + public Date getDueDate() { + return this.dueDate; + } + + /** + * Gets the integer stored in {@code private int dueDate} field and converts it to a {@code String}. + *

+ * Usage: + * {@snippet : + * String dueDateString = item.getDueDateString(); + * } + * @return {@code String} + */ + public String getDueDateString(){ + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + return formatter.format(this.dueDate); + } + + /** + * Gets the integer stored in {@code private int priority} field. + *

+ * Usage: + * {@snippet : + * int priority = item.getPriority(); + * } + * @return {@code int} + */ + public int getPriority() { + return this.priority; + } + + /** + * Takes all of the fields in {@code Item} and converts them to a formatted {@code String} for command line printing. + *

+ * Usage: + * {@snippet : + * String itemString = item.formatString(); + * } + * @return {@code String}: returns "" if there is no date + */ + public String formatString(){ + String dateString = ""; + + if(dueDate.compareTo(new Date(0)) != 0 ){ //If the compareTo funcioon returns 0 than the date is set to default which means 12/31/1969. + SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyy"); + dateString = format.format(this.dueDate); + if(dateString.equals("12/31/1969")){ + dateString = ""; + } + } + if(this.category.equals("na")){ + this.category = ""; + } + + return String.format("%-23s %-20s %-12s %-10d\n", this.name, this.category, dateString, this.priority); + } + } \ No newline at end of file diff --git a/src/MainLoop.java b/src/MainLoop.java new file mode 100644 index 0000000..bea2fb8 --- /dev/null +++ b/src/MainLoop.java @@ -0,0 +1,21 @@ +import java.util.Scanner; + +/** + * + * @author Lewis Price + * @since 1.0 + */ + +public class MainLoop { + public static void main(String[] args) { + String listPath; + System.out.println("Enter the path to where you want the todo list file to be."); + Scanner scanner = new Scanner(System.in); + listPath = scanner.next(); + + UserInterface ui = new UserInterface(listPath); + ui.run(); + + scanner.close(); + } +} diff --git a/src/ToDoList.java b/src/ToDoList.java new file mode 100644 index 0000000..6b36c8f --- /dev/null +++ b/src/ToDoList.java @@ -0,0 +1,481 @@ + + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.InputMismatchException; +import java.util.Scanner; + +public class ToDoList { + private ArrayList listArr; + private String pathName; + private Scanner scanner; + private String listHeader = String.format("%-23s %-20s %-12s %-10s\n----------------------------------------------------------------------------------------------------\n" + , "Name", "Category", "Date", "Priority"); + private String footer = "----------------------------------------------------------------------------------------------------\n"; + + //Constructor + /** + * Constructor for creating a new ToDoList. + * + * {@snippet : + * ToDoList list = new ToDoList( [filePath] , [Scanner Object] ); + * } + * + * @param pathName Takes the path of the list.txt file to open or create a new file. + * @param Scanner Scanner passthrough to prevent {@code Scanner} clashes. + */ + public ToDoList(String pathName, Scanner scanner){ + listArr = new ArrayList(); + this.pathName = pathName; + this.scanner = scanner; + openList(); + } + + //Setters + /** + * Used by the system to add a new {@code Item} to the {@code ArrayList} + * + * {@snippet : + * list.addItem( [item] ); + * } + * + * @param Item The {@code Item} being added to the {@code ArrayList} + * @return void + */ + private void addItem(Item item){ + listArr.add(item); + } + + /** + * Used by the system to create a header for console output. + * + * {@snippet : + * formatHeader( "Add Item" ); + * } + * + * @param String: the name of the page that needs a header output string. + * @return {@code String header} + */ + private String formatHeader(String pageName){ + String formatedHeader = ""; + int i; + for(i = 0; i < (50 - pageName.length()/2); i++){ + formatedHeader += "-"; + } + formatedHeader += pageName; + + for( i += pageName.length(); i < 100; i++){ + formatedHeader += "-"; + } + formatedHeader += "\n"; + return formatedHeader; + } + + + + /** + * Begins the System output and input to create and add a new {@code Item} to {@code ArrayList}. + *

+ * Usage + * {@snippet : + * list.addItemAction(); + * } + *

+ * ------------- + *

+ * Defaults: + *

+ * Date: 12/31/1969 + *

+ * - This date is read by the system as null and won't be visibly printed. + *

+ * Category: "na" + *

+ * - "na" is read by the system as null and won't be visibly printed. + *

+ * Priority: 10 + *

+ * - Priority 10 is the least important therefore the default if not provided. + * + * @return void, but prints messages to console. + */ + public void addItemAction() { + System.out.println(formatHeader("Add Item")); + System.out.print("Name (Required): "); + String name = scanner.nextLine(); + Item newItem = new Item(name); + + + System.out.print("Category: "); + String category = scanner.nextLine(); + if(category.equals("na") || category.equals("")) { + category = "na"; + } + newItem.setCategory(category); + + System.out.print("Date (MM/DD/YYYY): "); + String dateString = scanner.nextLine(); + + if(dateString.equals("na") || dateString.equals("")) { + newItem.setDueDate("12/31/1969"); //defaults to 12/31/1969 + } else { + newItem.setDueDate(dateString); + } + + System.out.print("Priority: "); + String priority = scanner.nextLine(); + try { + Integer.parseInt(priority); + } catch (NumberFormatException e){ + priority = "10"; + } + + if(priority.equals("")){ + priority = "10"; + }else if(Integer.parseInt(priority) < 1 || Integer.parseInt(priority) > 10) { + System.out.println("Priority out of range, defaulted to 10."); + priority = "10"; + } + + newItem.setPriority(Integer.parseInt(priority)); + addItem(newItem); + System.out.println("\n\nAdded:\n" + listHeader + newItem.formatString()); + } + + /** + * Takes a {@code String} to create an {@code Item} to {@code ArrayList}. + *

+ * This function must include a all {@code Item} parameters. + *

+ * Usage + * {@snippet : + * list.addItemAction({@code "name, category, date, priority"); + * } + *

+ * + * @param String, parses this string into different sections to create a new {@code Item} + * @return void, but prints messages to console. + */ + public void addItemByString(String inputString) { + String[] parsedString = inputString.split(", "); + Item newItem = new Item(parsedString[0], parsedString[1], parsedString[2], Integer.parseInt(parsedString[3])); + addItem(newItem); + System.out.println("\n\nAdded:\n" + listHeader + newItem.formatString()); + } + + + + + + + /** + * Formats, displays, and deletes an {@code Item} from user input from {@code ArrayList}. + *

+ * Does not save to the txt file. See {@code saveChanges()}. + *

+ * Usage: + * {@snippet : + * list.deleteItem(); + * } + * + * @return void, but prints to console. + */ + public void deleteItem(){ + System.out.println(formatHeader("Delete Item")); + System.out.println("Type one name and all items by that name will be removed."); + System.out.print("Name: "); + String name = scanner.nextLine(); + ArrayList tempList = new ArrayList<>(); + ArrayList deletedItems = new ArrayList<>(); + + //Deletes + for(Item list: listArr){ + if(!list.getName().equalsIgnoreCase(name)){ + tempList.add(list); + } else { + deletedItems.add(list); + } + } + + if(deletedItems.size() > 0){ + System.out.println(formatHeader("Deleted Items")); + for(Item list: deletedItems){ + System.out.print(list.formatString()); + } + System.out.print(footer); + listArr = tempList; + saveChanges(); + } else { + System.out.println("No item by that name."); + } + } + + /** + * Formats, displays, and changes an {@code Item} from user input from {@code ArrayList}. + *

+ * Does not save to the txt file. See {@code saveChanges()}. + *

+ * Usage: + * {@snippet : + * list.changeItem(); + * } + * + * @return void, but prints to console. + */ + public void changeItem(){ + System.out.println(formatHeader("Change Item")); + ArrayList alteredItems = new ArrayList<>(); + System.out.println(); + + System.out.println("Type the name of the item you'd like to change."); + System.out.print("Name: "); + String name = scanner.nextLine(); + + System.out.println("What aspect would you like to change?"); + System.out.println("Type 'Name', 'Category', 'Date' or 'Priority'."); + System.out.print("Response: "); + String response = scanner.nextLine(); + + int changeCount = 0; + + //Change Name + if(response.equalsIgnoreCase("Name")){ + System.out.print("New Name: "); + String newName = scanner.nextLine(); + + for(Item changedItem : listArr){ + if(changedItem.getName().equalsIgnoreCase(name)){ + alteredItems.add(changedItem); + changedItem.setName(newName); + changeCount++; + } + } + System.out.println(String.format("%d item(s) changed", changeCount)); + + //Change Category + } else if(response.equalsIgnoreCase("Category")){ + System.out.print("\nNew Category Name: "); + String newCatName = scanner.nextLine(); + for(Item changedItem : listArr){ + if(changedItem.getName().equalsIgnoreCase(name)){ + alteredItems.add(changedItem); + changedItem.setCategory(newCatName); + changeCount++; + } + } + System.out.println(String.format("%d item(s) changed", changeCount)); + + //Change Date + } else if(response.equalsIgnoreCase("Date")){ + System.out.print("New Date (MM/DD/YYY): "); + String dateString = scanner.nextLine(); + for(Item changedItem : listArr){ + if(changedItem.getName().equalsIgnoreCase(name)){ + alteredItems.add(changedItem); + changedItem.setDueDate(dateString); + changeCount++; + } + } + System.out.println(String.format("%d item(s) changed", changeCount)); + + //Change Priority + } else if(response.equalsIgnoreCase("Priority")){ + System.out.print("New Priority: "); + + for(Item changedItem : listArr){ + if(changedItem.getName().equalsIgnoreCase(name)){ + try { + String newPriorityString = scanner.nextLine(); + alteredItems.add(changedItem); + int newPriority = Integer.parseInt(newPriorityString); + changedItem.setPriority(newPriority); + changeCount++; + + } catch (InputMismatchException e) { + System.out.println("Not an integer. Nothing changed."); + } + } + } + + System.out.println(String.format("%d item(s) changed", changeCount)); + + //Bad Input + } else { + System.out.println("Bad input, nothing altered."); + } + + //Print Changed Items + System.out.print(listHeader); + for(Item item : alteredItems){ + System.out.println(item.formatString()); + } + System.out.print(footer); + printList(); + } + + + /** + *Opens a {@code .txt file} from a developers {@code main} function. + *

+ * Usage: + * {@snippet : + * list.openList(); + * } + * + * @return void, but prints to console. + */ + public void openList(){ + File listFile = new File(pathName); + try(Scanner fileReader = new Scanner(listFile)){ + while (fileReader.hasNextLine()) { + + String line = fileReader.nextLine(); + String[] splitLine = line.split(", "); + Item item = new Item(splitLine[1]); + + if(splitLine.length == 0){ + break; + } + + if(splitLine[0].equals("na")){ + item.setCategory(""); + } else { + item.setCategory(splitLine[0]); + } + + if(splitLine[2].equals("12/31/1969")){ + item.setDueDate("12/31/1969"); + } else { + item.setDueDate(splitLine[2]); + } + + if(splitLine[3].equals("na")){ + item.setPriority(10); + } else { + item.setPriority(Integer.parseInt(splitLine[3])); + } + + listArr.add(item); + } + } catch (FileNotFoundException e) { + System.out.println("No Previous List. Creating a new one."); + File file = new File(pathName); + try{ + file.createNewFile(); + + } catch(IOException failed){ + System.out.println("File creation failed."); + failed.printStackTrace(); + } + } + } + + + //Organization + /** + * Sorts the {@code ArrayList} by asking users which field they want to sort by. + *

+ * Does not save to the txt file. See {@code saveChanges()}. + *

+ * Usage: + * {@snippet : + * list.sortBy(); + * } + * + * @return void, but prints to console. + */ + public void sortBy(){ + System.out.println(formatHeader("Sort By")); + System.out.println( "- Category: Alphabetically by category name then alphabetically by Name.\n" + + "- Name: Alphabetically by Name.\n" + + "- Date: Earliest Date first, then by Category for repeated Dates.\n" + + "- Priorty: 1 is most important, 10 is least important. If Priorities are equal, sorted by Date. \n"); + System.out.print("Option: "); + String organizeBy = scanner.nextLine(); + if(organizeBy.equalsIgnoreCase("category")){ + listArr.sort(Comparator.comparing(Item::getCategory).thenComparing(Item::getName)); + + } else if(organizeBy.equalsIgnoreCase("name")){ + listArr.sort(Comparator.comparing(Item::getName).thenComparing(Item::getDueDate)); + + } else if(organizeBy.equalsIgnoreCase("date")){ + listArr.sort(Comparator.comparing(Item::getDueDate).thenComparing(Item::getCategory)); + + } else if(organizeBy.equalsIgnoreCase("priority")){ + listArr.sort(Comparator.comparingInt(Item::getPriority).thenComparing(Item::getDueDate)); + + } else { + System.out.println("Cannot organize by that."); + return; + } + } + + /** + * Saves the {@code ArrayList} to the {@code list.txt} using the developer provided {@code path}. + *

+ * Usage: + * {@snippet : + * list.saveChanges(); + * } + * @return void, but prints to console. + */ + public void saveChanges(){ + File file = new File(pathName); + try (FileWriter writer = new FileWriter(file, false)){ + for(Item listInput : listArr){ + String category = listInput.getCategory(); + if(category.equals("")){ + category = "na"; + } + String name = listInput.getName(); + String date = listInput.getDueDateString(); + String priority = Integer.toString(listInput.getPriority()); + + String line = String.format("%s, %s, %s, %s\n",category, name, date, priority); + writer.write(line); + } + writer.close(); + } catch (IOException e){ + System.out.println("File not found."); + e.printStackTrace(); + } + } + + + + //Getters + /** + * Formats a {@code String} from the encapsulated {@code ArrayList listArr}. + *

+ * Usage: + * {@snippet : + * list.openList(); + * } + * + * @return {@code String} + */ + public String printList(){ + String list = footer + + formatHeader("To Do List") + + footer + + listHeader; + for(int i = 0; i < listArr.size(); i++){ + list = list.concat(listArr.get(i).formatString()); + } + return list; + } + + public String getCategory(String category){ + String list = listHeader; + for(int i = 0; i < listArr.size(); i++){ + if(listArr.get(i).getCategory().equals(category)){ + list = list.concat(i+1 + ": " + listArr.get(i).formatString()); + } + } + return list; + } + } diff --git a/src/UserInterface.java b/src/UserInterface.java new file mode 100644 index 0000000..ffa5456 --- /dev/null +++ b/src/UserInterface.java @@ -0,0 +1,115 @@ + +import java.util.Scanner; + +public class UserInterface { + + private String pathName; + private Scanner scanner; + private ToDoList list; + + /** + * Constructor + *

+ * Initializes a {@code UserInterface} object. + *

+ * Usage: + * {@snippet : + * UserInterface ui = new UserInterface("./list.txt"); + * } + * @param String The path to the list.txt file as a string. + */ + public UserInterface(String listPath){ + this.pathName = listPath; //Relative path to the starting .txt file. If one is not found, a new one is created. + this.scanner = new Scanner(System.in); //The only scanner that will be declared in the overall program + this.list = new ToDoList(pathName, scanner); + } + + /** + * Starts a while loop that runs an instance of ToDoList. + *

+ * Usage: + * {@snippet : + * ToDoList list.run(); + * } + * @return {@code void}, but has outputs to the terminal. + */ + public void run(){ + + //Loop that continues until the user inputs "quit". Capitalization not important + while(true){ + printChoices(); + String input = getInput(); + if(runInput(input)) break; + list.saveChanges(); + } + scanner.close(); + } + + + /** + * Formats and prints a consistent "Directions" message. + *

+ * Usage: + * {@snippet : + * printChoices(); + * } + * @return {@code void}, but prints to console. + */ + private void printChoices(){ + System.out.println(list.printList()); + String directionMessage = "\n" + + "-'Home': takes you to your current list.\n" + + "-'Add': adds new item.\n" + + "-'Delete': deletes an item.\n" + + "-'Change': changes an item.\n" + + "-'Organize': organizes based on what you want to organize by.\n" + + "-'Quit': exits the program.\n"; + System.out.println(directionMessage); + } + + /** + * Recieves the {@code String input} via the instance of {@code java.util.Scanner} that was declared in this class. + *

+ * Usage: + * {@snippet : + * String input = getInput(); + * } + * @return {@code String input}, and prints a prompt to console. + */ + private String getInput(){ + System.out.print("Choice: "); + return scanner.nextLine(); + } + + /** + * Recieves the {@code String input} via the instance of {@code java.util.Scanner} that was declared in this class. If the user types "quit", the program quits, otherwise it continues. + *

+ * The {@code input string} is not case sensitive. + *

+ * Usage: + * {@snippet : + * if(runInput("Quit")) break; //this will break out of a loop. + * } + * @param String input: the input {@code String} that {@code runInput()} will use. + * @return {@code boolean endLoop}: returns true if input = "Quit" to end the loop in {@code run()}, false otherwise. + */ + private boolean runInput(String input){ + if(input.equalsIgnoreCase("quit")){ + System.out.println("Bye!"); + return true; + } else if(input.equalsIgnoreCase("Add")){ + list.addItemAction(); + } else if (input.equalsIgnoreCase("Delete")){ + list.deleteItem(); + } else if(input.equalsIgnoreCase("Change")){ + list.changeItem(); + } else if (input.equalsIgnoreCase("Organize")){ + list.sortBy(); + } else if (input.equalsIgnoreCase("Home")){ + System.out.println(list.printList()); + } else { + System.out.println("That was not an option."); + } + return false; + } +}