parent
dfdda34bd8
commit
e9caedae31
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1 @@
|
||||
use case 1:
|
@ -0,0 +1,28 @@
|
||||
class: PackageDeliveriesTracker
|
||||
responsability: starting point of the program. Handles the displaying and modifying opperations of different kinds of packages. Load and store packages to json.
|
||||
collaborators: textMenu, PackageFactory
|
||||
|
||||
class: textMenu
|
||||
responsability: Displays operations to be performed for packages. Take user input for the operations and returns the status.
|
||||
collaborators: PackageDeliveriesTracker, PackageInfo,
|
||||
|
||||
class: PackageInfo
|
||||
responsability: define the attributes of packages. Allow for accessing and motifying fields of package info.
|
||||
collaborators: BookPackage, PerishablePackage, ElectronicPackage, PackageFactory
|
||||
|
||||
class: PackageFactory
|
||||
responsability: initialize and return an instance of one of the package types.
|
||||
collaborators: BookPackage, PerishablePackage, ElectronicPackage
|
||||
|
||||
class: BookPackage
|
||||
responsability: Sub class of PackageInfo. Defines the field author name and allows modification.
|
||||
collaborators: PackageFactory, PackageDeliveriesTracker
|
||||
|
||||
class: PerishablePackage
|
||||
responsability: Sub class of PackageInfo. Defines the field expiry date and allows modification.
|
||||
collaborators: PackageFactory, PackageDeliveriesTracker
|
||||
|
||||
class: ElectronicPackage
|
||||
responsability: Sub class of PackageInfo. Defines the field enviremental handling fee and allows modification.
|
||||
collaborators: PackageFactory, PackageDeliveriesTracker
|
||||
|
@ -0,0 +1,30 @@
|
||||
PackageDeliveriesTracker
|
||||
fileName: String, packageList: ArrayList<PackageInfo>, rtaf: RuntimeTypeAdapterFactory, gson: GsonBuilder
|
||||
save():void, load(): void, main(String[] args): void
|
||||
|
||||
PackageInfo
|
||||
name: String, notes: String, price: double, weight, double, deliver: boolean, expectedDate: LocalDateTime
|
||||
compareTo(PackageInfo p): int, toString(): String
|
||||
BookPackage
|
||||
authorName: String
|
||||
|
||||
PerishablePackage
|
||||
expiryDate:LocalDateTime
|
||||
|
||||
ElectronicPackage
|
||||
handlingFee: double
|
||||
|
||||
|
||||
TextMenu
|
||||
title: String, options: String[]
|
||||
display(): void, list(ArrayList<PackageInfo> packageList): void, add(ArrayList<PackageInfo> packageList): void, remove(ArrayList<PackageInfo> packageList): void, sortList(ArrayList<PackageInfo> packageList, boolean due): ArrayList<PackageInfo>, overDueList(ArrayList<PackageInfo> packageList): void, getUndelivered(List<PackageInfo> packageList): ArrayList<PackageInfo>
|
||||
upcomingList(ArrayList<PackageInfo> PackageList): void, markDelivered(ArrayList<PackageInfo> PackageList): void
|
||||
|
||||
PackageFactory
|
||||
PackageType: enum
|
||||
getInstance(packageType type, String name, String Notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, string author, LocalDateTime expiryDate, double handlingFee): PackageInfo
|
||||
|
||||
|
||||
1. PackageInfo and subclass are created from PackageFactory
|
||||
2. PackageDeliveriesTracker creates objects of PackageInfo
|
||||
3. PackageDeliveriesTracker is dependent on TextMenu
|
@ -0,0 +1,143 @@
|
||||
* list packages
|
||||
* To list packages, user enters 1 and presses enter.
|
||||
* A message is shown if no packages are in the package list
|
||||
* Otherwise the packages are displayed with each field associated on a new line.
|
||||
* Packages are ordered to display oldest delivery date first.
|
||||
* a number is assigned to each packages.
|
||||
###################
|
||||
# Package Tracker #
|
||||
###################
|
||||
Today is: 2022-06-27
|
||||
1: List of all packages
|
||||
2: Add a package
|
||||
3: remove a package
|
||||
4: list overdue packages
|
||||
5: List upcoming packages
|
||||
6: mark package as delivered
|
||||
7: exit
|
||||
choose an option between 1 and 7:
|
||||
|
||||
$1
|
||||
|
||||
No packages to show
|
||||
|
||||
* Back to the main menu
|
||||
|
||||
###################
|
||||
# Package Tracker #
|
||||
###################
|
||||
Today is: 2022-06-27
|
||||
1: List of all packages
|
||||
2: Add a package
|
||||
3: remove a package
|
||||
4: list overdue packages
|
||||
5: List upcoming packages
|
||||
6: mark package as delivered
|
||||
7: exit
|
||||
|
||||
* If all inputs are validated, the package is added to the list.
|
||||
|
||||
choose an option between 1 and 7:
|
||||
$1
|
||||
enter a valid package name:
|
||||
$b1
|
||||
notes:
|
||||
$$ my note
|
||||
enter date as yyyy-mm-dd hh:mm:
|
||||
$2022-09-01 11:11
|
||||
enter price:
|
||||
$15
|
||||
enter weight:
|
||||
$15
|
||||
enter author
|
||||
$me
|
||||
b1 has been added to the list!
|
||||
|
||||
###################
|
||||
# Package Tracker #
|
||||
###################
|
||||
Today is: 2022-06-27
|
||||
1: List of all packages
|
||||
2: Add a package
|
||||
3: remove a package
|
||||
4: list overdue packages
|
||||
5: List upcoming packages
|
||||
6: mark package as delivered
|
||||
7: exit
|
||||
|
||||
* When user lists packages again, the newly added package is shown in detail.
|
||||
|
||||
choose an option between 1 and 7:
|
||||
$1
|
||||
Package #1
|
||||
Name: b1
|
||||
Notes: my note
|
||||
Price: 15.0
|
||||
Weight: 15.0
|
||||
Expected Delivery Date: 2022-09-01 11:11
|
||||
Delivered? no
|
||||
65 days remaining
|
||||
Author: me
|
||||
|
||||
###################
|
||||
# Package Tracker #
|
||||
###################
|
||||
Today is: 2022-06-27
|
||||
1: List of all packages
|
||||
2: Add a package
|
||||
3: remove a package
|
||||
4: list overdue packages
|
||||
5: List upcoming packages
|
||||
6: mark package as delivered
|
||||
7: exit
|
||||
choose an option between 1 and 7:
|
||||
|
||||
* To remove a package, user enters 3 and presses enter.
|
||||
* The packages are listed with an ID.
|
||||
|
||||
3
|
||||
Package #1
|
||||
Name: b1
|
||||
Notes: my note
|
||||
Price: 15.0
|
||||
Weight: 15.0
|
||||
Expected Delivery Date: 2022-09-01 11:11
|
||||
Delivered? no
|
||||
65 days remaining
|
||||
Author: me
|
||||
|
||||
* user enters 0 to return to the main menu.
|
||||
|
||||
enter item number you want to remove (0 to cancel):
|
||||
0
|
||||
###################
|
||||
# Package Tracker #
|
||||
###################
|
||||
Today is: 2022-06-27
|
||||
1: List of all packages
|
||||
2: Add a package
|
||||
3: remove a package
|
||||
4: list overdue packages
|
||||
5: List upcoming packages
|
||||
6: mark package as delivered
|
||||
7: exit
|
||||
choose an option between 1 and 7:
|
||||
$3
|
||||
Package #1
|
||||
Name: b1
|
||||
Notes: my note
|
||||
Price: 15.0
|
||||
Weight: 15.0
|
||||
Expected Delivery Date: 2022-09-01 11:11
|
||||
Delivered? no
|
||||
65 days remaining
|
||||
Author: me
|
||||
|
||||
* user enters corresponding ID to remove the package.
|
||||
|
||||
enter item number you want to remove (0 to cancel):
|
||||
$1
|
||||
|
||||
* The package is deleted from the list.
|
||||
|
||||
b1 has been removed from the list.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,97 +0,0 @@
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.chrono.ChronoLocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
private static final String fileName = "list.json";
|
||||
private static ArrayList<PackageInfo> packageList=new ArrayList<>();
|
||||
private static void save(){
|
||||
Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class,
|
||||
new TypeAdapter<LocalDateTime>() {
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter,
|
||||
LocalDateTime localDateTime) throws IOException {
|
||||
jsonWriter.value(localDateTime.toString());
|
||||
}
|
||||
@Override
|
||||
public LocalDateTime read(JsonReader jsonReader) throws IOException {
|
||||
return LocalDateTime.parse(jsonReader.nextString());
|
||||
}
|
||||
}).create();
|
||||
try{
|
||||
Writer w = new FileWriter(fileName);
|
||||
gson.toJson(packageList, w);
|
||||
w.flush();
|
||||
w.close();
|
||||
}
|
||||
catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void load(){
|
||||
File file = new File(fileName);
|
||||
try{
|
||||
JsonElement element = JsonParser.parseReader(new FileReader(fileName));
|
||||
JsonArray array = element.getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++){
|
||||
JsonObject pObj = array.get(i).getAsJsonObject();
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
packageList.add(new PackageInfo(pObj.get("name").getAsString(),
|
||||
pObj.get("note").getAsString(),
|
||||
pObj.get("price").getAsDouble(),
|
||||
pObj.get("weight").getAsDouble(),
|
||||
pObj.get("delivered").getAsBoolean(),
|
||||
LocalDateTime.parse(pObj.get("expectedDate").getAsString()))
|
||||
);
|
||||
}
|
||||
System.out.println("packages loaded");
|
||||
}
|
||||
catch (FileNotFoundException e){
|
||||
System.out.println("no packages to load");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TextMenu menu=new TextMenu();
|
||||
load();
|
||||
do{
|
||||
menu.display();
|
||||
System.out.println("choose an option between 1 and 7:");
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int option=Integer.parseInt(scan.nextLine());
|
||||
if (option > 7 || option < 1){
|
||||
System.out.println("invalid input");
|
||||
}
|
||||
else if(option == 7){
|
||||
save();
|
||||
System.out.print("packages saved");
|
||||
break;
|
||||
}
|
||||
else{
|
||||
switch(option){
|
||||
case 1: menu.list(packageList);
|
||||
break;
|
||||
case 2: menu.add(packageList);
|
||||
break;
|
||||
case 3: menu.remove(packageList);
|
||||
break;
|
||||
case 4: menu.overDueList(packageList);
|
||||
break;
|
||||
case 5: menu.upcomingList(packageList);
|
||||
break;
|
||||
case 6: menu.markDelivered(packageList);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public enum PackageFactory {
|
||||
Book {
|
||||
public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) {
|
||||
return new BookPackage(name, notes, price, weight, delivered, expectedDate, author);
|
||||
}
|
||||
}
|
||||
|
||||
Perishable {
|
||||
public PackageInfo getInstance (String name, String notes,double price, double weight,
|
||||
boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate){
|
||||
return new PerishablePackage(name, notes, price, weight, delivered, expectedDate, expiryDate);
|
||||
}
|
||||
}
|
||||
|
||||
Electronic{
|
||||
public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee){
|
||||
return new ElectronicPackage(name, notes, price, weight, delivered, expectedDate, handlingFee);
|
||||
}
|
||||
}
|
||||
}
|
||||
//public static PackageInfo getInstance(PackageType type, String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, @Nullable String author, @Nullable LocalDateTime expiryDate, @Nullable double handlingFee){
|
||||
//}
|
@ -1,57 +0,0 @@
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
public class PackageInfo implements Comparable<PackageInfo>{
|
||||
private String name;
|
||||
private String note;
|
||||
private double price;
|
||||
private double weight;
|
||||
private boolean delivered;
|
||||
private LocalDateTime expectedDate;
|
||||
|
||||
public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) {
|
||||
this.name =name;
|
||||
this.note = note;
|
||||
this.price = price;
|
||||
this.weight =weight;
|
||||
this.delivered =delivered;
|
||||
this.expectedDate = expectedDate;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean getDelivered() {
|
||||
return delivered;
|
||||
}
|
||||
|
||||
public LocalDateTime getExpectedDate() {
|
||||
return expectedDate;
|
||||
}
|
||||
|
||||
public void setDelivered(boolean delivered) {
|
||||
this.delivered = delivered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PackageInfo p){
|
||||
return this.expectedDate.compareTo(p.getExpectedDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
today.format(format);
|
||||
long diff = ChronoUnit.DAYS.between(today, expectedDate);
|
||||
String isDelivered = delivered ? "yes" : "no";
|
||||
return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: " + price + "\n" + "Weight: " + weight + "\n" + "Expected Delivery Date: " + expectedDate.toString() + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue");
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class PerishablePackage extends PackageInfo{
|
||||
LocalDateTime expiryDate;
|
||||
|
||||
public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) {
|
||||
super(name, note, price, weight, delivered, expectedDate);
|
||||
this.expiryDate = expiryDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+"expiryDate=" + expiryDate;
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
import java.net.SocketOption;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.format.SignStyle;
|
||||
import java.util.*;
|
||||
|
||||
public class TextMenu {
|
||||
private final String title = "title";
|
||||
private final String[] options = new String []{
|
||||
"List of all packages",
|
||||
"Add a package",
|
||||
"remove a package",
|
||||
"list overdue packages",
|
||||
"List upcoming packages",
|
||||
"mark package as delivered",
|
||||
"exit"};
|
||||
|
||||
public void display(){
|
||||
int tag = title.length();
|
||||
for (int i=0; i<= tag+3; i++){
|
||||
System.out.print("#");
|
||||
}
|
||||
System.out.println("\n# " + title + " #");
|
||||
for (int i=0; i<= tag+3; i++){
|
||||
System.out.print("#");
|
||||
}
|
||||
DateFormat today = new SimpleDateFormat("yyy-MM-dd");
|
||||
Calendar cal=Calendar.getInstance();
|
||||
System.out.println("\nToday is: " + today.format(cal.getTime()));
|
||||
for (int i = 0; i < options.length; i++){
|
||||
System.out.println((i+1) + ": " + options[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void list(ArrayList<PackageInfo> packageList){
|
||||
if (packageList.size() == 0){
|
||||
System.out.println("No packages to show");
|
||||
}
|
||||
else{
|
||||
for (int i=0; i < packageList.size(); i++){
|
||||
System.out.println("Package #" + (i+1));
|
||||
System.out.println(packageList.get(i).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ArrayList<PackageInfo> packageList){
|
||||
Scanner scan = new Scanner(System.in);
|
||||
String pName;
|
||||
do {
|
||||
System.out.println("enter a valid package name:");
|
||||
pName = scan.nextLine();
|
||||
}
|
||||
while (pName.length()==0);
|
||||
System.out.println("notes:");
|
||||
String pNotes = scan.nextLine();
|
||||
boolean checkDate = false;
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
LocalDateTime pDate=LocalDateTime.now();
|
||||
while (checkDate == false){
|
||||
try {
|
||||
System.out.println("enter date as yyyy-mm-dd hh:mm:");
|
||||
pDate = LocalDateTime.parse(scan.nextLine(), format);
|
||||
checkDate = true;
|
||||
}
|
||||
catch (DateTimeParseException e) {
|
||||
System.out.println("invalid date format");
|
||||
}
|
||||
}
|
||||
double pPrice;
|
||||
do {
|
||||
System.out.println("enter price:");
|
||||
pPrice = scan.nextDouble();
|
||||
}
|
||||
while (pPrice < 0);
|
||||
double pWeight;
|
||||
do {
|
||||
System.out.println("enter weight:");
|
||||
pWeight = scan.nextDouble();
|
||||
}
|
||||
while (pWeight <= 0);
|
||||
|
||||
packageList.add(new PackageInfo(pName, pNotes, pPrice, pWeight, false, pDate));
|
||||
System.out.println(pName + " has been added to the list!");
|
||||
}
|
||||
|
||||
public void remove(ArrayList<PackageInfo> packageList) {
|
||||
this.list(packageList);
|
||||
if (packageList.size() == 0){
|
||||
return;
|
||||
}
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int n;
|
||||
do {
|
||||
System.out.println("enter item number you want to remove (0 to cancel):");
|
||||
n = scan.nextInt();
|
||||
}
|
||||
while (n < 0 || n > packageList.size());
|
||||
if (n > 0){
|
||||
System.out.println(packageList.get(n-1).getName() + " has been removed from the list.");
|
||||
packageList.remove(n-1);
|
||||
}
|
||||
}
|
||||
|
||||
//due=true returns overdue packages, else upcoming packages
|
||||
public ArrayList<PackageInfo> sortList(ArrayList<PackageInfo> pList, boolean due){
|
||||
ArrayList<PackageInfo> sortedList = new ArrayList<>();
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
today.format(format);
|
||||
for (int i = 0; i < pList.size(); i++) {
|
||||
PackageInfo p = pList.get(i);
|
||||
if (!p.getDelivered()) {
|
||||
if (due && today.isAfter(p.getExpectedDate())) {
|
||||
sortedList.add(p);
|
||||
}
|
||||
else if (!due && today.isBefore(p.getExpectedDate())){
|
||||
sortedList.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(sortedList);
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
public void overDueList(ArrayList<PackageInfo> packageList){
|
||||
ArrayList<PackageInfo> overdue = sortList(packageList, true);
|
||||
if (overdue.size() == 0){
|
||||
System.out.println("no overdue packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(overdue);
|
||||
}
|
||||
|
||||
public void upcomingList(ArrayList<PackageInfo> packageList){
|
||||
ArrayList<PackageInfo> upcoming = sortList(packageList, false);
|
||||
if (upcoming.size() == 0){
|
||||
System.out.println("no upcoming packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(upcoming);
|
||||
}
|
||||
|
||||
public ArrayList<PackageInfo> getUndelivered(List<PackageInfo> packageList){
|
||||
ArrayList<PackageInfo> undelivered = new ArrayList<>();
|
||||
for (int i = 0; i < packageList.size(); i++){
|
||||
if (packageList.get(i).getDelivered() == false){
|
||||
undelivered.add(packageList.get(i));
|
||||
}
|
||||
}
|
||||
return undelivered;
|
||||
}
|
||||
|
||||
public void markDelivered(ArrayList<PackageInfo> packageList){
|
||||
ArrayList<PackageInfo> undelivered=getUndelivered(packageList);
|
||||
if (undelivered.size() == 0){
|
||||
System.out.println("No undelivered packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(undelivered);
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int n;
|
||||
do {
|
||||
System.out.println("enter item number you want to mark delivered (0 to cancel):");
|
||||
n = scan.nextInt();
|
||||
}
|
||||
while (n < 0 || n > undelivered.size());
|
||||
if (n > 0){
|
||||
PackageInfo p = undelivered.get(n-1);
|
||||
packageList.get(packageList.indexOf(p)).setDelivered(true);
|
||||
System.out.println(p.getName() + " has been delivered.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,256 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.gson.extras;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapts values whose runtime type may differ from their declaration type. This
|
||||
* is necessary when a field's type is not the same type that GSON should create
|
||||
* when deserializing that field. For example, consider these types:
|
||||
* <pre> {@code
|
||||
* abstract class Shape {
|
||||
* int x;
|
||||
* int y;
|
||||
* }
|
||||
* class Circle extends Shape {
|
||||
* int radius;
|
||||
* }
|
||||
* class Rectangle extends Shape {
|
||||
* int width;
|
||||
* int height;
|
||||
* }
|
||||
* class Diamond extends Shape {
|
||||
* int width;
|
||||
* int height;
|
||||
* }
|
||||
* class Drawing {
|
||||
* Shape bottomShape;
|
||||
* Shape topShape;
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>Without additional type information, the serialized JSON is ambiguous. Is
|
||||
* the bottom shape in this drawing a rectangle or a diamond? <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* This class addresses this problem by adding type information to the
|
||||
* serialized JSON and honoring that type information when the JSON is
|
||||
* deserialized: <pre> {@code
|
||||
* {
|
||||
* "bottomShape": {
|
||||
* "type": "Diamond",
|
||||
* "width": 10,
|
||||
* "height": 5,
|
||||
* "x": 0,
|
||||
* "y": 0
|
||||
* },
|
||||
* "topShape": {
|
||||
* "type": "Circle",
|
||||
* "radius": 2,
|
||||
* "x": 4,
|
||||
* "y": 1
|
||||
* }
|
||||
* }}</pre>
|
||||
* Both the type field name ({@code "type"}) and the type labels ({@code
|
||||
* "Rectangle"}) are configurable.
|
||||
*
|
||||
* <h3>Registering Types</h3>
|
||||
* Create a {@code cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory} by passing the base type and type field
|
||||
* name to the {@link #of} factory method. If you don't supply an explicit type
|
||||
* field name, {@code "type"} will be used. <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
|
||||
* = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
|
||||
* }</pre>
|
||||
* Next register all of your subtypes. Every subtype must be explicitly
|
||||
* registered. This protects your application from injection attacks. If you
|
||||
* don't supply an explicit type label, the type's simple name will be used.
|
||||
* <pre> {@code
|
||||
* shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
|
||||
* shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
|
||||
* shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
|
||||
* }</pre>
|
||||
* Finally, register the type adapter factory in your application's GSON builder:
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapterFactory(shapeAdapterFactory)
|
||||
* .create();
|
||||
* }</pre>
|
||||
* Like {@code GsonBuilder}, this API supports chaining: <pre> {@code
|
||||
* cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
|
||||
* .registerSubtype(Rectangle.class)
|
||||
* .registerSubtype(Circle.class)
|
||||
* .registerSubtype(Diamond.class);
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Serialization and deserialization</h3>
|
||||
* In order to serialize and deserialize a polymorphic object,
|
||||
* you must specify the base type explicitly.
|
||||
* <pre> {@code
|
||||
* Diamond diamond = new Diamond();
|
||||
* String json = gson.toJson(diamond, Shape.class);
|
||||
* }</pre>
|
||||
* And then:
|
||||
* <pre> {@code
|
||||
* Shape shape = gson.fromJson(json, Shape.class);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
|
||||
private final Class<?> baseType;
|
||||
private final String typeFieldName;
|
||||
private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<>();
|
||||
private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<>();
|
||||
private final boolean maintainType;
|
||||
|
||||
private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName, boolean maintainType) {
|
||||
if (typeFieldName == null || baseType == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.baseType = baseType;
|
||||
this.typeFieldName = typeFieldName;
|
||||
this.maintainType = maintainType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime type adapter using for {@code baseType} using {@code
|
||||
* typeFieldName} as the type field name. Type field names are case sensitive.
|
||||
* {@code maintainType} flag decide if the type will be stored in pojo or not.
|
||||
*/
|
||||
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName, boolean maintainType) {
|
||||
return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime type adapter using for {@code baseType} using {@code
|
||||
* typeFieldName} as the type field name. Type field names are case sensitive.
|
||||
*/
|
||||
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) {
|
||||
return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime type adapter for {@code baseType} using {@code "type"} as
|
||||
* the type field name.
|
||||
*/
|
||||
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) {
|
||||
return new RuntimeTypeAdapterFactory<>(baseType, "type", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@code type} identified by {@code label}. Labels are case
|
||||
* sensitive.
|
||||
*
|
||||
* @throws IllegalArgumentException if either {@code type} or {@code label}
|
||||
* have already been registered on this type adapter.
|
||||
*/
|
||||
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) {
|
||||
if (type == null || label == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {
|
||||
throw new IllegalArgumentException("types and labels must be unique");
|
||||
}
|
||||
labelToSubtype.put(label, type);
|
||||
subtypeToLabel.put(type, label);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@code type} identified by its {@link Class#getSimpleName simple
|
||||
* name}. Labels are case sensitive.
|
||||
*
|
||||
* @throws IllegalArgumentException if either {@code type} or its simple name
|
||||
* have already been registered on this type adapter.
|
||||
*/
|
||||
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
|
||||
return registerSubtype(type, type.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
|
||||
if (type.getRawType() != baseType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
|
||||
final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>();
|
||||
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) {
|
||||
TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
|
||||
labelToDelegate.put(entry.getKey(), delegate);
|
||||
subtypeToDelegate.put(entry.getValue(), delegate);
|
||||
}
|
||||
|
||||
return new TypeAdapter<R>() {
|
||||
@Override
|
||||
public R read(JsonReader in) throws IOException {
|
||||
JsonElement jsonElement = jsonElementAdapter.read(in);
|
||||
JsonElement labelJsonElement;
|
||||
if (maintainType) {
|
||||
labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName);
|
||||
} else {
|
||||
labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
|
||||
}
|
||||
|
||||
if (labelJsonElement == null) {
|
||||
throw new JsonParseException("cannot deserialize " + baseType
|
||||
+ " because it does not define a field named " + typeFieldName);
|
||||
}
|
||||
String label = labelJsonElement.getAsString();
|
||||
@SuppressWarnings("unchecked") // registration requires that subtype extends T
|
||||
TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
|
||||
if (delegate == null) {
|
||||
throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
|
||||
+ label + "; did you forget to register a subtype?");
|
||||
}
|
||||
return delegate.fromJsonTree(jsonElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, R value) throws IOException {
|
||||
Class<?> srcType = value.getClass();
|
||||
String label = subtypeToLabel.get(srcType);
|
||||
@SuppressWarnings("unchecked") // registration requires that subtype extends T
|
||||
TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);
|
||||
if (delegate == null) {
|
||||
throw new JsonParseException("cannot serialize " + srcType.getName()
|
||||
+ "; did you forget to register a subtype?");
|
||||
}
|
||||
JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
|
||||
|
||||
if (maintainType) {
|
||||
jsonElementAdapter.write(out, jsonObject);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject clone = new JsonObject();
|
||||
|
||||
if (jsonObject.has(typeFieldName)) {
|
||||
throw new JsonParseException("cannot serialize " + srcType.getName()
|
||||
+ " because it already defines a field named " + typeFieldName);
|
||||
}
|
||||
clone.add(typeFieldName, new JsonPrimitive(label));
|
||||
|
||||
for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {
|
||||
clone.add(e.getKey(), e.getValue());
|
||||
}
|
||||
jsonElementAdapter.write(out, clone);
|
||||
}
|
||||
}.nullSafe();
|
||||
}
|
||||
}
|
@ -1,17 +1,23 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class BookPackage extends PackageInfo{
|
||||
/**
|
||||
* It's a subclass of PackageInfo that adds an author field
|
||||
*/
|
||||
public class BookPackage extends PackageInfo {
|
||||
String author;
|
||||
|
||||
public BookPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) {
|
||||
|
||||
super(name, note, price, weight, delivered, expectedDate);
|
||||
this.author = author;
|
||||
this.setType("book");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+"author='" + author + '\'';
|
||||
return super.toString() + "\nAuthor: " + author;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class ElectronicPackage extends PackageInfo{
|
||||
/**
|
||||
* ElectronicPackage is a subclass of PackageInfo that adds a handlingFee attribute
|
||||
*/
|
||||
public class ElectronicPackage extends PackageInfo {
|
||||
double handlingFee;
|
||||
|
||||
public ElectronicPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee) {
|
||||
super(name, note, price, weight, delivered, expectedDate);
|
||||
this.handlingFee = handlingFee;
|
||||
this.setType("electronic");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+"handlingFee=" + handlingFee;
|
||||
return super.toString() + "\nHandling fee: " + handlingFee;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* The PackageFactory class is a factory class that creates a package object based on the type of
|
||||
* package that is passed in
|
||||
*/
|
||||
public class PackageFactory {
|
||||
/**
|
||||
* > This function creates a new package object based on the package type
|
||||
*
|
||||
* @param type The type of package.
|
||||
* @param name The name of the package.
|
||||
* @param notes A string of notes about the package.
|
||||
* @param price The price of the package
|
||||
* @param weight The weight of the package in kilograms
|
||||
* @param delivered Whether or not the package has been delivered
|
||||
* @param expectDate The date the package is expected to be delivered.
|
||||
* @param author The author of the book.
|
||||
* @param expiryDate The date the package expires.
|
||||
* @param handlingFee The handling fee for the package.
|
||||
* @return A new instance of the package type.
|
||||
*/
|
||||
|
||||
public static PackageInfo create(PackageType type, String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectDate, String author, LocalDateTime expiryDate, double handlingFee) {
|
||||
return type.getInstance(name, notes, price, weight, delivered, expectDate, author, expiryDate, handlingFee);
|
||||
}
|
||||
|
||||
// Creating an enum called PackageType.
|
||||
public enum PackageType {
|
||||
Book {
|
||||
public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) {
|
||||
return new BookPackage(name, notes, price, weight, delivered, expectedDate, author);
|
||||
}
|
||||
},
|
||||
|
||||
Perishable {
|
||||
public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) {
|
||||
return new PerishablePackage(name, notes, price, weight, delivered, expectedDate, expiryDate);
|
||||
}
|
||||
},
|
||||
|
||||
Electronic {
|
||||
public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) {
|
||||
return new ElectronicPackage(name, notes, price, weight, delivered, expectedDate, handlingFee);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* It returns a PackageInfo object.
|
||||
*
|
||||
* @param name The name of the package.
|
||||
* @param notes a string that describes the package
|
||||
* @param price The price of the package
|
||||
* @param weight the weight of the package in kg
|
||||
* @param delivered true if the package has been delivered, false otherwise
|
||||
* @param expectedDate The date the package is expected to be delivered.
|
||||
* @param author The name of the author of the book.
|
||||
* @param expiryDate The date when the package expires.
|
||||
* @param handlingFee The handling fee for the package.
|
||||
* @return A package object
|
||||
*/
|
||||
|
||||
public abstract PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
/**
|
||||
* PackageInfo is a class that contains information about a package
|
||||
*/
|
||||
|
||||
public class PackageInfo implements Comparable<PackageInfo> {
|
||||
private final String name;
|
||||
private final String note;
|
||||
private final double price;
|
||||
private final double weight;
|
||||
private final LocalDateTime expectedDate;
|
||||
private boolean delivered;
|
||||
private String type;
|
||||
|
||||
public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) {
|
||||
this.name = name;
|
||||
this.note = note;
|
||||
this.price = price;
|
||||
this.weight = weight;
|
||||
this.delivered = delivered;
|
||||
this.expectedDate = expectedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the name of the person.
|
||||
*
|
||||
* @return The name of the person.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public boolean getDelivered() {
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function sets the value of the delivered variable to the value of the delivered parameter.
|
||||
*
|
||||
* @param delivered This is a boolean value that indicates whether the message has been delivered
|
||||
* to the recipient.
|
||||
*/
|
||||
public void setDelivered(boolean delivered) {
|
||||
this.delivered = delivered;
|
||||
}
|
||||
|
||||
public LocalDateTime getExpectedDate() {
|
||||
return expectedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function sets the type of the object to the type passed in as a parameter
|
||||
*
|
||||
* @param type The type of the event.
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
// Comparing the expected date of the package to the expected date of the package passed in as a
|
||||
// parameter.
|
||||
@Override
|
||||
public int compareTo(PackageInfo p) {
|
||||
return this.expectedDate.compareTo(p.getExpectedDate());
|
||||
}
|
||||
|
||||
// Overriding the toString method.
|
||||
@Override
|
||||
public String toString() {
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
today.format(format);
|
||||
long diff = ChronoUnit.DAYS.between(today, expectedDate);
|
||||
String isDelivered = delivered ? "yes" : "no";
|
||||
return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: " + price + "\n" + "Weight: " + weight + "\n" + "Expected Delivery Date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expectedDate) + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue");
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* It's a subclass of PackageInfo that adds an expiry date
|
||||
*/
|
||||
public class PerishablePackage extends PackageInfo {
|
||||
LocalDateTime expiryDate;
|
||||
|
||||
// It's a constructor that initializes the object with the given parameters.
|
||||
public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) {
|
||||
super(name, note, price, weight, delivered, expectedDate);
|
||||
this.expiryDate = expiryDate;
|
||||
this.setType("perishable");
|
||||
}
|
||||
|
||||
// It's a method that returns a string representation of the object.
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "\nExpiry date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expiryDate);
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.textui;
|
||||
|
||||
import cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory;
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.BookPackage;
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.ElectronicPackage;
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.PackageInfo;
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.PerishablePackage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* It's a class that contains a main method that creates a TextMenu object, loads a list of packages
|
||||
* from a file, and then loops through a menu of options until the user chooses to quit
|
||||
*/
|
||||
public class PackageDeliveriesTracker {
|
||||
private static final String fileName = "list.json";
|
||||
private static final RuntimeTypeAdapterFactory<PackageInfo> r = RuntimeTypeAdapterFactory.of(PackageInfo.class, "type")
|
||||
.registerSubtype(BookPackage.class, "book")
|
||||
.registerSubtype(PerishablePackage.class, "perishable")
|
||||
.registerSubtype(ElectronicPackage.class, "electronic");
|
||||
private static final Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class,
|
||||
new TypeAdapter<LocalDateTime>() {
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter,
|
||||
LocalDateTime localDateTime) throws IOException {
|
||||
jsonWriter.value(localDateTime.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime read(JsonReader jsonReader) throws IOException {
|
||||
return LocalDateTime.parse(jsonReader.nextString());
|
||||
}
|
||||
}).registerTypeAdapterFactory(r).create();
|
||||
private static ArrayList<PackageInfo> packageList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* It saves the packageList to a file.
|
||||
*/
|
||||
private static void save() {
|
||||
try {
|
||||
Writer w = new FileWriter(fileName);
|
||||
gson.toJson(packageList, w);
|
||||
w.flush();
|
||||
w.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It reads the json file, converts it to a list of PackageInfo objects, and then sets the type of
|
||||
* each object to the appropriate type
|
||||
*/
|
||||
private static void load() {
|
||||
File file = new File(fileName);
|
||||
try {
|
||||
String json = Files.readString(Paths.get(fileName));
|
||||
Type lType = new TypeToken<ArrayList<PackageInfo>>() {
|
||||
}.getType();
|
||||
packageList = gson.fromJson(json, lType);
|
||||
for (PackageInfo p : packageList) {
|
||||
if (p instanceof BookPackage) {
|
||||
p.setType("book");
|
||||
} else if (p instanceof PerishablePackage) {
|
||||
p.setType("perishable");
|
||||
} else if (p instanceof ElectronicPackage) {
|
||||
p.setType("electronic");
|
||||
}
|
||||
}
|
||||
System.out.println("packages loaded");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("no packages to load");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is the main function of the program. It creates a TextMenu object, loads the
|
||||
* packages from the file, displays the menu, and then waits for the user to input a number between
|
||||
* 1 and 7. If the user inputs a number outside of that range, the program will display an error
|
||||
* message. If the user inputs 7, the program will save the packages to the file and exit. If the
|
||||
* user inputs a number between 1 and 6, the program will call the corresponding function in the
|
||||
* TextMenu class
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
TextMenu menu = new TextMenu();
|
||||
load();
|
||||
do {
|
||||
menu.display();
|
||||
System.out.println("choose an option between 1 and 7:");
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int option = Integer.parseInt(scan.nextLine());
|
||||
if (option > 7 || option < 1) {
|
||||
System.out.println("invalid input");
|
||||
} else if (option == 7) {
|
||||
save();
|
||||
System.out.print("packages saved");
|
||||
break;
|
||||
} else {
|
||||
switch (option) {
|
||||
case 1:
|
||||
menu.list(packageList);
|
||||
break;
|
||||
case 2:
|
||||
menu.add(packageList);
|
||||
break;
|
||||
case 3:
|
||||
menu.remove(packageList);
|
||||
break;
|
||||
case 4:
|
||||
menu.overDueList(packageList);
|
||||
break;
|
||||
case 5:
|
||||
menu.upcomingList(packageList);
|
||||
break;
|
||||
case 6:
|
||||
menu.markDelivered(packageList);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,280 @@
|
||||
package cmpt213.assignment2.packagedeliveriestracker.textui;
|
||||
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.PackageFactory;
|
||||
import cmpt213.assignment2.packagedeliveriestracker.model.PackageInfo;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* It's a class that displays a menu and allows the user to interact with the program
|
||||
*/
|
||||
public class TextMenu {
|
||||
private final String title = "Package Tracker";
|
||||
private final String[] options = new String[]{
|
||||
"List of all packages",
|
||||
"Add a package",
|
||||
"remove a package",
|
||||
"list overdue packages",
|
||||
"List upcoming packages",
|
||||
"mark package as delivered",
|
||||
"exit"};
|
||||
|
||||
/**
|
||||
* This function displays the title of the menu, the current date, and the options available to the
|
||||
* user
|
||||
*/
|
||||
public void display() {
|
||||
int tag = title.length();
|
||||
for (int i = 0; i <= tag + 3; i++) {
|
||||
System.out.print("#");
|
||||
}
|
||||
System.out.println("\n# " + title + " #");
|
||||
for (int i = 0; i <= tag + 3; i++) {
|
||||
System.out.print("#");
|
||||
}
|
||||
DateFormat today = new SimpleDateFormat("yyy-MM-dd");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
System.out.println("\nToday is: " + today.format(cal.getTime()));
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
System.out.println((i + 1) + ": " + options[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes an ArrayList of PackageInfo objects and prints them out in reverse order
|
||||
*
|
||||
* @param packageList The list of packages to be displayed
|
||||
*/
|
||||
public void list(ArrayList<PackageInfo> packageList) {
|
||||
if (packageList.size() == 0) {
|
||||
System.out.println("No packages to show");
|
||||
} else {
|
||||
Collections.sort(packageList);
|
||||
for (int i = 0; i < packageList.size(); i++) {
|
||||
System.out.println("Package #" + (i + 1));
|
||||
System.out.println(packageList.get(i) + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows the user to add a package to the list of packages
|
||||
*
|
||||
* @param packageList the list of packages
|
||||
*/
|
||||
public void add(ArrayList<PackageInfo> packageList) {
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int itemType;
|
||||
do {
|
||||
System.out.println("please select (1) book, (2) perishable, or (3) electronic package");
|
||||
itemType = Integer.parseInt(scan.nextLine());
|
||||
}
|
||||
while (itemType < 1 || itemType > 3);
|
||||
PackageFactory.PackageType pType = PackageFactory.PackageType.Book;
|
||||
String author = "";
|
||||
LocalDateTime expiryDate = LocalDateTime.now();
|
||||
double handlingFee = 0.0;
|
||||
String pName;
|
||||
do {
|
||||
System.out.println("enter a valid package name:");
|
||||
pName = scan.nextLine();
|
||||
}
|
||||
while (pName.length() == 0);
|
||||
System.out.println("notes:");
|
||||
String pNotes = scan.nextLine();
|
||||
boolean checkDate = false;
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
LocalDateTime pDate = LocalDateTime.now();
|
||||
while (checkDate == false) {
|
||||
try {
|
||||
System.out.println("enter date as yyyy-mm-dd hh:mm:");
|
||||
pDate = LocalDateTime.parse(scan.nextLine(), format);
|
||||
checkDate = true;
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("invalid date format");
|
||||
}
|
||||
}
|
||||
double pPrice;
|
||||
do {
|
||||
System.out.println("enter price:");
|
||||
pPrice = Double.parseDouble(scan.nextLine());
|
||||
}
|
||||
while (pPrice < 0);
|
||||
double pWeight;
|
||||
do {
|
||||
System.out.println("enter weight:");
|
||||
pWeight = Double.parseDouble(scan.nextLine());
|
||||
}
|
||||
while (pWeight <= 0);
|
||||
switch (itemType) {
|
||||
case 1:
|
||||
do {
|
||||
System.out.println("enter author");
|
||||
author = scan.nextLine();
|
||||
}
|
||||
while (author.length() == 0);
|
||||
break;
|
||||
case 2:
|
||||
boolean checkExpDate = false;
|
||||
while (checkExpDate == false) {
|
||||
try {
|
||||
System.out.println("enter expiry date as yyyy-mm-dd hh:mm");
|
||||
expiryDate = LocalDateTime.parse(scan.nextLine(), format);
|
||||
checkExpDate = true;
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("invalid date format");
|
||||
}
|
||||
}
|
||||
pType = PackageFactory.PackageType.Perishable;
|
||||
break;
|
||||
case 3:
|
||||
do {
|
||||
System.out.println("enter handling fee");
|
||||
handlingFee = Double.parseDouble(scan.nextLine());
|
||||
}
|
||||
while (handlingFee <= 0);
|
||||
pType = PackageFactory.PackageType.Electronic;
|
||||
break;
|
||||
}
|
||||
PackageInfo p = PackageFactory.create(pType, pName, pNotes, pPrice, pWeight, false, pDate, author, expiryDate, handlingFee);
|
||||
packageList.add(p);
|
||||
System.out.println(pName + " has been added to the list!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes in an ArrayList of PackageInfo objects and prints out the list of packages
|
||||
* in the ArrayList. The user is then prompted to enter the number of the package they want to
|
||||
* remove. If the user enters a number that is not in the list, the user is prompted to enter a
|
||||
* number again. If the user enters 0, the function returns without removing anything. If the user
|
||||
* enters a number that is in the list, the package is removed from the list and the user is
|
||||
* notified
|
||||
*
|
||||
* @param packageList the list of packages to be displayed
|
||||
*/
|
||||
public void remove(ArrayList<PackageInfo> packageList) {
|
||||
this.list(packageList);
|
||||
if (packageList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int n;
|
||||
do {
|
||||
System.out.println("enter item number you want to remove (0 to cancel):");
|
||||
n = scan.nextInt();
|
||||
}
|
||||
while (n < 0 || n > packageList.size());
|
||||
if (n > 0) {
|
||||
System.out.println(packageList.get(n - 1).getName() + " has been removed from the list.");
|
||||
packageList.remove(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes in a list of packages, a boolean for whether or not the user wants to see
|
||||
* packages that are due, and a boolean for whether or not the user wants to see all packages. It
|
||||
* then returns a list of packages that are sorted by their expected delivery date
|
||||
*
|
||||
* @param pList the list of packages to be sorted
|
||||
* @param due true if you want to sort the list by due date, false if you want to sort the list by
|
||||
* expected date
|
||||
* @return An ArrayList of PackageInfo objects.
|
||||
*/
|
||||
//due=true returns overdue packages, else upcoming packages
|
||||
public ArrayList<PackageInfo> sortList(ArrayList<PackageInfo> pList, boolean due) {
|
||||
ArrayList<PackageInfo> sortedList = new ArrayList<>();
|
||||
LocalDateTime today = LocalDateTime.now();
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm");
|
||||
today.format(format);
|
||||
for (int i = 0; i < pList.size(); i++) {
|
||||
PackageInfo p = pList.get(i);
|
||||
if (!p.getDelivered()) {
|
||||
if (due && today.isAfter(p.getExpectedDate())) {
|
||||
sortedList.add(p);
|
||||
} else if (!due && today.isBefore(p.getExpectedDate())) {
|
||||
sortedList.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(sortedList);
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes in a list of packages and returns a list of packages that are overdue
|
||||
*
|
||||
* @param packageList the list of packages to be sorted
|
||||
*/
|
||||
public void overDueList(ArrayList<PackageInfo> packageList) {
|
||||
ArrayList<PackageInfo> overdue = sortList(packageList, true);
|
||||
if (overdue.size() == 0) {
|
||||
System.out.println("no overdue packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(overdue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes in a list of packages and prints out the packages that are upcoming
|
||||
*
|
||||
* @param packageList the list of packages to be sorted
|
||||
*/
|
||||
public void upcomingList(ArrayList<PackageInfo> packageList) {
|
||||
ArrayList<PackageInfo> upcoming = sortList(packageList, false);
|
||||
if (upcoming.size() == 0) {
|
||||
System.out.println("no upcoming packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(upcoming);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes a list of packages and returns a list of packages that have not been
|
||||
* delivered
|
||||
*
|
||||
* @param packageList The list of packages to be filtered
|
||||
* @return An ArrayList of PackageInfo objects that have not been delivered.
|
||||
*/
|
||||
public ArrayList<PackageInfo> getUndelivered(List<PackageInfo> packageList) {
|
||||
ArrayList<PackageInfo> undelivered = new ArrayList<>();
|
||||
for (int i = 0; i < packageList.size(); i++) {
|
||||
if (packageList.get(i).getDelivered() == false) {
|
||||
undelivered.add(packageList.get(i));
|
||||
}
|
||||
}
|
||||
return undelivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes a list of packages and prints out the undelivered packages, then asks the
|
||||
* user to select a package to mark as delivered
|
||||
*
|
||||
* @param packageList the list of packages to be marked as delivered
|
||||
*/
|
||||
public void markDelivered(ArrayList<PackageInfo> packageList) {
|
||||
ArrayList<PackageInfo> undelivered = getUndelivered(packageList);
|
||||
if (undelivered.size() == 0) {
|
||||
System.out.println("No undelivered packages to show");
|
||||
return;
|
||||
}
|
||||
this.list(undelivered);
|
||||
Scanner scan = new Scanner(System.in);
|
||||
int n;
|
||||
do {
|
||||
System.out.println("enter item number you want to mark delivered (0 to cancel):");
|
||||
n = scan.nextInt();
|
||||
}
|
||||
while (n < 0 || n > undelivered.size());
|
||||
if (n > 0) {
|
||||
PackageInfo p = undelivered.get(n - 1);
|
||||
packageList.get(packageList.indexOf(p)).setDelivered(true);
|
||||
System.out.println(p.getName() + " has been delivered.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in new issue