From 5546ceb29cb811facf85dd758d2021300712a2e6 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 7 Nov 2024 13:16:06 -0500 Subject: [PATCH 001/267] Created the Data access object for the weather will add the individual components of the entity weather later. --- .../data_access/WeatherDataAccessObject.java | 62 +++++++++++++++++++ src/main/java/entity/Weather.java | 18 ++++++ 2 files changed, 80 insertions(+) create mode 100644 src/main/java/data_access/WeatherDataAccessObject.java create mode 100644 src/main/java/entity/Weather.java diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java new file mode 100644 index 000000000..a1ebebae7 --- /dev/null +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -0,0 +1,62 @@ +package data_access; + +import entity.Weather; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import org.json.JSONException; +import org.json.JSONObject; +import java.io.IOException; + +/** + * This class does stuff. + **/ + +public class WeatherDataAccessObject { + private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; + private static String city; + private static final int SUCCESS_CODE = 200; + private static final String CONTENT_TYPE_LABEL = "Content-Type"; + private static final String CONTENT_TYPE_JSON = "application/json"; + private static final String STATUS_CODE_LABEL = "cod"; + // fixed + private static final String WEATHER_LIST = "list"; + private static final String PASSWORD = "password"; + private static final String MESSAGE = "message"; + + public WeatherDataAccessObject(String city) { + this.city = city; + } + + public Weather get(String username) { + // Make an API call to get the user object. + final OkHttpClient client = new OkHttpClient().newBuilder().build(); + + // creating file + final Request request = new Request.Builder() + .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" + API_KEY + "&units=metric", city)) + .addHeader("Content-Type", CONTENT_TYPE_JSON) + .build(); + try { + final Response response = client.newCall(request).execute(); + + final JSONObject responseBody = new JSONObject(response.body().string()); + + if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { + final JSONObject userJSONObject = responseBody.getJSONObject(WEATHER_LIST); + + // get individual items from the json object + // final String name = userJSONObject.getString(); + + // return new Weather(name); pass values in + } + else { + throw new RuntimeException(responseBody.getString(MESSAGE)); + } + } + catch (IOException | JSONException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java new file mode 100644 index 000000000..b9a8c97c6 --- /dev/null +++ b/src/main/java/entity/Weather.java @@ -0,0 +1,18 @@ +package entity; + +/** + * The representation of a password-protected user for our program. + */ +public class Weather { + + private final String name; + + public Weather(String cityname) { + this.name = cityname; + } + + public String getName() { + return name; + } + +} From ed2bb11436cf05aa04dc9fd4b0302e09d72bed0d Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 7 Nov 2024 20:57:37 -0500 Subject: [PATCH 002/267] finish the WeatherDataAccessInterface and weather object in the entity --- src/main/java/entity/User.java | 24 --------------- src/main/java/entity/weather.java | 29 +++++++++++++++++++ ...e.java => WeatherDataAccessInterface.java} | 6 ++-- 3 files changed, 32 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/entity/User.java create mode 100644 src/main/java/entity/weather.java rename src/main/java/use_case/note/{NoteDataAccessInterface.java => WeatherDataAccessInterface.java} (89%) diff --git a/src/main/java/entity/User.java b/src/main/java/entity/User.java deleted file mode 100644 index e0c57e9a6..000000000 --- a/src/main/java/entity/User.java +++ /dev/null @@ -1,24 +0,0 @@ -package entity; - -/** - * The representation of a password-protected user for our program. - */ -public class User { - - private final String name; - private final String password; - - public User(String name, String password) { - this.name = name; - this.password = password; - } - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - -} diff --git a/src/main/java/entity/weather.java b/src/main/java/entity/weather.java new file mode 100644 index 000000000..ce426127a --- /dev/null +++ b/src/main/java/entity/weather.java @@ -0,0 +1,29 @@ +package entity; + +/** + * The representation of a password-protected user for our program. + */ +public class weather { + + private final String city; + private final int longitude; + private final int latitude; + + public weather(String city, int longitude, int latitude) { + this.city = city; + this.longitude = longitude; + this.latitude = latitude; + } + + public String getName() { + return city; + } + + public int getLongitude() { + return longitude; + } + + public int getLatitude() { + return latitude; + } +} diff --git a/src/main/java/use_case/note/NoteDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java similarity index 89% rename from src/main/java/use_case/note/NoteDataAccessInterface.java rename to src/main/java/use_case/note/WeatherDataAccessInterface.java index b71597828..b4072f00d 100644 --- a/src/main/java/use_case/note/NoteDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -6,7 +6,7 @@ * Interface for the NoteDAO. It consists of methods for * both loading and saving a note. */ -public interface NoteDataAccessInterface { +public interface WeatherDataAccessInterface { /** * Saves a note for a given user. This will replace any existing note. @@ -16,8 +16,8 @@ public interface NoteDataAccessInterface { * @return the contents of the note * @throws DataAccessException if the user's note can not be saved for any reason */ - String saveNote(User user, String note) throws DataAccessException; - + Weather getWeather(String city) throws IOException; + /** * Returns the note associated with the user. The password * is not checked, so anyone can read the information. From 24782421d77119d84a24f476e31347adb54014ec Mon Sep 17 00:00:00 2001 From: linhaoli Date: Fri, 8 Nov 2024 17:25:34 -0500 Subject: [PATCH 003/267] update the README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 5e1d8b77c..3ddf82c97 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,18 @@ knows the password for it. You can see the documentation in the various files for more information. +## User Stories +Person wants to search for a specific location. They type that location in the search bar and the map moves to that location and displays the weather. If they search for a place that doesnt exist, the software displays an error message. + +Person wants to view weather alerts in a certain area. They see that displayed somewhere. + +Person wants a quick overview of the weather in nearby areas. They can view a list of major nearby locations and select one. + +Person wants to compare the weather in 2 different locations. They can pin the weather of a certain place to the ui to make it easier to compare it to the weather in other places. + +Person wants to see what the weather was yesterday. They can select any hour from the past 24 hours to see what the weather was then. + + ## Testing The repo also includes an example of a use case interactor test, as well as From a342102082fb693902d80e826d210966af5a35b6 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Fri, 8 Nov 2024 19:47:34 -0500 Subject: [PATCH 004/267] finish readme file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3ddf82c97..8aa6d8de8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ In this application, a single note has a name (the "username" in terms of the AP can be read by anyone who knows the name — but only edited by someone who knows the password for it. + You can see the documentation in the various files for more information. ## User Stories From 40eb8e018f182e2803566452118331c6a29df3a8 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 8 Nov 2024 20:59:21 -0500 Subject: [PATCH 005/267] added jxmapviewer --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 527f61e36..e86052a71 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,13 @@ test + + org.jxmapviewer + jxmapviewer2 + 2.8 + + + From e8c9aef59922e4e341039af739afa2e8d7487555 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Fri, 8 Nov 2024 22:50:44 -0500 Subject: [PATCH 006/267] Merged and Updated Changes in Weather Entity, Interface and DAO. --- .../data_access/WeatherDataAccessObject.java | 37 ++++++++++--------- src/main/java/entity/Weather.java | 35 +++++++++++++++--- src/main/java/entity/weather.java | 29 --------------- .../note/WeatherDataAccessInterface.java | 28 +++++--------- 4 files changed, 59 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/entity/weather.java diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index a1ebebae7..a5f0fbfe2 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -4,38 +4,35 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; - import org.json.JSONException; import org.json.JSONObject; +import use_case.note.WeatherDataAccessInterface; + import java.io.IOException; /** - * This class does stuff. + * This class runs the API and creates a weather DAO. **/ -public class WeatherDataAccessObject { +public class WeatherDataAccessObject implements WeatherDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; + private static final String MAIN = "main"; private static String city; private static final int SUCCESS_CODE = 200; - private static final String CONTENT_TYPE_LABEL = "Content-Type"; private static final String CONTENT_TYPE_JSON = "application/json"; private static final String STATUS_CODE_LABEL = "cod"; - // fixed private static final String WEATHER_LIST = "list"; - private static final String PASSWORD = "password"; private static final String MESSAGE = "message"; - public WeatherDataAccessObject(String city) { - this.city = city; - } - - public Weather get(String username) { + @Override + public Weather getWeather(String city) throws IOException { // Make an API call to get the user object. final OkHttpClient client = new OkHttpClient().newBuilder().build(); // creating file final Request request = new Request.Builder() - .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" + API_KEY + "&units=metric", city)) + .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" + + API_KEY + "&units=metric", city)) .addHeader("Content-Type", CONTENT_TYPE_JSON) .build(); try { @@ -44,19 +41,25 @@ public Weather get(String username) { final JSONObject responseBody = new JSONObject(response.body().string()); if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - final JSONObject userJSONObject = responseBody.getJSONObject(WEATHER_LIST); + final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); // get individual items from the json object - // final String name = userJSONObject.getString(); - // return new Weather(name); pass values in + final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); + final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); + final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + + return new Weather(city, lon, lat, temp, looks); + } else { - throw new RuntimeException(responseBody.getString(MESSAGE)); + throw new IOException(responseBody.getString(MESSAGE)); } } catch (IOException | JSONException ex) { - throw new RuntimeException(ex); + throw new IOException(ex); } } } + diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index b9a8c97c6..4985fe4b3 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -1,18 +1,43 @@ package entity; /** - * The representation of a password-protected user for our program. + * The representation of a Weather Information Package. */ public class Weather { + private final String city; + private final int longitude; + private final int latitude; - private final String name; + private final int temperature; + private final String looks; + + public Weather(String city, int longitude, int latitude, int temperature, String looks) { + this.city = city; + this.longitude = longitude; + this.latitude = latitude; + this.temperature = temperature; + this.looks = looks; - public Weather(String cityname) { - this.name = cityname; } public String getName() { - return name; + return city; + } + + public int getLongitude() { + return longitude; + } + + public int getLatitude() { + return latitude; + } + + public int getTemperature() { + return temperature; + } + + public String getLooks() { + return looks; } } diff --git a/src/main/java/entity/weather.java b/src/main/java/entity/weather.java deleted file mode 100644 index ce426127a..000000000 --- a/src/main/java/entity/weather.java +++ /dev/null @@ -1,29 +0,0 @@ -package entity; - -/** - * The representation of a password-protected user for our program. - */ -public class weather { - - private final String city; - private final int longitude; - private final int latitude; - - public weather(String city, int longitude, int latitude) { - this.city = city; - this.longitude = longitude; - this.latitude = latitude; - } - - public String getName() { - return city; - } - - public int getLongitude() { - return longitude; - } - - public int getLatitude() { - return latitude; - } -} diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index b4072f00d..163d40981 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -1,30 +1,20 @@ package use_case.note; -import entity.User; +import entity.Weather; +import java.io.IOException; /** - * Interface for the NoteDAO. It consists of methods for - * both loading and saving a note. + * Interface for the WeatherDAO. It consists of methods for + * loading the weather. */ public interface WeatherDataAccessInterface { /** - * Saves a note for a given user. This will replace any existing note. - *

The password of the user must match that of the user saved in the system.

- * @param user the user information associated with the note - * @param note the note to be saved - * @return the contents of the note - * @throws DataAccessException if the user's note can not be saved for any reason + * Creates the Weather. + * @param city the weather is displayed for + * @return the weather information + * @throws IOException if the city does not exist or oi. */ - Weather getWeather(String city) throws IOException; - - /** - * Returns the note associated with the user. The password - * is not checked, so anyone can read the information. - * @param user the user information associated with the note - * @return the contents of the note - * @throws DataAccessException if the user's note can not be loaded for any reason - */ - String loadNote(User user) throws DataAccessException; + Weather getWeather(String city) throws IOException; } From f004b57ee64a4732fb5ef5963d7cc55a97e58cf5 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 9 Nov 2024 06:56:32 -0800 Subject: [PATCH 007/267] delete the original User.java file(since we don't keep information of the users), add new class weather.java. This class list a bunch of attributes that will get from api. --- src/main/java/entity/User.java | 24 -------------- src/main/java/entity/Weather.java | 55 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 24 deletions(-) delete mode 100644 src/main/java/entity/User.java create mode 100644 src/main/java/entity/Weather.java diff --git a/src/main/java/entity/User.java b/src/main/java/entity/User.java deleted file mode 100644 index e0c57e9a6..000000000 --- a/src/main/java/entity/User.java +++ /dev/null @@ -1,24 +0,0 @@ -package entity; - -/** - * The representation of a password-protected user for our program. - */ -public class User { - - private final String name; - private final String password; - - public User(String name, String password) { - this.name = name; - this.password = password; - } - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - -} diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java new file mode 100644 index 000000000..b0be05c1f --- /dev/null +++ b/src/main/java/entity/Weather.java @@ -0,0 +1,55 @@ +package entity; + +/** + * The representation of a password-protected user for our program. + */ +public class Weather { + + private final float temperature; + private final String weather; + private final String description; + private final String icon; + private final float windSpeed; + private final int humidity; + private final int visibility; + + + public Weather(float temperature, String weather, String description, String icon, float windSpeed, int humidity, + int visibility) { + this.temperature = temperature; + this.weather = weather; + this.description = description; + this.icon = icon; + this.windSpeed = windSpeed; + this.humidity = humidity; + this.visibility = visibility; + } + + public String getIcon() { + return icon; + } + + public String getDescription() { + return description; + } + + public String getWeather() { + return weather; + } + + public float getTemperature() { + return temperature; + } + + public float getWindSpeed() { + return windSpeed; + } + + public int getHumidity() { + return humidity; + } + + public int getVisibility() { + return visibility; + } +} From 580541c7f233f65c5a4e3e04cea7a0514f842737 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 9 Nov 2024 11:07:40 -0500 Subject: [PATCH 008/267] sample file for map added --- src/test/java/app/Sample3.java | 112 ++++++++++++++++++++++++ src/test/java/app/SelectionAdapter.java | 87 ++++++++++++++++++ src/test/java/app/SelectionPainter.java | 42 +++++++++ 3 files changed, 241 insertions(+) create mode 100644 src/test/java/app/Sample3.java create mode 100644 src/test/java/app/SelectionAdapter.java create mode 100644 src/test/java/app/SelectionPainter.java diff --git a/src/test/java/app/Sample3.java b/src/test/java/app/Sample3.java new file mode 100644 index 000000000..c22666b16 --- /dev/null +++ b/src/test/java/app/Sample3.java @@ -0,0 +1,112 @@ +package app; + +import java.awt.BorderLayout; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.WindowConstants; +import javax.swing.event.MouseInputListener; + +import org.jxmapviewer.JXMapViewer; +import org.jxmapviewer.OSMTileFactoryInfo; +import org.jxmapviewer.cache.FileBasedLocalCache; +import org.jxmapviewer.input.CenterMapListener; +import org.jxmapviewer.input.PanKeyListener; +import org.jxmapviewer.input.PanMouseInputListener; +import org.jxmapviewer.input.ZoomMouseWheelListenerCursor; +import org.jxmapviewer.viewer.DefaultTileFactory; +import org.jxmapviewer.viewer.GeoPosition; +import org.jxmapviewer.viewer.TileFactoryInfo; + +/** + * A simple sample application that shows + * a OSM map of Europe + * @author Martin Steiger + */ +public class Sample3 +{ + /** + * @param args the program args (ignored) + */ + public static void main(String[] args) + { + // Create a TileFactoryInfo for OpenStreetMap + TileFactoryInfo info = new OSMTileFactoryInfo(); + DefaultTileFactory tileFactory = new DefaultTileFactory(info); + + // Setup local file cache + File cacheDir = new File(System.getProperty("user.home") + File.separator + ".jxmapviewer2"); + tileFactory.setLocalCache(new FileBasedLocalCache(cacheDir, false)); + + // Setup JXMapViewer + final JXMapViewer mapViewer = new JXMapViewer(); + mapViewer.setTileFactory(tileFactory); + + GeoPosition frankfurt = new GeoPosition(50.11, 8.68); + + // Set the focus + mapViewer.setZoom(7); + mapViewer.setAddressLocation(frankfurt); + + // Add interactions + MouseInputListener mia = new PanMouseInputListener(mapViewer); + mapViewer.addMouseListener(mia); + mapViewer.addMouseMotionListener(mia); + + mapViewer.addMouseListener(new CenterMapListener(mapViewer)); + + mapViewer.addMouseWheelListener(new ZoomMouseWheelListenerCursor(mapViewer)); + + mapViewer.addKeyListener(new PanKeyListener(mapViewer)); + + // Add a selection painter + SelectionAdapter sa = new SelectionAdapter(mapViewer); + SelectionPainter sp = new SelectionPainter(sa); + mapViewer.addMouseListener(sa); + mapViewer.addMouseMotionListener(sa); + mapViewer.setOverlayPainter(sp); + + // Display the viewer in a JFrame + final JFrame frame = new JFrame(); + frame.setLayout(new BorderLayout()); + String text = "Use left mouse button to pan, mouse wheel to zoom and right mouse to select"; + frame.add(new JLabel(text), BorderLayout.NORTH); + frame.add(mapViewer); + frame.setSize(800, 600); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setVisible(true); + + mapViewer.addPropertyChangeListener("zoom", new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + updateWindowTitle(frame, mapViewer); + } + }); + + mapViewer.addPropertyChangeListener("center", new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + updateWindowTitle(frame, mapViewer); + } + }); + + updateWindowTitle(frame, mapViewer); + } + + protected static void updateWindowTitle(JFrame frame, JXMapViewer mapViewer) + { + double lat = mapViewer.getCenterPosition().getLatitude(); + double lon = mapViewer.getCenterPosition().getLongitude(); + int zoom = mapViewer.getZoom(); + + frame.setTitle(String.format("JXMapviewer2 Example 3 (%.2f / %.2f) - Zoom: %d", lat, lon, zoom)); + } + +} diff --git a/src/test/java/app/SelectionAdapter.java b/src/test/java/app/SelectionAdapter.java new file mode 100644 index 000000000..e5aae17f8 --- /dev/null +++ b/src/test/java/app/SelectionAdapter.java @@ -0,0 +1,87 @@ + +package app; + +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; + +import org.jxmapviewer.JXMapViewer; + +/** + * Creates a selection rectangle based on mouse input + * Also triggers repaint events in the viewer + * @author Martin Steiger + */ +public class SelectionAdapter extends MouseAdapter +{ + private boolean dragging; + private JXMapViewer viewer; + + private Point2D startPos = new Point2D.Double(); + private Point2D endPos = new Point2D.Double(); + + /** + * @param viewer the jxmapviewer + */ + public SelectionAdapter(JXMapViewer viewer) + { + this.viewer = viewer; + } + + @Override + public void mousePressed(MouseEvent e) + { + if (e.getButton() != MouseEvent.BUTTON3) + return; + + startPos.setLocation(e.getX(), e.getY()); + endPos.setLocation(e.getX(), e.getY()); + + dragging = true; + } + + @Override + public void mouseDragged(MouseEvent e) + { + if (!dragging) + return; + + endPos.setLocation(e.getX(), e.getY()); + + viewer.repaint(); + } + + @Override + public void mouseReleased(MouseEvent e) + { + if (!dragging) + return; + + if (e.getButton() != MouseEvent.BUTTON3) + return; + + viewer.repaint(); + + dragging = false; + } + + /** + * @return the selection rectangle + */ + public Rectangle getRectangle() + { + if (dragging) + { + int x1 = (int) Math.min(startPos.getX(), endPos.getX()); + int y1 = (int) Math.min(startPos.getY(), endPos.getY()); + int x2 = (int) Math.max(startPos.getX(), endPos.getX()); + int y2 = (int) Math.max(startPos.getY(), endPos.getY()); + + return new Rectangle(x1, y1, x2-x1, y2-y1); + } + + return null; + } + +} diff --git a/src/test/java/app/SelectionPainter.java b/src/test/java/app/SelectionPainter.java new file mode 100644 index 000000000..be57d652d --- /dev/null +++ b/src/test/java/app/SelectionPainter.java @@ -0,0 +1,42 @@ + +package app; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +import org.jxmapviewer.painter.Painter; + +/** + * Paints a selection rectangle + * @author Martin Steiger + */ +public class SelectionPainter implements Painter +{ + private Color fillColor = new Color(128, 192, 255, 128); + private Color frameColor = new Color(0, 0, 255, 128); + + private SelectionAdapter adapter; + + /** + * @param adapter the selection adapter + */ + public SelectionPainter(SelectionAdapter adapter) + { + this.adapter = adapter; + } + + @Override + public void paint(Graphics2D g, Object t, int width, int height) + { + Rectangle rc = adapter.getRectangle(); + + if (rc != null) + { + g.setColor(frameColor); + g.draw(rc); + g.setColor(fillColor); + g.fill(rc); + } + } +} From 8bc21c5481f3a8250cb8b2cbd1fa8131a6f9385e Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Sun, 10 Nov 2024 10:37:32 -0500 Subject: [PATCH 009/267] replace old names within functions by new names starting with "weather" --- src/main/java/app/MainNoteApplication.java | 6 ++--- src/main/java/app/NoteAppBuilder.java | 10 ++++----- .../data_access/DBNoteDataAccessObject.java | 22 +++++++++++-------- src/main/java/entity/Weather.java | 2 +- .../java/use_case/note/NoteInteractor.java | 16 ++++++++------ .../note/searchResult/SearchInputData.java | 13 +++++++++++ 6 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 src/main/java/use_case/note/searchResult/SearchInputData.java diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index c37860156..38a0bad9c 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -1,7 +1,7 @@ package app; -import data_access.DBNoteDataAccessObject; -import use_case.note.NoteDataAccessInterface; +import data_access.WeatherDataAccessObject; +import use_case.note.WeatherDataAccessInterface; /** * An application where we can view and add to a note stored by a user. @@ -46,7 +46,7 @@ public class MainNoteApplication { public static void main(String[] args) { // create the data access and inject it into our builder! - final NoteDataAccessInterface noteDataAccess = new DBNoteDataAccessObject(); + final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); final NoteAppBuilder builder = new NoteAppBuilder(); builder.addNoteDAO(noteDataAccess) diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index a68cb9ad6..8cdfd9674 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -6,7 +6,7 @@ import interface_adapter.note.NoteController; import interface_adapter.note.NotePresenter; import interface_adapter.note.NoteViewModel; -import use_case.note.NoteDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; import use_case.note.NoteInteractor; import use_case.note.NoteOutputBoundary; import view.NoteView; @@ -17,18 +17,18 @@ public class NoteAppBuilder { public static final int HEIGHT = 300; public static final int WIDTH = 400; - private NoteDataAccessInterface noteDAO; + private WeatherDataAccessInterface noteDAO; private NoteViewModel noteViewModel = new NoteViewModel(); private NoteView noteView; private NoteInteractor noteInteractor; /** * Sets the NoteDAO to be used in this application. - * @param noteDataAccess the DAO to use + * @param weatherDataAccess the DAO to use * @return this builder */ - public NoteAppBuilder addNoteDAO(NoteDataAccessInterface noteDataAccess) { - noteDAO = noteDataAccess; + public NoteAppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { + noteDAO = weatherDataAccess; return this; } diff --git a/src/main/java/data_access/DBNoteDataAccessObject.java b/src/main/java/data_access/DBNoteDataAccessObject.java index dadb0cab0..0bb066aaf 100644 --- a/src/main/java/data_access/DBNoteDataAccessObject.java +++ b/src/main/java/data_access/DBNoteDataAccessObject.java @@ -5,14 +5,14 @@ import org.json.JSONException; import org.json.JSONObject; -import entity.User; +import entity.Weather; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import use_case.note.DataAccessException; -import use_case.note.NoteDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; /** * The DAO for accessing notes stored in the database. @@ -27,8 +27,9 @@ * csc207-grade-apis-demo/documentation/fg3zkjm/5-password-protected-user"> * the documentation * of the API for more details. + * implements NoteDataAccessInterface */ -public class DBNoteDataAccessObject implements NoteDataAccessInterface { +public class DBNoteDataAccessObject { private static final int SUCCESS_CODE = 200; private static final int CREDENTIAL_ERROR = 401; private static final String CONTENT_TYPE_LABEL = "Content-Type"; @@ -39,15 +40,18 @@ public class DBNoteDataAccessObject implements NoteDataAccessInterface { private static final String MESSAGE = "message"; @Override - public String saveNote(User user, String note) throws DataAccessException { + public String saveNote(Weather weather, String note) throws DataAccessException { final OkHttpClient client = new OkHttpClient().newBuilder() .build(); // POST METHOD final MediaType mediaType = MediaType.parse(CONTENT_TYPE_JSON); final JSONObject requestBody = new JSONObject(); - requestBody.put(USERNAME, user.getName()); - requestBody.put(PASSWORD, user.getPassword()); + requestBody.put(USERNAME, weather.getCity()); + requestBody.put(PASSWORD, weather.getLongitude()); + requestBody.put(USERNAME, weather.getLatitude()); + requestBody.put(USERNAME, weather.getTemperature()); + requestBody.put(USERNAME, weather.getLooks()); final JSONObject extra = new JSONObject(); extra.put("note", note); requestBody.put("info", extra); @@ -63,7 +67,7 @@ public String saveNote(User user, String note) throws DataAccessException { final JSONObject responseBody = new JSONObject(response.body().string()); if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - return loadNote(user); + return loadNote(weather); } else if (responseBody.getInt(STATUS_CODE_LABEL) == CREDENTIAL_ERROR) { throw new DataAccessException("message could not be found or password was incorrect"); @@ -78,9 +82,9 @@ else if (responseBody.getInt(STATUS_CODE_LABEL) == CREDENTIAL_ERROR) { } @Override - public String loadNote(User user) throws DataAccessException { + public String loadNote(Weather weather) throws DataAccessException { // Make an API call to get the user object. - final String username = user.getName(); + final String username = weather.getCity(); final OkHttpClient client = new OkHttpClient().newBuilder().build(); final Request request = new Request.Builder() .url(String.format("http://vm003.teach.cs.toronto.edu:20112/user?username=%s", username)) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 4985fe4b3..828f75bac 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -20,7 +20,7 @@ public Weather(String city, int longitude, int latitude, int temperature, String } - public String getName() { + public String getCity() { return city; } diff --git a/src/main/java/use_case/note/NoteInteractor.java b/src/main/java/use_case/note/NoteInteractor.java index 369e9309a..4ecec532d 100644 --- a/src/main/java/use_case/note/NoteInteractor.java +++ b/src/main/java/use_case/note/NoteInteractor.java @@ -1,6 +1,7 @@ package use_case.note; -import entity.User; +import entity.Weather; +import use_case.note.searchResult.SearchInputData; /** * The "Use Case Interactor" for our two note-related use cases of refreshing @@ -9,18 +10,18 @@ */ public class NoteInteractor implements NoteInputBoundary { - private final NoteDataAccessInterface noteDataAccessInterface; + private final WeatherDataAccessInterface weatherDataAccessInterface; private final NoteOutputBoundary noteOutputBoundary; // Note: this program has it hardcoded which user object it is getting data for; // you could change this if you wanted to generalize the code. For example, // you might allow a user of the program to create a new note, which you // could store as a "user" through the API OR you might maintain all notes // in a JSON object stored in one common "user" stored through the API. - private final User user = new User("jonathan_calver2", "abc123"); + private final Weather weather = new Weather("jonathan_calver2", "abc123"); - public NoteInteractor(NoteDataAccessInterface noteDataAccessInterface, + public NoteInteractor(WeatherDataAccessInterface weatherDataAccessInterface, NoteOutputBoundary noteOutputBoundary) { - this.noteDataAccessInterface = noteDataAccessInterface; + this.weatherDataAccessInterface = weatherDataAccessInterface; this.noteOutputBoundary = noteOutputBoundary; } @@ -29,10 +30,11 @@ public NoteInteractor(NoteDataAccessInterface noteDataAccessInterface, * */ @Override - public void executeRefresh() { + public void executeRefresh(SearchInputData searchInputData) { try { - final String note = noteDataAccessInterface.loadNote(user); + final String city = searchInputData.getCity(); + final String note = weatherDataAccessInterface.getWeather(city); noteOutputBoundary.prepareSuccessView(note); } catch (DataAccessException ex) { diff --git a/src/main/java/use_case/note/searchResult/SearchInputData.java b/src/main/java/use_case/note/searchResult/SearchInputData.java new file mode 100644 index 000000000..5ca3346d1 --- /dev/null +++ b/src/main/java/use_case/note/searchResult/SearchInputData.java @@ -0,0 +1,13 @@ +package use_case.note.searchResult; + +public class SearchInputData { + private final String cityName; + + public SearchInputData(String cityName) { + this.cityName = cityName; + } + + public String getCity() { + return cityName; + } +} From f54e9b9645a4f0c002aac9352ef938191b885f43 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Sun, 10 Nov 2024 14:13:20 -0500 Subject: [PATCH 010/267] Boundaries and Data --- src/main/java/app/MainNoteApplication.java | 20 +++++++ src/main/java/app/NoteAppBuilder.java | 57 ++++++++++++++++++- .../java/use_case/note/NoteInteractor.java | 6 +- .../note/alert_pop/AlertPopInputBoundary.java | 7 +++ .../note/alert_pop/AlertPopInputData.java | 5 ++ .../alert_pop/AlertPopOutputBoundary.java | 8 +++ .../note/alert_pop/AlertPopOutputData.java | 20 +++++++ .../BookmarkReturnInputBoundary.java | 7 +++ .../BookmarkReturnInputData.java | 5 ++ .../BookmarkReturnOutputBoundary.java | 8 +++ .../BookmarkReturnOutputData.java | 14 +++++ .../CityBookmarkInputBoundary.java | 8 +++ .../city_bookmark/CityBookmarkInputData.java | 6 ++ .../CityBookmarkOutputBoundary.java | 8 +++ .../city_bookmark/CityBookmarkOutputData.java | 22 +++++++ .../close_list/CloseListInputBoundary.java | 7 +++ .../note/close_list/CloseListInputData.java | 5 ++ .../close_list/CloseListOutputBoundary.java | 8 +++ .../note/close_list/CloseListOutputData.java | 14 +++++ .../note/close_pin/ClosePinInputBoundary.java | 7 +++ .../note/close_pin/ClosePinInputData.java | 5 ++ .../close_pin/ClosePinOutputBoundary.java | 8 +++ .../note/close_pin/ClosePinOutputData.java | 14 +++++ .../note/close_pop/ClosePopInputBoundary.java | 7 +++ .../note/close_pop/ClosePopInputData.java | 5 ++ .../close_pop/ClosePopOutputBoundary.java | 8 +++ .../note/close_pop/ClosePopOutputData.java | 14 +++++ .../nearby_list/NearbyListInputBoundary.java | 7 +++ .../note/nearby_list/NearbyListInputData.java | 5 ++ .../nearby_list/NearbyListOutputBoundary.java | 8 +++ .../nearby_list/NearbyListOutputData.java | 16 ++++++ .../pin_weather/PinWeatherInputBoundary.java | 7 +++ .../note/pin_weather/PinWeatherInputData.java | 5 ++ .../pin_weather/PinWeatherOutputBoundary.java | 8 +++ .../pin_weather/PinWeatherOutputData.java | 20 +++++++ .../return_home/ReturnHomeInputBoundary.java | 7 +++ .../note/return_home/ReturnHomeInputData.java | 5 ++ .../return_home/ReturnHomeOutputBoundary.java | 8 +++ .../return_home/ReturnHomeOutputData.java | 14 +++++ .../note/searchResult/SearchInputData.java | 13 ----- .../SearchResultInputBoundary.java | 8 +++ .../search_result/SearchResultInputData.java | 15 +++++ .../SearchResultOutputBoundary.java | 8 +++ .../search_result/SearchResultOutputData.java | 24 ++++++++ .../SearchReturnInputBoundary.java | 7 +++ .../search_return/SearchReturnInputData.java | 5 ++ .../SearchReturnOutputBoundary.java | 8 +++ .../search_return/SearchReturnOutputData.java | 24 ++++++++ .../SelectRegionInputBoundary.java | 7 +++ .../select_region/SelectRegionInputData.java | 5 ++ .../SelectRegionOutputBoundary.java | 8 +++ .../select_region/SelectRegionOutputData.java | 23 ++++++++ 52 files changed, 550 insertions(+), 18 deletions(-) create mode 100644 src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java create mode 100644 src/main/java/use_case/note/alert_pop/AlertPopInputData.java create mode 100644 src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java create mode 100644 src/main/java/use_case/note/alert_pop/AlertPopOutputData.java create mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java create mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java create mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java create mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java create mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java create mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java create mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java create mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java create mode 100644 src/main/java/use_case/note/close_list/CloseListInputBoundary.java create mode 100644 src/main/java/use_case/note/close_list/CloseListInputData.java create mode 100644 src/main/java/use_case/note/close_list/CloseListOutputBoundary.java create mode 100644 src/main/java/use_case/note/close_list/CloseListOutputData.java create mode 100644 src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java create mode 100644 src/main/java/use_case/note/close_pin/ClosePinInputData.java create mode 100644 src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java create mode 100644 src/main/java/use_case/note/close_pin/ClosePinOutputData.java create mode 100644 src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java create mode 100644 src/main/java/use_case/note/close_pop/ClosePopInputData.java create mode 100644 src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java create mode 100644 src/main/java/use_case/note/close_pop/ClosePopOutputData.java create mode 100644 src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java create mode 100644 src/main/java/use_case/note/nearby_list/NearbyListInputData.java create mode 100644 src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java create mode 100644 src/main/java/use_case/note/nearby_list/NearbyListOutputData.java create mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java create mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputData.java create mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java create mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java create mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java create mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputData.java create mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java create mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputData.java delete mode 100644 src/main/java/use_case/note/searchResult/SearchInputData.java create mode 100644 src/main/java/use_case/note/search_result/SearchResultInputBoundary.java create mode 100644 src/main/java/use_case/note/search_result/SearchResultInputData.java create mode 100644 src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java create mode 100644 src/main/java/use_case/note/search_result/SearchResultOutputData.java create mode 100644 src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java create mode 100644 src/main/java/use_case/note/search_return/SearchReturnInputData.java create mode 100644 src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java create mode 100644 src/main/java/use_case/note/search_return/SearchReturnOutputData.java create mode 100644 src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java create mode 100644 src/main/java/use_case/note/select_region/SelectRegionInputData.java create mode 100644 src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java create mode 100644 src/main/java/use_case/note/select_region/SelectRegionOutputData.java diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index 38a0bad9c..9ef9b0693 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -51,6 +51,26 @@ public static void main(String[] args) { final NoteAppBuilder builder = new NoteAppBuilder(); builder.addNoteDAO(noteDataAccess) .addNoteView() + .addSearchResultView() + .addSelectRegionView() + .addNearbyListView() + .addPinWeatherView() + .addAlertPopView() + .addCityBookmarkView() + .addSearchResultUseCase() + .addSearchReturnUseCase() + .addSelectRegionUseCase() + .addNearbyListUseCase() + .addCloseListUseCase() + .addPinWeatherUseCase() + .addClosePinUseCase() + .addAlertPopUseCase() + .addClosePopUseCase() + .addCityBookmarkUseCase() + .addBookmarkReturnCase() .addNoteUseCase().build().setVisible(true); + // Annie: What should I do with the last line? First, I don't know if I need to add setVisible to all methods. + // Second, I assume noteView to be default view, and noteUseCase be return to the default view with empty + // search bar. } } diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index 8cdfd9674..652884732 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -15,8 +15,8 @@ * Builder for the Note Application. */ public class NoteAppBuilder { - public static final int HEIGHT = 300; - public static final int WIDTH = 400; + public static final int HEIGHT = 750; + public static final int WIDTH = 1500; private WeatherDataAccessInterface noteDAO; private NoteViewModel noteViewModel = new NoteViewModel(); private NoteView noteView; @@ -80,4 +80,57 @@ public JFrame build() { return frame; } + + public NoteAppBuilder addSearchResultView() { + } + + public NoteAppBuilder addSelectRegionView() { + return null; + } + + public NoteAppBuilder addNearbyListView() { + } + + public NoteAppBuilder addPinWeatherView() { + } + + public NoteAppBuilder addAlertPopView() { + } + + public NoteAppBuilder addCityBookmarkView() { + } + + public NoteAppBuilder addSearchResultUseCase() { + } + + public NoteAppBuilder addSearchReturnUseCase() { + } + + public NoteAppBuilder addSelectRegionUseCase() { + } + + public NoteAppBuilder addNearbyListUseCase() { + } + + public NoteAppBuilder addCloseListUseCase() { + } + + public NoteAppBuilder addPinWeatherUseCase() { + } + + public NoteAppBuilder addClosePinUseCase() { + } + + public NoteAppBuilder addAlertPopUseCase() { + } + + public NoteAppBuilder addClosePopUseCase() { + } + + public NoteAppBuilder addBookmarkReturnCase() { + } + + public NoteAppBuilder addCityBookmarkUseCase() { + return null; + } } diff --git a/src/main/java/use_case/note/NoteInteractor.java b/src/main/java/use_case/note/NoteInteractor.java index 4ecec532d..455eb942e 100644 --- a/src/main/java/use_case/note/NoteInteractor.java +++ b/src/main/java/use_case/note/NoteInteractor.java @@ -1,7 +1,7 @@ package use_case.note; import entity.Weather; -import use_case.note.searchResult.SearchInputData; +import use_case.note.search_result.SearchResultInputData; /** * The "Use Case Interactor" for our two note-related use cases of refreshing @@ -30,10 +30,10 @@ public NoteInteractor(WeatherDataAccessInterface weatherDataAccessInterface, * */ @Override - public void executeRefresh(SearchInputData searchInputData) { + public void executeRefresh(SearchResultInputData searchResultInputData) { try { - final String city = searchInputData.getCity(); + final String city = searchResultInputData.getCity(); final String note = weatherDataAccessInterface.getWeather(city); noteOutputBoundary.prepareSuccessView(note); } diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java new file mode 100644 index 000000000..7d635bfb0 --- /dev/null +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.alert_pop; + +// No input because alertpop is automatic. +public interface AlertPopInputBoundary { + + void execute(AlertPopInputData alertPopInputData); +} diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputData.java b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java new file mode 100644 index 000000000..02d613a5a --- /dev/null +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java @@ -0,0 +1,5 @@ +package use_case.note.alert_pop; + +// No input because alertpop is automatic. +public class AlertPopInputData { +} diff --git a/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java new file mode 100644 index 000000000..4e431ba03 --- /dev/null +++ b/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.alert_pop; + +public interface AlertPopOutputBoundary { + + void prepareSuccessView(AlertPopOutputData alertPopOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java b/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java new file mode 100644 index 000000000..50f45b31e --- /dev/null +++ b/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java @@ -0,0 +1,20 @@ +package use_case.note.alert_pop; + +public class AlertPopOutputData { + + private final String alert; + private final boolean useCaseFailed; + + public AlertPopOutputData(String alert, boolean useCaseFailed) { + this.alert = alert; + this.useCaseFailed = useCaseFailed; + } + + public String getAlert() { + return alert; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java new file mode 100644 index 000000000..4b46cafdd --- /dev/null +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.bookmark_return; + +// The input is one click on "return". +public interface BookmarkReturnInputBoundary { + + void execute(BookmarkReturnInputData bookmarkReturnInputData); +} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java new file mode 100644 index 000000000..e53789e11 --- /dev/null +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java @@ -0,0 +1,5 @@ +package use_case.note.bookmark_return; + +// The input is one click on "return". +public class BookmarkReturnInputData { +} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java new file mode 100644 index 000000000..ce8bdd68d --- /dev/null +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.bookmark_return; + +public interface BookmarkReturnOutputBoundary { + + void prepareSuccessView(BookmarkReturnOutputData bookmarkReturnOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java new file mode 100644 index 000000000..688222b79 --- /dev/null +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java @@ -0,0 +1,14 @@ +package use_case.note.bookmark_return; + +public class BookmarkReturnOutputData { + + private final boolean useCaseFailed; + + public BookmarkReturnOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java new file mode 100644 index 000000000..b8cfda36e --- /dev/null +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.city_bookmark; + +// The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the +// InputData. +public interface CityBookmarkInputBoundary { + + void execute(CityBookmarkInputBoundary cityBookmarkInputBoundary); +} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java new file mode 100644 index 000000000..47d6cb8a1 --- /dev/null +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java @@ -0,0 +1,6 @@ +package use_case.note.city_bookmark; + +// The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the +// InputData. +public class CityBookmarkInputData { +} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java new file mode 100644 index 000000000..02f755b2e --- /dev/null +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.city_bookmark; + +public interface CityBookmarkOutputBoundary { + + void presentSuccessView(CityBookmarkOutputData cityBookmarkOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java new file mode 100644 index 000000000..55b08fce3 --- /dev/null +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java @@ -0,0 +1,22 @@ +package use_case.note.city_bookmark; + +import java.util.ArrayList; + +public class CityBookmarkOutputData { + + private final String[] cities; + private final boolean useCaseFailed; + + public CityBookmarkOutputData(String[] cities, boolean useCaseFailed) { + this.cities = cities; + this.useCaseFailed = useCaseFailed; + } + + public String getCities() { + return cities; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/close_list/CloseListInputBoundary.java b/src/main/java/use_case/note/close_list/CloseListInputBoundary.java new file mode 100644 index 000000000..be422c7e9 --- /dev/null +++ b/src/main/java/use_case/note/close_list/CloseListInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.close_list; + +// Input is one click on "close". +public interface CloseListInputBoundary { + + void execute(CloseListInputBoundary closeListInputBoundary); +} diff --git a/src/main/java/use_case/note/close_list/CloseListInputData.java b/src/main/java/use_case/note/close_list/CloseListInputData.java new file mode 100644 index 000000000..caba5f836 --- /dev/null +++ b/src/main/java/use_case/note/close_list/CloseListInputData.java @@ -0,0 +1,5 @@ +package use_case.note.close_list; + +// Input is one click on "close". +public class CloseListInputData { +} diff --git a/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java b/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java new file mode 100644 index 000000000..fe3d9a723 --- /dev/null +++ b/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.close_list; + +public interface CloseListOutputBoundary { + + void presentSuccessView(CloseListOutputData closeListOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/close_list/CloseListOutputData.java b/src/main/java/use_case/note/close_list/CloseListOutputData.java new file mode 100644 index 000000000..e4a99360d --- /dev/null +++ b/src/main/java/use_case/note/close_list/CloseListOutputData.java @@ -0,0 +1,14 @@ +package use_case.note.close_list; + +public class CloseListOutputData { + + private final boolean useCaseFailed; + + public CloseListOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java new file mode 100644 index 000000000..1c679ef8c --- /dev/null +++ b/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.close_pin; + +// Input is a click on the "close" button. +public interface ClosePinInputBoundary { + + void execute(ClosePinInputData closePinInputData); +} diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputData.java b/src/main/java/use_case/note/close_pin/ClosePinInputData.java new file mode 100644 index 000000000..ba3f16d7c --- /dev/null +++ b/src/main/java/use_case/note/close_pin/ClosePinInputData.java @@ -0,0 +1,5 @@ +package use_case.note.close_pin; + +// Input is a click on the "close" button. +public class ClosePinInputData { +} diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java new file mode 100644 index 000000000..da4e3b1bc --- /dev/null +++ b/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.close_pin; + +public interface ClosePinOutputBoundary { + + void presentSuccessView(ClosePinOutputData closePinOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputData.java b/src/main/java/use_case/note/close_pin/ClosePinOutputData.java new file mode 100644 index 000000000..eab6e91f4 --- /dev/null +++ b/src/main/java/use_case/note/close_pin/ClosePinOutputData.java @@ -0,0 +1,14 @@ +package use_case.note.close_pin; + +public class ClosePinOutputData { + + private final boolean useCaseFailed; + + public ClosePinOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java new file mode 100644 index 000000000..06cd776d8 --- /dev/null +++ b/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.close_pop; + +// Input is a click on "close". +public interface ClosePopInputBoundary { + + void execute(ClosePopInputData closePopInputData); +} diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputData.java b/src/main/java/use_case/note/close_pop/ClosePopInputData.java new file mode 100644 index 000000000..dfeeafa7b --- /dev/null +++ b/src/main/java/use_case/note/close_pop/ClosePopInputData.java @@ -0,0 +1,5 @@ +package use_case.note.close_pop; + +// Input is a click on "close". +public class ClosePopInputData { +} diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java new file mode 100644 index 000000000..4d881e40f --- /dev/null +++ b/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.close_pop; + +public interface ClosePopOutputBoundary { + + void presentSuccessView(ClosePopOutputData closePopOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputData.java b/src/main/java/use_case/note/close_pop/ClosePopOutputData.java new file mode 100644 index 000000000..03ffe9913 --- /dev/null +++ b/src/main/java/use_case/note/close_pop/ClosePopOutputData.java @@ -0,0 +1,14 @@ +package use_case.note.close_pop; + +public class ClosePopOutputData { + + private final boolean useCaseFailed; + + public ClosePopOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java new file mode 100644 index 000000000..22407c6b4 --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.nearby_list; + +// This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. +public interface NearbyListInputBoundary { + + void execute(NearbyListInputData nearbyListInputData); +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java new file mode 100644 index 000000000..5e6e7aa29 --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java @@ -0,0 +1,5 @@ +package use_case.note.nearby_list; + +// This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. +public class NearbyListInputData { +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java new file mode 100644 index 000000000..4ac7b4bd4 --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.nearby_list; + +public interface NearbyListOutputBoundary { + + void presentSuccessView(NearbyListOutputData nearbyListOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java new file mode 100644 index 000000000..e6256e43f --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java @@ -0,0 +1,16 @@ +package use_case.note.nearby_list; + +public class NearbyListOutputData { + + private final String[] cities; + private final boolean useCaseFailed; + + public NearbyListOutputData(String[] cities, boolean useCaseFailed) { + this.cities = cities; + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java new file mode 100644 index 000000000..77475633d --- /dev/null +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.pin_weather; + +// Input is a click on "pin." +public interface PinWeatherInputBoundary { + + void execute(PinWeatherInputData pinWeatherInputData) +} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java new file mode 100644 index 000000000..623290d9f --- /dev/null +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java @@ -0,0 +1,5 @@ +package use_case.note.pin_weather; + +// Input is a click on "pin." +public class PinWeatherInputData { +} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java new file mode 100644 index 000000000..6eac48913 --- /dev/null +++ b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.pin_weather; + +public interface PinWeatherOutputBoundary { + + void presentSuccessView(PinWeatherOutputData pinWeatherOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java new file mode 100644 index 000000000..cc0446619 --- /dev/null +++ b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java @@ -0,0 +1,20 @@ +package use_case.note.pin_weather; + +public class PinWeatherOutputData { + + private final String weatherInfo; + private final boolean useCaseFailed; + + public PinWeatherOutputData(String weatherInfo, boolean useCaseFailed) { + this.weatherInfo = weatherInfo; + this.useCaseFailed = useCaseFailed; + } + + public String getWeatherInfo() { + return weatherInfo; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java new file mode 100644 index 000000000..93b43e15b --- /dev/null +++ b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.return_home; + +// Input is a click on the home button. +public interface ReturnHomeInputBoundary { + + void execute(ReturnHomeInputData returnHomeInputData); +} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java new file mode 100644 index 000000000..27162a91e --- /dev/null +++ b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java @@ -0,0 +1,5 @@ +package use_case.note.return_home; + +// Input is a click on the home button. +public class ReturnHomeInputData { +} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java new file mode 100644 index 000000000..258573eb3 --- /dev/null +++ b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.return_home; + +public interface ReturnHomeOutputBoundary { + + void presentSuccessView(ReturnHomeOutputData returnHomeOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java new file mode 100644 index 000000000..49f1ba0c4 --- /dev/null +++ b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java @@ -0,0 +1,14 @@ +package use_case.note.return_home; + +public class ReturnHomeOutputData { + + private final boolean useCaseFailed; + + public ReturnHomeOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/searchResult/SearchInputData.java b/src/main/java/use_case/note/searchResult/SearchInputData.java deleted file mode 100644 index 5ca3346d1..000000000 --- a/src/main/java/use_case/note/searchResult/SearchInputData.java +++ /dev/null @@ -1,13 +0,0 @@ -package use_case.note.searchResult; - -public class SearchInputData { - private final String cityName; - - public SearchInputData(String cityName) { - this.cityName = cityName; - } - - public String getCity() { - return cityName; - } -} diff --git a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java new file mode 100644 index 000000000..e54108eb8 --- /dev/null +++ b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.search_result; + +// Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside +// search bar. +public interface SearchResultInputBoundary { + + void execute(SearchResultInputData searchResultInputData) +} diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java new file mode 100644 index 000000000..4dd04fc47 --- /dev/null +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -0,0 +1,15 @@ +package use_case.note.search_result; + +// Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside +// search bar. +public class SearchResultInputData { + private final String cityName; + + public SearchResultInputData(String cityName) { + this.cityName = cityName; + } + + public String getCity() { + return cityName; + } +} diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java new file mode 100644 index 000000000..cee8789c9 --- /dev/null +++ b/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.search_result; + +public interface SearchResultOutputBoundary { + + void presentSuccessView(SearchResultOutputData searchResultOutputData); + + void presentFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java new file mode 100644 index 000000000..15acd46bb --- /dev/null +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -0,0 +1,24 @@ +package use_case.note.search_result; + +public class SearchResultOutputData { + + private final String location; + private final String weather; + private final boolean useCaseFailed; + + public SearchResultOutputData(String location, String weather, boolean useCaseFailed) { + this.location = location; + this.weather = weather; + this.useCaseFailed = useCaseFailed; + } + + public String getLocation() { + return location; + } + + public String getWeather() {return weather;} + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java new file mode 100644 index 000000000..654457ce1 --- /dev/null +++ b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.search_return; + +// Input is one click on "return." +public interface SearchReturnInputBoundary { + + void execute(SearchReturnInputData searchReturnInputData) +} diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputData.java b/src/main/java/use_case/note/search_return/SearchReturnInputData.java new file mode 100644 index 000000000..626e3ad64 --- /dev/null +++ b/src/main/java/use_case/note/search_return/SearchReturnInputData.java @@ -0,0 +1,5 @@ +package use_case.note.search_return; + +// Input is one click on "return." +public class SearchReturnInputData { +} diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java new file mode 100644 index 000000000..90e7ca950 --- /dev/null +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.search_return; + +public interface SearchReturnOutputBoundary { + + void presentSuccessView(SearchReturnOutputData searchReturnOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java new file mode 100644 index 000000000..c787226d2 --- /dev/null +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -0,0 +1,24 @@ +package use_case.note.search_return; + +public class SearchReturnOutputData { + + private final String location; + private final String weather; + private final boolean useCaseFailed; + + public SearchReturnOutputData(String location, String weather, boolean useCaseFailed) { + this.location = location; + this.weather = weather; + this.useCaseFailed = useCaseFailed; + } + + public String getLocation() { + return location; + } + + public String getWeather() {return weather;} + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java new file mode 100644 index 000000000..17c3d0394 --- /dev/null +++ b/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.select_region; + +// Input is a click on the region. +public interface SelectRegionInputBoundary { + + void execute(SelectRegionInputData selectRegionInputData); +} diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputData.java b/src/main/java/use_case/note/select_region/SelectRegionInputData.java new file mode 100644 index 000000000..9d72aadd3 --- /dev/null +++ b/src/main/java/use_case/note/select_region/SelectRegionInputData.java @@ -0,0 +1,5 @@ +package use_case.note.select_region; + +// Input is a click on the region. +public class SelectRegionInputData { +} diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java new file mode 100644 index 000000000..eca8cecf5 --- /dev/null +++ b/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.note.select_region; + +public interface SelectRegionOutputBoundary { + + void presentSuccessView(SelectRegionOutputData selectRegionOutputData); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputData.java b/src/main/java/use_case/note/select_region/SelectRegionOutputData.java new file mode 100644 index 000000000..a8fe7a631 --- /dev/null +++ b/src/main/java/use_case/note/select_region/SelectRegionOutputData.java @@ -0,0 +1,23 @@ +package use_case.note.select_region; + +public class SelectRegionOutputData { + private final String location; + private final String weather; + private final boolean useCaseFailed; + + public SelectRegionOutputData(String location, String weather, boolean useCaseFailed) { + this.location = location; + this.weather = weather; + this.useCaseFailed = useCaseFailed; + } + + public String getLocation() { + return location; + } + + public String getWeather() {return weather;} + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} From bd4ed0cc6a86d79b070e3fe0358edaa49ac06e34 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 10 Nov 2024 21:08:18 -0500 Subject: [PATCH 011/267] Add more features to DAO interface --- .../java/use_case/note/NoteInteractor.java | 79 ++++++++++--------- .../note/WeatherDataAccessInterface.java | 1 + 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/main/java/use_case/note/NoteInteractor.java b/src/main/java/use_case/note/NoteInteractor.java index 369e9309a..55abc122c 100644 --- a/src/main/java/use_case/note/NoteInteractor.java +++ b/src/main/java/use_case/note/NoteInteractor.java @@ -1,59 +1,62 @@ package use_case.note; -import entity.User; +import entity.Weather; /** * The "Use Case Interactor" for our two note-related use cases of refreshing * the contents of the note and saving the contents of the note. Since they * are closely related, we have combined them here for simplicity. */ -public class NoteInteractor implements NoteInputBoundary { +public class WeatherInteractor implements NoteInputBoundary { // Note: InputBoundary is not done yet - private final NoteDataAccessInterface noteDataAccessInterface; + private final WeatherDataAccessInterface weatherDataAccessInterface; private final NoteOutputBoundary noteOutputBoundary; // Note: this program has it hardcoded which user object it is getting data for; // you could change this if you wanted to generalize the code. For example, // you might allow a user of the program to create a new note, which you // could store as a "user" through the API OR you might maintain all notes // in a JSON object stored in one common "user" stored through the API. - private final User user = new User("jonathan_calver2", "abc123"); + private final Weather weather - public NoteInteractor(NoteDataAccessInterface noteDataAccessInterface, + public void weatherInteractor(WeatherDataAccessInterface weatherDataAccessInterface, NoteOutputBoundary noteOutputBoundary) { - this.noteDataAccessInterface = noteDataAccessInterface; + this.weatherDataAccessInterface = weatherDataAccessInterface; this.noteOutputBoundary = noteOutputBoundary; + this.weather = weatherDataAccessInterface.getWeather(noteOutputBoundary.getCityName()); // Note: getCityName is not done yet } - /** - * Executes the refresh note use case. - * - */ - @Override - public void executeRefresh() { - try { - - final String note = noteDataAccessInterface.loadNote(user); - noteOutputBoundary.prepareSuccessView(note); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } - - /** - * Executes the save note use case. - * - * @param note the input data - */ - @Override - public void executeSave(String note) { - try { - - final String updatedNote = noteDataAccessInterface.saveNote(user, note); - noteOutputBoundary.prepareSuccessView(updatedNote); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } +// /** +// * Executes the refresh note use case. +// * +// */ +// @Override +// public void executeRefresh() { +// try { +// +// final String note = noteDataAccessInterface.loadNote(user); +// noteOutputBoundary.prepareSuccessView(note); +// } +// catch (DataAccessException ex) { +// noteOutputBoundary.prepareFailView(ex.getMessage()); +// } +// } + +// /** +// * Executes the save note use case. +// * +// * @param note the input data +// */ +// @Override +// public void executeSave(String note) { +// try { +// +// final String updatedNote = noteDataAccessInterface.saveNote(user, note); +// noteOutputBoundary.prepareSuccessView(updatedNote); +// } +// catch (DataAccessException ex) { +// noteOutputBoundary.prepareFailView(ex.getMessage()); +// } +// } + @ Override + public void } diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index 163d40981..e1c13927a 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -17,4 +17,5 @@ public interface WeatherDataAccessInterface { */ Weather getWeather(String city) throws IOException; + } From 36de08e7515aabd1ef0c36c3f3eba0224bd9ebbd Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 10 Nov 2024 23:18:29 -0500 Subject: [PATCH 012/267] implement AlertInteractor, add getAlert method to Weather --- .../data_access/WeatherDataAccessObject.java | 11 ++- src/main/java/entity/Weather.java | 8 ++- .../java/use_case/note/AlertInteractor.java | 72 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/main/java/use_case/note/AlertInteractor.java diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index a5f0fbfe2..c0194cee3 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -6,10 +6,12 @@ import okhttp3.Response; import org.json.JSONException; import org.json.JSONObject; +import org.json.JSONArray; import use_case.note.WeatherDataAccessInterface; import java.io.IOException; + /** * This class runs the API and creates a weather DAO. **/ @@ -49,8 +51,15 @@ public Weather getWeather(String city) throws IOException { final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + String alertDescription = "No alerts"; + if (weatherJSON.has("alerts")) { + final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); + if (alertsArray.length() > 0) { + alertDescription = alertsArray.getJSONObject(0).getString("description"); + } + } - return new Weather(city, lon, lat, temp, looks); + return new Weather(city, lon, lat, temp, looks, alertDescription); } else { diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 828f75bac..16084ad5f 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -10,13 +10,15 @@ public class Weather { private final int temperature; private final String looks; + private final String alertDescription; - public Weather(String city, int longitude, int latitude, int temperature, String looks) { + public Weather(String city, int longitude, int latitude, int temperature, String looks, String alertDescription) { this.city = city; this.longitude = longitude; this.latitude = latitude; this.temperature = temperature; this.looks = looks; + this.alertDescription = alertDescription; } @@ -40,4 +42,8 @@ public String getLooks() { return looks; } + public String getAlertDescription() { + return alertDescription; + } + } diff --git a/src/main/java/use_case/note/AlertInteractor.java b/src/main/java/use_case/note/AlertInteractor.java new file mode 100644 index 000000000..ba93e6887 --- /dev/null +++ b/src/main/java/use_case/note/AlertInteractor.java @@ -0,0 +1,72 @@ +package data_access; + +import entity.Weather; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONArray; +import use_case.note.WeatherDataAccessInterface; + +import java.io.IOException; + +/** + * This class runs the API and creates a weather DAO.. + **/ + +public class WeatherDataAccessObject implements WeatherDataAccessInterface { + private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; + private static final String MAIN = "main"; + private static String city; + private static final int SUCCESS_CODE = 200; + private static final String CONTENT_TYPE_JSON = "application/json"; + private static final String STATUS_CODE_LABEL = "cod"; + private static final String WEATHER_LIST = "list"; + private static final String MESSAGE = "message"; + + @Override + public Weather getWeather(String city) throws IOException { + // Make an API call to get the user object. + final OkHttpClient client = new OkHttpClient().newBuilder().build(); + + // creating file + final Request request = new Request.Builder() + .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" + + API_KEY + "&units=metric", city)) + .addHeader("Content-Type", CONTENT_TYPE_JSON) + .build(); + try { + final Response response = client.newCall(request).execute(); + + final JSONObject responseBody = new JSONObject(response.body().string()); + + if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { + final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); + + // get individual items from the json object + + final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); + final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); + final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + String alertDescription = "No alerts"; + if (weatherJSON.has("alerts")) { + final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); + if (alertsArray.length() > 0) { + alertDescription = alertsArray.getJSONObject(0).getString("description"); + } + } + + return new Weather(city, lon, lat, temp, looks, alertDescription); + + } + else { + throw new IOException(responseBody.getString(MESSAGE)); + } + } + catch (IOException | JSONException ex) { + throw new IOException(ex); + } + } +} From e00f322eb456d278a48db81e9147d9e77baf8bb0 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 11 Nov 2024 00:03:19 -0500 Subject: [PATCH 013/267] add AlertPopInputData and AlertPopInteractor --- .../use_case/note/AlertPopInteractor.java | 35 +++++++++++++++++++ .../note/alert_pop/AlertPopInputData.java | 9 +++++ 2 files changed, 44 insertions(+) create mode 100644 src/main/java/use_case/note/AlertPopInteractor.java diff --git a/src/main/java/use_case/note/AlertPopInteractor.java b/src/main/java/use_case/note/AlertPopInteractor.java new file mode 100644 index 000000000..cf8758a8c --- /dev/null +++ b/src/main/java/use_case/note/AlertPopInteractor.java @@ -0,0 +1,35 @@ +package use_case.note.alert_pop; + +import use_case.note.WeatherDataAccessInterface; +import entity.Weather; + +public class AlertPopInteractor implements AlertPopInputBoundary { + private final WeatherDataAccessInterface weatherAccess; + private final AlertPopOutputBoundary outputBoundary; + + public AlertPopInteractor(WeatherDataAccessInterface weatherAccess, AlertPopOutputBoundary outputBoundary) { + this.weatherAccess = weatherAccess; + this.outputBoundary = outputBoundary; + } + + @Override + public void execute(AlertPopInputData alertPopInputData) { + try { + String cityName = alertPopInputData.getCityName(); + Weather weather = weatherAccess.getWeather(cityName); + String alert = weather.getAlertDescription(); + String noAlert = "no alerts"; + + if (noAlert.equals(alert)) { + AlertPopOutputData outputData = new AlertPopOutputData(noAlert); + outputBoundary.prepareSuccessView(outputData); + } else { + AlertPopOutputData outputData = new AlertPopOutputData(alert); + outputBoundary.prepareSuccessView(outputData); + } + } catch (Exception e) { + outputBoundary.prepareFailView("Failed to retrieve weather data: " + e.getMessage()); + } + } +} + diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputData.java b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java index 02d613a5a..2bb4bb6e1 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInputData.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java @@ -2,4 +2,13 @@ // No input because alertpop is automatic. public class AlertPopInputData { + private final String cityName; + + public AlertPopInputData(String cityName) { + this.cityName = cityName; + } + + public String getCityName() { + return cityName; + } } From 95e26cc81fce74c4bbec2b0fe23af6b7646fd3e7 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 11 Nov 2024 09:48:37 -0500 Subject: [PATCH 014/267] delete the files --- .../java/use_case/note/AlertInteractor.java | 72 ------------------- .../java/use_case/note/NoteInteractor.java | 59 --------------- 2 files changed, 131 deletions(-) delete mode 100644 src/main/java/use_case/note/AlertInteractor.java delete mode 100644 src/main/java/use_case/note/NoteInteractor.java diff --git a/src/main/java/use_case/note/AlertInteractor.java b/src/main/java/use_case/note/AlertInteractor.java deleted file mode 100644 index ba93e6887..000000000 --- a/src/main/java/use_case/note/AlertInteractor.java +++ /dev/null @@ -1,72 +0,0 @@ -package data_access; - -import entity.Weather; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONArray; -import use_case.note.WeatherDataAccessInterface; - -import java.io.IOException; - -/** - * This class runs the API and creates a weather DAO.. - **/ - -public class WeatherDataAccessObject implements WeatherDataAccessInterface { - private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; - private static final String MAIN = "main"; - private static String city; - private static final int SUCCESS_CODE = 200; - private static final String CONTENT_TYPE_JSON = "application/json"; - private static final String STATUS_CODE_LABEL = "cod"; - private static final String WEATHER_LIST = "list"; - private static final String MESSAGE = "message"; - - @Override - public Weather getWeather(String city) throws IOException { - // Make an API call to get the user object. - final OkHttpClient client = new OkHttpClient().newBuilder().build(); - - // creating file - final Request request = new Request.Builder() - .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" - + API_KEY + "&units=metric", city)) - .addHeader("Content-Type", CONTENT_TYPE_JSON) - .build(); - try { - final Response response = client.newCall(request).execute(); - - final JSONObject responseBody = new JSONObject(response.body().string()); - - if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); - - // get individual items from the json object - - final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); - final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); - final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); - final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); - String alertDescription = "No alerts"; - if (weatherJSON.has("alerts")) { - final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); - if (alertsArray.length() > 0) { - alertDescription = alertsArray.getJSONObject(0).getString("description"); - } - } - - return new Weather(city, lon, lat, temp, looks, alertDescription); - - } - else { - throw new IOException(responseBody.getString(MESSAGE)); - } - } - catch (IOException | JSONException ex) { - throw new IOException(ex); - } - } -} diff --git a/src/main/java/use_case/note/NoteInteractor.java b/src/main/java/use_case/note/NoteInteractor.java deleted file mode 100644 index 369e9309a..000000000 --- a/src/main/java/use_case/note/NoteInteractor.java +++ /dev/null @@ -1,59 +0,0 @@ -package use_case.note; - -import entity.User; - -/** - * The "Use Case Interactor" for our two note-related use cases of refreshing - * the contents of the note and saving the contents of the note. Since they - * are closely related, we have combined them here for simplicity. - */ -public class NoteInteractor implements NoteInputBoundary { - - private final NoteDataAccessInterface noteDataAccessInterface; - private final NoteOutputBoundary noteOutputBoundary; - // Note: this program has it hardcoded which user object it is getting data for; - // you could change this if you wanted to generalize the code. For example, - // you might allow a user of the program to create a new note, which you - // could store as a "user" through the API OR you might maintain all notes - // in a JSON object stored in one common "user" stored through the API. - private final User user = new User("jonathan_calver2", "abc123"); - - public NoteInteractor(NoteDataAccessInterface noteDataAccessInterface, - NoteOutputBoundary noteOutputBoundary) { - this.noteDataAccessInterface = noteDataAccessInterface; - this.noteOutputBoundary = noteOutputBoundary; - } - - /** - * Executes the refresh note use case. - * - */ - @Override - public void executeRefresh() { - try { - - final String note = noteDataAccessInterface.loadNote(user); - noteOutputBoundary.prepareSuccessView(note); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } - - /** - * Executes the save note use case. - * - * @param note the input data - */ - @Override - public void executeSave(String note) { - try { - - final String updatedNote = noteDataAccessInterface.saveNote(user, note); - noteOutputBoundary.prepareSuccessView(updatedNote); - } - catch (DataAccessException ex) { - noteOutputBoundary.prepareFailView(ex.getMessage()); - } - } -} From 1890aa6203e2817d55c08987a4f1cb56f3d20be9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 11 Nov 2024 21:41:38 -0500 Subject: [PATCH 015/267] SearchResultInteractor implemented. --- .../use_case/note/SearchResultInteractor.java | 60 +++++++++++++++++++ .../SearchResultInputBoundary.java | 2 +- .../search_result/SearchResultInputData.java | 9 +-- .../search_result/SearchResultOutputData.java | 10 +++- 4 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 src/main/java/use_case/note/SearchResultInteractor.java diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java new file mode 100644 index 000000000..12cecce16 --- /dev/null +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -0,0 +1,60 @@ +package use_case.note; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import entity.Weather; +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; + +public class SearchResultInteractor implements SearchResultInputBoundary { + private final SearchResultOutputBoundary outputBoundary; + private final WeatherDataAccessInterface weatherDataAccess; + private final Map historicalWeatherData; + + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + this.outputBoundary = outputBoundary; + this.weatherDataAccess = weatherDataAccess; + this.historicalWeatherData = new HashMap<>(); + } + + @Override + public void execute(SearchResultInputData searchReturnInputData) { + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + final Runnable weatherTask = () -> { + fetchWeatherData(); + }; + + // Schedule the task to run every hour + scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); + } + + private void fetchWeatherData() { + try { + final String city = SearchResultInputData.getCity(); + // Simulate reading weather data + final Weather weatherData = weatherDataAccess.getWeather(city); + + // Store it in historical data + final String timestamp = String.valueOf(System.currentTimeMillis()); + historicalWeatherData.put(timestamp, weatherData); + + // Send it to the output boundary + final SearchResultOutputData outputData = + new SearchResultOutputData(city, weatherData, false); + outputBoundary.presentSuccessView(outputData); + } + catch (IOException exception) { + // Handle exception if weather data retrieval fails and send failure view + outputBoundary.presentFailView("Failed to retrieve weather data: " + exception.getMessage()); + } + } + +} diff --git a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java index e54108eb8..99054de87 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java @@ -4,5 +4,5 @@ // search bar. public interface SearchResultInputBoundary { - void execute(SearchResultInputData searchResultInputData) + void execute(SearchResultInputData searchResultInputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 4dd04fc47..63e213ef5 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -3,13 +3,14 @@ // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. public class SearchResultInputData { - private final String cityName; + + private static final String city; public SearchResultInputData(String cityName) { - this.cityName = cityName; + this.city = cityName; } - public String getCity() { - return cityName; + public static String getCity() { + return city; } } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index 15acd46bb..310ed041c 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -1,12 +1,14 @@ package use_case.note.search_result; +import entity.Weather; + public class SearchResultOutputData { private final String location; - private final String weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, String weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; @@ -16,7 +18,9 @@ public String getLocation() { return location; } - public String getWeather() {return weather;} + public Weather getWeather() { + return weather; + } public boolean isUseCaseFailed() { return useCaseFailed; From c84a75f11c2553b9e178960cbb665b4669dab6db Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 11:49:20 -0500 Subject: [PATCH 016/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 12cecce16..b598748ff 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -13,6 +13,9 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; +/** + * The interactor for the search result use case. + */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; From 333dcdf99177522b12650b2dd55697837c34aac2 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 12 Nov 2024 12:10:02 -0500 Subject: [PATCH 017/267] Added the Humidity and windspeed attributes. Updated both in weather and WeatherDataAccessObject --- src/main/java/data_access/WeatherDataAccessObject.java | 4 +++- src/main/java/entity/Weather.java | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index c0194cee3..9e56b8c45 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -50,6 +50,8 @@ public Weather getWeather(String city) throws IOException { final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); + final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); + final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); String alertDescription = "No alerts"; if (weatherJSON.has("alerts")) { @@ -59,7 +61,7 @@ public Weather getWeather(String city) throws IOException { } } - return new Weather(city, lon, lat, temp, looks, alertDescription); + return new Weather(city, lon, lat, temp, looks, alertDescription, humidity, windspeed); } else { diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 16084ad5f..8c3827a38 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -11,14 +11,18 @@ public class Weather { private final int temperature; private final String looks; private final String alertDescription; + private final int humidity; + private final int windSpeed; - public Weather(String city, int longitude, int latitude, int temperature, String looks, String alertDescription) { + public Weather(String city, int longitude, int latitude, int temperature, String looks, String alertDescription, int humidity, int windSpeed) { this.city = city; this.longitude = longitude; this.latitude = latitude; this.temperature = temperature; this.looks = looks; this.alertDescription = alertDescription; + this.humidity = humidity; + this.windSpeed = windSpeed; } From a264d73c8c67e08a06cf78d593e16ba97bb5685b Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 12:16:22 -0500 Subject: [PATCH 018/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index b598748ff..16630ba91 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -14,7 +14,7 @@ import use_case.note.search_result.SearchResultOutputData; /** - * The interactor for the search result use case. + * The interactor for the search result use case.. */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; From eebf4249f449ca2a42ee7b19f8e51139675a8714 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 12 Nov 2024 12:21:06 -0500 Subject: [PATCH 019/267] I forgot to code getters. SO here are the getters --- src/main/java/entity/Weather.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 8c3827a38..544f82ca5 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -26,6 +26,14 @@ public Weather(String city, int longitude, int latitude, int temperature, String } + public int getHumidity() { + return humidity; + } + + public int getWindSpeed() { + return windSpeed; + } + public String getCity() { return city; } From ea5c3f43d837c9031f799d42b71119daf47bf319 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Tue, 12 Nov 2024 12:49:50 -0500 Subject: [PATCH 020/267] deleted sample files for map --- src/test/java/app/Sample3.java | 112 ------------------------ src/test/java/app/SelectionAdapter.java | 87 ------------------ src/test/java/app/SelectionPainter.java | 42 --------- 3 files changed, 241 deletions(-) delete mode 100644 src/test/java/app/Sample3.java delete mode 100644 src/test/java/app/SelectionAdapter.java delete mode 100644 src/test/java/app/SelectionPainter.java diff --git a/src/test/java/app/Sample3.java b/src/test/java/app/Sample3.java deleted file mode 100644 index c22666b16..000000000 --- a/src/test/java/app/Sample3.java +++ /dev/null @@ -1,112 +0,0 @@ -package app; - -import java.awt.BorderLayout; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; - -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.WindowConstants; -import javax.swing.event.MouseInputListener; - -import org.jxmapviewer.JXMapViewer; -import org.jxmapviewer.OSMTileFactoryInfo; -import org.jxmapviewer.cache.FileBasedLocalCache; -import org.jxmapviewer.input.CenterMapListener; -import org.jxmapviewer.input.PanKeyListener; -import org.jxmapviewer.input.PanMouseInputListener; -import org.jxmapviewer.input.ZoomMouseWheelListenerCursor; -import org.jxmapviewer.viewer.DefaultTileFactory; -import org.jxmapviewer.viewer.GeoPosition; -import org.jxmapviewer.viewer.TileFactoryInfo; - -/** - * A simple sample application that shows - * a OSM map of Europe - * @author Martin Steiger - */ -public class Sample3 -{ - /** - * @param args the program args (ignored) - */ - public static void main(String[] args) - { - // Create a TileFactoryInfo for OpenStreetMap - TileFactoryInfo info = new OSMTileFactoryInfo(); - DefaultTileFactory tileFactory = new DefaultTileFactory(info); - - // Setup local file cache - File cacheDir = new File(System.getProperty("user.home") + File.separator + ".jxmapviewer2"); - tileFactory.setLocalCache(new FileBasedLocalCache(cacheDir, false)); - - // Setup JXMapViewer - final JXMapViewer mapViewer = new JXMapViewer(); - mapViewer.setTileFactory(tileFactory); - - GeoPosition frankfurt = new GeoPosition(50.11, 8.68); - - // Set the focus - mapViewer.setZoom(7); - mapViewer.setAddressLocation(frankfurt); - - // Add interactions - MouseInputListener mia = new PanMouseInputListener(mapViewer); - mapViewer.addMouseListener(mia); - mapViewer.addMouseMotionListener(mia); - - mapViewer.addMouseListener(new CenterMapListener(mapViewer)); - - mapViewer.addMouseWheelListener(new ZoomMouseWheelListenerCursor(mapViewer)); - - mapViewer.addKeyListener(new PanKeyListener(mapViewer)); - - // Add a selection painter - SelectionAdapter sa = new SelectionAdapter(mapViewer); - SelectionPainter sp = new SelectionPainter(sa); - mapViewer.addMouseListener(sa); - mapViewer.addMouseMotionListener(sa); - mapViewer.setOverlayPainter(sp); - - // Display the viewer in a JFrame - final JFrame frame = new JFrame(); - frame.setLayout(new BorderLayout()); - String text = "Use left mouse button to pan, mouse wheel to zoom and right mouse to select"; - frame.add(new JLabel(text), BorderLayout.NORTH); - frame.add(mapViewer); - frame.setSize(800, 600); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setVisible(true); - - mapViewer.addPropertyChangeListener("zoom", new PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - updateWindowTitle(frame, mapViewer); - } - }); - - mapViewer.addPropertyChangeListener("center", new PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - updateWindowTitle(frame, mapViewer); - } - }); - - updateWindowTitle(frame, mapViewer); - } - - protected static void updateWindowTitle(JFrame frame, JXMapViewer mapViewer) - { - double lat = mapViewer.getCenterPosition().getLatitude(); - double lon = mapViewer.getCenterPosition().getLongitude(); - int zoom = mapViewer.getZoom(); - - frame.setTitle(String.format("JXMapviewer2 Example 3 (%.2f / %.2f) - Zoom: %d", lat, lon, zoom)); - } - -} diff --git a/src/test/java/app/SelectionAdapter.java b/src/test/java/app/SelectionAdapter.java deleted file mode 100644 index e5aae17f8..000000000 --- a/src/test/java/app/SelectionAdapter.java +++ /dev/null @@ -1,87 +0,0 @@ - -package app; - -import java.awt.Rectangle; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.Point2D; - -import org.jxmapviewer.JXMapViewer; - -/** - * Creates a selection rectangle based on mouse input - * Also triggers repaint events in the viewer - * @author Martin Steiger - */ -public class SelectionAdapter extends MouseAdapter -{ - private boolean dragging; - private JXMapViewer viewer; - - private Point2D startPos = new Point2D.Double(); - private Point2D endPos = new Point2D.Double(); - - /** - * @param viewer the jxmapviewer - */ - public SelectionAdapter(JXMapViewer viewer) - { - this.viewer = viewer; - } - - @Override - public void mousePressed(MouseEvent e) - { - if (e.getButton() != MouseEvent.BUTTON3) - return; - - startPos.setLocation(e.getX(), e.getY()); - endPos.setLocation(e.getX(), e.getY()); - - dragging = true; - } - - @Override - public void mouseDragged(MouseEvent e) - { - if (!dragging) - return; - - endPos.setLocation(e.getX(), e.getY()); - - viewer.repaint(); - } - - @Override - public void mouseReleased(MouseEvent e) - { - if (!dragging) - return; - - if (e.getButton() != MouseEvent.BUTTON3) - return; - - viewer.repaint(); - - dragging = false; - } - - /** - * @return the selection rectangle - */ - public Rectangle getRectangle() - { - if (dragging) - { - int x1 = (int) Math.min(startPos.getX(), endPos.getX()); - int y1 = (int) Math.min(startPos.getY(), endPos.getY()); - int x2 = (int) Math.max(startPos.getX(), endPos.getX()); - int y2 = (int) Math.max(startPos.getY(), endPos.getY()); - - return new Rectangle(x1, y1, x2-x1, y2-y1); - } - - return null; - } - -} diff --git a/src/test/java/app/SelectionPainter.java b/src/test/java/app/SelectionPainter.java deleted file mode 100644 index be57d652d..000000000 --- a/src/test/java/app/SelectionPainter.java +++ /dev/null @@ -1,42 +0,0 @@ - -package app; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Rectangle; - -import org.jxmapviewer.painter.Painter; - -/** - * Paints a selection rectangle - * @author Martin Steiger - */ -public class SelectionPainter implements Painter -{ - private Color fillColor = new Color(128, 192, 255, 128); - private Color frameColor = new Color(0, 0, 255, 128); - - private SelectionAdapter adapter; - - /** - * @param adapter the selection adapter - */ - public SelectionPainter(SelectionAdapter adapter) - { - this.adapter = adapter; - } - - @Override - public void paint(Graphics2D g, Object t, int width, int height) - { - Rectangle rc = adapter.getRectangle(); - - if (rc != null) - { - g.setColor(frameColor); - g.draw(rc); - g.setColor(fillColor); - g.fill(rc); - } - } -} From bd3cd3c9ea07cb4f99093207ae2a0c4262bc5b63 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:40:29 -0800 Subject: [PATCH 021/267] Updating WeatherState and WeatherViewModel, this 2 classes will be used in MapPanelView.java --- .../java/interface_adapter/note/NoteViewModel.java | 13 ------------- .../note/{NoteState.java => WeatherState.java} | 14 +++++++------- .../interface_adapter/note/WeatherViewModel.java | 13 +++++++++++++ 3 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/interface_adapter/note/NoteViewModel.java rename src/main/java/interface_adapter/note/{NoteState.java => WeatherState.java} (56%) create mode 100644 src/main/java/interface_adapter/note/WeatherViewModel.java diff --git a/src/main/java/interface_adapter/note/NoteViewModel.java b/src/main/java/interface_adapter/note/NoteViewModel.java deleted file mode 100644 index 6e185d0fa..000000000 --- a/src/main/java/interface_adapter/note/NoteViewModel.java +++ /dev/null @@ -1,13 +0,0 @@ -package interface_adapter.note; - -import interface_adapter.ViewModel; - -/** - * The ViewModel for the NoteView. - */ -public class NoteViewModel extends ViewModel { - public NoteViewModel() { - super("note"); - setState(new NoteState()); - } -} diff --git a/src/main/java/interface_adapter/note/NoteState.java b/src/main/java/interface_adapter/note/WeatherState.java similarity index 56% rename from src/main/java/interface_adapter/note/NoteState.java rename to src/main/java/interface_adapter/note/WeatherState.java index c5b2234d6..1d2bf9657 100644 --- a/src/main/java/interface_adapter/note/NoteState.java +++ b/src/main/java/interface_adapter/note/WeatherState.java @@ -1,19 +1,19 @@ package interface_adapter.note; /** - * The State for a note. + * The State for a weather. *

For this example, a note is simplay a string.

*/ -public class NoteState { - private String note = ""; +public class WeatherState { + private String weather = ""; private String error; - public String getNote() { - return note; + public String getWeather() { + return weather; } - public void setNote(String note) { - this.note = note; + public void setWeather(String weather) { + this.weather = weather; } public void setError(String errorMessage) { diff --git a/src/main/java/interface_adapter/note/WeatherViewModel.java b/src/main/java/interface_adapter/note/WeatherViewModel.java new file mode 100644 index 000000000..7d10ebde8 --- /dev/null +++ b/src/main/java/interface_adapter/note/WeatherViewModel.java @@ -0,0 +1,13 @@ +package interface_adapter.note; + +import interface_adapter.ViewModel; + +/** + * The ViewModel for the NoteView. + */ +public class WeatherViewModel extends ViewModel { + public WeatherViewModel() { + super("weather"); + setState(new WeatherState()); + } +} From ec948e4525805a612515f0728eeccccac27c462b Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:42:28 -0800 Subject: [PATCH 022/267] This is a example picture from the Jxmap API --- src/main/java/view/MapImage.png | Bin 0 -> 99551 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/view/MapImage.png diff --git a/src/main/java/view/MapImage.png b/src/main/java/view/MapImage.png new file mode 100644 index 0000000000000000000000000000000000000000..699acf98433a5cf50e999c8739b330f117ce1dd5 GIT binary patch literal 99551 zcmV)=K!m@EP)Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBXyj!8s8RCr$O{RiA+MV;@DHz4Y+x@HV02nq@&RE%q0bHp4F)0#y@ zf(cYmkc{F0!wiZbOkzL~CNO|ug~_lNm^^?h%nSlE?kXc(+27vF|NX6Z_xGviobG;} zL3i)|@1euPhb?VfqQ=j_gZ*8^wnnj)aKKG5leIxLH`v~m2|5rPp{hs?i_l>}P zBk+Iq2po3UVXu7UE4ye1^Y@keM&P~?_`h`o?nC>13*3Dp@c+sP^g;XIKIL=wt~_X$ z&r=?}>%I?u>b?(o>KFd*XoK_b*Z&{`CDH{*3(}@r*A$@|jx7*{O?VfYcW1f5PW1jov$3E}NkK6Mrl*d2+tJ}YT^0guw7nt_^z+|_O7q~ z_EZ1iJCvur=7`;1OF44)*HOOv^w)p)8E-g>^2|3L{meHV{j4_~^XxYt^X#`AyT@CO zea>5td(PXAe=gSj6ZYKe#690};`876J<1E-_5Bx8-hI-G-b4Api{JZ$m%MKR zC%)oC6JN2_6?DlrK$x7v+E%?>=zGdk#GJJqOKv@4=Mw z-uLD6-v5>JDIfUiPe1rI$_0CW{ery@x$r}WT)5AnKilUUKl|`EF8c5{FZ#$gFaGGa zW_|RqSsy!W_QwvN{qb+l`A5ok=6>P`$|avX@{&(|cOK=_M_u}vqbZkt_87|LpF8&Q z&mZ^m&mZ@TeUJaez9;wX`MV$f^41^y>ee6q(`{$`(``Tg_3b~t;`TGI*m&lZ8_$}*=_iy0zdw5+mA_X7XvMsIeI&$x>8UyX8p7+b& z|Ni&?@gM*3zp4*Ef%+fTT>0<+{_mdV4ArQ7AKLFj`+aC1r+QD08r*JC{Y3k{xM~cv ze}CGgn>KCw|EdoN-@JMA?=L%k(}^#Fq~||Wqw;-d|389uSNi+p_WurY`<9|N>kqN< z*C_o@MEfyk&A#on+wQJDfB3^6ZolN1jYsbKZ~yjh8?U_-!22iFsGMl8ISsUQ{!~ln zFx(9$)ytp5Tn-F;~P@1v#ruSdJfL`~}JGjb5F5o6Hy zZ=Zg_?|%2YyLum}`mH}d`L=I9o|CuE`u6Qd?8+Jc2Jds@Ewy~zv@NR&A3($VZ$o!cv|4ke!I+7CM6CpX=6lc?r{aDLmd&*RLk2S1o& zKI_)4yXBT!{`Ft~m6KE+f_B(=Ct}*$ImX^z&ra;^{%p{8PbS*6w|jC-v|CMkyT`-P zZXNCI9w*xUS)<)EV{-CVYok5w?N&&%Yj5|Y_I8gG?b_QtS)<)E+S@(8&))uDY;R}G z|Bs+O0pGa$7NC9KqfYTO#IAuf3)`@r*O={ z>E~VQ`J>OcVD;+NRNhifzU@orOieakUpi0zC1`K>(zTZW&%nuh(D0@6WbI4mnZCYs z<3zjF^riFouZ8yeeChrV`qJ?p|LbY{Uq^1==W8dfS+fQW9Auo&++Q!5^XtWw3xB@g z!k;f(ef^Dq{3G9-c+43WtXQ#v%3G?X`)i>c&shPJp0oZ;+TQk@wSu0r9_u;l@o=gXqL{WjVgS~}{qIr;hlJ#K61vJMtFkB4jNs4#xoo{bOJ(oyX`PX7NO zC*L-q4@dhTlly;>z5VU`9)A7x*F)R?jkEm!<)|1( z;J&Ds|F%&vyq$Z;$&Y!}5DVOpYqvm4_l8d$3eIo6_12k}Ej;SXS^J$ZwOx?vQO;A1 z%J-rDKiik?KD7TgkAdR_0kCm?^qd`M&!6sYd1h zY_#7O@p@mx>wj~!1K|JEk6v+GdW&)S((Uk)FFbdz{a^N>1I8>=qw;-d|IeoF_o4m2 zIokhw#=4FR?e`*~#eMPZ_r2TKDld7xN_gK zuRdz>l0#2gaKNTT3pQOc=f+#EoAW=eo`1tdfBe^5hnG8VUi9Y`)Be2lIKDSuf8~;i z=TAENC>pd(yXJ)9mv8>v>f5JH{r!fu*1vf9*YyZJ@!subs>>XZVXQz5eyD zKl|*nFTVI<4mNJwIJ11d@|CYloH+3x|M4G>I_fBnciU|@BJh_kUCOt|YgSyxB^=cC zX@SaI@}d{L$O~!2lO9mt3jBQk``_x3pSx+}x@9+CvFL``6gohCesVj`_k9a^Rot+4`E5%kE|`BQgTwdg)eEn< z;);25E?#xnB+gszzIwuKlTZKSEx)~O)n$}FY+7Hp#?Rm1vgY>RUbXqw)f{hHw~X(z zt~#PICiMB-D~>q-ilh6M)35wmdkpI{=lt`rv~a|X ze8UxYFF%{EG7cR4`=9ST?zrQ4J7dmXDsb)XXPh}^O&*FNy8ZeqX`kb{*IrYX6-(wa zN^_SiX7rdOb!!YhHE&qoeFeOc;ZMrHKe%$g-z_Wt_SKApgwoS?7Z@}+iwK<%WfLg+~`-n!Jofdz4Fupjz9L2 zF4|p3n5oQN{@rlfnntIc_X`$J%YOf2%?#^+_Peg1Lj{(MM0>&yDEYMiI-lcJE2lFj1U5+6c-xJauA1Tt75|*~d3g$l7o^{C!}Xw@X$sDl zEn8N<8X9qpxaIm4vuDkWwQ2sP%yrPt%;qoJp)6W(#j>RfM7Wo8>y>LR88o5kJiuHFnmT|aA%nuKM^U@aRCcp3-o z&^E`}p$2l?@wywYU$k-|lxf-8>&}}!=d#N#<1eTY-;{-`R#NK5d7Hxl4|L}&{0e}l zu#}7ZKV5e=ch7bh@I*V{u8YYjCZ#3Cr~r-&z!z(^5k>pd_6C5Mc~00KBhRw-d)=6>lB0{kYVkj{q8#wguvTl z{*5D4*vb_J2~b?Tn^^_)T;v(@*aUf**%UIamPl=?-$Kq zJ$*VYuwt@6P{*biB>=y4@%*xsujQsdee&WiFEeCLgZZfo4uZ}Dbtdu#znkU$kV6g;+Y=^C;5?OG^sT^$OX`}V3DtTTgh3pTm7&Rclw%XQ>QIG1)9U`gs!r^<2p=TOAK3+9BqAc$dqUE#oJcm$vg=bMoIl{cu*z3Dk)!oT8{`m_LaA@Z=k zK%(&%KcV^jMdK1i??QbBBwOHM?fR?g1#UR)%6}pC!=av?cOeFHtZ_cC4=w?SMe4Ud z&!OOncHMPXe+K_@!}VE{lgZtT%x8p@$)~fT4VvLRATVa|ff=k&Ez7XTvRtlTdJYGS zE!B`~fc=JBgRl=;L0lPm?~Roas8a@wi5&i&tIub&a|}7|+wFm9uiwpr8ApTmA1(TU zC*eq;$%>R+24>Sb=#SH}QQ!i&EBO5Uz4T^m@&BXiYruCg2{q zS6)Ij1|e(8(zhRz#Zfx1_?=J9GlFxzS=!_R7_NLkmO`3R+6UXTz{s~7hp8M>qIhaS#Q}h4A%K3eUT{E7 z&NNz>vtSy~9Vf`Qv>J5GRfY}-U3hpH5HUc^{RZ^3_nS#=rqiRZ2kp=mWc5 z8S}kzmm2LU*oWp1wcqbXloR{~af3oqWC~aXKp>r5b?u~uOTP;n0#x|-_$faF?XE{M zq8#(WRxDoNPYQpboB8*ve?YfE*Uh)C;3UU?^Jaic@XSr_DxGz;ssvf%3^LcX3?Nu`w+M_Z()W!?hM0?v7T9`oVWO7+p7BC9sEr(>gi z(&YzTclPlta*I~23@y=y=rqeu%8e;4{9wTWGZFHOB8TrqH_S<%5BV?_78N ztl@Ka*0R7k-#piClP1rsbQ7Fs#2j1sJu6$d3u8N^@#}9{Q8WvYXn+G?kj!n3Lr+qN z5622Y)K5_*(OwvqoB2yraLgHRAxJ#1LGX}w$rk2ZeD0FP^ZT-I_X6Qw!Vs-ow{X+O z^{nGO^30j%g5=va+zfh;E}vqTIX4)P)m@De{p1;81U%0gK{d|s(=&r;dz|02{*vh6;Hu9k_k-1`5}L@Ut&IjiJ8#u26q;8G*YtGer3_$xl7& z#462Fc;v<^&n+JFn8)x$30e|w~1JSyaFI@=W!3f7d`uEpfRbK6iQEi4jY3)_N zz3iNRcD0dPT)7{z#)P5jC5MG!)+UJLl0$|=|78d{GJ+9^rB>tOvCFJ36#dG}^D z2$~7Sv&X4fxP93SKq3Rrc&gNFP-g0b3USW2iU}{VS!sLTMI$KxCfd1>Svaq!IvQEI zmK@5YoO$iZ#-6Ef)B1DgEg+cI}g+O3~G%0*?a2$X=i#o_* zXqS5}6kY-YU%*2}H?TOMx?i;5jztS;N3b!H%rV9mDAN9_HJ9+1azm;HxLy6zGcKLf z=O=gh_iHD!aL^Qua8-l0^MKrozZh-awK!Lu%=@A~@5L8HSJf!_*67thv@e=7dG(Z2 zDa=d0SIwOb+MSM)Zl)uIj)@Dr`%cX*eV29p1{hpoYH5T)fo}o!G3fp5|F^%B!}1h@ot$+4{~(BO)j z7w3KZ4rxN&3+vT~Nx&P0q%ghe4 z{w1jLXQ1f!H;FE8#DtrF<)yP1O|PF6{PUP#a?BaR()rT`2V1PnRSAhHGv>rQT^p7K z`f&EuM{{3r#jODV?^*KE~5>!%Pwgfhm~lv?hWR`VX+bB`YDUU9fkJ=F9&@6Tc?L?9%KYw>IH*%{IR$sNHYGig{@X_j*9+65qom4biy$=b1K@pox_ z=gpflbzbOP;p$_ylm!}2dkEU;q;4d9)3U8`z>TDS92|M} z9CR@(RWcwltKnpEcdS0S1|`oT|6DI;<00(bX|QSinyFJ)O`a4_2R&G{Ab9)oAPkx! zkJ=5!3fKcMRUs;Lq`LJ_Er|K=Q=j@&&`3LZlJ$Z!^j1#(^x`zdQVxlxvgRb^k(!gY zLA5IKbo9^)EDZzE4w9K|fO*c6Q+Pr+-b+^Fk2OLAYbq2PkxlD|-~qWEW`4}IJS*_B zxha^>Ga{jl)gbcA&kld7t0z!|J!C)pL#~^2!WH}5f@tTvFWO<|^E`J6TkE3vjob0; z%G*Ppf`1tb`@k9m9t6KdQwk!+Z8ImXS~I8CcQjUnHtF_E8~^PyP(SWV0k_UYUJWcI z%R%3sgE}6q>xf4Eb<5(yP3v#J=_>u?a4ZWp82`wn#{utL3u44JtzWrf8XyFdtRvIs zehoZeJ(Wuru>v))x?tjhrKdvb`KB{eo;&M^m6xAJsYl7RNo>0?G0W*5kHE6RI>NF= z1SAQ4ty- zFMy}4zIGCt1ujg|NB;+*z01iLRa}>&;gJ{3*N83VrAV|n9PJI>C**?LZk)8}D=ZUq z?@u>ef#Q&Xbx2c-IUdiGLHK8USoI~FK!`aZ$*lz(rU-!1`>6&_ zxC4l}$fu;_Or5p{PQbU-$nX(RV_6=HsOBVO|Flbv;v0n)1y&g~*z6@EV$R8nzC5aX zVc$NP#RaHC-lgq)#IRb!hWTA7Mj~JA?Oi2hFf3!afl~o3AZS@|_BmaqkFhGl1=J}? z+r5PpRUZwmLbei${sg`LghbO@xO&~LCF6Zh+Cu>^Th2Exod>r~1)1dAX`Gge{q@}1 zlY%v67$@&-AatmyL5qB2V|0oS<|v(E-zfzrzopDPXrD9tNVI@`-v{6cHvZblNfwf& z&n1bzCFw&9K}&b^PcCV<2HG1Oev0m3RiekjC-R4AD7al;?t}B%FE{|4(5n;{XpJ*= zvayZ~S_0b34PbE0!5A<|T?Vs|`Qch1uRe$?2{`p8J%k->3u%~q8(Fzxv6zRzDmgp( z+6{vCur+MC2Ci!AfO!k&GE-+=dJ(UZf=Z(C))X9AzK=X_QgZT1+uLa8OzI9{gQdV- z@njrmzjW3`u<;W1iU(W|RllLQW=Pu=(b1NRUZJZ;X2Lsv$_Q{FtB)!-Soiv5E&=tk zGwiP2440&y)kGr&4@d#_iYk9zw+#twJ!-8`zw*`JenFnEJkiO7nnYAgsGh!hupc?FXJJtgTBY@COX$&l9@QSV1Rv8}& zJB=gF{`t3;YyK%d0t=ZC08e=ya1H@Hn2D9WtZw3&GahrmWa1zf4$cf}O0*A>8ioi# z`4>D0x8pGp_#yIZSB$c)%4boTzd-xZvyb9o8*;leR@WfK=^E|)OnduyXgi&Os<*A~ z%Wk+HP|zRs1yF1zq5QMAmW-<#=ZtmoXR`GCEBCH!FQ3mzz|Xge`g$$yJGPu0p^Hdi zXPn9MB=^CR#QS1d;XwwX{kKckP_DjU(b9u|aLJU}(-ut?uBTu5^@i1&7c&I#+TMmk zoy)s6^G)k{m&*Ux+hM2aahlwU0y%`zu)S5--n8~&!LPcmT73=with0Z0SE0TO}nxl zJ_b63_Qpy9S6?*q$}-fK$)|6F{Fzx(>UD6C7c|U~cKh|qmV{k%(R^;9*ObKks`cTf z#+>-{r#}tT!A}+}uHxV1;*#vMMsQ58ki8LTQHf<8rWeX8CL#ymK`e=XR|n{M`sZ|+ z`4rlnUgceI2}1`l;TFk60QEuC`^32i_T}X5K%4XDOy84AB`EWO0Wx#_%9y)ca>TUh zaPlY@02L%rTN;nAKX2RoZZ+w@`s%Tb?PU;FUow{`s;PQ+`7Ug{$C~$8ZA0yces|4E zxFHrtR!{$8^cK&V%t>VaG|mSBE993hWzjUq$w3A}K$|bZQDuE}DYrA)3)bCyBMv-3 zeZ*!t#7`ca-+IGMS4}!+`ax4pIq1BJM;|%;+|wxM{@^11%Fzb~PQJcG51dQYp;u1X z_Uhiy1sKXo!PF0V=U+&7?M_p_c-Aw(fcg-zFcd-yPYL~8xYLKzB2CGPgD6nSA_dyR zW>b;(P{>#2Hwk$7MHF3KnBuy6*L4!xLDDa_vE=p}yhH6LQ=1Z5P(lv;*IR3K-Jdpx zo{2SR-THO(4Zj_HbvdRmQ{V80H&B7&KivVVeFMkwv)IXuX;JqhadQHBz!^2w5fOBE zcW&{Mg#cVh%(Enw;9!ekP5nc5(7;+2R0U?mM#&QgJRM7#j;PrlgliGF3 ztN;ToJS>-U#`#nKHBMtY>UW?HZEw6&xMF}b${((16RZ{{x=CFbQ!9oh^xGCrL;$&D z?j&>*tYYi0@8gp@a-#vJWmzyrz{Q%^SL2ygsj#KdGVhm8);%AClV`fmzw{CaJ5v_$ zqpsipz$fiWe=oFjAW9=VFasORY?X7=83Yo#+pw$Us-Y2%H3GELLM{s2nv*cD6qb*y z4@Y1$FHo1&PdZN>pBXX^+H3OOFt$?%&?+o!zV2+4=U|d$Vz^(8ya_$*Bf4)|j}_fz zj;F92IP-*=t?26bnT>}x=;qB&d)m{$Irt1hbjL=BJRfM0{;(XYPgXkB6HarBvLD~* zW;D`3=sb{LP&Lg-F7!Cq&YLa+Z{0ajW|(F<=1`k}_a(&%T`q*M;Psq5|9DvUA$6F_ zC<`FMfHr3>9pgMuKXuC7uoo03HjpOrYv!)Y7i?PJP+K;jTeqC!pox(g2r~2TEFV^A zlTA)CQFB$&CSTieSyC0LC~!dMoIknoT!VTw@H_^Q(aUsr{!N<9+5}76;mEQGCU1OBiq_@29XF)xwt zniA?A0PJ<7fxe+#(?StccQC2!0{FJIS~NoaQEZK(z3VwwK(2O!0_;`M)l<&9bSW*s zgQEuU#mAo2v(3U_jI0~qVzjsPi!L!Mmn@>?>}1V=3`9ER;{e-I7w50M>!m^mf?m)=W?JPOG7b(^_@($Bbse$ z?uN0)ug-s^}~6?9|KqN(ls(km%*+ghRAtCI|j4-1o$ zMR&Rsy#N==Hs>-&A_`b{3W$ZsLz8(CdNIk#`?rNw^PLR3 z8>M*)(MxST?G0z^n!Bu$o&$&l_stL@%@p zDGanTTv+4Avq02!B4NYrJQG6Wk z0I@0|GHhCpWMSWU^>nx-&j<#SZ#607MSITI#QdV^b3r>E=Av3loAjJX-!QNoMqAD{V>grvWKSM(ov z`$)!l$Abh4=WgA})DiMT2Cibs4_&~O^W*}&M0TB_(_xunBYXqtKW|zWV&wAa+8u&Y zT^B3k?+VWXLVzEW5=i@knTRmJ5UcdBhFoi>q3|z1{Y%vmtmY7F{P;ne+IZ)83-AN| zj$P0J2J{UQBHBSL-?-V}Y?plq{7k!Y5N+pLn3qQQQ(vlEqfTd`Fl6>bE&dISWr)>Dll~DFJ+I2()gkqjc z;M;4>xsTVS$(5U`@o=@z{E*29NDSs__*#N??giR^IOTlUc+lSPsNvRkEI*fZXV564 zM9{4;E68g=!-rTLl642nbPQU}fy@v@uNL`KWH#KZKh3w57z@M-R~GKU4T+Yo$a$& zz;T2JSovsN46fv2@){n%w_c*RZ2TjldvG+@hnSjgM5t?nlqaP?NI-km(H?2D-IJTb zUywpq>uIBYn>sqHWecLc;o(=b!u@rD#vSoSZe4Im6Y!C>b|fg6L2Ila!!X}t;OVv` zy<}cE0I8>59P4*C5baDm9^j5eiy{Ji$th(e3ul#Svri>fJh|nrJ8cyb1OD5-Gz6$H zWhF-{tBURXC(+G+~itwf=0Wmm@uvS`*2)42esk0!8E@A;nJTK41;tgR} zCZxc3q}v=&PmlC5hwd-0z=UpSo}rdHv}qp^%r0`WL~4f_lr3nh1_HG^t1El&(r z&&z^W4%DTt>3!iG;=wc4wSnq3f&EKh-|(veMHz`D()g5Qfq`Un4ID_W!MS-LSQI#D z)a0i%b&})2)POpxa?D2;@wyTI0`n>|vOyi`Fzdnx~_oWu1Hv=4cG!_dxU zi>6Nm?JDu5x|yIV>0AAf`lXA16?;r^s1SsmpW46;S?f#H>yGLKo}|7(-Wvw?Huu}s zzuxzUFUFcsDUtD!6p0rqW=w2HxU4jqN@1K+?E~K^n2x^{%CbTK;dY0)=Zx z0iK@lbo7K(yB3-IuN~sN#Mo=wmxqtVXmNNY4EKE;h<5GUs~1dXf(i+K);?|R-pFT) zc4l)h)sabWA@dA9ZL-9JmO!tPp;gMQYtmXndaqdwF4Vp?WSYVNuex*+R2}jTwgGV7 z!eE>Fc66X#FBpvkJXh&;6OK2tqgUyB6Ff*s=g=)PC&ns(lwM9E^Q(TN&>#$mjyH}i z&GseibUSkFEj`*x6iM20xO2sX2M&U0m-2&TGdA+_sFlrhEoajpVz7BH?V z4#A!X)cHs6bm_C8wF1!9^Os}MZhUCg3_mv1sCR{zyNRFl5!8Aca z`0b}ap;(bnM~WF9k2HqoEWl%?;yjD7cT9;wMzp&=m2?Ptt&^J(; zVfKT3$+B=Q29=1G0TM%|BXb?v9)VLoxdf{|C9b{c=V2EZt%?VG4X=LsKWg<^vjV|e zw!HQT@a|#;+75dk1b^m4a893-Szsu%)g_0bxxR164V;lVAuQ6RtDNaOIqecW@2?S4Wry9$xMM(Ss2l9-%OdlLt{~jF_?zF+}(A zpgmGGlq^d^==Rk=50LcYItK--kJ)lc4I(Guogwa~g@Wk8=rW;UC7AK73lx4L<#L{X zXUv%b+9ytlYl5{q_( zRTN7Nw41rbpl<4j*yQBvbwQq7U%&?1xrCGEkbuvx8%gOvPQDM?i~WLrHsV{fy@4O2 zU)q+orW{&m8`Im6!7&+fZDu*;=zrggi6c~f(qvSU`s&(Y?SJ%;F$C@QkR@O^^ED9d zIYG@-1$l3<)-^nYv4kDLUW*ZWc$sa^r0IA_BSSEsOgk|9!zEJ)*gxulgdwKE*71m{CaitJ;N^@Vn5S*x2~ z@#AFChgSpb^orK_=0@6FRgam-P30WL1HFJ$s_P?^3cN;5DjNizx_XjNX7V}C%gLMm zB^%+4iu$}Gytn-sl97(C5+AM^yv@ebLfG?0``!jSaMM+(c^T7?Caq4CgKY3gf~Oo+~VA3L8s7en6Z9HzKNZxnqEcf;>B(1q_up_bUU zYf3I}+{pSqCP|ks;DKpeUR_#R^b-*t6F#lC-KenuHl(kQ9Se=__YuEYd}dY1vt9%< zj|WmqM?h~Ij{UXV9^EdU^S<&wtv>(OrA3A>Rs+ku6M$3KNQY@WGqk~~_zI2c#S0h- zE3)yGB%F|IrkXBOQdfOc@~!hz3lIpTV@4b$h5xJIyly08FzJur1gQFZ8AFDzTb}oT z0!J-Xq;Sm47LaC!2w8gFGKwCrzDG`4V%fc8qlvT_3X1;fG^OFq3ViE4H$3^II`csL zrqF=__U6^0roT#V|)zc7~R zlteT!^nIZUg9FiylMIF>gE|b)WI}f%MhXIfAMPm7AE*;ViP-}QjVy~xj#43~FO8mI zgL2vp0la3?Of{!ZEB1f4+6B6xok>5)ZN7eHEd^Yq7aeHF4Fjm)vCGL3eS2?l?dvC3 zTLJX6vGe-jbASpEw?9g1>F^P78;lUTrkvW>L|6BdHAP=K79e_6=i#y%qwPtD#jGA0 zft<(Wgft&Bkd|mmw>_B&Avwq#k97zBaw1O@9qK^U*WgWOI6j!N7zB^o9}MZJ${Izh zSeWHYzEnPd+1ORlo~iP>Ar-yMd7js_)=;E}3Vo=ljBZCt*|~GLDeDLt`#P$`CD?}= znYx6H6c3_$BvVT@OgT?FdR0F~aKMF@QL3eew5X>*!Cksg?=9b~;Po^1mD}YI`5w&4 zfAM(coNFzx585?zV!#i@o6+OfoedjlkQv_)9G;d*#xcO)s zq*yO7dWRvfgprPiG+7M^Inj>WY#0kxpU09>2hX{E&md!1gbARZD{qKCbl-QG0bJ;! zrdSScwZH>%4kY+)#gW@`XtbL@JCyAjJ2+5!w`I77*xah99(+t*7)z=PpSDbg)Rhq; z4~8=zvye`NtDmDN<|MyhvyEXKXH-nRIw-o6J(3)>}otV*;?+okhcgmxGKfX8yc zwSWq=gNGXJ()QqZE3^~0s}I z(+AOR+-uO}@i>)N!wy;MP^W!FPuAHA6jkDNX{dI!~GUCS5XigqwAxCIr( zHp6;s-c+Te53+86G2zYzgK=r+*?aVXX zQTYV$7ET27^e2JM+|}0wW}a__cExG0;-T8)U8;pli)8ENGT}AayNR^dEvwOPYxNmr zf$^X{fH#Yc-p(a_ja4Ji-h->lO`yF5mSsu8&H%b=&G-ph(hM5k@Y4%}9+Yf39Ms8e zg1i@tx{<$NyEY}j>JB1%zHS%vfoKQnq8%+Aa}i>wmAJMf^}PY@LQfz{`R|}q@TnN9 zd1*axxFp4XC~DFAOhA_Ql5P&EGTg&$?5yF)s)pIn#p-m{fn9ufkQm1D70rkCS?k3t<+5tv#aSiu4-Zw-( ziFu9o#v8oXesw?*UAi8!Xur*YNteWPi0f-s>awc7jrzv(>LG_l9j!R#Ixf*}$AP}| zdf<79q5Cw>o=_CsTBs1I8cTe1tOZ5PWI*(pt#e~@+zomg8d#QSXO)4LLR3}41)=Vt z-OLVIa@-mbZ1ql$!x;+xH5MpDo@vtnyxFY6MVFCTwSXX2pq^f_ylYd8$@xp$jkabL zkR?}BqZ=hJnw4k_EggUd;o(4Xpq+n3yE=KQnfO_sIbB@!mJ{us)DOpP(kQykcnRO$4ybTGwRdL7 z9(#W%jN$k}tzF=jl}I9butcQ&#>jXjZLi6D+P&JExiJjyqZb|8r&%m*=ASWeH9%f) zPDD_0UTQP~=b0*}@A_2?uAtou0sk0iCzS1i115y1dF4Ea5>U4cVdiO9LlFmk;gNHl z`Kk|@>oF5o?vx5#$kc3Syh*NDGXY2&Lfh$ZLn0-f2kp+Zsq+|C0Ka+3Ij9?GLEku` zj?99GT-TgF+IfclsM{aK4xmmeN$kd??aK4%ODo7VD`bORZD`TJnM;$u+RQv-%g}LO zmKfLadW~y1RJkFP71Yh%JCnhXC0>x5Bv0sSR5Lf8esVyuM!S0tZ7U!Q-GwC?0(e?5 zM2Dv~){O(|hpDn$820m9S41QdZnm?#*^y!;x@~P=ts$BP^dpR(p>NEj+%(3N!z$t1 z@UFL}q>kFVA^0DUFfVNfX{O2qY?<^DcNdPq5C1l3yS6udW2Eph|G-tI9Z4k=a32>5#4<$7#2+u{H2)F2+MU%skvitZi?Gl!_C}a77ar?^b?#z z>vUpC!X5`}uULQmubJf{yuD#Fwj!n)Q@Q^-)bpQLrRNG%*VL;_+uk4u75{{=!x=HE z`jCQxP#t043l-hb4RaynJw$gmaws6T5A>%m0n9uT4NXLl*=r|bk7P{x51_IN;*`CiB?3Avz>Q}`F-NLy=2Wd>QaGxI`jDkeABc#w~JNsc|KdUniJfS=0q zE(b#hemnHNv4cHL)ttO3v83=4YDuv)xxvYU9C6Nswi=M*phmmAx^8w<;HNUbb=;E0 zp9t`RTmfOcXeUwRnw6|dwJ1SWj+TFJMr zM{*D*jpv}N)F=}VY^%S7wgY(3?oXH+1^70U&7JOXOqeC-ur9#WrkD7AW?fmUdH55QMQ);b*)yR!djL)77?dN{Sy zHf2(`wsugo=MX>`wg06TU0<}z%)9+#7~Tu7j!{60ZA=b59PV;YuUP3&>FN4L*|Z{d zuwZc7GEQw&v$s4ZJVIm1kXO=G&IBH&%AscN3Da0g3?-KPsQ(hrZJZ}FFFmgXc$N0@ z0vh~=7~!13b$ z`f~~n(tj=yLW&Ij+otV_1ck@gDShTd(QcmK;O94QpjUw3{TOY{WrYL&%J4ht^OG*s zf6+oEuExGM(sLe!`bZo~1U`t{$k=o564!2sU9tV?I$|BG`EiE{b(1FE;$YO?GDWRe zuMq>$4pj&0VPQt+T;x)q4xAt|l3bup0nEwew)b^p;&N3Wyg078_3He^BOCg0ZS7zO zADhWuL`6M`lWAuu!AP!{ox8_yEt6G?6y4@H_IPbM5|S!YS9xT0_QnXU*phQh3&SoH z+(Ms%+_1f&J5X`J<15aj9zkYa^3FpgDF*xvwnddhQyf6IOme=Gqe7j77oQ2BL`Ll6QTi|4gt&qO7918~i z^?(^)&vMS-Hj5Fi-kaG*nC^zSt0n+i4Lf`$pM(ZV2H9f=dz)wnezGLAqpFXOtC;=d zKzb|YRaNlO9zh+qsiJ0T%WJTS_Ph%R1_Ik4_maP8{LJ-B1!S@q*5?e3$ZP0XOy{*A zw0VJnXpfYvOHRokvv5MXE;dfi>B!`Rlria(geE@^2F$4}#ZYw|ZtXqJzn(+23%YE1 z9a~x(tMf(yA$;{poVkq~GvD<#DM2_vB#Xn3r3Nh%1=#vylKlS;e8yx6vMw{02ic$b{K=#}ug?uhnq_20aK1JKAV zgryYTg~mGM=kP+`MT2z}?E;?4ni!ON6d7ocW*a{>GQbZ2-3pon&UqR|8t|w=ySWj2V|mLAhpy$>dr7DP(#CY|brM^zc-> z`%Y84Dp|PJ2xb7^cosbQsm3w^dFOH^9rYdbL^Zw-NIQx%LS5Z^vX`~=f!VLIYen02 zM_0M}J3VLGfbT2D*VWQ=m%f(6X?y+)DN77XQi|Wi$(ye_D>R@4z!kaF{g`4XdLJ19 z$+*RKJfn%8i5sS@p4T7;$h44mh)3JRrI}qTPx!P$x<>=M@6SZLm=RQdC)({y$_Ug1 zsDjN58B`z@muOFAN3D}fw97ao+66y@BV7HdCBmPyuRvjxK98nWf}d_#%TFGB1nnB+ zLOa$?t*fKKFfCmuke#?h8kD&UhEb|9p9Fkulal~^K!d-r5B_%U>~IlV{c|u0FgO6} ztP$;9Wpb{#1cE4Lv%xKW<6FF=)&VXFCatLDyBteNT*>*AoFVV@ma7oa8lmKKzFudcZUav}g@G;)agCmr@Jk5-eo*2K>Y@j zK5GXKz+=QJi9G`C#SO+#c1>B(tG0nXP3X0WUgn&s%(V7G$(?HRwg-#4D;f3iK%F{w zEb96K(x5bx@02o}04y;cc%BDz!$uxFCrL^i{HudqP2Lmj)Ca2q74!mHo|lsV+c9bU z1kB!o2?@JS<0)Lwh%vvm$>ll))H~itS2#Hk?Jj*~5TYGo&WJEN=E-ND z2Dez_{G%WJXpWgxZp_4owSWp%qmD9L{Rpwx-4uQ}xfN`XclRM&IYTj?5m1+=&N9Yr z;VBG`8j4Ww^}OQSp*V~N;>HlGo-wdKbvR~k>ZT3%%ea>X2nha5@o?9)S;Ns32>&uT*NjE?24?C^oEHZ80d8e611xak3i5w@tMH{ zmBe3g;XK<-P+8JiV0GtSja}siI?Qc~ki=S-PM`JpVNz+T zWE^-XeFRi$a=!6Xog=QieFb_ zUBHfQR(Tm$<_CIjC_KP8erhC~x0sq%C0}1Azda+Z=6acyGjKv5`YOX!xruh?5XY$E zK|8}LJ+F7gk?ix$s4R5-}-O|_DZ7~JyAYK#}=v$H<`bB0zY#R)c;RoJC`8Z zDF~>IbLF!C9B1ZC9*TfJ_Ti%g+|)fY_%`as11?V&=rV>upQY!yxzd=Z9#nzuDd(F) zBdY;*08DmtSP5LduoXpA=As1&_z`DS(n}LPN)+lc*1iy!A%?Q4j4kt?HB_Y+C;12l zwb1_M>YxrhU2&|5@})t&)xg0}a69gWU5YYJ+8$6Jjdm{7Rh|Rl#+h#>sKcpF;@MX) zZY##>Gy3o_2uAzM2rwGj`TYbBU+Fmi%vN*rE^R0&)6XZbst<gPb5P5rWWxxAQ7zgg_eot}=e7nFUKf*B&mH(ndh{?2O1#3A|flB~98$xo7K#>RP zCK~qeL20M%9qiT8C+6J(0WWSSUgW(jv7fqs@y#(F-4?Pegu{6yGXp|s4%93eC6FwY z;~>!vwq0uZOA~$mbWXcoprw;tH{~lm6ojd4H-haiL_4nXAuRNii=drHGZOCJ0UnTR zPLG^ZCCVlI{|NZM`9^*kOK&v0yf@Rp2)XtK^3-H;oHuXS4q4-+?RtIJA~eS}!KXs( zVNenzrjMO00IDfhhupuNV-i~ON@{0vMD$vlO3y^Q$!ayfDe*RDDm}qMUfbItk8Ky) zv|5RF_fZql9{Axn@t<|_uLjz=5l~kn0N@d7cq^=lz*|?M;Ni(P%x=&tFGC{$Tw~kD z8*UJ^xvaQ~^9?c2?Y_;_5Wpc=pQK4?V<&ydC6m30ra zPdU{I3Ji?pFgF8b;&l@#?%c#TXlVqZ(LF>>rYR&&*n{3Qu*-+@6#gYW=cgugt@j*| zlun(zuJ6j{$y11VPm&m8T!1gig+@)FNIv;GZVI%sA4|v%H(jM}e@iL6u5y6c(EUtM zg^)jO>8UhsW_Xs-dM}FZ@b-3$O$-|j9NhcRIG_A?SkBq@yRT`xYB`fq)o53lr=N+N z#?TJ(HfNOHfw9WAw6v?N(mF-S5u~QBqis(zW!l(Wy;xuRG6iWiW4g$+gEw`mGKw54 zxBHiJJAA(9bqjIkN!#P9(aC_K8wKicK=j`LzO=n_3H!A24K;SdwnVIr16oxH9CJtI z2zO}r)`@Bk=&;HKuJwRxo&9{k1F%U~kTFw~jfd3hnP*MRY^13$3>yaC-5Q`v&`))5 z{N%i72a4xUxPWh58z>meaQT)iW{7yMFpQH9us0^!$u*AX5aL+*X)~_#<}asB(VjT3 z!`)I#r!#{1Y*ZM9?F#K#jVQDR+CeF_-8;I_xU2;1$ALGV4z$yzZt$Yrgfp(lr!AQX z;3-`f_qxsAF0Qqo95+RPS8q3-GOkQjzVEiu4q!uLBa&>iGEcxOy`M7U>tI`(9B8li zjkJI0tEA)^37?89{b#AuH+)xzGb)&9eaQ4hW`?5Z1OMy>@?@_NtaK|gI@ zuyG)Z%gHqPjtA01>bM1sP(v?e>f<`b&T&l6? zSs?hF#C}FU1KUfd=p>`xsMa`lhSCjAT!q!`h8tX5nBTNE>#{Cw?`i~l$geRB6cHbg z-qqouVCzfg-LR=%H3YnJyIMf!YNDNgZPOKM%zfrU%~aT*E)QSO&Tf`GQJrmuaSmtu zeyQ*5fI?HlF?Nh3meoQqUbNT7wi?@-rr~ClRMSvL5_NFSUU6)$kmmt_bi0oF0@96u zmb6Q80BzU9QBT{()Fe0$%#SJU!y1@!%jLs;;85wC*1~Z_7*mbePC+|FE1vx^Y9JW+ z<mmuTugpSBkVJ+)IT_nB8B@F$h)10^@uxxXUX4X$h`{N~O&f{|z>VC$x2Dz0*fk<4R>d=v0R$Y)5| zzYPvQ(T)V(H@;oZ6IOw6JNf-hwY?o?frSIyy1V;`!LNX@QR;wpsBwQ8zM$P4*xmPD zHe-a-?rtVg?!x;GU0PAgchO$>1up5j5~b@$gReH3%Nqz)=FNAQ4FcMXdvtj zxuBWZuD97^0-k}5WL`@ajS2Yi(spKcnBVZU>3NCC#tT|0JX-hJ=T4$5S~OKjUfX-u z7Pa;Yg?yFRXt{z0E}u>TYAbG# zkawKqA@4ZJ(;$tgTGxJN7FUW!)DX08x~lejS994Qn^a&m!NeHLL>Ulu6Jd(GVb16Ss{Cu6xOvNy+`_Z#ZX0m21y-M=VY3(i4)m}GkgEFWC1Hz>9yfFEQryb3F0w8rU__rM(>~0A#YDD2>N9OhqQ| zOWSL-s}yJhK2DC_YgxiBoMJ&KKED?8!zCx!gVaElMEIeAbmq}~4roHv|p!qaB%Y%c-fylENc zt_w=Bov7HysB6){Mgffo!1D8{z2|bhO&PMJ?Q~4DwsGV9RcrF;GfRd!a4DJ70#Xe3 z5uR|P)gg3=rwB=}_z?~Yo~`FSx8N#N^xP;J4Qy8kAoL1MvfLP!Yu|WA&eJ9R_R!w* z%_C6U{>h!~3GC5UuPYAcvknc$$X_~%2H{bm3>2FA@I#Wj_hNn}l=#2X0nb);O-xDHvGNc}jgws+FWQatfUHeg^cA5S0dNJ$y2^&ZsaT%c?srxIy1Zun$+PI| z)*u(@Id3{j{~Z-zz}AbAK7E}jobz(vlr4igdTX|3hYy^%LnEUvGfy2zW%$gGX1%y6 zxYcWzRa{HNaOs`ZN{*nGDNNCa#g4AFBiQJ6-QisC^}TEOwDc9iab92q;I8`u`!6@V zx${ik8niDvyJ-zohsPxAW`pd7zDUU%Ts<^7+zRJUOHLlJ4T^7v$rt$zdpp;vIa4Vp z$z@UQE0ebs=HYPNWB5l%eT8<#;OvfW4@Rs0ZTdrv^H9k-wumeBfNZykts6ky4+hMlQOP^EGn z||6 zP^Y+Hka2O>!M3>qUeVn>qCHUVb&a0O#LU)jOBqP@sMU2VnMD>NSf zR9c3YmOtmrpm2KsYV$8$!d`hYyHj1Jj!*cFX%WDcRlxt{#C#CuW5ll94;MNBU)M1t zo`UZU2@e}SZ92?~Ngxf*q3SLHhMnLL8omj4#XgO}#P(7(9c=lEi@RuN&h_kz#`cV;DvN)y9D83# z^T>4`xEw}$m4o0rW@Th)GcQ0^8y0_Q+3_EGEw!29?E_2h-wt_}5Q^0Pk83P>8q%||*c z+WTQ}QCO13>!0US^tLCn9lKqFD=i}q*Whdx7fnZNO`%0-a?YVlS)m}B zXcyrsv?b}FMX5gYb_EsG=W^7`^{N(IP4r{tbJFXdtGNygC-)2fsZ&%SOM(d8cB3k~ z+%mO2@2RZCj$(p3Rv*Z_K0K-eZ6CIr$I0*}tPk2F0OW{6Vb4O5J2Cb}8c)}z*xZq| ziA5@KUItC#L;saWR1FSE_1U-=`ZJym*aJ&L(~{J45URnYrv}t60t7-DpbRyW}He=D|E@=UBC03JXO$Iw5Jhqe+Db zaV-fgw6v+J=qrrm-TTsZBh11=f%{#t{4s7!Vnc(5y9V+vbtnzZ9|(v1!qO+^IS}f? zkGbmsBVV)q2;Lglv(G>sMR&lU$Oy6q<}Gb66SY}hov?QaL@k`S@RBKfGlS8_*AsnY zbEOvG6Y3b}dn3PIKU~4D$wp&1_@N9(`>3QB+Jky&s&w^TxFC{V;3}(rt`^tnGbn{7 zyWgukc^>eSwJdbw6=>m~1MP)lH-{uV0>IOjp3&y~Y{OVby72(MPpC|B6EO9CCKvHt z=)E$Kwi{W=+l@%|=@Us)XZRYhWTwJhhozdW+Lj&{QQS9Ol{*loQ&9wp%$@Cv@u`4^ zT5dFa(=Rz1E*i`u6o7VP=GsuV4_!~2;`CCdqZGgmY&1M!^vvhhk%E5a#QGNM>XN+c zx05fR>t@sIJko)wby#RT|1h@mmrn9{xw8Bdl1)is%O%ulY+9CAfn*Buxq2qhu5_R|lfQ!K-Lj%D zU!a;WHkK~>GvLRRMKi}X3;-$oEQ(uOqPIcfRFz|k;u5L)wJSz#u8IpCCn56rg1Trg zrZ{bK4Q9S}ylwN$yk9oS6z%XSbT9NKb7E`C2D{GUs7(%adM;93%r9QdE>6&P!_>J8 z74(yfpqeW$1?0tM95`2BDB4A}fVYCh<$wd%qrNMG&r;L&yby_rI5={|T7J^X4_xxe_E2ZD?Ph5KiXb0-F3EB~Q z`=Xr*)K%jb37>_dp5LH-NOl)i0jQrgc35#e0%{hL@(MUa00^AUc|v zY8qouN~tS=OgAmdld1A(l4`oPEjtqUg#551nK3794C$y6hc2y$`WS0S&ht}iFd`(>{<(av4MCB6tL zbdqD%H6fHTe`L0p7py*=1ja%dm4v9H5Bv-+VCHmcq8haS8G#$P9i3hxg^Rp}I8Toq zSA;>5e5{Xn`xc#ivJ5a#XhSmuP`M!692VcMs2q9Mmz)xbD=z+Sn3pd)A(ekMU=*s=obipOJvms?*Yd!9rDaY= zrmd2f)+{#^q=rWPEPF*UfqppUd;rfSQ120|SXn{SZ5~NPuRBmGG4H#DOS?02@-_W; z#bkjSH48Vbr^6<|Z0O;&P6KkG4xKkv-w;|N#*L^mB*u(|W_rp@DP~GG^N9(PT=?ts zPmQKneSmjtX-vS8%0rz>(S z1vWwQo_qm>)KD2vO|wBoD!)2U_J?}0oC|ddb;1TdC-T_QnmR>EtA*zhcogcG?oJdX zjSY2OFGH4#lut3J1J3HMc5{$jeN${lmHcwEDfWau<4n95k_*raFod%LSfC2202td2)fOhtqpq55ElpR#n>NO2oz1?HN&F0E^?H6MzSnkMn ztI%_|d>FL83_7nGPo=#=ki&@3;mcr&(FHKvjY~!#R;5(YfkXV{4V%$3&tpMu<|ds? zwPTyT6q0U?9ois0R$DwK0QLU6}n8R)l=%yqwP?)?fC=I zt|KR;i~`a?JDhy&rkYdPgjV2OX*|A*Uy5pc(8YufPdk)zt+bXWLfvc`O$yv2??#(ZIJjZ$@(j^4rDU4Z$8>iY zMBy2VK?;0&s|&qqeAPc1JQ2wbxD~_ zGR!=HZ%<|L6DDYl&%Jci>sI_4+HU1gi5H*qKs!=>6-5Vfm@dfn%#VnoTRy$Lm0CKw ztN-Hx3PTlvF_d(eX*i;&uJ5t{x2;VX+h=L$?Q>suERM#diFxLCn8%9Tkq_S24R#R1 z>+_Lvd)1;;d<Oon9zRsm_a6W3T*6FHenlY>l{VFkYH-I1(gN>l#gT63E=(m#2v zXph7j1??l=orRooMgp$-hwlYTPldb#n4Go1ua=he-&Vs%{cw8S7$MvoNV3o&vm$g& zYdy^9Qcg*7&E-O!nz05YmtMk71$?eDJc3DD`KY!un?2u5>{M8~@bRR2?}BsCE<==J zQ7(mvJ#*>gvPgxIP}z)Z=|_jbIar_=+&ZMtrqDG(CAUjny}nBJ1T918^ZtA%!{|EB zhXa4|7vCsuc$LE}Z~&vW=;C1tGe2mKqO@Zw2URc0=Q$=v6+Ah3mgY4&g$B zrFXrqcx_G_v_ob~PLG9M@13IUivZZ=XGb>MDW~d!R`b}R-Sp24P{y3p;(cybk&d)= z+MI|py(j|FR5aXcw9_#b2*v>xgJ)qyOC%2(%n04@p`AKhr3LP?YfcpNnS=+NGx^Y~ zGlPk8HAfwVS;DMk2D`;telme67ecJ+zdUAgNEmbDm!O{o;b2%bGJ~JSExc1y+7Du( zbxP9#29QhAllkX%Vz|NI@-y?{AWC4kPG_4DSJ_?!4joH{ynq*?CVp3QA)ehJz>xtA zq8&McZ?kLgm#IN&sfTJjMJxyFZgv9s3a$ibG6dpat-o846$5P!mj>swxf}TQcf~i|DD+u#>3( zYb-0+;h0Zs?e2|2GqiFB@uU=bTf6seDQ)LozHdWr861|6;r=sqqIiV-FfNpIlzsgU zac;>3Z~5Yx%Fr|?H*?*%OO#2V0`}W+M!Tl69k^1Y396bP7g&9pj+w6OTSJ(n~wt%idCQ^33?0?)tRAySl4c+l!XDo}&XX$F&anjF|wa zLoh>{D#@6`%y!0^*xOtP0{l}(wwJVHT$n^Y3`-@%#gevn03UYm!al$n7$gVGlGtvM z+^#5I#LLjSyXrB~vm5rRLF7SrI;e*2`lg>7nTwlEB%EI#euNRvzy1n3!{U_!yxR{- z&zU03+Ca;aMfhE@9SXV}l}XWu-(C*XnS#zjwe(7%!Lke%bsERK8!y`E9X^H{iTN|YNG4W9#7g4Nh;L|Zw>Pe{7m>1_%!*XF$jCNnNhmCpJ zj9Sk3b(6AUoJvIQ<*TH9gtMYr~fn%_=umdMRewi9kMx3vviv_m1?iBYfkk(F}I3YG9+o`WRm=)m-} zVHIH9q3W?55K2`xzyQV?z)_eZz?-#h;>A-Hu`tVlv|8S#|HCP>nXS2&4n+QfTb8jl zrI-^Mifbox>*QbPOk+&ae?I6cdb^^BXP&83VEs0yU1;V>|5&_hSmvFtOb8D6iw_5G zEpm6+CY`CkPq4>d5Pu-yzqIea9Os2H?O+uh8_R@F8pfQ|Q#QcgGIVimy0vI>Z`+Wd z$@r_1lu|ZcplVbzYF!hW%YoUcg1s;1F^eFdGUfEwzU?i$JZ+aJKJf`p+F|?Mp8Di> zzy0+W%$k*)ybQb`VL&(#Az(n-u4!5z0WF3iw`xtaD-^g))BtOvJ=paX(`21;WWrni zhB+*(V^Vc1)U@5zss_0n9A{jcXdFMk#zJ5V@&%e;dEHxvcG+VcUE8pfo+stkmX;oJ zCZz%M$wGsfl#_vRU#NSRTqZ+eTt1yO0z|n|jBCJBV?&h@VH5nmz*|J!Jco}_@v}iSbOcSU-bMvw%&T{Z6ENU$L#ciCqL(1Pk!#Z zAG`C5wtc{Zx7uo}M?UhAZ-4vSC6B3iQ+1c>NpWjbIfIbAeQwp7XjjLn!q1)LT^1W? z=b?~{+;W4L8?SPxHg3?rVpZ;pTQtzFS}|$6G(Smt&6w~`UG;2j%h2uwO`}&|zz=eO zZC9?{R3+LqgmO^;s0nG&E_54$B1Uxu_z+O%23aU5oIIiLbM3jklM)7yaOUTL&TtAW-#x~*>yP03lLNso5aK`PbTVZhIT^hLV~>X@=_ zS*flb&vv(J38i`=;O+|Q2IKr>`AD=w+o4^Y*DTM!0Na0a9y5W$_OofdA?vX8?wT@A zMl>g}5&>w>XGvBciYnbc`O2=*d+OpTz&@$EnIRA*QX3E8lWD(j%Bg?zHxGQ!Lm&5& zcOLiAqt@*=>3{D(`5p=fA3J)(%ied=gCFt42Rz^brsz|ZRh#AVn8(zVt(uc+=}oMq zBX^1S5_S8H*7AALU&Q{_CEA}iKBhKq2-N~w|c zz;9lwK9pN1w-=~u$8OVhHP1}edKdRLkm@s;$0oB!q%18YBz>GrV5eg#Y;bp^+)fl( zv}`63yCW|-2Sq(Qv0)c9Hr^1FFr=-V5njDT$(MY7lKn<+O>q-Mz5t#j0JVj_G5EvC zR?s)2Q$x8>dg8OVrqEluLFXHyKAmT2)1wahpE>pwOw^8|cN+d(@D`3BmFNJThL zPM&{V?{m9fjulFo0ZbQYmuUBA{ws^9hEEt|=_W!dqIKWW@KNQB7>ohnBTviCEob%O zDnkKgzrO0%@S>nyKUNIsLLEDHGWMC5o`WBr^}}tp+4_mQzwQ&qZ#>}id-j`r&*x7Y zDPK749!`Gh`+wMJkGDhlKlA<1=o{N8ssPe26?UxQRSlI+rm`k2ZiCg=hOg$LueEHv zM85b7qg4rlQ8v}k$iji^uNF0z8*axps}hA_ zfb4OPLFCat7e#>jKf0Z?7nC;m@WxMfXhTT>Jugiu@>Lw&CGvbT zUHW?30(cmEx|bSzo{MMK(BPoSiO`OTWzA0OJ`^0|4L72GYEbm%ZlYf0?=wLcTV%&h+6dx>fB!IrMb|Y6LrCq-;H1`Ts@ru z@aedI$=oitq8*M3#*hN_uYCWaZSVhpC+_z8eJ9?%Uj_0S@Er5k7bgD4&d+(r{kFZ| zQJ0rci*_kqE9`+IFc@|Ak7S)JWgLrMAMyae9XLx639tN7B>Vt<{;Cz znn$2Q;gWQ!5v#z|=|WI{tGk+y3M@eCAp235{43Nmt}NYkrlVp7fIo zKkK~|piwz%N}1CaRZn$7yHMJxeq$DDv8&xPy^5N#AXch7`UYYfV3UnE3%XuRhc}ifT|~6dw5hW0ncYc)R-SRXtAg@8ookz~fNuEAUmMOR zIf$lhVYs^|fm1Pw(V+Vu3y}b~%38sF^=y&hVfg^ke1jHfCN3*&GzJVd zZ+1@$0I#B+BzDkMz^{{!%Tu6hGj{Osw`+)|HEsv3cWMXI5Xd7N8&m5VXc;13i#Bo- zR0~bSlv9a9ha!>uDBg>&zvzm>#y)E%6rg_n7~3%p5sS_=;(TK^ODGVY*DQ!IkJOVp z9XTU;&+utCeoT@s-`?;o32IZ^=^6;puBOfpwCisZLVhpi9L8P`Sut;<%CCMo59a)( z?>Z4)y+O?T{-oNg_nEx))?3Y)bzvK#5^A&_r2TNr85X(s;9S;4Mz{JZdHCT_=ihsQ z_Ac{Z%#a#BIH=Qv@XFkKlg9JB`@ z@9yqW;^gQmf0-hl1FmIdu}uzGbbLB{#lO5!1bFYRp`q>e!?37#fH9#bsWRZ{V6X6H z2DJFbh<51!j33lHA~6>Q9jh zNs9ADCuwr7H}rW(8Kd&0^}=8v?@_bxbl|*rCJD@QbNS}hQh-GGrQ`nFLb~xj(m61MdyAp zgZc9zA#2$OMh|3$pF(Lzw2SjByr2eHmJ&4fK5}AhUH|rN5*v1dPR4qwda+YYqu7uwL{eCOAbQ9ZULFtA#zh^t=61G00#LGZH^5ib%!RSCh{-Y_$-`v-(^>j{OKkz zx$%n|HgnRTbj5ELf_BTcFo^Sqyu$(I*z(koil^sO0K#X?oRZmNw7{FmJTBR^KKG4b z0ztR2sAbkFrX6oke|V-fNQ;25D&i_b--6mNxCCF6Mz%Ado~%te!zW?X$X|m^l^cCX z-Cm*U5vI-okK^?1=4>`|^R#Km?N8fnx9xU(UPCQ6oXCH1(mjvg<>k+O<}-RTuuHDt zP+}HMD=ds#uaxx~guAqTg61xalyo8|cbBfTYy1YcTUP1XTf7T8VA9Hm5nP>Xv0M z>-;vJPu~)SRoP?x)s(T59Z*(*DCI3gHJFDFw6)+V7R`swOF8pVHMaXxwCe?}Yf8NV zqdt{X81xsLC{qV)aNzc=T3;JK0WM{|MU)Hb3J@&CXJ?m{> z8Xp_)DnR93U+}@5cizbkD2?Za^SazRTr%q1Xv0r0q{8geC%xnCZ-4qOyFBSJk9pE# zAHDn2p8CG`zI)b%=PJ}_amWMuUtFQWO^B22T=9rVtYSPDZ^wt~YCVb)H035SPa|z* zTO+|?3SzE|Ea>bl$2i{`PF`a*vx-tvc+_JwhqwqQpLjOMgDicP#Ixz5a43Wc`1+>FZrBuav2RKo#?~x4^7Gmt z>doZOzW6lPbvb#r3aeCxq1w#|ZK<&io=&@jcU$Jf81w09?~{6IaN_XHkuBXS@pqrCkC8!#nBUc6{t(ci!XeTZ;ClzHslIc6w6IOd)Na z+4K&CZDB2=X!d*l^PfM+Z|4Qi-sQ%tW-+$Kt0MGjnjtbT6>ZY(IyqcE1&oqnQ53Wu z>y~9MDnpMX>1}RY5v-8`k$1`xk9!ht#62Vn+DG|)dC3@ZJIuMM7qnDIPNDK2*J| zqantd$~L_8E}djFdxIHP>22Joh=no>JQF`@#Ns1OHYH=@FQEuG-Z=25d%t^$x&UsG zyn|FdZz21TXS`6&xypj}+UyW%l?YdyBFKQ}Ty41o_0rVyelmN}bT=3aw3j;d`dc4s z>`_$qTbo&%3uV@txrw=$I&)NLNs$`2Xa{(+l&CJYrfhuZ_D5%x;uc+sx2h|M0(e)V zu)vjkkI&j+hwXOQbBj3n{ZGGV`(0nLCBhYC;VIx8(NWF(=~qTPskzyqoNb|< zN!ggSQvN`4$;~VUmTAv98A+I~m=!^h=wG zb`KJb;FAwOA%VGDZu(;v_Ci#XSR9lbQnqY6e&pdfkl+t#xi8x3d{?_s z3=?uO^|}_u;Z5t&pF!T$iH4SYDB6{eXst_5Bb{U5zpY`y@P??LJbwb7lk(o$gcI|9 z(>bJrjb?TLk4CWGtx<{H&Ty~H4~do7jTYT^VehxT6+hXJAG2ZK!It(~jHlYCPS}K& z?)fi!Jw4PLS6SVX`F1?M=z^K!_uH9r_K)+a!BXzZ;-pQ6ziq7XDl0U0$gWUxfH=1R zY<_}mif1%x@Dpc5$h$x5zcQMLI;_qSN_5R4%3+5c_R3ejvcu6m_uS(tIA@d0@y&73 z+)Pi~doa~==eR4Al6jkkG_svDW%Vl4ims&4xC#s#rjq-vvfE6^{3YB4(rpsh%w}oE zII#_{L6-s*o7STSZ%e-_%=o4QQd&N1Zoe9e9iHLE5tUCK;N{Zzi@tEC2ZygSaQp%i;G0 zyef}Iwr}4lWI1U#m)CXlKpBdJ}jHmbkk zgi~vuUX^%uZ6T&3$qCM4J(vT6atU~kUpOZ_6bg&x~6A1qe?x^8CP2zS^Eq!v@ z+!3rA@~yHHzg;8bb?_#JgsXyL7gu@pbN*EV>hYJlkruYyc3ZwRs=LP{IA`t9LD)w# zwr}OimG{5@{daoyUi+Q)A7j|wCjW1=@!M>3zi)hh2I4vq{+X{T2#I$uc!;p2^N-$U zn{Bq-Z)fYn&)A>o>XVusppAU?mP*+h+B;>&9JHQ@LOHL@EW*zu*SrW7s}OVE0%(s+ z1Z59DRWr<%GKC`Pt@c#cP|zM*S@cqdCPxOTAB^_0ficA-GY}%6PPVy78og|m{AAGE zH7g+U`p;5ej0btk_T~0Dx$OGol5ulFp$^2UCc3zGIR}XAl-hd9dI3Al+F!>onCu0* zhj1|*z?u*4UEbJyH{1&ZhEr_`m172TjFCcXJR$KeF+MWWDgIp$G#|>JYE}9Wyj&5* z^8wRZ5gYQ9t=({2^uDS*bnKB?prE4XtwUbm;nOh2;6<3~EUdK$B;Z5ET>zhi$ce62 zDFx=5)DXLd9=a&p!KP<33ITo|Q`nVTwF|Gmb{7I7)sSs6EhzfY^Ci$VkfoM<1uLy=&ajA4ZMDDfAL(sxct601dK~oo{ zt_xWg9GcTk;7RS}V=X*}2h2Ahji~JU%E}_tIYZ-+G7jkU-FI%rVqV--+^UIt z39XPh=YA8w580dkuKn2kpqxhQS&SPa#5%NO)GROn1SEb;WzV>x#Gz=0ol% ze!;=QtO?UvM86a{MZHG&FU>xe*j4J(?gNpFx=6W<6)FrBmN5wyO^1K3O+Hwvu`}t* zk<6aC(;*8whh}{z4K2eLB-%CkjO<-C+I1|^&aFkeY0UYEc4#%k8LS#t8}0xlGnDb0 z{0o=P8N+oF?Np`?%NCQ>06t+)1<@`G!1uGB^(>_E7ryQA1Af>?fCuU?f8P%}oetMF z?#S)EhM&tf%3Lu&C?ZNaLct#yQ8xEWEN|p0kRwl<-Tx?Z!e0 z;*(J4JUEmiGMg6@nhKz?>pfb$&GVQFKo-34^@QS8F4hvV7D0*PI3PAI3yIylY~Bp%>E< z{U=$fp)5tYWeyC^Gpdp!o|g*Tl%!N}G?eiCMYU0Eeq2ROmU9{1`UOV@=-yU@%#Q@T zdOJO2rR{Ld+Jq#VZ!=Oz0ZzRQv1)_wIDIdgp<^L={)F^gw;@Z!Npu{r{F> zZ`@I;&K)@bJgiXWgrGA!?zrQ<^V@mKQ=a1Eu>Wj6jvz-#mQISU(P;!>VWlwmFlET+ zmeXfXz;6O8TI%7^ckmX}nx$uPaPP&W@5jw*JT_9Wfp*537eN__b~7ummartG2P?SJ z5gmS>c?n(R03z?ZF~d2Nn`z2G>u|ak9+bXpZEHwe)b1@HN@{)X(yYI71~-x zDzkEhPusO2GO-A{lw_P7@%fYQstt0WeaC0Ki3ZzuRMF`20r1>HBhh~E{B}e;4TA7|92oe}p)8&+pW>eI z$m$43(%yE#_c_X}DFOJIrwMphfzZV)oEsa_7Ubt1RVrM3*9H!e+efss+-nZV`ULh4 zqwOQ^ar(EA&berYLAXJhAOvy*QRp<2yh{f{7?V%Pq6DRd(ZdMyAI3TTlbyK$x}}LLHmw6vC&(W$OhV<{`9BcJHH({ z`MB5AnfW+^8T9h_X59t$4rxa9IiBd@+FD`QG3*@z9vL2`DL|9MWyzrP9BaTs1dGjl zrcI-L#vk_HjUTy}&b&&9N?yazj_OM*k-3&g!@>+E7$)gnSCTJwY-zg)*E76(d`B10 zf>X37!eK-`j>jldA0*euUIk{X%uEC7`ZA)NmgSPV^JQP|9 z$H$+%6@Tho&mh1?iFT$wW1C(&u8CrvfszX-@2FVIMl*P|!AYQ|F1_vD73RZ*kw-ba zWtc!^JC`()3Ht_1?;J|BLzBru!8A=gv%WA3T?^z^YP4hbuF=kM%I(f575*#%j0|^& zR@Z2UK}84tzz06??;g3+=O)}Kc_#*DhuvR?a<17;L9&2JK zTvE9OJOxkZPcv=7-;I&YLZ4Z_^$mb^XMP)rq3KJs0FoN*Qeb?}owywH+GIh4O5Yix zxG%5%H>o|-w?58lygciBc^mD=obh$Sn8%a72+Duh$zQ4kY_;_5OwWo2Ilt630u7sHceSj!+^G22hA_3obBS8QU+A+UT&7}lWKm9Z>GK#2;f4qa| zRWSykGg+Gd$_1Ej$1{reoPnfMQ&J4(l?BYVmzBfq?}jUW{No=($=~>?nURzZiT$t@ zTWz&9`6v6{@zPlr$zI95^DzN42jRD~%{KSKZ|BlWFSS>!`}sIb02CjQ6{ko^Mgj2M zKs)zEOM;MvCPgR6BtmfSv~bF-8Hn)!KGDuCL^}rztkMeY$Ru*i>*I+Ue>r&u(snh^ zbQ)CasTvY{2{LmB2t&2O34hU$N;PLH$K0NuAxq4i6Vkr6&GqXd@q77Dv;LRAG+)Il zua5OvH)53Yt{OJwH~Kja)~;O(Ro{~AMcaJyf)SQpvs_=a>zUtFQ}vRc^XzU@13ypS zRL;Zpn-w2#JQaS?Kr=GTaH~`*y+UtSKTjadoFjM@?_^`$^jX(v$ zcJOk=Csc23!#wK#v&PGTr>Bjf?5=2PfP$;Pe6E3UIYIk6d#e|abYP#i<=7UooP;Q$ ztU`UoWTl|2cEg#N9_Yz>M(>+9Y@!ZYXf<0_riAUi7;7@?j?Eg55?w_TIqy;wY>3>T z9e)0WZ#|sklVSb-J!02NhE&5o-&_@r>ty3yx6bV-JfF+i%U9k#yZuE<}|}p^x~!(;w#_SnUQ#7->6F`u~_Kt zrUfVsa$4zGKK?LgE>VpkFD#7!JK-13eAk@d1~U5R@KYz5^i&nIuG7t|AX+b%hI zb@&Z&ox9U3w|{S=J@&Ni#h=E7SL|PtchMeB7lqg212S2#6iFo1$RKFi^C#;XRL@z% zRAa-Io}Wf@5JubNOhMs>a7EUL%J8`H_E z+D3chFD~J!2cn(Ln@y0UvkJ3w?&8=Z2}d#aMMqs1TQwSvR^m)44KuakJ#$)1vVm*3 ze*puE7g9JQmF~*GC5bhb^M=#wpn3oDcRl;wc|q;@hNq?K!5llaFt6{LOAms2-?^S! zDaeV?VOW^VLeGF?^gb^Me_NIRbzXq_XX60@d@w|8Yq{izbQy9;bA{p(6CoQ!Oedkn z%vw1{gD$)AaBB)B=_TZb4l|8(q-WJi!JcTZ9pjN%^d^9+BN|X}Q!)7ja*Dns4}S22U;3UC z-f`eB(9f+n{sdP6TGOWJEt0Tv#%(0|j`PIrQx;sJ|LKV*o;V)Ao!xfZO)3hKftDHF zyR^N>Q6nS3X1gL-neRL){pU&f1V>P=;@b)y^Ow1$T~lZ(^yNjV!5M{f^}C*-a{Dhv zkL7^#1JRBHJoBuvD;u*JIuCV%O2>e%yev}0mCX-oVp~&4>02Yiq^O2~;rwh&UPlzXvwjovlIWYSpU zmEQAl%p?bvSULwSSVPXEogPz)NZQt9A%W zv`5s}*>f;Q^WY*gX*k&1?Ij<3@m@zg^q~)peeWdu)23;I2{>lXLKTh~D=x;UIkc@C#+nBX$l)mv7%sLz5twMV4vPYYJs`?osv$YQ*Is)){wXhG zb0|>Hg~{ae;G#Vimj#!o`{aX-O5>Kv{NRshP=87w_JJPOyW{(d_Td)UL0N~;p5 z!8Y0(f^^b$=|4Y#sK!M;xq)O}B`eM|vJeE$Z@41t=Qmuz(6QNu`paNaie7+&(5g(>P^7#RPl88zS$V8;G z8l%k%qCerLT8JEI|LL@I;OG1L?R@{lV-v3WJ2lWQP{)IIYUTpeUJgV%>j>ID8Gb&o zt@V;ckxjTfS8Rj1IF?TGWV23DIOdzj%rJfg8O)+MBMw8m;g&;!OklP%p+#S`Gmf>U zN}hj^?|Os0)3R=`bOVL_AjfrXvHO#rc<;QRcG&fCi7Uw_`ZL1O)mEsbX9RK^EZyu3 zTmk1S4Gnc8CnNCwhAX`wVAW{Fj~(Z-bqJ&X2N-+G(-qoN}` zPEOvfvO+UoLc~Vc`<`y^{0SGR^T*>2sDp5!&Z1zRkLN#Qr?%hDBOdVx#xT(?p%(4A zzxp`Q&V_~v!>h}>x7P^Kj!7lCl@wBZp*&Y$8&&1m=Wxs>nLYxTuNg7p-iO)S5uOEe zU!<9=YQ@Fh1sm?WL^zj~lV5d07gjKKeQ3y;!zVfzqXR~LV!<8)jQ79h@9&)#6wdQ? zA0WKU=G>1lXfo=FnSHe4{H0b;#aL>^IUp7lU502UNY3_I3d5A$OB(Bduxboh!s?E3 zIWhA{?+dP*gbjbpt4us>fwV$$(TXX$gSvL!$i@;7s^DtR7Nz>S4wGAB7-$jaevlnf z+NXZ51xgU6Ra4nvBoFfs+)CkP$ZZF-x5GBO{P}33n$87WIP=IO@v-6ajc$@6Sv68lc1AW(6UbWs! zmNkyXs&rR3V%K9F#^a#pb;3}nGxsXa>+plfO=UffSds`Xrlf;Coi-1$Ds5d)E!J7~$wjItosjR0s1RZ2X{p0z#fnB2Q)MJX$(d4bhHY zjogjKh>=a2OX%Vdrm1~L7LFqEE*uX#0BxuJTB*jdd779Cy4-c0sE4ZAN5#gMSQ<*Q z?tmFJyCgKAzTsvKOWk#$>^zZ%t{9(HE7jGB2ZJ~G<~*2BncUf|xt?NppC74~{y(|C zT=(l4mmYcKQ6Kn#Xn)y@o;~NQU#%_eG6fVH@j|oQrA07#0ljz9LuSV(Jf`8d!@uAv zHiRv^V$u^HO@kQ+;qg`c|F{L;T~T809Q0>s(IC-oh7o=~8*b(xNb#(hVP?nsb;C{2 zXHEiL%oCAxY~ft|XVolZ2^Wct>!~9%!UiQWI3@yd4dtbXN5gDlyMg6rQ-+~EIr(~b zG-ex=HZ=CdNS5aD7|_{~^nzR$$gZJiSw5Y4&qVK=%4VEUx0+lA6t%5EU;*ORyFTlQ zTj~Y%#HVd%guH;niO9^ha46lRnq@b59E65P!Yj!e)^6+&M#@AxD?%C?4R{m`^*$M6 z4h2t*p8|n5kaw(}V=kShH)#OgEVN84{ivb#n%N*_x^uLpdL6uJiadu<@*3yi@m3gY z)j}*KU8wg|13;ZA$hQ=pZ*r%o%wtj-m`NB3ygluQMPS8ZSZfQIR5O==U$9`omD8rq z-2Y1xzWI%>ANZMn{J`tq{+j1M_u0EY{;`jK+*VsXx6^q;r?Yh_FY0uT-Ft5q1?_F! zWum9vA71GF6uR$btX(w%Tv!#V>lH%NG6Tc^N=BWT7r`7V4CLS+zR$ zkeYWX(lvGXSDU;lQja;wjdZ!GjqM>)t(wA1Byk0E!|yEWhUI7&b{c2J;SENw$^xp0 zq(T(Bi^QI*_As=&%@`$FNANFe4X`o4NoP2qg!z5iR5aM2Meo|!2(hH2S$F-cF(>r! z3P2seD;Hz}IWMu3%a1#raF_9WL2Yxtt-n5FpG>O70U|M70(9L>GQhLs97sAUI*oAddu53wd?gz*tV93LLNiXaJS&l_PYm+HQz*1E9Psox zoH|DDA3ma%FP(w5Ks~@b1zsBYS=X9AG=J0j+8?H7-2q8xw#pW6v5@uC0y3c+M)*wd z0NQJ3n{Sxb6PtZ=Tla{6nX+ zPp9*hPKP`d=XE*@JDr<4o&V@`?y1V*oz4MoezUHG8E}?b`WojFd_{L3s=EvoEjP!2 z_UgsIuKjj?@crXm#UQ!bGIaw7UED%GykRZpBsbL`reU9NTv%TYClBC>JB|p}Yp$uu zdstq0eQb159HJRsy$Qk(y@z)0$Qd-Ob+)oGV&KFQNRyG)kxq^}($SXvUa5or370ay zjgU*+QjN<|ZZnNc|IoLLDTQ)XEmH_Qu0mO0f>f+iNY~#z^uzG;vWFpbk6Q{e%|SFP=9%+^TEIWd!$ws0Wijxpk(F|acgZHgq@{IH=7ZTqd+|inE$&6|4sVstX#1~ zFXIqBicG+tzq2*n7HFq&1P%3hpZNA(TW!@DGkeiH4|s(_fgE^3D{|&vA08k< z*!wxm)*^}h*DZ(oI2uO8&PCH%G5{yKeT{IO1oJKm$;oGIywQX{Y-aD)VW}ZL@R&fI z7FdtyC(#E3R?lcn9=?{_>r^($YxF(fDyT%5>laRx@Jfnd-SKAUE!0VoRQTuqQ+0!D zZ(M!uoY_a8e)_>j9{KTo_ucD*?|t<^RcNWo2InC!+;BZ>mdhEi*9phPP6s;%;TgN`sNc@RAO6tb zpL=Mx8Zf3E5MF1_;ACwrH|A6?y4pV9zOZ4mbE_}JocdkImYzk2nyOR7mN0^-1ff|3 z{^Z^PIS{-mK}w{yT{wTE{g8FDv;0A z2k<~0)c|+zI_IA{iIe~E{ud1Qg4*LBcA*blak@v5P;{HPR(GICiC03<8+b6`Tmy%U zKsU+kl2d>ga=W?Qm_q>GP?<22Z(5IS&wZfXf<7s{gUmNW8qUaNU$lm|5~CMMELUEJ z03Qjh7oL)O&>Yg(@wdC3Zquhd8NcCB&wo?KR_pHh(DN0mxH%8`{BHg!|NM)o=bd-n znLj@L*kg|T(*9p~|NGwaidVes$-C_Qs0Tf0mrm!EP})xC;7;dzozA(P&Xt|czjQix z4?y+*?sV37I*U7<3p$;XJDsn0Iv?qDUfb#HPI|cqK9E4SJ)iTOcRc_3pMC9X4}Z^l zCVldg7ae@?>WdEhM3~I_3iZ%f~0w@fCVmZ6vdYvGZ3rO2dbg-LF!SxE}e?zpH6~*y#w|=^Tio1ajY) z8rba^xW2GoyLQc?-<$rigHL+bC%>`JC%*XE&wTQo?|3^}=pDD;?y>jZ_8Fbd>pPu~ zbvlQ3I;VCzKkIasb~?8VhV=jJbZ+c)e%ZfMmbCVgjmvA|V?{a`+ zeBU8rgBp6N#hgaNN-c9k~DAAAJ9-UitDT?zr>A{`Mh2 z@nxOP`%r6lI>&c9(>fi}zTMF2+%*{00RE~1{)u?DbUGg|#;|9?dzY+|yYIgHOJ4Hg zH^2GK`|R_fFMe@9b|Cw~4^BGgoU`?`0iqP0e?VG#&gFaIj6h9TQmuQY5b)qTEkR zl589K3)eY5n11-A34yFC1 z45`Ts;O$vG<&uI0SbZM1;Fa@e7zJvl8rBy%kw!@udY1p2{$vUkSYh8DJ{D)3wWv6pl zr*l@P^W9Eo-%jTpoz4q89oYECJmSH-@3O=5p7*@hzVd=B{dn{K+~o55`rZ(rP6RPtNM z6)8A#7f0Y1GIp7nd_&b6?+fS>{1?mplB06pu6h$lU=Plf+tJMPEx7{ZZVf=u!za0S zD%ZjYBM+aVM-X#d1!=)=t~jLk+6!vi``?cWEJ=phQ*!+iWBD_(%}t%Ey1qvH z$PQN8&&zrNmu}dck09Fhy8!bXIHytLN%I?aa$^TMsaa9or(3~{INtR#6= zXAe2|!$>aseESXW{KCuj`}}9#{jPWX{olWM=bd*#t+iXH^O{cQ!=298I-Lof&QCj? zMV-#NPUn9OK=r>D725owPWyhR^W{#5bnUO|baqAW{kIQz!V@09=N?ag+iPC<;rG1Z z(;xrnj}QFR>>qvh`il>_b5ZPMAO_G0$uUw)O~J>+={dX{=(VnP02N>av5j`JS~Vn7C4S^C`u!ReW1X!yT1y@ZrEf_ z3rHoH3Ge+?m;LDQeYProJ7^YO^uj%-OgV=>z);Y*>xJGd9I#-4s|;J{F_P=SBpBwq zjRIBy2>XZwVo5>Ux2FD)IUzGn+4^QHpfw)H3>gl%Xy*YzJK?coaPoDmOKdt-v~kiR zh$O1`HVXjKB0_Vp!)g7@Zb;(tmPs!&AD(=Bs;otz+BJ8HrK#>tX-iH?&I0m&$?Dm! z-ut<=7u3$r-rjaX{2u+$sisD|+u&f0eI6w=mSMp7cjs9V4Ub)v9Y3Tt54pVIJ)O=Mi)redVy0Tt>0q)NM5u4;bpA)DGpo~?-06I))A?jEhV22Qx7p_LkAM7g zp7R{C=zaLZA3pftgO5M{`15~!>~-gVW9dcTSLrPnbiy%MmFP=m5(tc_wW7OHWv$;1 zvk)^r#@@b+v=+V*!&r|X8{mQWXs#WiU0(ni2Uq;1EzOpJD>zR-IRFn2FW2Bol*Ti4 zZ0h!6QSM3pKwaIni&v0D(7tfuyWjS@W6EIi{l+)Gfm@r%Idt;9^f)-QL3>RI@5_yy zn|f;C$lF!ubKk;3(AX0)b-<1Kb>h%&cybX368YW9SvK?Jc}=PdKNULTYp&tv7-)y` zkUK3xz88Kq_9`VhqNtapLT#wqKcKGb+mMniL(H>C&)w9G0@%XSbM3`Ax~as5uqWQ& zHEdr8UVhR~kp$iqPi*R&gM@S9IO)YTK*?#hpO^>iQN8MQt{ zDR#9iQhw0x=F{1kFv6{z0eyB=(m9+xVUgZp&TF(ceCdAhi-YIS`SHc4fAvR)zyBLw z`p73f^p3Z^_JuEe=99L6++!ZM&DNmt%>|i<6_k=N9mL)~7}A>y=6_KfRG6l$1@A8F z!j7HJBOdy&$2{T5yFBxSuX^?C58U_TM}OzAGbf*V*@b5=TQJLHX-2J5&*fYTmmXZ$Bjn2`Mp1%6p*HvIHL)`f!S17s*dQPLv=HE-V+4siGi4(TmJ z-}=@}+Ri$XXm3KjOi>#|Q7_sV2Yvg;KszMVbjT83I^<8}=Y+bd^16S}_T=RITH~mk zEjJ!4*?aCt0!D8K&ei8T)$%3j?ji#pLEyOktXhN^k9CUsKIlOY>UlwJHGTf5)Fq&u zv4eUypf1`&^Vd^J)(4GbHKFP&%)Gf-F|GNqT$1~`ao!2dx&YdjT{q>>^FOlRY485{ zk#Bwf0k4MvAr9{;&wIjlJ3Rc6f4l8d3+Mcy!bP9d>C7yA^=~^Jc-!k?dC zc=fLqz8&{cc=*RY@PRvT|M-{ey6b!1`sV$<@VTRo{Pvk=OrAIUg0s&0@ej_r2(A^_ zfC1e#!E6WAdx}5-&xkcbl9l24&i%8^hnqgj zxt|1byJ=?>{#69fX67Br{eNmtDxc03nKwcYH8-ND8;EvChYx(62iz5U*zK85&}3{>ertY%p}^2( zMjbGWZH%1udO?wFq%p~0^)a4Pjm#5`zlNYaSKoTNxS@q-=s6TSZ1Pu}y6B=)X3m)M zgOg5p-`<~i-pk+mTvTLFeZnIj`Oqg8{nk5+uIs3x_qx33!2URxP;V+)w7Es2_U)ow zdu!3OJ$9?kLm&O%ouB^1*S_|(>|t==fd?LY?6GH_dFGs-UAXp#KV-Jm9R@RC8x~al z*<8r^AQ`!pqrq|@yK5x5TSP_ul7*VT+H0TMAgE{^JjbgDkrIU?_0MSk#Ok7`aXI*zgE@3t%+Szn9HqTgf z8G!k~2R;BZ1={h<|Jb`;m4oAEOzB75$hjcaYFE{om{ z`y3y0&ZQ5sj`4t*Rg7-aJt4rt!D58=K1sUD`9ABH{QS}>p`Ix31Y7&5yU2ZJvdwHn55#!Rii3dFhq2ex zA5!=7>9Fo0M3v089N-%RlHax0>-B=dVWRL=VQ+m1hKcvI^0Fp*UwcJkOn;mo7H zb>YWgQj%)gSAUi+SDpi1wO$NBU)zq1)hD7ZhF4nJSWWQafv}_JC)MM_acHuQmP!X_&#? zO`S9Dsm`jQ?}~LeW2hO_61-91FD_ePDm@EGG+t$IPd^PTS$3GOGW zrM=6>x8YuxwDrrD#D3M}1N-Cc*DjuO$$681@}pCZKlZ2tzx2fqe&D?rsGs)KT_5{* z4|z)Q7$LM8?~xOWC&?AXtK`pvQN5w~rCeBiR1PWrDzEEw@LhTI{kPfiiI0EDbD#RA z*FN*3AA85)U-`_W6Aqa-_o9*gqr0oz}RANkb zNi@j!K(tG%rNHe9E)yd5(T{#KOo1P3W}7wz)9z+wb(^ky^ub2lA10#EH*W~vW<=|< zhYWww2RC4$spRBAJO55P_8`5WP%pbQP&0OwE89-^hdksVcyvC$cz1rT(>bEkVI!h>#rN}H2SXaa(dEU5l*;&% zav{E@c$jVv`~8^h_SoZDZ+ye+KKjuQees~reD<&pe)5F39dyKm~FNDTGzpAbex%Jk3A$XVz0RbGafymHE_a*Hhozv zE;5EpJa=UW-X73x(>a1GhR6f{qP}OS=@}ZNGQ-7Rw3$g``OBq{15fh(RX*hvqZWPT zD_?0lkZS|W+n47}=@R`hsWZp4$va|HQ9>u$>7)xWYZi4xd%I10%NuV$5hNXkACfMT zYyK-?&*idUk-lyS+TH01g!DywOuOEmM~wFgqSGN7hb5nOHJnXCPoNDRALS77b8C#Z4X_&2K z=B-SjZ(v)r@YZz8A!{%F8DhR(2 zDq+IeocB+gU-9ynVf*0i6I6fPF-O^sG#o~$eRGZPsYFCLp&by3=C$YrmHo?HC{s;uPHn(smx(?L^(N(5+OZr9wBiXKYm9G2G`+ zNc)q@@&fTZcWlh2IPflDz{ z*-+{G-S6QKfB3Gu?)r|s_S$Ek_kH`YZ=62qlvx*@fAy02x2!{_73phH4X7$JBo5D? z+G$4*g0!y&+6kds{d2wUleXtZadJ8-D{&xO#JiW0JHwb3dazL;(QXB249AQiXkmhC zkF_v~nMp=&i*_(9)WLn5QIxi;nWtu|jz;KziKnnoGqc&7Ri46J%y>IwehRlnLCCFL zzvwD}lt4+_1v!XHv~yD4*pJxeJ2dv2A^~2W5h0>Wj=&w1q}wtMz!H%g8EVh1x5ki3 z!i?uU;t{|6E@+ zIBv6^Ow}E_eO>X|FNm5bSsmwLXlIUsF32fGv6%zCI5X)g_hZvV6z^GqpYG+#EaaO# z9+|ahsuiuZ)nkjM*iay=}TYws7F2Olb`zJ;fEg%&foElcX%Vdo1S(BJd6(-M94MAM!aKqXAlzb9;9C& zPYT)@92KxiQgZUzJ`(Nn^EKM}7owDCPo-C)oeH@eF!N}Z;Toma*%X_%k=xL~4@f;F z)3CK?lA^nQV6>wciDF6cZ&6Vn9@{6byV4Zky^>ZL@*)-~8dmHrmr-1>hTsI?*2SsjI?UejsfhPqxFh zcMU^HN8=&auZtNuZE9_A?~<&wSHP{MV{AH^n8>y5SHM-!Z8&zC73X4}8@X?^Xy>P^ zj4yx%g5849nbq+A|H@LmpyWBipiRyrn6y`SI%Gk5%-{SCB07Zn=}&+99((LTwDz>K zPQk48idVb>^-SF?_u`JK59L$TGKL|#_!JxTsvDf-T^|9-JDxmkBmit;V2p}ozsDQ| zlp3NP(`KTbGwy87LDF{qWtNC`O;d)H3_&}3DII%d*J0+VFSP7os^!`p4)2t*CpnBj ztshp)-7PB?qmwr?oPP3cv#>4O4LJoJzd?cm2p{QS{ z{7kgFmkVn&YlmoWx4A`VFY@4*3&Ys8t?D_e@fAzTFz=eSW6U7uxdud;n$#qJBZ5jB zz5L}4=l;cA>XpT$j*VOn8s`;9-5?dP0Wg*TSocIb|8hP#I?U`?zj$GUTfYT&}*Q z>B8PnHt-KKe_ec|MTfQrd2dL+f}A=fa>fXD3%rsti#mDLlS(Vm$<3SN-#=~UrSdP6 zhRNY#rxHt?@Y8QTRA57O&(xvprZfX)OpCO`OW2t@?JZ(BV;a+136C9^KEqY=`Z8uK z5Ad-C^X5FR3y{z#DAXB4<~@#jp-;Xmo>V18JTJa6^DfoU0Ny-MkOoWc*1|W>s4BEKQ%lWA;jjI@2dPoao!g=QX?uV-)UdGS5|NSq&@)AAIxtyV6lmLJGa&Hkd zpu7>Kqv=U8z|40xdU;I!s5 zefspLY`ZNl4CVQ*+iU~fCNRqu!n(G3GmAxiiN}7U^Al7cxzVh5O#1?OQ;yJuc2wyl zv0w=>OctV-NzQ9I;ltzcG7T|C7IO^v!W!t*$ygUgl`jzC|} za8ydbsWD2%!?B-~F0Q(u>)0cOXBE?I-gRPG73Og!G)^p%${=4Qb1Rh%JHxucfixq{ z)cU1quST2As-*dv;_mT0%cZ}ahb(!>;a`QMLnk2bZ+QLdXaPS?Dswpxh*u0hiBa`( z85xcCydZ~~j_L1^f4LMYv9jc`mf@w#_Ur`Dh1VVXLlhIKm**qvH9)g8o@RFM)psv8 zZ@~&nCl$3!^$|kE&5H)2o#Ae5`RF8T(`wE@%o~gVKUuVf2f8TxW@J5EDc$@n z*PNi}4#twW@iP|b9&HDo){z)8++Y%(9EqLRhFT6qot6S9HWgI)_$`stSSXjSFanIZ zW4qZtXy3fK58CxS>$sX+K!^-j?h|6L$jvA)uXd%B&d}$+9U#M1rOJVmnU)8-Q)Ft!jC_JFze` z;VAr-$Y&NNW1j~)sE3WJ7d;+}&Q)i*y$K~?cH51#!%gwMXJ+CvpNa`}R5+Q{p<{54 z0I8m<>3?R=>%YJo9boHN&g;bX%vU^__#&naq3xeL_@metGVKx-SWRXxIR@~sF3>mb z4)%a3-)0kG9OxcvdI{_5hQ6st%W!v~P90z$A_-|Ed$B!+Cp6xsVX)jfd)OC-;+ztS z`ohoq>Vs=5e#8UOZVuKud!*Tv2Hi%QlmF_w&VDk3>T}-B;j@A{;lw;s*=-fQDc?|3 z<<&rYSv%$Gwa^6Yiy}}Q0$0AN49AXMp4Ucv7|D;cx62f$rcyhtx(iCKZl42jP75*% zjb?2pc(yybcc&e?)FABqjM&wpr7M#l0{BcvJ8kN`M5Dp5NmO%5<*AdCGP>SGx2W#J zP3R7EY-~udA{@WU)&-U%<9R^Kymd0Sbd_O3y!U~(l=wqqfju$aHH!{CVZbvrQUm!y zU9ayXH2_a?+FO`Tt`j6X7YUVN-g6$V!N79PI9Y`gjlcl9H44)Jv}dwp+;2>SAz;Y3 z*w|lzc4|?vnt=z@i&QxuaSgc2(g*Xd^YhE+?7iFHJrMm4ireRHz4bTG_$>Wl08`V% zBg=A2Ei`s;%(sCnWW|9i0c=V%JSl~LImtJV=GsK%ybwmf)LIwdr}GMca=xqNkba2 z&%c~`!rtXz$U5Gjv_onhb#=QTUhIY2^H{&6D~3y3q*R~k-ejS+Qx19G@%W)6Vo zFQ&4Y9_qrisTdkW;ZMBcM+NN%xZEV!B&-Cy**152EH>Or#JCb#oGMwt&E!}e z8lz;O7+Vo1$1d$nGR_1e79B?*bpcQ_nF1?-_BD$K##~c}*6NKb6jYBsp&yG zCY#rN?D>t>=qk_7_yakX0PP?QBStk=Og`GrwV$bt_b(P`Er|L@xYHvw^FkL~D)1MV ztBv=~reP(oYPav*WvS?-IS6u8-Sc;hh}S{tw8raHQ3uG~D8`)$hoHSyFqn^#>E2DW zw253F6Wk_|z7pBan6mSEBmS&reSIX*g~}=;)iM4>c+AqNFMHX`$ePB>BNNM!`+P*G z1MKBX7oLV3c-_Ql%g-@KRji;~H9Oo|>QcvwaU-lMq@V(*X=86>x#_}kUF;0qxK{FR z0!(+0A|qYBBIteKZWENG^YvmU+U>AGN1S2m=)c8;Z~|$s=0HhDUpj>p4ydL&+DXPq zD>wz~`p!8j$h)TP3UV|gNy9h+FI{DJs{eyySMrB|=MINB+aTHYXS zJbEvXFL49y4Xse!AGd!$?c&)9c);&6amdUM@A{|*;TVsx7AN`7e19)aN|WT|spbkx zhq;SBe>(6nO01H;8oo6FXdz0_a^PaY_`A+F{$*5CMhJ^zZ!NB`8q$8~XqOztN|)hu z33yr_I}4?`CC2meNF9|SD=^-X%W=-YlpWci3rZb6*-aEjI4ZcqYc6Ixz6C@i6mQ0fpJb znIrTZz^nH{;osJ-N%ny{;|%b$@I@-frKg(Sv+sRT*QN8HXjg8haQ6=!`Wg}eDf;dB z^v53itIw524wyUZ2pEkc&znT$ba%yU>AP?+<)K77gO*+f9K$h5qJ_Qk7d1JkUzR^L z;N^RiN2{-*F#_^x#YtWxlh4)^-W)hI!VFep7YXNkXs@%}>PMKvl^jG8gyiI%5YQYT3W;u@ z9fq8V1tZ6&<_{Sk5Zj(}ee2t%H{zQK$8-ekV4yCD)^0pZF>_O0k}dZDfR&9ON774X z1=`8^78%!iJ51M;kjm$rALK-AL(qUa9Yb%25{p@sm6PUkCSb5B_D)ktp?)p_|H8NI zPAEIGg|POQz4fgM8fLk`Lg_K)I=uj7xsxH6y@K~iPM#iW;Ro%wIdH&F7s|elPp%sL zmDVCxaD|2XD({=^!&A7L7)47l8D1li#<I3$ALMMud5Y>Na5ad$i*{fmcz8Ep z7}!I}jV-Sc0;rhx^%-e6Xs3)gqOOZT8s5jE>5-7o&y91w^Yn*51Qja*rC>!Xf7 z$_;9>0&G0Ye2w`CwyT->64}mOpz1Z#ZW7+UQhl5(8@B)HhGtZJ*0(9ids^@MCcp#s zBN=aLwig;m<8qbG5~h)U*SvM+0idl9n3}qL)PzDRVa=M`R3fPB*Jx*M4MKYZ{HM>J z08dUy2^@S{hl4KIN(Bm)=^h7dx{@1}HqZ`}?-@8mvl}H>pEffqp!|oGNK|L;3Jh;T znsU$yKYh}6kH4m%9S_UBzi@KK;?ipQaG=Ubw|T4%)cT zPHpqR*BZMaTa<<)U5WP~2n1XWal%zVWj2S;8Cx1&HwmOcS_AO1(1m8Qa6l4;M+9}> zvJ7|>v@f9~0BcyZMZy&ZsR&-Z>_Hx>60A30Y^KR`P94$iL8HFsRRMCKewe1l$;ks?D12bP*rF_O?1828CgohD zjrY(0nRzi<(3y>n_Cx$pBuov$rfhm&_Ac-kGb4q$BEckRbioEc z33U$+_`>JOvdmi~dD}m}^Y3H(%97}&i=s{I-FF>@8JtC89%Z4s;)v};dzYT~R-!?e zZ&=a$RNJ&30P;W$zv9e_AbB6Pl(ek?rEAD%+hyxTfI&!oT#yZK0^Z zL=5M%bqh^$#$Q@@8zq*%b?XRm$IXj^6B~1}Tj%CQE3TcyoI`bA^w^_P686LDzEW&( zQlmXZWiQcq-uH5_N|E1AI-CkNUwU2Ie@UXD&+LV+7ab+pc!rVW@OCH{k>MqlZXtS@>-beE#u8n1)>nLkr0wpV#(^?$Zb(oA{`AvNCvY9KlRWg9Pv8Bn z#mBJ3sN!l&3%K$?tp5J1<~uTK#h*i&WQVPe!4AJW%iX#`VRy z{_{L390YPZJqPe;9Qv*u+U>cdHcW(5WN!znyo#COya{;c#9Ft^9J1(X1RhI1YccaR zvOBf74})QJQ#ECJ?WbagyynadVM zF2*gx8so2l!zsZd=+3CIW6RL4{ya5yu@6qmyN)wvp?9w}G9+O_J8s2yKKGHR@*+{L66z# z1thL}@^jz)*qvXr?E@Z6QtCaQ_nc+(FRXR-av#VJsOUH_xGk8Djq6sd8Ic9@DL7Bf zA+#DQ&3+OrAL;@qk|qF;v7jCecot=xw%r~U=Bi2O5Y(CV4KHCrxM6^EizU(x)hNtG z1YPr-XBsmDQEWtJ66e|2Bdu(QibODK0ot^l2>{EW+6>$dhdPu$Meg)tgL9^zn7HYx zCUi=8&VsFn#0h)4<++=(zPFe{ z+qsd0uZs)Ag%yCFG)9tFqmvwk=aT#;FNuYmB> z-zY=kwixYh>QukrwoL94pxlmjEsp0*X7`mrSGieYU4p{n8?$_RZf~5*umIj@w8Lye z9--}Bv^SXe-cPc!l3@n&PF8TD3m^2*$Gzm8$9?pub^A^F-}_I#hr+?fj^6OH_nq|M zM?CQX54itvlfE`W-oeI-@TE!f82PQdU81z+BmphELCK#tO5+m$t*bhIj#f%i30VIRb9^S7=+RRI+kpAbj zf1dNzf7?#@da7wDNaGX0Mr){+ORbm(+z3WMMI(hZf@hR^*O#DTNc*sKr*fm^<=;xxv-z{!kkkDPwa8P zyKF=LQ=i$7UBt=dOmd4S?*6(@9KZ2^)9=}D@;#qFZKQnRw0k)Dsqg<`r#;@j_10S- z{Jl>Kcx~)Lom+Fe#IO;p6!vnZG_dVoxWo^t!zBq+VJzC~r6j>zAJnT%;+&Pf;lP`O zU6ptSuGTE2^oQBN0*&IjyTjR(Q#r^CGtL_WY-9wWmZQ~XBQzWs!<2&dhQC@voc1Si zIH9*M>^%)~6_i|40u)=c>lCD2s$n}w-$Bg^8WA|zxI|->jtNxL^~k3DzU!{L9{SLS zW_sB}4mm^vn+|YPsA-jozy_gqtVliwsW-ed!r*~fQTjM^@cdo-Yp9|k&pczEAw7lz zG_b&06Kiw{SQPCHnv6Q2fQi#bC^e2OL!#YPMzO1q&tNgO4DCF#u5WGrP3~RBUbpt7 zFp>V5{j|}F5yDX|U1?0Njm%jgbW00Qk-~TN^S#)TV1Tdw=Nb}iikC#szdp48u_UPa z8=$`1>-U{__kI<~Yru2NUtgH`A3Hzi9rxSze#gu@dg8@XPx;v_*B4ZSy0|x^R;!1K zxW${vSQ1=%K8rfYieV0=qw%e2cW}RViVnHp7Ry3=9n3S_XvKLK>uVrw>1!t7Mp&Vl zG0Y5V#(ODosZh40KM`ko(^ZI_Fz`fNqq5>m(g$c!PT%?#HCYy}Dz|wAm1-0Y>Q^Je z>oZQ%dLa<)`kCltYCcIm0Ix-4hEdHmy{7TT_< zuiH#L;pLp6!_HfSUWGKyysVPE=*G@Mazly(M#~~QKootOv||>E(4>qGXGE)7quoI^ zxLC%`r1YpK67wwCZ3Tgh#@J}bJjTQ|QiXQWqPs&Y$Bh8k%u9haD|S#QV_^Zbv9$(ax*|Jfa=kO3dZz{Uq82p`5myykL?F+ca5^BGF-}1}qF;-yfuAlJ zVqQ9*yHlxIpk@Q8m_PH;aCo^`WTB6pb*`LkExU?d5RL|06_;t7 zsL6BIJiHt@)^()lvrah*4ctrLbt1fagP8aINwrt+GkL46w*K@X$I%U1HZC3A*mx}M z?S-HjAyeYs)lk$lU%>Np0=|FDd~XefT}mb`CRVkvnQH2g1`7|Lb4UhHLS#;;$ojl^ z@#^z`hM+!oYEzjC!KZ=>uo}8)6-%@Oa&E+2ueW6CyC4d6tmWxZQ&Y}FI}RtJ9Rgkl zfta0Av@>+Lrcj6XF840->q`W=)uip_pUe0Her~`0_L*MRv@o_{KHmmym%{}DzBpFT zZcmQ*G0Tid9%p3<2|I%OAu)nw@#qAR#{okf5bt9*lP(au5c@fIBW(o@|tucpKD;k9N& za01}8pYf9h_1M#ZFKwqL8os(Uw3YOhb;@kk95a7_Jx^^$YBd@I(O$dC$)Ype->CRv_4*ci9GfS`|S#!ZOB5{@-%k-Ow z{WM5F9a3&>XoK?{S)hydLfdP!(_zh);9RdqOpLjxab9oSfoKP}?F<&guIGDYf;No6 zeTDELq}yoINJ_P6DzF#xND55%plMgm>-x{>%F=UaNrxo;UZdO`ggxbUsD0b&zT=KN z?)0p;eQA7bysH3}cYVPJciM4#NP4bE_kyZBV!G?~M@2u6dY&sWuMjaRi8TiQ60XO$ z7_M7ZZiI4@4^MLV&o1p42@Q@=nW)@447qD=1bpfU6>BUSMKfD_?L7GlA zE=D-sG{`1DQ~xKJO>xtx#OU?p|xHshMXKSqIH0X*-R;=$a-G>o?vt%I!?1?h;TIf+YT+edj&izNKh? z>I?VYX~!pE&#!Ion?oh)~rYu4wdbE zhi7Pt>m@s#9AlF7uHy}PI3`bGQE^K$8C7)f|I90; zj2d-Lwg%Ki2;Hll_T&rd$!W?XiWwRy$}A2@U}@b#uHt#s4(7FA`qBHI^}t?w*#~ZW zz!~qWn?+%{?CcXRJHL++%4+F0>l5YTC1K}#$V$P#x-&`nA?cdp&Bn=F3%y+t#MH2y zdtG=mQK-}K>gDmZP=IZ9oLUg!3k;MR1MSAWvDlz{qbp`a(`Sa_?9|PR{OA0Pd`~4$ zs|lXW5~sKh0SAp>FZXOV)05R2vq!?-@F9(DB+7o5!d`K=-I|yu zOZ;{_?72mp{Qjrkv;D5Gc*ZlH&UBGO;c><}*PE<Y7>{)5d=8 z4=%d;g7BAslc!KKwd+g^NCXyF(mZHxWjeaSYh!n(m{rAF&Xg~0+Yik$+a$#lX!{m% z?0uh9HXg|z3@EfWz+j?9N{SU$0PQt-AL3M>4LW0Zs<#J^)L3V^(J;JIYV z?2*`>a=8*EW>S7qIU2Q>%?@U)8;jM~>(tupd$t&JP8+zw#Q$I0w42=p`2ZWbz?QuI_$&0HJm zZJ2raaI|X@4;)^(AIdqPe*T0DQjYN2I=$?3x8CXt6W`TcO|CvVt!SK)y!XAGkt6(N zRIhb(Y8c+V#=kY%75J4zaDylDHrP%T9heWZ%erNZTQlIMhw1I~sg4i+Y%6iz?W=Gh@`uB_B=%D^O=e$i|tSnf5&0T~g~l{-+*N z6Vo769j1eC5TfDD2o}~CeRU`&UvuJkKr#sJnYkHb6$sIFobO0mHmRFDgPaz5i#omR zQ=YrMNuBtnV+M`NE%VLgZ52aT$zRf4nx%t-AnfH`w*zK}KN@1ZL|cA7I=^-SuPJr% z$;oRF)f@3XYaM&Y5y^X?QQb^MjOA)Huw9+_h(2&F}aUlXm_=WT+Zv) z@y?PDf^}E*FdRRzK=e}3TeItxw5Y4;M8?tP#BvNLZ#Y-lz#*Yp-5}{*2l!%dv#GEf zO`8bXyNbHoZcIZCFi7u9juk%tDo}T7vMSLxZUF+>{y}dLRwCwWrI{OvCug#PoZ8ML zS_0DKobD0Qgpe=;3DPk?0ES={+<_tN+}iKFq>)~hQDuB+r{0Ld%5Blz%~(SBx%j(r zNiXY8y1Tb~J{;|?4vG2L1AEnFY{HrLb{@xpN{eItb{OHl?d!a(oH!8e5C>)zekpLF z4Nvtp+H+Gx;hg|B4ZGW|xE3_fuK%-cGr@1Lb9PZjo%H2jgWJ@=<;#nCvo7-3n17NU z0)7Y`HEV%37YJDZ=>N1uQ>pWv2`3Zovdi;7FhpJV#mV>V{?bq4MfZWvd^6ird>v!z zS83`b;Pj2%-QdhMv8ZSqPTPGerr&d!NK0F~Uh~u@oK7tr$5@!fQj&U{)%2?Y>azNo z-7WoXl>MMuwZlwKn!h62xw{?XUT~*IYr$#5W1EA;&{xR5*(NxnqOQ%@Yt~NfcamRf z(qW38XZg|g&LjJb0A7__JH2eJL}(xfxxLoRo7_$p240hP_yq0h z^F_N`aptp#_Sz-6o|Em?A_2z5vl)4}*&BxT@boBYl5tZJ@U?HIw~@BHt%`^h(&kI! z7_{>f;@=?qiG0@r)qD7*N}qw2WY9OK4=gd^#K}_#q2<^_?qMTXw@e9Etu=n&)F@JVAISF zVILdk*|O<$uAPjl9Ml_&Mqs<;U#Y#_1p=0j0x1L7!oDsBNV3ek0fUdgjFg_IAsq%d zXABc}i=K3NWobJ%N_D!%YLZDXef`b=@;X|(FTGOLEGb6Os7)a|z`bg;bL1G#;RPmh6$8np@ zzRrtn+Ag1h&w}%TQ5}eOQ?fBeI-k~A8EX}^+m)nGE3njo@y@&NP`j>6V;-0_Ex$MY z@eYnz4p1j>UO>X7%kBbo{?*q#xQrqIQ`|C@WeDU8``Y;oWa8+m_a3c5Q5h^yngsu; zPu-={+3KAK{t{JO&C&z)y}z~We)s>|cfRB8IdvqhV7|Tu&5jqk#IDSoh-xhx3=PQe z^`dyr1l=xS1tXzyt*cPlmF#-!nQe;eh{uc%1cw97T?uAVBXG<&nV9*j!3eMx;96g+ zk=r{u{3YNwsZOMtnK`9)m2Ftp0iiJ`=7&i&TSErsVdZb3*nBs5kT%-&v6IBHvdq8u zXj-n*%l^aO&+jWWBnV+iTq8UaX(x(WM878bV_E_1eD{K+=NiF5hRU#xkdQ;Jp@DWV z-+mW7qmq$q1>f2iup02L$%?@v3`V<@yk{1o6L_$iB~B$on$0}OkRx4R&}pS*PN-{m z1KzsCB-I6n{skK!N!@#1Ts)yTUp+TGVI#`DnEJVw-(lo0soE&Sz3?t+#8sf-qRaB( zc!5$FhfjR&poerikKFzlpFjDo+8_tocYMa1*ay0z66=C~mcSbpuiDoo`3U3iuo2cT zfIG%;70`lqlU_oiX`xM`^-aiq-Tp9V?j4I3VIPU@9ih!vm+wKYFHBEyZocM z1?|p1Gu4%WisWbM1}E}e0_=a<(hDaQ(e zEdCDMECe6pQyu=nzcfM^?14$ItI_azRh^ZgTImg|!fg#C;&xqHLC54U^} zE|XuwUc2C`xwA#MD@7=TOL%{ti8%jWhAC{2dLo3{0>`0}OjcWFJpSFW!5c+4hgeC8 z2`Ss!QjG?=im4XCswKqYfBoS%?oTGvagw7jHH}5BvneOdr~i7$ndYfxDeoQB>v?a) z2oAiO-UREIeOrim7Ku5L6Tkphe7H}ZMa+uDxVtQAr@r}KQe({V2vPg^OxOuEVs ze>=QNx3AO1h;^37AB&SOQ>{ijB!~e8z{U(R?c6hnZw+s5Y!13o8xL+dU)N+R*S0q* zxRr7?B>-gF8#w2}Hu80?@jRl(>IL0^IWSMuO$OfRKY#AU^Pjlg_PcjFfA`3pJ~!b` z$vZJHJM8{C5}45K5ww$W)mO+@uh!JztWiTC4ALzGh!RaN$=^ma5?1z)55$LdT zfd(Phg1a|taH{}DfLkznS}_y(xui1kdF&wbp;=~wfuEiM34CXeW4Kt|9bshcY|t9p z=rD>LCI{%Mw{}zMmCp;0YMt22p={Eor>Z}h-&8ih(=3RbguKv5D9PE^sV7II9jm)j z;HR|L8Ko(eoDM8k+leVLr<0s$FU28@x z`oxK~?TxiVwAU5F6?b%&RiBEclBM?yKWm+NWV2h*4HA?lC!Hr}7Cb*^{^1|~;lM)P z-}tGSk(3UJ{je42;XnK7kA=9QD}LD)&Ru1=i;P2#Y}hPHp80UFDIt1^_6AqanuQqB zpgExvS+fFK<}ax+33@VhQk zr}n;L=B3Gvc>pW{r{OeN0HguVeS^TpL`W?ZkUd`7o+r_A~w+f68g$0~mWVO^ z1#4k56?GDJToP2#`CevB`$?vkea?>CpD^z$(BZyjb{|AbJ|Mh(Q3My@i3sc|G-c9m zr$l%z_cSK;P}f?C#*J7Jz>zP@Y#evrH6jt~_s;9%7W|bza~k;X2=~{^pWT%*Hbu02 z{Vs-j*YuVvtUmu~9CeYgutIB1r@A zE@Yy;LECc=M$zu;WLPBNjHf5_07#qBg&C7*_bL;%0DCTEt#o_SWHJ-&&Ivj5zb@Jh zO(!WTXh(W?uXU(8C1inKq`khqI`g|<0;WX1>+OK;n2vNv>>!N?p}~Ot(kUgZ<75sP z^W^6x?6uI&&;9q`Khw)HVxWkdY9~sKIvP8Z+p^*$??AKesG%%otN{)%qTLqc^J|!~ zLgj!%lj|Fac3zDl7$lGuGE$XUk;fXX6m^YwfzF$RN5^=$13K)w5DQ=FMuS-!<~b|C z2sj4-u`Se;sbTUd`k_Ru>LsRK2uSPKX?Wu&Xs2@_e{Q^;qB)%p;8y`gBWZi%r#dRW zA=g&GMV~mloOy)e=^j@X0Iy+;M3F&|_5ZteWREx6!5bG0i*};uIRn~xoaaA%$Ek&x z-|I`i_{0etx7qdqUp(|sQqxlztDf4m27}nA;RrYo{59I?Vb00=-3>%Lb}u;I$oh(Uxu}%&uCgYb2y0V0;4j9GNgovc%6R~i1URJ7@BpaS+s^gn9#bXG8lmOy z=CwbEiq@b4+bHcasRj?lY*@c+)<^c<>w75bI-Qrk=Y)40_zMDHrd@V9;sALa-8w4w zfvsE9QotFvtf+CG$C7s*iW`koC;_d-rV=hgY9B;ii4KIxKBX9nxN-$nc4#q#jF ze};{)2XzkMJ0$*%QUe~4w{u|B-Zfxe+n9qdVb}IXXU;!=8XL3!N2kLk?U`QISTTCb zgoI!UGnQIqRfbN!NdjvH>Klb(9TozGQ-7isWdY(6e!A16EpUnNs9Wuh@I8^X3u)uk zcwc-=w0V8r$iG-G{K+wGrU>90_pci5^}8F0c0ryT3)?@0Lt8Ic1x__h-$5>lTRRS_ zy1Vih9KlG=*?w`|_oG&edETp81DGoW+e&c4uK|VsniX^`HVL~Wwq69l{L8dp z&he(HqRpB44UuGZr$H)EKT=BewgGhe^g6YJ#Jq;qy+Aul2B6I)lAcJ4U0D!%F=bIl zjX=%GXa1bglc8&z&tB15BZXdU$zCNmhQp6_wi|}jCG085@4x>SGrjEl-}`RXUtuQ6 zHA<9m27zM9Mbk6w3es5lsa$HUnc4FAmuB7m)oS%sqMgy;UpMNdzQVjaMtjU99=Hlf z-sw3vf+=836#o4y(TKbvLe!UPQ<#1^Vs#NN84G6hWNLzKnVCC zs#W63kgKa?yF9gfvpK5rSrMMldy6l8;R`dp?1Ym}5bcs&Q&Xz}0cIj!-56)onYSwd zEz{T00$7y^PqNQR(5NDY@n<}}5ga~O(JPkb5JT2q$zPo33_t0To9!x)b6%N(Z@Q5R zd@)Z=8p)dUgx2%|YKUM1(O!p(N<$3lkdi0PrRPwy@p_W>JhZ_~lqIM1Wzjh~cj?hW zonwf6V}m=P9-(QA=9rWkgn)CB;WmVAsHGelAIN^}h+MP`eDAsEo}cJ+9`cACAGY1D zFWGfhL={d3S9a&-r0wwYN--+!w3fRAeA>*zXRc>RSKd*Z(BA$*@}9{8B9xd6wmr0` zWzpeHw5Mwzfalg=KB3NEm{n69ZEDfX9uL~vX05KoUMOuH{^@!1(&bATKiWZ~VPW;^ z2$6>lON!AE5Ru}s&=uz;U@>yG4KF2cQsi~w0TI-d=P|ZNg6C@Q)Dkj$GJ5-T=`rh$ zvx4-p&)a(I&7ICooz62J{NUxwmxCWIAc9b`EHM|o97siL3ZE6E;fZ#MHa{iN@?whR zb+d_fy5#bT9g)Wg-vn5jtlKI zyd~ohEJ)@?;0=Hu{pd%#xH7nqQ>0(cK;b|B@sEFiy`r|cKPtMH?7mw7wV1L+dl%#v zT$q5@cb%e3F9ppd#1;hd%`sb7w0pa0W-ZQzIY?Gf|U){4K>vO8;4?5_eOfUO{Cp+x#`vv?X7BA1?J72*o{J+8hiozzfny4{CWDx>pbs4qFo0y zMhe5B7Qs_aIpr1j%9alcFvdmxwGO6454eh3z#wR~&X4Y^D(#dG{F%jmdS01`f(9Y% z4r`a!zQ87*jyxR8&q3e8&ykctS5F|#cHHHn>6w#X!j4peoZ2?Moz?Y!WObGFcSG*$A%bs}Ri6Dn{mf(|!FDUsQB6WJPciGdVg`XhPod0!#s_x=-+l~AM$TwegmS=e6$Uf53f9WmX zH#VjLJw}*UlXjMYXcys;&b5_3txrO=hU8f&IhQLnSqx$o47`5#d!}=-OJq^V0Zw*? zM2xpM+xV9i0W-UHbs+@iBf$$!wJR=0?gcrJ@oq+~t0!RSk|p*QqMZd*S0C=qfoKOC zJ8aE1knwrUR$Kl0ieH0pD&Kk6pP5x0==9>{Y3}AEXQ-fDqnP6zEvg<zPMK~&u_mqd&c z?XuG@D=rN++Ub>Blt#jwk_3{qCRZ8N^7U4y?FERI_2+XHQ&fSr>t~jQTSMv@J&A-X z8m~s>2xJyQ{j;C_>^Tp7;O(8xZD?m7_&|O#fDljM6bpKZC(q&@8zzU#41YA0!76Ed zHEW1YKFMp)2OaO|01S3Ja$dnlC)v8hy>7Tds;);Mo%iMD!|FV%15yr7{>vLNK>*8W zV-5^Ndnh$Zq8P9(ytCA!+(;Vh&w9gSL&Ti=d`Dh%GNoTU2lB-@hHb2Dftrcda&<6c zj3&KYH8|5%!mV8%KI+$?b7-CbvoO0 zI$!8?cG_vDv(Gu3%JTd|TCa7l#p1=c>{-zEDly*wue~>qyQHe_y&nf6IHHMQt{TLF zD9+-5GHS$oz2b^PC6qpZofJs?VpoYS*q^Rr|N*wRY|^!$2=6RdwfK zAv(N}-o_y@Eo~$MMSz+vXibEcak)Lvd6vXXDTApX|8yBpW}y|Ay2#Ni$7*4dHDs&S z)Bx^!;1u=wWk{ZlvZo~oN^--Fl^6mQ+cxWUYdQR6+5mMzNV&EEH$vHn_%K1e*_Jem z&&${eq1QkVAsEZf&kLau{GD>j$yr_&ChrSOv6sJl>Fi zvT`fZfiK^jpK!%jE==Gj&WQpVt^-#B^=kT}A%@|pogvGlahJC(+6U&$+)M?MG7 zEx8~`0BAR}1!mshysQkI=E!^9YoC4g`QG=wC)yS4k>TCvNp+~Q104x!SU7wO$pTmk#VKPGB0K>fJ4?Hk z!kfHR(`oW@u1YDuU?iubp$b;@;n~TtAtlyg-ns)L0jtP(G&Z868zGzQt_5{Vmnlm# zQH(7?)MSM44J)+KGu?U|V=v5;4}=iQjc6lKIc|mHniDWh0enOmuUJl0JiVEIOM7m_ zhB1lXjH2PV8QR>7UnefeL9|A$HiC`VHBw^W?QBM{DlkU?3`Lf9T*Y_>zJ>?{c08a3 z*c|)3=bl@>_1kA=-uJ%u`FepgHhd(1;AB`1+|^)pgYcnfydU;OqafEh5P_1{U2fKz zH)8xXOyh&uRJ<2>&WsRUB)O%0M)jIUwLO{Yo1 znI)EvDFsL(^?GOUE4Dyp36EjZlF7tnF8*ZCEv9f#5!FCCK#nZx#ARADYmFjEB-4z> z*24&HS#rFc$IUHnz1b=hZepH3g>>V0DXSxR1Z)!+gS@~FeA00DL^~q^w1%UI_IdN? zf%Z4g%zS@l20JbDV9U(Rhrs;r|NimEAI~X7dU{B-LoB#39(=HTrFJ_#^FyCSsg@_& zc|cy8aTg50SQ=xB8HVd#h4foumgL@U@^d!ct?2_{gWP;R-a(x0^k%3cPcf8cH?0LH z*nT(#NaXNL0zd_$t6l4^&B}CP4BCo-7W*2I=-gVxf}j35WyNAz3L(RF%$eg_ZB)RL zQ(|6UQSdrq%a<&HMt}tRq<=^QXD#+(&rk|L#enVBUujl$4yx%&u{QPaU+mnO1A{Gx z{@Ys9Z6H`279kcwUmn>CI<~JqwaFN_}eXSz^a)x0*K13mq ziR7{~N?g_(m#B(&g{GU9U8p>tSEYT?565u}kko{dQTe32F$E=FyRKG#xe@L0#dK|3 zlcl!V(XKVyX{vXMcVv2|?1i(2d^xSPX8B+BWP?3LJO9;7(d{Rhl|9pptGKWBEj|B; z_nc+%7R2~mgRx=bSFQvPE-V%1?m_v7M7tsS8a72cw>b9LW1skhCp`S&4}b2=%$H_n z{&&Ir`k9#%XJ#IBm%DuMuRi#NuYW_d)81r0WgNzj8$Xt*9;C7pfW#Iqx(nxHoY%wv z+5xu8IhX4Qw1?c0je9Wn2{ERDURHYWzIm26X`nF&4d>3rcEx|qjblI815^A4=lH#l z10e*a&G6MC*z@ws+1K_9dO4L@w5HiO!VDT=3`zmsnoewQgZv9G(akrT7^|b)$xyY~M^Z89O2Ut*`}A$5ThM1yM=}05>ML4QJ|2kgQm4D8?{Q zSj@CxL*hvDq+Hzseq7F|6h?4YO-A@slDzj;-8DN^Zv>M})i)335#u`R2J$rKpZ0Jt zXR z&_4)d>HvFgO2ozUp7%WT_Lt7ge5K3@wtt?PLCt&ogC6#gk9_2iLk?k78uR^QR9fSa zCTdsQ)V)M~C&kMnPY@Xs^$Dkh6AT(3SC+a$t7^mENNW z(ioPeX%fhVu`-t_7ECf7PR3^8s<0o40{fl((f)GGMkQ&$~oN1uL0_eB>4jdFtup^cHVHqCr>~9sHZ;l^)oXo2bf3#;xVZICaP~8+cK?1YepHowv$(1S-ENan$=tA8bZz zOGC3IN95afLK|iYe@)|p8JWDInaF`#wv;{5&S%v*4E7|@u00@D^Kuszg9O-^KXyVc z_+Xw;7)U|B7?LB#s~ow(|}tLN(kD) zd>uH{DlhxZuQisx$dKQ7K1HvFSrFJd(JiHJdv*m8c>Qrf9kE**H&g61r2cWL#@oS;os87*e z-sVmvdFG!~Jg8~;DjZQ6_Eg=#X4=4Ov@6`U`Wc6IZY^U+P)8LH{qyW^gKZ@FUU;|G zhtA-iaAFPq(hQd2aVGr0`7gWdvJ*}?;gAC!{I;1H4R~zl&CI-zO0`EG`H|C4!O5>` zO^2erwYm%a=zwtXW*%1F4l;d4$xUXhf?>ra-gfRIN2JkCwAW|zNaW1@{5H5KNb@gF z6}0m!$P=!ub;y<&7 zY6GbW4Y(=CnHb*41{_bc+c{c5cFuo6LJmxo!3X3nu*a~v?Y==_-o!qYm%6;{Q=WXt zo|~F@uq@ob-9aXu>mx8&2y}s>4DsT>8Zr%82^qdBL1(a#0M@=}2mo9#(H@o2cW>t) z*QP-(O4bw+1KEUpo|b%pjYG3s%a`W8BrDScek^al_KIr~?K^ixHCVr*+)3Wa_E-qw=C1A@@ZE|K*@>uRbfMu(b1?FpOg%lSRN?X8EOzG$S;gGy=#`-Al!&X4`RPVh6K!YjI*O z1b#4QGuyQS@|$^=pxRh5nz6%KPVpz;`POu63WxNf)gV6f&u`-_Odd{1-V6VgXE0ys z!3R;Spqbrrq_^|dz(9oqqfb?0(aslj@f339 z%>oef8vhgO-RKEJ73wg=X#hVK?S{?fn&AjYW`^tBh7-0DydstTrtQ!Imod?uR`2v$ zL9$uzS=n+%%b>RtE~@oQv{P`79dM2&4{vN)?-2F5HbE$W{S)m*5J4;m&ciNXmQ)?~ zFSkGU+;d;{vKJnGx4pnQXb1BkAN(J7-}}7s4KMnqQh`t}AooJusL{@;CKILv{A4j{ z(axBmU)T{6Q2Ls=4bfO9mQQpekHbD+w2xheB(Br&Z`g8l4l|5-)bpxyJvDS2gC02EaRm zWJEi+;45%1IO;!s`jc5+_A!6(!0SH!naFEeG>;H~#VbE8<4LoGo0Klayt ztX|Qz*SE)2jI$N>G%Mi8q8))5`I(pyz2A7Yn5=-=*cC>PsDI;iJJLfQ28_O9>0@Es zX9BJ57JS7h7ta#$)e5ty>&y-Wb#mQMsFdmrM{hiHHG3}w>cSOQ#+Fc5jE{KRYcJEP z$FDY?7TUQmX~crho$=yho{S`qJdacl=8^D`^Plm+-+#}$PFT14GD8xeI~gg=wNe3t zD6*I*sj@sm2G3d~vz7FMGp|`dqSVY9S-H6o7Y58PXa_}XDMr>WycN5~WHP{uxn2ij zB+lzjnElf%gpkUrq*-Tp#*pP;=nWqd%oCQY&3xTi7lOBXDaEvJB{6cnWXO#JBcdjP z^QxH>QR^kj%@vx;hi-~kXgcA@Yyb4st@5(G1hQ^}^AC#58S$2YZ_M34`nIx(&PXVc zqy!m63y6jfg&I9`G%#pCP4OI|6pvngop1)db3ChADOJ(cK#4dpxq2GmyTXM8v2}bh z;3wJS18M&mb|ZyPe(Q2eaC-os4Q?l@M={S^*6x-3+yJB6yKYHYZ`{lnFBlJ*e3sl!o6Nv!3V!siKvMm4rgu_WhK~xOW zRjCFmT`>G1l-8S@gc%M-=X-XkVezLagd-srQ2+bZFj(>q4Sna$x6s}j2MrPIO=p%w z_FC!3qP@|gON~VBaE%_0Y)0|vN)yim`SGPx5kh-h5VUW*tNcPbkG?i;TEr%#^#=dXFp!H<9S z%*@gO=JD9!w>#)zkAB1J|KdaQFBIyKA)Ih^-fIXfTfY*4fSZ)C>W?*L&Us2q z?C3z^H5orQ#8QcS0aPdvx$<0>df;{Rp}tdCUwG z5a%@J2<@|!MegugG(c*YFr$|JY#`bVK;U-9(#Y8P?fn*J0rM2yEQWD_AB%RqFUEM( zR(A%C^v>+e2H{P;tuYHj6tp3yOQ|32ncxi@FEyAWac$GmE>^o}cU`(B)L}popg4S5 zVsF~EIt77hStV;ff^ZQPnPl6;`w)S*>lY_)ci7!koHz*P(Qz(5>+gDvmjdipE@7@S#a;KJH`u-fQI}!!4*-DnkefgN z%Rn^0JG}ji|EQcCOddJ8#EKv;(QU89(E)#yyI?{)aoG1ox|sOGTKUl_@_0qhG} zFdTR(E>h%zj1=UQUQ(l;Y^j@rH&qu#w`{u!I8$zvdj&at=22*!$Rc7wQ4sYMH8J@3hofQx1U{FDwcE&}E-yi2Clo}$!^ShMl`^|-BnxSkOx+%_Ur~iewz?xTTTbrg z{;ar47Y?i**aLVOK9in(4l3%8+kkEsiZHxqi1P&tv7*)dRwf*)GL4qLY;~UW2*m2L z(iF$#-lF?aRI{7odzxj~c=nU$uQ=e*`)7GsyzY4~9vo6Kq7;yDan+YB_~m9{NxhOv z^2VM(1(@6JBZON?#=t?t3gzKEtQ=bspzy1g(TGEO;Fp%XMt10d{q(vak?AJvzI+bW zYsHMqd&6oNnL-=S=Slt0W6`cBTrQoGe3mo@(!C9m95k1pmJEutgf+6*rPX14p-%nq zSWJiZVCmadDdO;@|qVv`>Pi&p=4Dn)!#&5mHcpIY}-j2 zWD_>3WmA^NQ;G&0gcj68%6%H(sul2XbvO1!)Ht+*s0j%br~n`z=a4*K4c`UK#Xr}& z>Gch2RZ2}ZysJXGva-C6X>Ebc zH+gHnT(1h$Nt zeWbZww2OQrnrtB2xsiR!+b0O{HIbT73&bFQt(Zt*#Dk4RyN+Cj($d?Lw@+@6XwMZC z+GKuEixMDVSY~UWI|z60#eWoaF9xt z^eD~gUD$IZxjj7g^zZ!x%vR;x${(kk^PyM1?j=Xw>z-uJ?kt$+m;Iyeb+12r;~Q2k z|0Yt5x%xHo=|SUss`^cFp5kQ$_OX@ca#iViv!D>jDZvQCvi7bSKys@bzFU0G>`QGw zfNEUrI?f^rVy_C_e#!iBl`UM5>E-T(#9p-A_^+yOiB{6e-P({#xtFRtzYGAr#MZS! zxqzIpDB#>Rsx|m`yOkW|8vw(Sx!1h)#aUkV8P9!UZ%!zUGch)A>PKgH0_ZoX!q9biUX?Q61L{us8;0RP87DB(`QdHcn zm#iS|oE<)ZCe`J#IGx1aRe$eu8bs)P;^j7@p zKi&BgW+!9ih#q)$;u%W)bI!)W!Ev+GqvdFMgBtJ=+*Z{9Z_$Ervc1;qqy=C#%-ZEQ zwrejlZ3eDLmb=9Xvgg{xMdOxeP0eOH=X<2tsTM|%f@+?e>=zv#@t(8R%Uhx)mMYNB zjx)0Lu9)aNsc3ibc*U3&812~Pat7FNP(yBRU32aPEnWAXVdUxlp=XwJxManGX1$~( z5hd13*`r9w4}M@l`$$SXXStp9awq2TP+F z%(`^_Eem@G#w4y%nr`0O_km=Nw9qcp|9)k2F3n58pxDFVBit}*s%2Dwt1|HjTr1iQ*y5{O zt~lTM@r9_@+4beo;FH@Px%IwTQI$Ji? zCJP98Ii`GfCrq00#2C+uIP*XM{OMU<_Hjo&Y{IkfaxAmO7#M$V%Opv)o}VLW64ZC^ zP_$8tp~K*36yYeUjWG!5I~KRdjVI-fbPGQpEkQLjj&hc{SMpRM-3Vbps9Ugv4;`At zFr7IrHHQ+4OT?B^ zoIwt%FDOsu4G8r!fAGof0B8fGEi0hko|qi<1%AyDZ1#72i<{=DR4ddz#-bh5cb&-T zDrNiu@34^dd8eiV^Tc=?AcUGa?sXGrp^0wjwA&tzDDPYQ)gnn|u=Z=$lnwZ;fmshY z(avjCdygQTvT`#tMa(y~vC8d2l(=+(lD4qtrf_&yeF#C|hihHbhS9V8Ete>~x|M!IlKY0JyxW+qq`>ZnxS992Hlw1KH9d zOMDw{g1Y>xuYzYM=A6KIoe_TSkDc?r$L)Pr%geHJ;ul}hy_fOlCW>2fYZ|m$PP5Wa7Qi%<_AN$8#Kzk7Mk1q7@JTT1Uhh0XqCZ zJ3a#bYs#Q;0hR!; zb@g7HhabCd1-J=Bp?5Kf{7%fFOmR_lk5^p8fi%ClG870w`_<;hLnh!6Net0TLwz$C z%`;`$mJGQ=QfL_q&871aB!AHEzNs~AxXM90yd4_{fVT{;7Gw5*aM1_e_x3j&@!$t_ zvuIy>+>6g!{N)s*d?*&QW>l2c=W#$j@;m}gS7~&{*J#f-EUP?g>BYQ(#cPLbGp5%d zS<*Q-nW1&hYM)OpnpF@}+=VXJD|T|PmR8wXTbBNn^FzNYRp0bK4X4VUUF3=Z6&_QU zQfdv50LfWy8#Z10=D&JvmY03h(+}u4=dEi8Rta1YtHDg2lj^IW!(Xfn5PV@_pCvCoHCeie9hU7Q5}^> zV&XE}G|}ZR$mjMz-GX!M{Q8WY9^ma0rX3UL-!?2jzh!Hx^A>Q{PzR!D_{6Iki^|3% z&`Ac)Rl+ltHpk4VR_LW%z3m#1y_asW0%F+99&!wN<2)Wobp+~FT|s3oTl$5!zWL9N zxZnL+S+qy*v(M{Z`|71%i&BSPj?|zvo?`o;ea-TPuzCn$_f>0gO)H(O8}6Yv4XY0u zbydindDg9PK0V-ZyfbAJP_9C=6P_mg*@lx%urVBGzE7Ch}96Vd~g*IyJ_|g@{1$-CnM&mZ? zt_&Wei}uDrC~v2}?b>0bk!0_mU-T8U_gF}0&o0_)0&D;eu_&>CJjKehPkO_vUU<|# z`?RuXkGS7`-};v0&7y^2fnhT-89=V6)^)sW8c3t46hEJUg+n zRrB3dgZ0K6lRt2wF+Ipfe8PSAwY)55`M;ch+_-0~sf+;#)1aNWeQ8-1sB?V?;GM;7 zQhAXw)**>RF0dI*G!4{Kk_X9v77PMC__kFB*yo6Gc!mJ6qe#ymZ)_^G3+!~NXOS5W zT9=Ab=EE3%GbNrUHv=TSABN~rgji0cFb_-T^T5;K_Db)8X9|Evm`xP4GSx(vc(C+M zm&w?J25(wgEA1SKJe+HyJr~N2dw4sxx{As$n}fI@*bffM-a(_rd7c!sYj5WkvA;9c zghKR)VU#q!uYUF~UiQLcx>>Y`Klnjr(PDJ;h2+9`h%Ma0)oCD(NJFAsClCqYn!)%L zCqe?@c7lt0f_Jy|IU;|KMOv3cb?WX`i|Y*7+%-!?8AXz9 z>*BVY8=c_iv$O_}6ThXhIQ!)Dn@-Qhs|eHdX&=w>vJZdK11FF(hQa&cEg^sa*Sap% zxT}PES}|*r#5ltT@;p(AsoK;a7wt%4vwF^XMYT-8dPcj@3!zw4_kY#Y`ul>k=;hX;|i< zxh0yTU`=L{YJdz~vV^9Yfn%g92hGOGZV@)mE^$rorL5Q+o-*M94K(6ci^HsF2kLBH zhlPxK+>MauiA3hZacwg5bgiesZ(JIZCJZa;=yI3DxT0&l@wf_7f0 zGQ2@`ziG5PHKF$~^L%&g0}{EMb`;Q+X=JYEn>Yub0$v#&mwQ7Cbkr3|UM;;waubPN z1@P&~A3^($t6&94*CECi6Pb-~oK+AXJyBLM2gU1e-wMp=%= zY`W!?)fuo6by2>maQ@`^wlU2%!}6Md+=-bvbPL*D*%qZ86CJj9V}y+SVS`3Asp)GL zhcI7agtXPM)5H!Iz@u)kDJ(>li<0WIee2a9`{>DsKkl*JEZRd4eb`@r;>4S8BrtX- zKKTal=bv}_<-^4Tbbt|mf=Hh}VGha)Fp2R_>RgmLarJSQxw?~99Ii#(673+FKbSDU z2Cm3HRKPHwL^;!7a_vd%@T==cku}k7_6S`m+!~jTT%g@O@J=@`aN>e~U2e!wTb z`_}Gb>gPAIh~b5wZ|CZWJX`xQmxyhdFw=C>N+2~PrrUqo;f>pA@pJx*i_QY_VRyJG z>SRv&EgZ8;H7D}9%Sds{J_{OT1>!h9mhOhNFja)r43%TD5^qB#W)n#3%5&2Icy4V5 zq4M~;)z}rfV8Rh<2Gr%@M1~bs*}(pXYa{HmEGfgx2I`R^Q%vh>^^J&LWN9sPVBY#R zbwF-Ul>XorJ_Tc-XNF`fP2FDiJHB^>3+jAvN63(?HM&yOP=hE^iD<7&*8c1F*AQKM z_<;}UX3-vd?EfGpx48sU--=MI1h6JCOmxs?pk9ZUdDE|4xyoFWDJPcAnCLEMHqJ7a zb8bOrsYzKS6I5R@0U@zW@-L&b6W}D%OEpl@-GhmC%RFcv(y$D+^B~CA`6MAw(}W7p z>{WmA@+>d=%vV1tA9jMIopJK!(z%L@JTr0LE5MJFz4M(2V<%0Y=+mWy&Gv0vU)*#ED<;GC#%fE*tw&r^*mRrB0UGM`0h%wXpVTm z{;e!p@@-!I%9meo{yCU1!nVI6B-?dsuXK3ngwsTyV}^@@_E~dLa$;dahM8ktiYgby zEQgV-mrO9*u%hXRYDMNL%wsqtZvUZAedwFs`zFxHXazP(CP39=1ZZ1mx3q)8xgjF# z3vYT*sl?Bu&q>Vl`?j~e?Qsu1Aj`|X@e{{RL)y|ZU!y&2IvdYt{Jl80+bk?M>s^%O zbHT=N9IiXHUJWY06!XLk#dM?AoeOWpegIEsQw9i)gBamSL?2nRU=rHFSO#yw)d4(W zBwL_vv_8ZnFc(ME?Lm9(?%sa6P*2NN6IxT{$>*|=KwS@92-tQqP}lRnIUXZb;q&95 z-W(qU&vGH%qO?z-4x;_ccbsNKUBug7do4Oh_@atI-lZ?B#?_{tgC|n^Sh?bx$N%w5 zj=JYPT3NJ5-0Pl)z2vc{ob@WEBN-_G0GpN%6&aM zKp>$_QCVoED@fySg76nSC_^24$d%%7}@UF_&6o$6bkV$?~r(v7Ox2_D=@b(VV zcH|L{S;Y9+D`Zt6x|--()S*Fdxlu3L!)U){4VyOkhVGO?S|HZAONNvIh=KNI3a(!I z`47JORWI*m(H`=9cYnbjKXu)r6IQP}zs?4Y49zle>sJkXABT33sag)gk=twM@L89f zO3y8AzfQ5P(GD9)Ru4-z2A&<4D+Z`K$sj$ENVk5T(Qi3}r68u42KI_mjh!%qEjp&k_h*REv(Oycbf zPGP{g(LiTJ#m_@OE%Wh?`-vnK{$T zw0*xIiVgwW>}V%9BV%TZiEe@{V8M*!?Ytjsdk8q(B^=->v!wZ;C?*XF7=S!qNNV-t zvS^=r!2Tz{<=8bVzhr3_B|v9wb`r~>ubXyM|MvvD2&3%}pS$ZywkPs&zq>TPYj793Wla zTKjG;P=SGyjr3uJM{^?7XX6bQ4xyq>7DMFQu2}`tY0Mm$w4yV!7POB|fT3b8VsN2? z{gD3kl4p41YSa=GeQff;u+?q7$eTvdm;!Z|ZI6ZG@rMn{U5vw|%7x;?tR}i-yxtM& zFd6OXb!Ti5;aePa60ar-Xdtryaw~93$kInxztVbP$(wK7IsbE??aiV+>QN8=oAJ9b=oSuY7wcJblG!gV|7GUC$M=jFIiM5HrNJ#mot z!A{;zOB({SMP{^(0e;XW_zkBUCkW^>Q!l`hDu)k3wsfiS_AL-`DtpsD%@#X@fMP4& z)RD#c#;m#@P%o)?K|4_IN|}>MXwN{g-qNe~-r^yxkEEVY>^fTOgxVFo#6sDjmy|@o z`63*G1nalCP@HsO77g6WR@(*!yn^=0dVBr&lTCEqTC~q!8csN#J=UKXpgjt2T)VCb zuqmt1`ye{x8?OP$ITZm-|6IN$vuF=Jzf zw3a`aqp|#G$+&JY_Qe-{nXR6_X^oqJ>ItWq(|Oj#VJ^IQh1scHkhJD8s4#3+Zm*jl znW{zRUhw*7XL;EpUUW#ePhg345VN1kKUP31NoqbYq$iCC^*(Pe+gM3Xn`@nJpa9P> z^tx$CGruje56ezw-KAUZ{AG&(XI+gWznTVrx}B5kj5&Z8Md2{sPhHQ)ZYQBVZ!CN7 zXY$2F-!&=QUPZvwT_U=BN)6xOnTb+ECYD8<$@%A{l#$y0teDRRvpU-w-ahb_p|rOO zT{fI~U>#7B2kn^U@y`Ku!{%v*Louq{8nj>hf~}x^rIMPykTBbo^mx6SuKxbtocuvn zt>|XaKJ&0Az2hD4XcvCivkQq1bYZUJat*&0SMj^lx#d)%9-zVI{>eas=zOk zr_dGSp|BLJ58=Y9bQ*lyreegeO1wNm*X@)K7nivsoL%5H!)Q zOAo}d1KN$u(Oqw4X!bc<@7HZayLj$O@8g1JB|UY>UB=S!Xk8=rMGUxKosho>;iHNau zyu*-#3Wsleii4YWSB$RT39e}!{{H>CS+s{Ae%R;EJgsgFFiie!IOn#_s_V8% zgHx|%&iR_6`0YTuR_>M-z+e`gAB(Hzag744@6IHqn0y@67FCu**Wm{wIR25(pOEEc zA94SCuwc6bt^o;Y0LkWu3u(}vL4J7h4BAP~pZj$iuI0jU-usp+)RHfZ>Ph4acplAl zqk1R&loBzOW-!QwP0ocbH%7d67dx|~o%>}RD=Aqn>X=)oqo}4X)l}gVlm0M2T-&(m z=;M`q5UyA|8Rro*S0ZZY$^w#@-<8HETjs{$*}+fN@bh_r<%(~{Vs8o8uI`Wl^Q6Z> zk3f4=vnfTUjJk_AQzg#^;7fJ=I>)XdF`ZRVTA$Eln9G)a@vU$9^KKUH5x?_0&wu{& zmwuzMad54rU7~0Y9CF!(b=4$3H27&*=34VL#DM{4o)z%uv~?RT^O-lsv|*pYu-1hL z&r{6`men)^5(omKU3nxZ<4xCVW|v7!;M*CDn~WhEZ+## z)xfr{SPbBkY;|=9I&6wqed27`J5Vv6ut}s zazPWKxAYrddEKAG!_(o8SCr-(7y8Q!1C5K!;DpZs$y|mSwI5o2JTDF`6=~ zntWB0%!@UyWuh0-vTn^_u8!z?5bcbobro8DYoZ&I;~-m$%*nkU|I~wLEiapBH_Zmk z92hIQTLCJAd<@_*;D`OXjgtIa(Vl7i<$aFSoD4VHg%?=ddRn2qqJt&~QFl0s{|}V1 z-hO7W(s2#ioi;Y-Wmk0%H}baSEVK-aBYt~eDv$QXn=Lnsg0LHxg1NR$@!x*$eQ$p8<;y?Ge4})q zQ8i`=M3PGTpnnL^Uw`o}Prmb=>+-VN##*Ebv>UEtvI=3mW`hcKQ}Nhwxrln-mbNjB zr!PD{Fg#9@=Y292;gsew&PbN+435h(;HOZ%Q`|Z?I!r56oF5lxy+o+TC_?Kerv9hx2H%rl=CaDpv2)4F0M|| znkpxM=>1t<_Gy3g1ji4fYH?r~takF$oFhAU-QRH#Duy}`UYwOO+?r4?_@oO5gPbFgCE9Jzzy**rpea|7Eh3+GwO%iB20&XJvvl_0iod+QXmt*wa7u*Vk^3%8lCX*kS764Qh2_F_!k6 zi$y!vWaL@BcG?8auT8$ec>#Q)T_v1rQ>3@qrI#!vi16S?{^0{2u>XMvKIG8{KkB8= zde&Dz{_)mbj(PU8vb^kHo$^l4GE2vKzdhb6p2v}Y+i+IxwMu7uw;!ww=iu$q()2Uv!gr(Oc$u9_@oHN=Z%4h8d z>#o(o{59(hz{z1Mtu+c*E~C*J$oBOmkdZWiqkhaEQmbD#N_Et}!67-^+w!tc+-IN5 zzS{&EF!BlUZQW#bAPuXpr(z`YAJ7WUJ&e;Lp`~iFRRqxpm z?Oc**_Y#D8Cbu9*{BGG}nL3-lell6KhaGreH;eWe&v?e$-x({tBP+o)CVhqS?aT=s zk)@mBB5fa%VcV_E=v2gkh(g;G{(q>9W<1#j`(Ix)@9z8TbC3J{{xe?k_pd*7=i3+j zzwcc5D>ioC@bTS8yy7$Wyx)WGcDLWT@ch8ZsegM)mY03bF@KcfpPZo9s)4QLY}1AX zhP9#2FgB{(68$2!MKxgv8AmL7`7g(5!0(*O{$Ud_#s?Z?}9Uc0OTKxJ!TmdnWr7okC;<4qYk zP@q+7$QqWh&w=&{{CHa9(KJQ4FD_VfQ z`_C(nKmPc`_S>(OMSJvJ?sCMDNB_w?V=+dSUP8fZePzQx6fYZ`cf2QEA5x34*RYps z8SMjG%a9u``R3Oyyvtqg^5BD?^QO~oKJn~dy?x=Y{^G3R_LpbZJE;<}o$vh7FEy33kzJYVisCJK-r{rA@KZRKGt0d}I}&nTXCfuL$w6|B z*{=j3wwQlS9fV?50f30e+j-AGaa@26mzd=O|7S&A&>qHx(QlE9$tBvmzWPa3D7gpL z_};Y&T0m_H_OBI<_oc3^8Int_eBR zcLwFIxgBUXc#A)FTq=`&v%5VQk@h8!8%dtuZ~~QjVV=c5G?sK0HCuw)a`0Sm{<*Jw z#mnI8t+i;MyzlS5^X+f_##b&P>O-q9qT{wz^Lu%I>%QEmF}x2^g==G!6cS^ z>1gaxow^i$7W1%(wTl)5c+l>W5?D0YaI-g5qX-BRDaT*e?bX?4Z&t|7Ef?x(UDAEG zjTwAYp0Asobka$O9{RMNwP+vqQ1twN{r+l`!_Z(wzVht^(PN79*~30f_V_gEmmKBR+JbU z+^!4wy55d&Og=e{v3;~nsPSyQYJ6Q=DqZfD@fbnJo?Si&@0?F*rg}C=qrKDEp_*5# z{=%?ZNsZ_!<5z|nEM__{=fLXtWO31i;fFougHiWnsp|IQ3z^H;+;hphcGnWEM1$=Udlba_Y$^J^8T* zce7}ZJp36{zs7q%{J6yuCh}2q6ZzPR)4~^T{<_Osq4Kq0zwBEP^$fEmzD1}!_>ueV zcfcVnv)p7R|BeN}`frao^5H1$Pk8jMt5?v!gDJ9fyO1kf9jiMdpOA>IZ7&Ltm-Uz@ zXSqzK0$K!GYP=PuvTh{%33wFv1iV=;T+aK9#c)PLO*7%u3Ub{ z*yLLvFN<2X=Vh5^Bd&ElF3r3jDA-!Cj8xH)KEzm|1=OX{M2AH{zZdw|$Vv{EH70xL1@`%YG0ztQ+Szy&>g^un0qe3>Nh#`g zn5jqc(gsQX^uuwssW4x-Yd;Yw!Kc9}_C$;t>^;(BO33QJ{L`XmANS{veeeOjYtjD0 z7Zw;{mRln-6w?Dnpjz6$as48&H%^%6cADrY>YQbpfA2x}Iq-2WIAJ<5UMfK2gP!{8 z`_0V!#T#EvpF$l1)OEjUhX=hAJab05#gb3e8nxK-7$M_y^_w~IdDVFQc3#!QDOCox z6y_82P#Lpac$pR&!7K+k=IKlpQrz%CYS{C+86F|Mng(3IJz^yWx0_U9`i^4h_T#Ko zLXKYq=B*d0FvEd?Xhf}CeGVFUQ~0^yys@qo%UMGjO31y%YBG$+02_s8fE|5~7Lbjs z)yfv&^BbG3%P@4~Dms10cuVdLZCF62g`70haW8A^bgeA%_Vd<#4zz1!AU2^3b*+iL zFI@elCEy_}%&KIKOPN+ANms3wUfH{h7wP&#pIC6hTl?3defG1T{q?VZ9qXVG<_?S< z{RO!FU6u%w5=>jR&o3fCT?xabpl}o7@MD7Jl1ZTbp-*_>T+#lAPkYTiGc)Hb`1`z_ z4^p$`-dLI%x0aeP!JeIjH?X(tY%bK(anz43T$k3twA&41*9Qm$&sabWsvR=oyrMmo~6Q>k#>aDl|&n zfL!H#SZ%5*Ff)G&68UYSS}3(m55o6lC5cI4z`guG^UrS8Jahfain;?VLJWH78( zndkyjb*+f{Mw<5+Noe?;@H^1H=Dhh!)+{dJbk~-Q*C;IATL!PohZ$$M8>aDtj(%4S zIpYFagJTewQMw)Skio=aVFN?xPx|QDWYHekw-zl~p9dd&uzm#p%p@_5ls^Ld+yT{f zv)s4k%|E-9^70;JxPo9$`|IV|2^}vIU+Gp>*p+Qm>4Srb|L&!~rCW%@KovU0W-jMQ4MH-;>>=Vw|1&02_STf9=xDiZ zo5H}^W=uP&zS#L&@-x_mHu2$yGDuO~vsp;&6h*z{<3`tTJPPKGj|;$6&U4j-G79p{ z(ThhNF%;ia6On{kz?78}Dha)p(j6fBGJ* zbO#)8fMkpJkHp(53*C*S87Ga4WYpkZBwK ziLR*%Q3sg2#w1ecHZB8@k9_1K4Hq$z%!CjgPr}b6)(g!alMGb+Vo#G&q9oaHlCoqK zQYEtog!Aiiv<94Y|H9){a&o$f<*MZZrX6%J2=C8IxSHs+`R6m@X$L%n)@Y&w?Xm29 zZ!qun%kkb3OK*vr>>&*k(`!`|Di+%byrqt~WCk=VPdM^zn?X2ecOxqn@c;7Wn~yl+ z2&!WAWYPY?AK=3~?6AY+)&9EJleOR3p$=T`C#z2>fc6k&J{hoo`qQ6I6x~s;JOhqB zjR%fc+GoH1A7*A|Ui#AGco4&WvnZ{osAYJNFfP%>kQ+sSZgf3Jw(Mjp(Us$BA|gLx ztJa;W&CHB|+>Db$Zo<`{cFoYCR?n{;9BAfr!d;TRC$`o3>!R0b>dWadL7?Ni|3)PF zbU_6_pH2kelM@zd4It4j@`c-O<^#($V8p7E4FKQU^h2$0@^KKf4g}57$0wAiW@Jt_wp!UAT0S>0z09Y zsom^k47n(+Pazi=SmsnSZv5>&d?4)LF1HqUGsq;%x-TW-1KDNlLIeeQklZWis)haUQJ_}&)&zgXk%f~Wl%&oJ}P z=tJHTHf^{lLNf1!wJRpb?c$twIE|-m%8K!IWuDNbx35BUPsb!fWt@f~7}0E%TX-)c z$3cjskZ7-+h#KT;$t7g_Q6!Faau-dFcXEfJeVDsC9Y1$kvk`nE+GW2WP_zSk#ryn= z7_!2s>r*C*CCP;rKfxk>L*$c`7*YZ7@)gvtM>^6vv747Lej9QTyGuyZR z43K8y(W1siVeD3_;s}QHt{5-c0Xb*U<3=p)g$zv=j+my)*HK!#N>&*cY~un0rCMt( zzi2vwZ*)t+DSU3&bS+Gt*9D^noS58EGS58o%+pUl{ppW+OgD@6zyl9F`Q($gY}tYW z53izUb`wfB!k{iU->T@K4(2>3JUwI81!$5WB3X{MzPodyMU`5@yy;K9Je9A^3%O&^-dlEddTle&4l+eJ z$W$gbhTQU?908)OQwip*`ebsrc&>3i0qwQpy*8vN+Yhabtw6mN;H&jy2$+SjQ-xB- z-jKEoE*M-$Ag#Q;TfnQgA{~PnhV%}?3MLnm82Jjt_trxDWmmPGi(b+M*q8l{+jp{2 znwrRVrZo#T(#a*4U-<6#zVon$_hiw&@OjVq@;@xZ(`J~1G?f4HQJDSAY_eRTBj^ja zu33$-;Q#!`Er=4>(!naC0c)_6#QwAw{LP7<{`-ITyWeGc zz|Wx_B#l~Q!=-7u+_;7Fgj1`^4GOudFHMhj-ig|%f95r~G&MlwsR6&53%?pNLXrIW zZ4THF2Hq8`S;Q)FyRP8w^vRCJcG7!ShX%1R)Dhn1E*}z_=InZTS!6ZQ{FyO6{j+r8_YN2@g4{G z%Ke7G685=87o)Mu*jtcmvIYl{|BZ!jv{|jRXF_3k`vxgSjXQIE1cLX1 z69c>^i-kf|>)lyPFV3jAfBM>4Z+p`#4!{5JcGjZ3%PU@V%z0;@TF1|&X~Tj!in2tH zXieayvFs!fDJ&`bCx3)Z@J=r|>7Oyh)gnDmf6d7o@A^A;f5ptq!kL-pKKHqBOCG_{ z@e)-P7BWQT78@Lg^9gvK5OUYOO0+Yt0Ikd^ryT!9(or~aOVt{iahLt ze{Kin{Xnhf8u7Flu-qxlj@ciyBX0cKXm8b`n>hKp+@6t{i-MG%W^l7U^t!w6%-(tP zPk1jocZDH6PlcJS@RlHids0u+MKJmY4RPrLna)jMc4$ZGGvnj7$~! zlCJn+%TDQwYd39-%=Ur#ZK}|>j>9}d=u(fE(&RZwq}shBc{`FS4j#~sM%P>ag!{H^ zegK}pZxh#Ag<_X3`qUd=|C*!j)y|@Q#y#%#hF8CUvx#{DPY+NH!RhSOrVu{M6@Nu| z--^Wx_Sa*3QL+Z(uC=bXEl7l`CZCdw6me1^okoO^GVjb zhC1wjXzW(t`gPGhxdd{HvG`wbrT8%nn;jL2TlMF(c#}YCJ!z6*G9#_)qf)PKIm2=o z4OR!aYfa4TU~Q(lq~s9l1M<sHDgo}m4zpNO~z&`Sk4h?M*TWI&cTmoYU*fyhQ@6JRT=NHJxxmFA%GQy?HzM09+zb@LRstjFbA&QV72dm&p zUfM50kMdXy;CQVmK?mA_kaDj;HCv`DD);g?je;!_gXY{6vCMMRWtHWIs}IOf&p1n9 zf4j;}c~X>i4Dv+OkjH`mHizK$K{%k|23>!9}64M?-HQF%_iFWd<254t#@va!( z+^ZuQCa7G(jV+|a0(f4mHC5mI@s~d7S&!_=qJ78%-~0C0um08r5Em}Q;Ga%u5WDco z4`40BK>*a*E?T@85&iLxfBe0F_rSNF@t?AHa$x@8;OE@EF!pn1Wk#JZ=`IL(cGZbA*jWU7)%I#ShoY!Ri6Dpg#1^Wrd8gLqsi!^j!g)wDzx^cm~#Z!fA-Z zb=+K{(AZDebf-Jr8Rs8p#~twA4}K7+oA*|ytP6F+ z@8@J!|8-yw+S5b_8yC{BXnu_>bYVGnKs5)68qO#ZTl$M=;3ckUqXNa)c;}Pw?;Q$5!`dlL<4A{cn_xASEWNM-=fs(VnZUal|^4 zGIq+;z~_g>B*yXf@wS6u?0xDE+lPztMBHoP>I}6V;@XOMt^eC9V)ySiVvPsw@OJRV zqL)A&CXZ*Xt}{JO`rx?rGvWo7$OSr?6V&N}_8^%J&Q=qnp!Wkwo@Sf{CveoP{oXsO zZX_udY>*Gk2<_Hx*PF=wk>ziC$%#iD`ox|r+J`>!iSPNqhkv|do5fWSMCpxr$;uX# zg4lY=3Rj**3V84Xf1gwt(2hL+wCDc~UN_6jK4I^@5#yQG&>92j=*LxG6Y8^~cS;xf zto_gcYM3$qmWYcZx8AG;G&->Z_pq!I)I?_(cBFA;+StO|M+$hws zoWno>59}1)t`QFE0AHPJY-uCLCvPvA@TRpiymX)>&jIb7WEjNw451?dj#&tER_U5X z8ke5{fIxr0hcvYLe8hpdLY-THUeOL`s}*w5o~4Uu2~H+MU2UROvr%xGf5Ljq695kk z$fEt=yWe`)BOcPtqJ7*EkND%0pQC#z!YD6UbjgYZgqH=!CiiQ}5(InPv3uY1et-6< ze@Bep{~=F(Kw<1uk0+=;8M}5b;K6vJWYC%@>X6AK^pDWdx4KItkW7Q*+t;R!c(?vs z2va2to?rj#H)<`F&GhDp5Cn7{>6z1Q0p^pin(h{ky0WTNnp81@guiY3s@jJ-izJ__ zV^=F~=HeiOtwk4f$h9)P8#%UG>?K!Lg@IG26~Gf%+LU=HR&GGfcH@;RHO@&6njp5) z0KiWYE~fDg43>`8v(@se#~L_;x;JC9S+2m~pv!bIQhmB`A zjTDMaLvrn&toIdxWrxEL1d}i6?)WM3HPEf1d#mCgRs*`K{TAlw_29}~6-Mj^O;AHH6>B*qdf@m8H0q}CN zEc}!Tf8Ih#zH57nl$a$;Tw!Q%cc+!9R_6o9SpL);xd~{~!`hr_zaYNs0V|>*v9!~8y!n=f&7ykXN+4C%FHOwfIKZRNlhsE9$G{{Ws{~E= zXzGN$DnK14pJ?xjZ!HTS9}#7^X74TGvj%(=t1bE1k=niU29s3`l2@U9<6oV6$PxeZ z@Vni$l|_5lzWYA!dCxob)Q`DLk}>3<{V@-I@S~pbhNr*i)VmGJ%O3UQgJk1Ip%JMD z258I^@tIo1@Ei>91k)F7Xpe>*TGgH*+UKgk(;2v(%Fp@LJS+HF?=i@5-$`A>~ydN|?k- zK~)Ra0ClFjesvc`gyAd0>#1o4XxXtO0hYBH2E9!IGsShjCG)#h z-OGoLzi}+u>^D^#(atuF-DDj3(B59N>-4Bck+VS#9ISqvByZR@ziDYVuT$Y%cHQMm zc;mFv@POC6<~6KEi^U$0 zFxry~q7^$rYmym{IfCS3oS?aPO#Wj#haH}+mCg*PfX zLTFLu>!~6I52|-_6c^`q1TyfwpwwV~Hk*904387e`)6ATbQ^*CK+SI2Gs+!TA+(EL z0q;boo}{8RFh+)F-fY->tyeXD78#+b5?Sg=%(aefJ!UOot)~FtQKq6=ntE2vHXDFv zzoo)_EE<7vj-;2tUvF2~@OWyfbY)PzMfgLcUmlS?sAk0^luu^SNc`i*{qhfr{(iL;z{=PFct9Q=j_OG0%NgH;eX& zgAYF8gcBAmT13l_e)OaFy59l&?sw3OW@i3(DK9&3-aM{#d1iBFU1&MGm4`!;7z0#5 zazIOvP`8&wg9M+t1$z`0I@E3EADw`3w@ZJtlFfZ?N4JK@@}#_8E;M|bKTa9+%_B37 zjgW5^lPy?CEj_Gp<-bw^kAo5A7aq_f5nW$`M?>p0g}FpbCnw0Nasi?|DX>|)NYj^OzC>^_gF*2~yEF9kAb4ef?e|SNAngC*8 zbFA)y_d8c>8*Ahnc)z+L?gZqkdy8w75zuZ{3{rZcU3tF7p(+xOZ=`MV|IoXtS|Hu~ zN-IaCDihs$#gKA}sUId>Y@bDMMEb3HJ9Cs&uoXY}0h@6$HS2RtVzW&qZ*&gp2J;)Q zyH>PY>X_Mvh)zOlA^~{7`9J*O56_=>=I`F`e%&nE{rBCMELzf;?tGWu!9@4*nHhBV zefQn>m}8F77maX^$iNO98!QPhyXC$Bj|a4(4sASGx7YutTfS?wW7zt@!Z7~JCXWTO zV(K1{Gs6!o(JcgpKkiOrv=#HX{o^2~bgJ=d^^V*bcaRIYik_7gy(zz59_zikYDmdz z48RwlSrv=Og%;X5%ZwU}c6n@5acvM@Hng-`r==8QZUwrkpVzhDv}p}}Y^ej6I#cSj zNb*?VW!hAsLWW1)tE)cIgXF_l7kBiZ%_*=Hs3#sK1f>=uN4w`3ZM8OYFRonI1+taG zJgobYtrrV;SHehFT&*H0&yVz3>gtTsp=OadDk2MAw|o*inCO}mlv2^1nNj-%&9RRh ztSzfVI|%2$L7qy7)@A_hU4_$I7~Mh0Du5?#PPCIeN3bnNKnQ48hxZRI2mIKfRL0?l zAAapnbQH$+_ z<%s#J6qyz6rjdk@KUlJceRbXL``6N|p*T!;1>xQTn;EAFR;47f5K7(-+O3Kqy;qb*d$1gYK8AUrE#gE0#f;I2qVQ16Z z&0{HxoXAm??MGHb&1`KKMJSt`-wocbrH$F_J`ErNj){Y0wqkx)RyUT0-v+>g(D9)p zU&39r$22=dfe$CYjWcca@^)l$7JFnf;5U-tRxHQm4$if@Gcev> z-hCQVzoY@RWlrQQw4_Sv7Wr(E%7W~->_X9=uPB*36pfjo*x!AD)?Jgy>-y4eB*U)* zxl?Z^kKM$01aE-KWQCtw*MUC(X?_UP^k*wC{l(6ml%qNBxZ@7H|NYIP{n^aSUNbY4 zsrlB-%>DP>chja##+lI-mw=FXic-R`)vd&Z3+jl(zaB>J9H@3C*&gI>I?AkP(>)W5*i5YG&pk z4|xc&8NyG~m%m9kL|}Fc!b6b$WmG6rlCRrqKR39|h@i|Z;Z<1op7yX-%>>HQ;EiWD z^#z>!jPi5ah;VMLea;?gv^)5kw|CK=GQ4-6742C{m}ex*NUe&Gl|{1f)J%=`1bhJx zfNu&siQWRawjjD^7tvt4+!N$hQ?HFl2=Fj=C$x5WYPmS`^x-R9^ps&ARFaDZC8ZtUb;wt-;bE?G3=eykkavO^}22i(Wki_Z|SUye-)RCrpkDc_Z@zNNZC1@lx z{LzLZ8qaDYLN>^qJX<^J(v4SNTiZBNOvs&~BtP)BXg5)S=hqro&K3yS)My`oSzg3s zh0ny23Dr8M9MnxM>{GSQ=o&-i8mJcu9~BotmtWeaaW1EFYR<;YX4q`YaG*sn4R{fC zpG!U!e}<(aYlKXT_Dn=$g{iC(HBcG4Y!-DL8D7doCJZ~_fje)06lr+ZB24sFn|2XM zb|yR6I16>C!*Y1B@i@pVmBQaV7p4${fy=N6}IE$6tpLA&k5lYW&Rgd0DrcE zLYG!XW>pacT4?vb&=E3QxC=AbEojR2omRg=s&6HVATz^$#YuXn7;RK;z4hiBwp{i4 z*Sz|`10V9>2R-P9A6=iAq4YJv1vDjdOENFTHb1=Oden#dAT3eX<94Mo6t)Ho4Q#3> zC0MIxnfd@#Nlh6hnUt5ztFG~;mwO!T=6JW%#DvD4s{7Bz-MfT9UE*yBQeY!ao+GWQ zRlM_Q(Vo%ZO{~ixz%vL*VRR9KRw7t2LirEp1x@8Sa4@Et~;J_fb-1lsW0X!^3JMT<3)m4W zNhNoRI$|ua^_6cRz_TC>#>J#BKl$Q6LR0E=BksZi46TJ0Cj`%AIXc7{CT-TV11G^A zQU}} zl~UhPztO$`62=>Wv8z`_@Z1g8=~ts4;%Y`5?By2nxc%ETHUP&Kl$+I+=7VRNo6-)R88*(FLmRHj@;1!0?oQ9vv%-wW5 zF>6N{yRkZDrB{qwsq+s_eHOiGmA)xTglg(YURqVExs`k}cehpywbucz43F4SgBI#Q zH4At<=`j|xVTb?b6ko9Rtd#1}>L&mmNuge6A_)+L%(|Z0NA*TMuic6!9v8AE?lwdG10%U{%=@znl{W)+VI~q z*EDMeLJn%ckNfrsb%;W)_iSV3PvBwrbg?hQ5uIc;2|!Jy#-ofKv|9(Fbw@65!f#v_ zZXlC~$(Kc-;p&Y*7r=`zRe9;VgXb(z&-{>-1k~sfQuMpNw_`4QvBxNNao}%M|IIt)=7e-^@a5UJkEi5V-0a7^l6@S)3dr z;U_w~16RC?cZASvBMKrS zT(G?d?IjFTU~A{A7XYt&cEV})o4}nId2Qqq?F#d0_OFHc3o|`<&x;*s79g>;;D_3KFw0_s<)w8+iCJ>sYFAmzyn+0z&1`7; zF6$PeOomy$pfQV8h}E!BZ`_DG3SI}=ZDZUkEw$f>e~wEUJflM-)wr|^71A_t|D7NBFbG2hEzNGGG@N(n;179KD0J@J~zJvz0~Y?_0?xV z-1&%rnJrxI_%p7afAP9`5UKDXuV18|!Z3s!$G0tB+{#x4>Rm(Kti|C|m5?(x_W8ks z4;ELApjyd6_yPuOPi}AQ>V&OT5Z0Q1h9@=p!Wb1GnXBSPLsmu`*9?q0v!Sf9Qpi){kZH)HAKbt#c) zxDMm%_Ena$a1-PVz_b~D6YW&XXz?Nxbr&;-b%S$sQCEXeJqf44x>Knw9j?ShBL!zM zL!SE;Bi?7(YH8mUU_nJ~qN`s;X&h*`8e}W7*msKv9o&A+i2E};;oT;0PiY+D0*P0s z$sonl!X!GPpzSFb{Y>@SgHRF*AvHvI^F2(;ffKiEq^6BUd*Q3WtF@2~AR(TCL=#|( zx4cBcN961voKBq_qM#Vh1FQd=`V#VLv9|%L+Ic3}Bq+9w{aT*yREcv`N%<_WGd(*J z(!aTuDNJZL&eyDB2NrFx>%lHrNIGY#eMsTHY=} zF#vg1xv_^R6sNJrmG>y{I&9|I4tuGSXW{d8kp|5K%tB@)-@*VMchWmhNADUf537M2 z|LsK!vY=fT>Wm6_8|VhEKs)!*XyhfAVD-i~@x_0{#?hjiz9J$8=^Ud-ac@8h1_2B_E5a5hGAw%3>S*~Gx^*)_L95!*J2^Tv_BZBwxKb>{+gaNZTmd#if* zW?WLDi$HigIWrpS;OgvSheNz?wd7SW!`!S_C;nqGoS#SLvtbynH`W`H!Ew&Q($l1* zO}kOlRX#B|4Tur#?MgSk$1QQu8k-iu^!y3+F4_^u`OqZ8rQmHrJC>0^MQ_nx?vhm; zmEp6ZW-IGnhhkkD~IX9YfG_3ozXo}mG~ZE9lL0KSQjXsSxJSoGLp z{u7mg`qs^2k0WNIU1s1$ZL+fb4)0_Rv2?XbTr*o8+|ojO$$MKzL1?__=<1*yOO;vW z!HNspPuChVfI{(&@vq3|jlNKnq7if2AojjVeKo)iHhb{}V2^s0>8tDEdxI6Mu+PuJ z*dZbtuA)ON(hbgQjyEp*ed6cA0~ctAUW_)=0%vF)Fm94wC+ly69)LQ3L}(LyZn6X_ z1H!qnYxQP?DQ#S3kyFN~M!@X0&0&)(<(%`9Y;PM89x`WN*<5E^qFtOP;Mqa+4U^dF zh@PTGZOu*zTm|j&{1G}r#idf7l~8t|j)`8112(#4Cvrk(&lu{uMXyoat=UwUrfl(c zO7tLT&~gHjr#z+fWc9domo#qtp*43`!_}w8cI)nH1U*x_6s}#lvQ(;FxddY*a>^9E zU8Qu8SZ?~7mbOG!3++VCAh!eZZi;xwennk34A#nX7cGsD7}ak;tM6J2-*U-fHn=Fq z*^Hl!or^C>(K?U`<_j`yW+zQQ1JJ^d<AFK9hjZb*Op!& z+BDCaq}ht%&KPXl*KGuR_j$DjH<9@R|8pp1yF(I5KfKG!)F8C_6-?NrrocQEZ%oMH zy{WV-#)EbXWA@gB-gwUGlwqye``H(tk%l@nZL4clI#<;8$+hBYz%wMaTxe-ZVAst? zUXikWnNj14M&6EF)R(lNzJ1e17JkG2YGq+2Mz{=?g}Z@mQhs~wX;X`CL~(WXl5^HT z3!JREQZE#29H;~MHfIJ-!WjGN0F$P&6J1wp#R9d#o*Hris?4@#xeZAx1G{8PDIaD+b-v+DNQhFeS+ zSbF1}>#c0r@D=Te$XR1%-Gq8VH0#oXe05`$b_`=U;Xr$DF)6!(f}pxHF~Gdk1gOK_ zd8O8D!or`Gc72NOx^XUdLn*FJ8y4u{8~40vilh-YtRz(eOCw{X1d}IdfjS$UEpP~2Hx(UWG+@Irn9>@}LfWXb>ZQY9bv^9u zol*0N%d zY=t9sfUZfVW@UOx243@R8e8ds%j@>phD#=(9Z8jXH9*t_q+AgpRRd55mbAl*&nR)X z_9HE28({04D}Yb5zs0B6nqMgFz#XMRA^FE{QQYsOObrL=UMmz90AXjtb z7MUnIJ@K8~vWW$nPDiV|a=|PB4BxJ45F;c20XoQ&f^B|jSreTo{=0N3VK%%IRj{#W zPuaK?C#0|~bYrJDz#}BKWVzJ%kNpehTP0G_TEqsPH$^oYHcfPV6-OBc=YbtAcaZ!I z0v%#|kY=mZP=z9vh{FgcX_$g)GO#IIW^Y1$%6Qur%?bnlAYmpuRB0zY2KyWl^)Pn6 z3V^Te{1d=m^L9}xIQcW7+7d_>OK~x9bH7c=P9$d~RwV-3BmdjpHcbh%@oyFF5ljMU z7ck+wfX`&7qDu=rK<$Nk8r38U81M$X{cUDz14{(#mWi%wcn=f(qIod1M7v0~nEYUx z?J}q)tZ@Z?wqYJBq$m_jVDH@t*2B_UuWL{-5|mDm9fIiGa6Py+FMv;j?j4au>(+>B zeCYs~9exRq1=0cXF+_yV7v8wC$jl_Phv|i=RkY2;i}$R#at}gy*%#08-)k@5z5OzN zH*a1|kJ!;c@2*X;ageTWyK!r@zxVI&OiS=8q~E}Jq{aZKGDpohWv5xpo0!#r`6szlO_3E3mv>^%eM&-g17J4 zGc1+Mce!r&H5kUg@W;-%_{Mb~-?Hv+C%MNiKgpJ$9p3~k=^3N%?whvJ6~Ej<-F}?a zeaqSvH!WPadhud;yI%ofsszs1Qe$Vwvp@auwtw5c`Tx0QF^`ZE!B471b>=irXpC{Q zdr7R>1e;tFbzobaM|qhwt5>X8!S~{qKmNanSrZ`+*gRA66n@lr(y_HX`CsU(wL%Ce}an3n`ZzGSsp zJBM&jsi%7W2WL@v~I@=)!Y@nU3p8dUc@A{*z+%{1<3xYXs7p zZd%79Ae%71w=7<={hH9*K{%u0EitNuI%d&fs(h?JvF_IOU%r-AOa^~-VoyGfz~hcq zvtXZRuc;gRR<__b+t5rR3rYdJrUVYgbFEn|!r9^Obywb${sA2=BW~xCQMh*WLP^o!h?yOF#eoc1d=z6eM%^wg&B3;O%6z zpNOJcQchJk=PEAe7utc~aP!6seoiJ_X#=+Ff|lUF;c|0@dU;2)M$6Yy^e<*zsbZ86 zT(>){@oMkA&UWT5xLtJK%1c(S%-R2i^&jphD6F`?c@Z1kqN_PD_Sf&aV)M>5Yqzap zmRLB2U-mi3{B~n%>W7cniF~nbGyj#1=&NV5fo<}?&gP~~AG4~b8cvEWo6n1>Ste)@ z;%hGhQS1Zt%_|oG+E0D+v{|7}1Db*MPb@$0^vh4;Ek(}7&W#&)Tn^Of4L%I=+30`! zjw^u;(g%M?D?AjnE7*}XF~8T%{|cON_f0q4eA|zCEs%q&c3s9V(gANKFGQl@ErBSD zz0)VZz6XxCcZ$^m;>d5luGpbvdDR?u4A~|=R`~;ayTAH%_hsf=wytXUJgGI?Hve?P z_eC}MjBVkx|}B)AXTnd{XPZ*kbpNEXhhiNAZ&l$qDyLn{AA37cGy6my%^`Y9E9hMB9*;p z3Ops`30(0wl$2GMQD*@~$~8=Vjss@?%PEEAa8=&+W8MiZEj5J-!>@vm)(u;xaHIs3 zl2K|s%G-Grccdln)*6y(Ml|5sL^}vfey#>l(h~;27Uat=h%Z%=4$+c;cX)h9!^Yw& zn0yI{qLVP94ah{I{kChbkTe8YS-fPDza9DWm+Mc{mmW%Z2eEM46-zIK{etaKynl4n z)-5X#%hjtxwchyM5aWw$y?1MPyJriwBP%9cwF5Ahn(B)2o~nZx8ytq^Y^Ws9X$H^E zu?vuA{Sb(e!!WXZ47r$ufY@&Bc z#x8G9v_lhXw1aci?~tE&hBX01!BM#ij;+FC-7%E|0_$^vq1QVK5-?VOS{ za6|!{{v{9`6vLvI1^^ghQD0?;To|LO+Au=V9-i=`VubEp;3^LXtE%WJ9Jx~y)1P-H zd2sJR56Q`IUE3qxBR(*yS)yxxyl(N0tLHUy6rXnCw|d&Qth?l5s?c11sq(q{b0dWB z+~{OQ&YuZ1bPaHdPI*S%@nz{X!56CpjPh=AkR}Y%j4avtRX4+ z@LHgb5l+#4+u3I~l6hg~0G^LhP*RxRvfymYoUOYj+G|OEf{2SSPlwP@&`yC$ z5Prcm=dcO#Ru~Wq71|_&iW&`^2~26E5_{ z=TD=t(}wm^2MqFImb+#nT>+IE6*;*@6lXEcHOMck&1Lasb_8AxT~urJ^OWQ>42fpC zDtgf_rQj^MZ8h*J?*&&^HAqT9`{kI*iV}`^#Re2Q@4yc;9Du{Q&gyUsZ@_OQ~85#wo~BrnJn z)N80~W*;Y|mmI)JM)E1CKy7T7)yEy@9tFYeisammghwh#2V@MX%9(>jBgylsr$NH! z*1QL(a|!Z1JK)@3P~GwcXnan<%lY|lxTXr)nS8x3C&kG6th_X)lcCO&hU)(PGg{((_akaO$yeR-?~Fw|IJ7SS0DDhU+~t>Fh5?V`n%3I+ zFzD4qs#oCeM|<&&OCuV8J6d`l_wKFrk)yhOmbr24-6)`0t@Kk;kh+-yj;_9-hSy&1 zK2!iz9ASPMw1>GXRP;?iU7Sl+;Pxu#If2**hfHOT%idGY2kmH#bJf@r?LHL!JDGY7 ziZ|_8uPcrXCjaC0OLU%333bK(Q1UPPBCa)V2NFimzH_5yd0r#tD;hu%WT*UMZ)bR- z)FXUQ{d4}8Ki>~G%9e;czueRK@UoeW70WZ%Ap0SF0QI2}7^=?e8(CW0HcIR$&v5lR z?1Ham>5ggURjhqHn|+D~7)pHG%$b%|brRZj>arowqIN=tkhk%-rJ)F@!^4?Xd8FlI z6YWuUzQx`LE;qg_fXB$!|Fo#(V{GPd_1kTk>)tD^`o9UZ>ue8j>dP#3dk|;BJb|(F z`~Qj)4nR)81ERiA=RGIR2iV)hwJnkl0N9YaQ^FVaID60=$1!#~%xII|&mnKmDw7iNd`dux%@-uK^{oLw>AHv>_Sz4KhHi7^T7upRHpZKy)? z?GlK~Zw`g;A>f(2AQrZhW<237+CeN{v|jC9v`-*xz2R%OBMfd<+Uct_l4sV&tpXfusx z6511ohS`8~#CRO+^>Fo#87CL-tL&$5Jb8NjslTnm*+v@5-{ zVZTwct!;I%dSv*p4;2q>3)rcXk9$l#`MUbxhrL!h83UUfTSwYgmaoPwhn}3z_1P=l zKL6YAx!~gWuUUS!<&Z@n1n7cgjWu2t-FWrZ&6Br-SRRUz13cHUVJb5cAhdN+tY9^a zOED-#-}PXNkk#GSa0!SNDm;jz;$XgzSYWeWFLd{gt;-um&48f@t;`YMShxv_M~#s{ zv*@||CKWE`%1daU8DD8FPN?U^tJMKsT^*i0JKEK#V`K#e{8C#DFN6C{U;4z@M{x{Zfy^p10ic%A;`{wBou0Az8tcTJTDJE-)= z8Uu9zpDy%z2dIaeZR?dV)!KHbKmiFDB*w3TNd}+Xx*1?ItpQJ(<+&E4F=*E-oA0EK zTABVuO=uYrb=w-WTRons2AkzZEbFjl@q%G+m}o4&MuWgVzxwH~8AV4w@aIqpwtPFP zjPH&(834~L2bSOywDaH#uXz8rzVcBzfqbMI5?C#vrpBCzc8)+7#I|BT?V&rhtPvGK z*L{#Xwp=iV>qDMyDgkYB{#rhV1jO-+=C4@(F^O+&NoihJCB_@@Ki3x?Hi#P{J%s-G zxLi&@3>Xn39d$t(3Zdtv5%S>EiFTx+*?D`-T?wbX^pcB5Mrq#rC>k5yUTpHBog)O^ z#c(NQvHmnSzz;!TLQFQTx3OKEf^&US)3n#f9|M~@wWj?l`fQC|w1e}DuQ~$?CkJM92~PcKUdUYA=p|As zma%`ftPv0(NmQ>{6$#keR;eum<3@fin1mjww`;g&V;(bcQQZSV*Ig%RW8%gFbwuM9 zUJ4GK)*N@tp<^mq4>qn+6i+Rq*H8i>AXs3_h6Sx_ZLB7YwlWNB8AP_i_LFwdNi9D& zLmCz1>qHlZI$4;fvGRGVnWgf$SFQH*?7RoQ1?Ex#PcsfqTG2UqyV|THmc1j*`9hoc zww6WR$cGXPMB9d{y~Bb4?bni zOe;>d1(IIgzGlOMrXX(tJRBYudV(B&o?GqGD^YQaG?D0d_g=)w87k*~7o~8yVC=<> zDkGgMlBa2}a3tDwyoEf1$!cK~Y!a^Z9}+L3G6fGN8z7eM0%hVoOa8%VeHU_ylDtE2-OQi4#)lnE5@-e z*ti5Fh=H`9tJ^a??dP>yp#@Pu4p#^5^qih*u1&`Q1@I%U=11S+2;<>lF-g#Kmx2JW z8pG@};1sF4R@HpE38z{fxHK_JgCt~(Hl-NQp7v4g2$Rsxd+&y_!Pr52xZkIUKMD66 zB^<`LY|uWi{P!#5itd9>enV)lU3wWQ3=LA_h={%J0`--AVQjDIK!y?|P;0a|`TxD) zMp!xr3j7sUg&h49zLIFM*!}k-7t0j04F9o(N5$nBV^V}LD1((1w|Ze^24Lg!XA<^~LhYNq2aG`Gz^Aw4w>a#YNlR!4k`8 z8?2YnkpM2WIAV%Rhu$uS zXWk&h)>AFQHkXdL6>C0oJ8*7xw{atN3`xqFfL4t?CUj98R6A?5XC9cjr9c#tr2M~l z$=@?VW_+fR^Jv=7c_A0CpU2rWL2;1%2MEfaH7G0H|;li5Hx6 z5ZHq^VVstEZ=G%h!x;pj(L{ByDyU2ILB3mn+Ut93y?n*{+TS6`vstsG?*MmcbR_7o z*9O6}D5rRq_G8fw(=e>H)|tI4Tx+axev||>Suxd`1V+*2L)N_AgT03Fv>nV^QsQ>Z zT`oy#GC?5MhBu`qUk@YEUMJ_*(FaXsj*@GHIg^*BLrxW)HwLgv)+)b|;;tNlp5J;{ zH9*?8^guXgD+gw-Xm5#^ARJ_x9B$?;JEn*S&)K>esE44z5|L$=3mZ+!hK}V1)nIs$ zNp{_GND}TkHa%WE1=PesI<|pf!oD!eC1cN7u2dhzX9{TRjZ-S&fUtFn-V||_$!n&n zFCdvbr(o$`-ikruzl5&=cy0vkNLD=ZbxOQVcXGCL`w0rX_6r;MpgCoa9V*M0bT}kV%kY0syEh8`A)6ba^|+{nlNy=lcO>y1r6R zPWEmhTHX#OZ%`1!Fqp3ftu}eJeXS~-RS;A2ik&?>bsVzK$RXTHRT3SDhzW>1*ECR9 zF@Xl<2*;vbfZ^!{?Q9uEn{VNoh}JkC20k)xz_~?Wuf05K(e+hOuiN)V&UTrtp|TBM zy<^c{M2VC>rbLm&ehewo?kiFSKSv|oMWl`T=6*=*pth!qn0qSz7PoH7KUw%$Pt zj5$fjO~@xrcSA2ntz7^X*iIySq2hgT@)F3%FXjyI%R$3zWcVSX7d|h~=NEXVa6vQv zJFBkVq5@VK@Zeaqx1dGfhfH34Zra|2a0vL!erG_;^5pH|ej8=Qaw-lo#U&z^#6Y3N zMomx&zo`!^32TABefcU~7_>83MtS=kg7fS|tDb0YmDVJpY@hN9@j(rwd~%Z-fnx*uH6n+Z;>X^4s#am zp5-dfD%G1Go;xYPTTjaWD*0y{Ald>vT6AMY->}e#SK27p+frKwJGCedZjC=pWVXZO z2lG~;I&_38grKHJ7$FXSd)`VfIfq5aCu!r;GkmGNJLGgkxKlJ(DjK*Q39}NEVL*zU~CW)wJ z6W-zC9w@zWut?f-s^vZh(EjGoJ_r-YqI6KPEY6*1=O9A+xB(kZ3&JD6@U|cGwh3qC zSEkBq*D&U$Wvf2oamv5cIqepl?KYdxL*62${)X>EFLaw(Wz~H;1l}6w*tdF&XC1BO zVieKC2w#f8Q6iR26FtW{$SL=;H;dugh7McIO*|rTwiMl zEg10Ww8oA55YPhLd$U@_XrO7ZHqoV+oC17ZKr-)WthU`dYCXIo;SRh z#oYkrc@>lN_Hj>c4Tgk0JIu(&L~qz>sr00EDhyZrw`ko)s)%HuPOU3`{jX@pE(rKr zxv?BHg>IU7o;l!r5QN)GftXVd6B?%vfAzVG8vDg4+VgQHSlu85ylU&!Fyn#Bd&-}J zG4DJOHK@~|+$*$P<~2_#RC{Vdv(jf2UF-fu0PM00nrzTDtHimF?>_mk;dooKTGLcE zKy&6u7Kee*@ZV5n%TLC$85qyoU?e&VAuE~d!rUcz7K=2;VNfkx!NI~Nx`Blaw=u=l;ZtZ&bg`o` z52@Z2tl*Q%x4P3NWI!_b)$5~pZWq!Su7gpaWkF19LRtjOmdTHvHD`^etzVtaIqiH> z0h8X`X4T#y2Q8BXS8;H*DwLCFWHCV_PXcu}cy;=sd)GpW;qKWbjcAf*ODB`j&e=Id ztc}vxJ4&Aa zO~l)W6>Z>L!0;g{Y@vOc@oT8p(`IoSFkka_&`z)eSfveslxg!r<9Pw=iSf zOh~tSs2k9puDEa<+LN)%e%ZoOwR2-49AQ59Yc8rpD%y#e1+MIq<;J`x5AvcGde9h=Z;p$=Vjt4V_s=kus0G7mY;_E#4!^Y^KLePX-Y&>>iFFe~_0=_ihdfsS zvkl1~*x_R}sKJU6G5gCl8SUJf7+%$WHH9hJvHMP#UWsto zdq(dIPSPk`DZH32D*X~Rf(4Dt=*m;7)+f%6aMy6=!#-njk-RX z@<3PSwAZAtMgA-tP=Bdd)nmtc-v4+HT;jP%+D&j+d4LHMH~ne|pMmx&(JKA+Kz%}m z`Ei)Hxa}~G?RG8a;6#-DPSDeSO*#^n4-E34oiHTV$-Uj(0T%)2{<_EnAjCcgSLe^w zi)y_+-B+o%16>tzPq`y+cd>-rshfGK)d2n* Date: Tue, 12 Nov 2024 12:47:59 -0800 Subject: [PATCH 023/267] Those classes are responsible for building the GUI, this should give the JFrame after implementingWeatherController and WeatherPresenter. --- src/main/java/view/MainView.java | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/view/MainView.java diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java new file mode 100644 index 000000000..3fdcb1a41 --- /dev/null +++ b/src/main/java/view/MainView.java @@ -0,0 +1,33 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; +import java.awt.*; + +public class MainView extends JFrame { + private MapPanelView mapPanelView; + private WeatherPanelView weatherPanelView; + private final int frameWidth = 1200; + private final int frameHeight = 1000; + + public MainView(WeatherViewModel weatherViewModel) { + mapPanelView = new MapPanelView(weatherViewModel); + weatherPanelView = new WeatherPanelView(); + this.setTitle("Weather Wizard"); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setSize(frameWidth, frameHeight); + // I choose to use 1X2 gridlayout so we can have both panel side by side + this.setLayout(new GridLayout(1, 2)); + this.add(mapPanelView); + this.add(weatherPanelView); + // pack() optimize window size + this.pack(); + this.setVisible(true); + + } + public static void main(String[] args) { + new MainView(); + } + +} From 52f1399bf21935adb6f7d1e5b879a85f014ab615 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:48:56 -0800 Subject: [PATCH 024/267] 2 simple preview act like tests for map Jpanel --- src/main/java/view/mapimagepreview.java | 12 ++++++++++++ src/main/java/view/mappanelpreview.java | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/main/java/view/mapimagepreview.java create mode 100644 src/main/java/view/mappanelpreview.java diff --git a/src/main/java/view/mapimagepreview.java b/src/main/java/view/mapimagepreview.java new file mode 100644 index 000000000..44d9edb57 --- /dev/null +++ b/src/main/java/view/mapimagepreview.java @@ -0,0 +1,12 @@ +package view; + +import javax.swing.*; + +public class mapimagepreview { + public static void main(String[] args) { + // Create the JPanel and add components to it + JPanel panel = new MapImagepanel(); + // Display the JPanel in a JOptionPane dialog + JOptionPane.showMessageDialog(null, panel, "map image preview", JOptionPane.PLAIN_MESSAGE); + } +} diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java new file mode 100644 index 000000000..232391e1f --- /dev/null +++ b/src/main/java/view/mappanelpreview.java @@ -0,0 +1,18 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; + +/* +* this class give a preview on MapPanelview. + */ +public class mappanelpreview { + public static void main(String[] args) { + // Create the JPanel and add components to it + final MapPanelView panel = new MapPanelView(new WeatherViewModel()); + + // Display the JPanel in a JOptionPane dialog + JOptionPane.showMessageDialog(null, panel, "JPanel Preview", JOptionPane.PLAIN_MESSAGE); + } +} \ No newline at end of file From 1961439b9fff8dd74e727c4dd6c4c62ca9f08a2f Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:48:39 -0800 Subject: [PATCH 025/267] Add method setoutput to LabelTextPanel.java so it takes a String and convert it to JLabel --- src/main/java/view/LabelTextPanel.java | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/view/LabelTextPanel.java diff --git a/src/main/java/view/LabelTextPanel.java b/src/main/java/view/LabelTextPanel.java new file mode 100644 index 000000000..e17a8efe8 --- /dev/null +++ b/src/main/java/view/LabelTextPanel.java @@ -0,0 +1,30 @@ +package view; + +import javax.swing.*; + +/** + * A panel containing a label and a text field. + */ +public class LabelTextPanel extends JPanel { + private JLabel output; + + public LabelTextPanel(JLabel label, JTextField textField) { + this.output = null; + this.add(label); + this.add(textField); + } + + public LabelTextPanel(JLabel label, String output) { + this.output = null; + this.add(label); + this.add(this.output); + } + + public JLabel getoutput() { + return this.output; + } + + public void setoutput(String outputstring) { + this.output = new JLabel(outputstring); + } +} From 14e18c476a18748b8d660846371e487b2328a535 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:57:07 -0800 Subject: [PATCH 026/267] Add another constructor that takes in two JLabel --- src/main/java/view/LabelTextPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/LabelTextPanel.java b/src/main/java/view/LabelTextPanel.java index e17a8efe8..00b67c912 100644 --- a/src/main/java/view/LabelTextPanel.java +++ b/src/main/java/view/LabelTextPanel.java @@ -14,10 +14,10 @@ public LabelTextPanel(JLabel label, JTextField textField) { this.add(textField); } - public LabelTextPanel(JLabel label, String output) { + public LabelTextPanel(JLabel label, JLabel info) { this.output = null; this.add(label); - this.add(this.output); + this.add(info); } public JLabel getoutput() { From 18172161fcede86988f93a345f67f73cb793815d Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:58:34 -0800 Subject: [PATCH 027/267] Class MainView intergrate and conbine class MapPanelView and WeatherPanelView. --- src/main/java/view/MainView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 3fdcb1a41..786a235a7 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -12,8 +12,8 @@ public class MainView extends JFrame { private final int frameHeight = 1000; public MainView(WeatherViewModel weatherViewModel) { - mapPanelView = new MapPanelView(weatherViewModel); - weatherPanelView = new WeatherPanelView(); + mapPanelView = new MapPanelView(); + weatherPanelView = new WeatherPanelView(weatherViewModel); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); @@ -26,7 +26,7 @@ public MainView(WeatherViewModel weatherViewModel) { this.setVisible(true); } - public static void main(String[] args) { + public static void man(String[] args) { new MainView(); } From 4c55dc4b64d07645aee837b69cfa04d2ded424f5 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:00:17 -0800 Subject: [PATCH 028/267] Remove PropertyChangeListener part of the code because I realize with a fixed map, we don't need change anything. --- src/main/java/view/MapPanelView.java | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/main/java/view/MapPanelView.java diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java new file mode 100644 index 000000000..ef31154ff --- /dev/null +++ b/src/main/java/view/MapPanelView.java @@ -0,0 +1,74 @@ +package view; + +import interface_adapter.note.NoteController; +import interface_adapter.note.WeatherState; +import interface_adapter.note.WeatherViewModel; +import WeatherController; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/* +* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: +* 1. search panel where user can type the city name. This is connected to a Action Lisenter, which pass information +* to our Input Class. +* 2. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. + */ +public class MapPanelView extends JPanel implements ActionListener { + private final LabelTextPanel searchpanel; + private final MapImagepanel mapimagepanel; + private final JTextField cityinputfield = new JTextField(15); + private final int mappanelwidth = 370; + private final int mappanelheight = 400; + + private WeatherController weatherController; + + public MapPanelView() { + + + mapimagepanel = new MapImagepanel(); + cityinputfield.addActionListener( + event -> { + // if the event is coming from cityinput field, execute controller + if (event.getSource() == cityinputfield) {WeatherController.excute(cityinputfield.getText()); + } + } + ); + searchpanel = new LabelTextPanel(new JLabel("search bar"), cityinputfield); +// this.setSize(mappanelwidth, mappanelheight); + this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(searchpanel); + // adding a Jlabel + this.add(mapimagepanel.getDisplayfield()); + + } + + @Override + /* + * prints a message to the console when an action event occurs. Will look something like "Enter city name" + */ + public void actionPerformed(ActionEvent event) { + System.out.println("Enter" + event.getActionCommand()); + + } + public void propertyChange(PropertyChangeEvent evt) { + final WeatherState state = (WeatherState) evt.getNewValue(); + setFields(state); + if (state.getError() != null) { + JOptionPane.showMessageDialog(this, state.getError(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + private void setFields(WeatherState state) { + cityinputfield.setText(state.getWeather()); + } + + public void setWeatherController(WeatherController controller) { + this.weatherController = controller; + } +} + From 93f4c2eff4c4ff3148eece51358d100144c082af Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:01:25 -0800 Subject: [PATCH 029/267] MapImagepanel.java can take a file name, and turn it into a JLabel. --- src/main/java/view/MapImagepanel.java | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/view/MapImagepanel.java diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java new file mode 100644 index 000000000..b61fa74c9 --- /dev/null +++ b/src/main/java/view/MapImagepanel.java @@ -0,0 +1,46 @@ +package view; + +import javax.swing.*; +import java.awt.*; + +/* +* the MapImagePanel is responsible for displaying the map file. + */ +public class MapImagepanel extends JPanel { + private ImageIcon imagemap; + private String filename; + private JLabel displayfield; + + // if no arg given, use the example MapImage.png + public MapImagepanel() { + // this is a local image + this.filename = "/Users/sophie/IdeaProjects/WeatherWizard/src/main/java/view/MapImage.png"; + try { + imagemap = new ImageIcon(this.filename); + displayfield = new JLabel(imagemap); + this.add(displayfield); + this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); + + } catch (Exception e) { + System.out.println("image cannot be found"); + } + } + + // or pass a filename as an argument + public MapImagepanel(String filename) { + this.filename = filename; + try { + imagemap = new ImageIcon(this.filename); + displayfield = new JLabel(imagemap); + this.add(displayfield); + this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); + + } catch (Exception e) { + System.out.println("image cannot be found"); + } + } + + public JLabel getDisplayfield() { + return displayfield; + } +} From e87aeb0bf276af88b28f576d3dc5cf31716e25b2 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:02:24 -0800 Subject: [PATCH 030/267] Delete the NoteView.java --- src/main/java/view/NoteView.java | 95 -------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 src/main/java/view/NoteView.java diff --git a/src/main/java/view/NoteView.java b/src/main/java/view/NoteView.java deleted file mode 100644 index 331d76493..000000000 --- a/src/main/java/view/NoteView.java +++ /dev/null @@ -1,95 +0,0 @@ -package view; - -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextArea; - -import interface_adapter.note.NoteController; -import interface_adapter.note.NoteState; -import interface_adapter.note.NoteViewModel; - -/** - * The View for when the user is viewing a note in the program. - */ -public class NoteView extends JPanel implements ActionListener, PropertyChangeListener { - - private final NoteViewModel noteViewModel; - - private final JLabel noteName = new JLabel("note for jonathan_calver2"); - private final JTextArea noteInputField = new JTextArea(); - - private final JButton saveButton = new JButton("Save"); - private final JButton refreshButton = new JButton("Refresh"); - private NoteController noteController; - - public NoteView(NoteViewModel noteViewModel) { - - noteName.setAlignmentX(Component.CENTER_ALIGNMENT); - this.noteViewModel = noteViewModel; - this.noteViewModel.addPropertyChangeListener(this); - - final JPanel buttons = new JPanel(); - buttons.add(saveButton); - buttons.add(refreshButton); - - saveButton.addActionListener( - evt -> { - if (evt.getSource().equals(saveButton)) { - noteController.execute(noteInputField.getText()); - - } - } - ); - - refreshButton.addActionListener( - evt -> { - if (evt.getSource().equals(refreshButton)) { - noteController.execute(null); - - } - } - ); - - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - this.add(noteName); - this.add(noteInputField); - this.add(buttons); - } - - /** - * React to a button click that results in evt. - * @param evt the ActionEvent to react to - */ - public void actionPerformed(ActionEvent evt) { - System.out.println("Click " + evt.getActionCommand()); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - final NoteState state = (NoteState) evt.getNewValue(); - setFields(state); - if (state.getError() != null) { - JOptionPane.showMessageDialog(this, state.getError(), - "Error", JOptionPane.ERROR_MESSAGE); - } - } - - private void setFields(NoteState state) { - noteInputField.setText(state.getNote()); - } - - public void setNoteController(NoteController controller) { - this.noteController = controller; - } -} - From 9272ce3db00fd4e33d2c7206fbb1ffbc3bdfec2f Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:03:29 -0800 Subject: [PATCH 031/267] WeatherPanelView.java implements PropertyChangeListener. Updates weather information. --- src/main/java/view/WeatherPanelView.java | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/main/java/view/WeatherPanelView.java diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java new file mode 100644 index 000000000..215284763 --- /dev/null +++ b/src/main/java/view/WeatherPanelView.java @@ -0,0 +1,78 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Observer; + +/* + * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch + * of LabelTextPanel that displays varies weather information. + * This part of view will have to change based on the output, so it depends on the view model. + */ +public class WeatherPanelView extends JPanel implements PropertyChangeListener { + private final WeatherViewModel weatherViewModel; + + private final LabelTextPanel weatherfincitypanel; + private final LabelTextPanel temperaturepanel; + private final LabelTextPanel skyconditionpanel; + private final LabelTextPanel humiditypanel; + private final LabelTextPanel windspeedpanel; + private final LabelTextPanel visibilitypanel; + + private final JLabel emptylabel = new JLabel(""); + private final int weatherpanelwidth = 370; + private final int weatherpanelheight = 400; + + public WeatherPanelView(WeatherViewModel weatherViewModel) { + this.weatherViewModel = weatherViewModel; + this.weatherViewModel.addPropertyChangeListener(this); + + this.setSize(weatherpanelwidth, weatherpanelheight); + weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(weatherfincitypanel); + this.add(temperaturepanel); + this.add(skyconditionpanel); + this.add(humiditypanel); + this.add(windspeedpanel); + this.add(visibilitypanel); + } + /* + * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. + */ + public void propertyChange(PropertyChangeEvent evt) { + final String propertyName = evt.getPropertyName(); + final String newValue = (String) evt.getNewValue(); + + SwingUtilities.invokeLater(() -> { + switch (propertyName) { + case "city": + weatherfincitypanel.setoutput(newValue); + break; + case "temperature": + temperaturepanel.setoutput(newValue); + break; + case "skyCondition": + skyconditionpanel.setoutput(newValue); + break; + case "humidity": + humiditypanel.setoutput(newValue); + break; + case "windSpeed": + windspeedpanel.setoutput(newValue); + break; + case "visibility": + visibilitypanel.setoutput(newValue); + break; + } + }); + } +} From d819cb2a9513f0f44417d6ce1dbc9adc5a0e321c Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:22:32 -0800 Subject: [PATCH 032/267] Note we might want to add a convertor here. --- src/main/java/view/WeatherPanelView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 215284763..b4f1fdc1f 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -33,6 +33,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel) { this.setSize(weatherpanelwidth, weatherpanelheight); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + // Note we might want to add a convertor here. skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); From dbbc26b51aa9166e6d24d2fc75b202d5d346b32b Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:37:12 -0800 Subject: [PATCH 033/267] Fix Checkstyle for import --- src/main/java/view/MainView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 786a235a7..9f2dda417 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -2,8 +2,8 @@ import interface_adapter.note.WeatherViewModel; -import javax.swing.*; -import java.awt.*; +import javax.swing.JFrame; +import java.awt.GridLayout; public class MainView extends JFrame { private MapPanelView mapPanelView; From d8ebf9dcb1f5fc006f3ded469b33ebda4a5ef89a Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:42:02 -0800 Subject: [PATCH 034/267] // psvm --- src/main/java/view/MainView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 9f2dda417..e689a9197 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -26,8 +26,8 @@ public MainView(WeatherViewModel weatherViewModel) { this.setVisible(true); } - public static void man(String[] args) { - new MainView(); - } +// public static void man(String[] args) { +// new MainView(); +// } } From ac579ffb79cfdbcb9e4a02d863bf81eb0f14806d Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 21:05:59 -0500 Subject: [PATCH 035/267] null tag added --- .../use_case/note/SearchReturnInteractor.java | 31 +++++++++++++++++++ .../SearchReturnInputBoundary.java | 11 +++++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/main/java/use_case/note/SearchReturnInteractor.java diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java new file mode 100644 index 000000000..bb67cc4c2 --- /dev/null +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -0,0 +1,31 @@ +import entity.Weather; +import use_case.note.WeatherDataAccessInterface; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class SearchReturnInteractor implements SearchReturnInputBoundary { + private final SearchResultOutputBoundary outputBoundary; + private final WeatherDataAccessInterface weatherDataAccess; + private final Map historicalWeatherData; + + public SearchReturnInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + this.outputBoundary = outputBoundary; + this.weatherDataAccess = weatherDataAccess; + this.historicalWeatherData = new HashMap<>(); + } + + @Override + public void execute(SearchReturnInputData searchReturnInputData) { + + } +} \ No newline at end of file diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java index 654457ce1..ac47665d0 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java @@ -1,7 +1,14 @@ package use_case.note.search_return; -// Input is one click on "return." +/** + * The input boundary for the search return use case. + */ public interface SearchReturnInputBoundary { - void execute(SearchReturnInputData searchReturnInputData) + /** + * Execute the search return use case. + * + * @param searchReturnInputData The input data for the search return use case. + */ + void execute(SearchReturnInputData searchReturnInputData); } From e32e174f63e66618b0b43550bdd61988d01a7d5b Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 23:05:15 -0500 Subject: [PATCH 036/267] correct mistakes being sent to the SearchResultOutputData --- src/main/java/use_case/note/SearchResultInteractor.java | 4 +++- src/main/java/use_case/note/WeatherDataAccessInterface.java | 3 ++- .../use_case/note/search_result/SearchResultOutputData.java | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 16630ba91..e11801a68 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -39,6 +39,7 @@ public void execute(SearchResultInputData searchReturnInputData) { scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); } + private void fetchWeatherData() { try { final String city = SearchResultInputData.getCity(); @@ -51,7 +52,8 @@ private void fetchWeatherData() { // Send it to the output boundary final SearchResultOutputData outputData = - new SearchResultOutputData(city, weatherData, false); + new SearchResultOutputData(city, historicalWeatherData, false); + weatherDataAccess.saveWeather(city, historicalWeatherData) outputBoundary.presentSuccessView(outputData); } catch (IOException exception) { diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index e1c13927a..1dab1f0ea 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -2,6 +2,7 @@ import entity.Weather; import java.io.IOException; +import java.util.Map; /** * Interface for the WeatherDAO. It consists of methods for @@ -17,5 +18,5 @@ public interface WeatherDataAccessInterface { */ Weather getWeather(String city) throws IOException; - + Map saveWeather(String city, Map weather) throws IOException; } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index 310ed041c..f2a6ab4c5 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -2,13 +2,15 @@ import entity.Weather; +import java.util.Map; + public class SearchResultOutputData { private final String location; - private final Weather weather; + private final Map weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Map weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; From 17e2816b247f10ae2a64a747a36e38580731501a Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Wed, 13 Nov 2024 11:25:56 -0500 Subject: [PATCH 037/267] Created the Input/Output Boundaries and Data --- .../ConvertFarenheitInputBoundary.java | 5 +++++ .../ConvertFarenheitInputData.java | 4 ++++ .../ConvertFarenheitOutputBoundary.java | 7 +++++++ .../ConvertFarenheitOutputData.java | 13 +++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java create mode 100644 src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java create mode 100644 src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java create mode 100644 src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java new file mode 100644 index 000000000..84670f1b9 --- /dev/null +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java @@ -0,0 +1,5 @@ +package use_case.note.convert_farenheit; + +public interface ConvertFarenheitInputBoundary { + void execute(ConvertFarenheitInputData convertFarenheitInputData); +} diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java new file mode 100644 index 000000000..97b2827ee --- /dev/null +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java @@ -0,0 +1,4 @@ +package use_case.note.convert_farenheit; + +public class ConvertFarenheitInputData { +} diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java new file mode 100644 index 000000000..dc5d3c646 --- /dev/null +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java @@ -0,0 +1,7 @@ +package use_case.note.convert_farenheit; + +public interface ConvertFarenheitOutputBoundary { + void presentSuccessView(ConvertFarenheitOutputData data); + + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java new file mode 100644 index 000000000..1da847392 --- /dev/null +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java @@ -0,0 +1,13 @@ +package use_case.note.convert_farenheit; + +public class ConvertFarenheitOutputData { + private final boolean useCaseFailed; + + public ConvertFarenheitOutputData(boolean useCaseFailed) { + this.useCaseFailed = useCaseFailed; + } + + public boolean isUseCaseFailed() { + return useCaseFailed; + } +} From fe5fe86e74ae4a88426aaa3c695c832e01bdd627 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Wed, 13 Nov 2024 11:38:41 -0500 Subject: [PATCH 038/267] Created teh Converter and Added setters to Weather --- src/main/java/entity/Converter.java | 13 +++++++++++++ src/main/java/entity/Weather.java | 12 ++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/main/java/entity/Converter.java diff --git a/src/main/java/entity/Converter.java b/src/main/java/entity/Converter.java new file mode 100644 index 000000000..ef4177388 --- /dev/null +++ b/src/main/java/entity/Converter.java @@ -0,0 +1,13 @@ +package entity; + +public class Converter { + public static final double KILOMETERS_MILE = 0.62; + public static final double CELC_FAREN = 1.8; + public static final double FAREN_ADD = 32 + + public Converter(Weather weather) { + weather.setWindSpeed((int) (weather.getWindSpeed() * KILOMETERS_MILE)); + weather.setTemperature((int) ((weather.getTemperature() * CELC_FAREN)+ FAREN_ADD)); + + } +} diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 544f82ca5..ec99bba68 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -8,11 +8,11 @@ public class Weather { private final int longitude; private final int latitude; - private final int temperature; + private int temperature; private final String looks; private final String alertDescription; private final int humidity; - private final int windSpeed; + private int windSpeed; public Weather(String city, int longitude, int latitude, int temperature, String looks, String alertDescription, int humidity, int windSpeed) { this.city = city; @@ -34,6 +34,10 @@ public int getWindSpeed() { return windSpeed; } + public void setWindSpeed(int newSpeed) { + windSpeed = newSpeed; + } + public String getCity() { return city; } @@ -50,6 +54,10 @@ public int getTemperature() { return temperature; } + public void setTemperature(int temperature) { + this.temperature = temperature; + } + public String getLooks() { return looks; } From 1bab4823d4a77f20f974d63ea2dff136d755a80e Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Wed, 13 Nov 2024 11:39:01 -0500 Subject: [PATCH 039/267] Created teh Converter and Added setters to Weather --- src/main/java/entity/Converter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/entity/Converter.java b/src/main/java/entity/Converter.java index ef4177388..cbc21f4a3 100644 --- a/src/main/java/entity/Converter.java +++ b/src/main/java/entity/Converter.java @@ -3,7 +3,7 @@ public class Converter { public static final double KILOMETERS_MILE = 0.62; public static final double CELC_FAREN = 1.8; - public static final double FAREN_ADD = 32 + public static final double FAREN_ADD = 32; public Converter(Weather weather) { weather.setWindSpeed((int) (weather.getWindSpeed() * KILOMETERS_MILE)); From 499cacf1ba46df822972201b31de7aed2c2044e2 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 11 Nov 2024 21:41:38 -0500 Subject: [PATCH 040/267] SearchResultInteractor implemented. --- .../use_case/note/SearchResultInteractor.java | 60 +++++++++++++++++++ .../SearchResultInputBoundary.java | 2 +- .../search_result/SearchResultInputData.java | 9 +-- .../search_result/SearchResultOutputData.java | 10 +++- 4 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 src/main/java/use_case/note/SearchResultInteractor.java diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java new file mode 100644 index 000000000..12cecce16 --- /dev/null +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -0,0 +1,60 @@ +package use_case.note; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import entity.Weather; +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; + +public class SearchResultInteractor implements SearchResultInputBoundary { + private final SearchResultOutputBoundary outputBoundary; + private final WeatherDataAccessInterface weatherDataAccess; + private final Map historicalWeatherData; + + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + this.outputBoundary = outputBoundary; + this.weatherDataAccess = weatherDataAccess; + this.historicalWeatherData = new HashMap<>(); + } + + @Override + public void execute(SearchResultInputData searchReturnInputData) { + final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + final Runnable weatherTask = () -> { + fetchWeatherData(); + }; + + // Schedule the task to run every hour + scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); + } + + private void fetchWeatherData() { + try { + final String city = SearchResultInputData.getCity(); + // Simulate reading weather data + final Weather weatherData = weatherDataAccess.getWeather(city); + + // Store it in historical data + final String timestamp = String.valueOf(System.currentTimeMillis()); + historicalWeatherData.put(timestamp, weatherData); + + // Send it to the output boundary + final SearchResultOutputData outputData = + new SearchResultOutputData(city, weatherData, false); + outputBoundary.presentSuccessView(outputData); + } + catch (IOException exception) { + // Handle exception if weather data retrieval fails and send failure view + outputBoundary.presentFailView("Failed to retrieve weather data: " + exception.getMessage()); + } + } + +} diff --git a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java index e54108eb8..99054de87 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java @@ -4,5 +4,5 @@ // search bar. public interface SearchResultInputBoundary { - void execute(SearchResultInputData searchResultInputData) + void execute(SearchResultInputData searchResultInputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 4dd04fc47..63e213ef5 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -3,13 +3,14 @@ // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. public class SearchResultInputData { - private final String cityName; + + private static final String city; public SearchResultInputData(String cityName) { - this.cityName = cityName; + this.city = cityName; } - public String getCity() { - return cityName; + public static String getCity() { + return city; } } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index 15acd46bb..310ed041c 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -1,12 +1,14 @@ package use_case.note.search_result; +import entity.Weather; + public class SearchResultOutputData { private final String location; - private final String weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, String weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; @@ -16,7 +18,9 @@ public String getLocation() { return location; } - public String getWeather() {return weather;} + public Weather getWeather() { + return weather; + } public boolean isUseCaseFailed() { return useCaseFailed; From 1b20cab7b6dea69f51a4e17b8a03468188b78580 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 11:49:20 -0500 Subject: [PATCH 041/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 12cecce16..b598748ff 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -13,6 +13,9 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; +/** + * The interactor for the search result use case. + */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; From 8e866a4276f47255ac6352909181fe661f775913 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 12:16:22 -0500 Subject: [PATCH 042/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index b598748ff..16630ba91 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -14,7 +14,7 @@ import use_case.note.search_result.SearchResultOutputData; /** - * The interactor for the search result use case. + * The interactor for the search result use case.. */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; From 2d8c7d1d8bbd86eaf342e97a1840611a5336a515 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 13 Nov 2024 12:15:42 -0800 Subject: [PATCH 043/267] / --- src/main/java/view/WeatherPanelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index b4f1fdc1f..5c5441d0a 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -10,7 +10,7 @@ /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch * of LabelTextPanel that displays varies weather information. - * This part of view will have to change based on the output, so it depends on the view model. + * This part of view will have to change based on the output, so it depends on the view model */ public class WeatherPanelView extends JPanel implements PropertyChangeListener { private final WeatherViewModel weatherViewModel; From 330fbfa707671b838241adcfc45d46cba5297962 Mon Sep 17 00:00:00 2001 From: harman Date: Wed, 13 Nov 2024 19:21:51 -0500 Subject: [PATCH 044/267] Updated README.md --- README.md | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 8aa6d8de8..e03030fe2 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,11 @@ -# Note Application - -This is a minimal example demonstrating usage of the -password-protected user part of the API used in lab 5. - -You can find more information about the API endpoints in -[the documentation](https://www.postman.com/cloudy-astronaut-813156/csc207-grade-apis-demo/documentation/fg3zkjm/5-password-protected-user). - -If your team is considering an application for which it would be convenient to -store data in something like a database, you may find that the API calls demonstrated -here will be useful in your project, as this will allow you to store -an arbitrary JSON object associated with a username and password. - -In this application, a single note has a name (the "username" in terms of the API) and the note -can be read by anyone who knows the name — but only edited by someone who -knows the password for it. - - -You can see the documentation in the various files for more information. +# WeatherWizard +The purpose of our Code is to create a Weather Application that is User friendly and can display several features. ## User Stories Person wants to search for a specific location. They type that location in the search bar and the map moves to that location and displays the weather. If they search for a place that doesnt exist, the software displays an error message. +Person does not understand metric units so they convert to imperial. + Person wants to view weather alerts in a certain area. They see that displayed somewhere. Person wants a quick overview of the weather in nearby areas. They can view a list of major nearby locations and select one. @@ -29,21 +14,17 @@ Person wants to compare the weather in 2 different locations. They can pin the w Person wants to see what the weather was yesterday. They can select any hour from the past 24 hours to see what the weather was then. +## API +The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. + https://openweathermap.org/api/one-call-3 +The JXMAP library is used to produce a map in which the user can drag and drop pins on cities. + msteiger/jxmapviewer2: JXMapViewer2 ## Testing +[To be added] -The repo also includes an example of a use case interactor test, as well as -an example of an end-to-end test which automates button clicks and inspects -the contents of the actual views. This is something we discussed in the lectures -about testing in CA but had not provided a code example of before. Note, one -could also inspect the contents of the ViewModel objects instead when testing -CA to make a similar test which would be less dependent on the details of the -specific UI implementation. - -## Project Starter Code +## Want to know more? +If you would like to know more please check out our presentation. +[Link to be added] -Your team may choose to use this repo as starter code for your project. You could -also use the lab 5 code — or start from an empty repo if your team prefers. -If you choose to use one of the repositories we have provided, you can either make -a fork of it or copy the subset of code you want into a completely new repository. From 98b395b1c057ba7cc74d48b949516c35ea69e652 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Wed, 13 Nov 2024 23:51:41 -0500 Subject: [PATCH 045/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- pom.xml | 6 ++ .../HistoricalWeatherDataAccessObject.java | 95 +++++++++++++++++++ .../data_access/WeatherDataAccessObject.java | 11 ++- .../HistoricalWeatherDataAccessInterface.java | 27 ++++++ .../use_case/note/SearchResultInteractor.java | 12 ++- .../note/WeatherDataAccessInterface.java | 2 - 6 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 src/main/java/data_access/HistoricalWeatherDataAccessObject.java create mode 100644 src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java diff --git a/pom.xml b/pom.xml index e86052a71..63e13760c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,12 @@ 2.8 + + com.googlecode.json-simple + json-simple + 1.1 + + diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java new file mode 100644 index 000000000..0bc5c6e33 --- /dev/null +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -0,0 +1,95 @@ +package data_access; + +import java.io.FileWriter; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Objects; + +import org.json.JSONArray; +import org.json.JSONObject; + +import entity.Weather; +import use_case.note.HistoricalWeatherDataAccessInterface; + +/** + * This class provides the service of saving and getting historical weather data. + */ +public class HistoricalWeatherDataAccessObject implements HistoricalWeatherDataAccessInterface { + @Override + public void saveWeather(Weather weather, String timeStamp) { + + // Save the weather data to the database + // Convert the Weather object to JSON + final String nextLine = "\",\n"; + final StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{\n"); + jsonBuilder.append(" \"timeStamp\": \"" + timeStamp + nextLine); + jsonBuilder.append(" \"city\": \"" + weather.getCity() + nextLine); + jsonBuilder.append(" \"longitude\": " + weather.getLongitude() + nextLine); + jsonBuilder.append(" \"latitude\": ").append(weather.getLatitude()).append(nextLine); + jsonBuilder.append(" \"temperature\": ").append(weather.getTemperature()).append(nextLine); + jsonBuilder.append(" \"looks\": \"").append(weather.getLooks()).append(nextLine); + jsonBuilder.append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append(nextLine); + jsonBuilder.append(" \"humidity\": " + weather.getHumidity() + nextLine); + jsonBuilder.append(" \"windSpeed\": " + weather.getWindSpeed() + nextLine); + jsonBuilder.append("}"); + + // Convert StringBuilder to String + final String weatherJson = jsonBuilder.toString(); + + // Write JSON to a file + try (FileWriter fileWriter = new FileWriter("weather.json")) { + fileWriter.write(weatherJson); + System.out.println("Successfully wrote weather data to weather.json"); + } + catch (IOException excep) { + excep.printStackTrace(); + } + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + // Get the weather data from the database + // Read the JSON from the file + final String filePath = "weather.json"; + try { + // Reading the content of the JSON file into a String + final String jsonString = Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader() + .getResource(filePath)).toURI())); + // Converting the JSON String to a JSONArray + final JSONArray weatherArray = new JSONArray(jsonString); + // Iterating over the JSONArray + for (int i = 0; i < weatherArray.length(); i++) { + // Getting the JSONObject at the index i + final JSONObject weatherObject = weatherArray.getJSONObject(i); + // Getting the city from the JSONObject + final String cityNameCall = weatherObject.getString("city"); + // Getting the timestamp from the JSONObject + final String timeStamp = weatherObject.getString("timeStamp"); + // Checking if the city and timestamp match the input + if (cityNameCall.equals(cityNameCall) && timeStamp.equals(timestamp)) { + // Create weather object + final Weather weather = new Weather( + cityNameCall, + weatherObject.getInt("longitude"), + weatherObject.getInt("latitude"), + weatherObject.getInt("temperature"), + weatherObject.getString("looks"), + weatherObject.getString("alertDescription"), + weatherObject.getInt("humidity"), + weatherObject.getInt("windSpeed") + ); + return weather; + } + + } + } + catch (IOException | URISyntaxException exe) { + exe.printStackTrace(); + } + throw new IOException("Weather data not found"); + } + +} diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 9e56b8c45..2ed681744 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -9,6 +9,8 @@ import org.json.JSONArray; import use_case.note.WeatherDataAccessInterface; + + import java.io.IOException; @@ -16,7 +18,7 @@ * This class runs the API and creates a weather DAO. **/ -public class WeatherDataAccessObject implements WeatherDataAccessInterface { +public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; private static String city; @@ -27,14 +29,14 @@ public class WeatherDataAccessObject implements WeatherDataAccessInterface { private static final String MESSAGE = "message"; @Override - public Weather getWeather(String city) throws IOException { + public Weather getWeather(String citySearch) throws IOException { // Make an API call to get the user object. final OkHttpClient client = new OkHttpClient().newBuilder().build(); // creating file final Request request = new Request.Builder() .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" - + API_KEY + "&units=metric", city)) + + API_KEY + "&units=metric", citySearch)) .addHeader("Content-Type", CONTENT_TYPE_JSON) .build(); try { @@ -61,7 +63,7 @@ public Weather getWeather(String city) throws IOException { } } - return new Weather(city, lon, lat, temp, looks, alertDescription, humidity, windspeed); + return new Weather(citySearch, lon, lat, temp, looks, alertDescription, humidity, windspeed); } else { @@ -72,5 +74,6 @@ public Weather getWeather(String city) throws IOException { throw new IOException(ex); } } + } diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java new file mode 100644 index 000000000..ee92c1262 --- /dev/null +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -0,0 +1,27 @@ +package use_case.note; + +import entity.Weather; + +import java.io.IOException; +import java.util.Map; + +/** + * Interface for the HistoricalWeatherDataAccessObject. It consists of methods for + * saving the weather. + */ +public interface HistoricalWeatherDataAccessInterface { + /** + * Saves the weather data. + * @param weather the weather data to save + * @throws IOException if there is an error saving the weather data + */ + void saveWeather(Weather weather, String timstamp) throws IOException; + + /** + * Gets the weather data. + * @param city the city to get the weather data for + * @param timestamp the timestamp of the weather data + * @throws IOException if there is an error getting the weather data + */ + Weather getWeather(String city, String timestamp) throws IOException; +} diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index e11801a68..241c4af63 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -12,6 +12,7 @@ import use_case.note.search_result.SearchResultInputData; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; +import use_case.note.HistoricalWeatherDataAccessInterface; /** * The interactor for the search result use case.. @@ -20,11 +21,14 @@ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; private final Map historicalWeatherData; + private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; - public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess, + HistoricalWeatherDataAccessInterface historicalDataInterface ) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherData = new HashMap<>(); + this.historicalWeatherDataAccessInterface = historicalDataInterface } @Override @@ -47,14 +51,14 @@ private void fetchWeatherData() { final Weather weatherData = weatherDataAccess.getWeather(city); // Store it in historical data - final String timestamp = String.valueOf(System.currentTimeMillis()); - historicalWeatherData.put(timestamp, weatherData); + final String timestamp = String.valueOf(System.currentTimeMillis());; // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - weatherDataAccess.saveWeather(city, historicalWeatherData) + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); outputBoundary.presentSuccessView(outputData); + } catch (IOException exception) { // Handle exception if weather data retrieval fails and send failure view diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index 1dab1f0ea..163d40981 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -2,7 +2,6 @@ import entity.Weather; import java.io.IOException; -import java.util.Map; /** * Interface for the WeatherDAO. It consists of methods for @@ -18,5 +17,4 @@ public interface WeatherDataAccessInterface { */ Weather getWeather(String city) throws IOException; - Map saveWeather(String city, Map weather) throws IOException; } From c626f36a95474b079117b166e68823bf4d1cf04f Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:22:31 -0500 Subject: [PATCH 046/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- pom.xml | 5 ----- .../use_case/note/HistoricalWeatherDataAccessInterface.java | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 63e13760c..c181fb0f6 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,6 @@ 2.8 - - com.googlecode.json-simple - json-simple - 1.1 - diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index ee92c1262..904670ccf 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -1,9 +1,8 @@ package use_case.note; -import entity.Weather; - import java.io.IOException; -import java.util.Map; + +import entity.Weather; /** * Interface for the HistoricalWeatherDataAccessObject. It consists of methods for @@ -13,6 +12,7 @@ public interface HistoricalWeatherDataAccessInterface { /** * Saves the weather data. * @param weather the weather data to save + * @param timstamp the timestamp of the weather data * @throws IOException if there is an error saving the weather data */ void saveWeather(Weather weather, String timstamp) throws IOException; From 844df0a394184d0b67a692497cae600d6cb02da4 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:25:48 -0500 Subject: [PATCH 047/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- src/main/java/use_case/note/SearchResultInteractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 241c4af63..91b9fdb5c 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -28,7 +28,7 @@ public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, Weather this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherData = new HashMap<>(); - this.historicalWeatherDataAccessInterface = historicalDataInterface + this.historicalWeatherDataAccessInterface = historicalDataInterface; } @Override From 2e621168392e8dd19a536b0f68ea64a5b4a7bd92 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:32:30 -0500 Subject: [PATCH 048/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- src/main/java/use_case/note/SearchResultInteractor.java | 9 ++++++--- .../note/search_result/SearchResultInputData.java | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 91b9fdb5c..f15698cb6 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -1,6 +1,9 @@ package use_case.note; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; @@ -12,7 +15,6 @@ import use_case.note.search_result.SearchResultInputData; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; -import use_case.note.HistoricalWeatherDataAccessInterface; /** * The interactor for the search result use case.. @@ -51,12 +53,13 @@ private void fetchWeatherData() { final Weather weatherData = weatherDataAccess.getWeather(city); // Store it in historical data - final String timestamp = String.valueOf(System.currentTimeMillis());; + final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); + final String timestamp1 = formatter.format(Instant.now()); // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp1); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 63e213ef5..0aa65bbef 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -6,7 +6,7 @@ public class SearchResultInputData { private static final String city; - public SearchResultInputData(String cityName) { + public SearchResultInputData(String cityName, String date) { this.city = cityName; } From 22e5bf85f3b38066faf3c784c21f61aad6ebcffe Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 15:45:50 -0500 Subject: [PATCH 049/267] interactor and output boundary finished --- .../java/use_case/note/SearchResultInteractor.java | 14 +++----------- .../note/search_result/SearchResultInputData.java | 12 +++++++++--- .../note/search_result/SearchResultOutputData.java | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index f15698cb6..e0ca7370b 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -35,17 +35,9 @@ public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, Weather @Override public void execute(SearchResultInputData searchReturnInputData) { - final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - final Runnable weatherTask = () -> { - fetchWeatherData(); - }; - - // Schedule the task to run every hour - scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); + fetchWeatherData(); } - private void fetchWeatherData() { try { final String city = SearchResultInputData.getCity(); @@ -54,12 +46,12 @@ private void fetchWeatherData() { // Store it in historical data final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); - final String timestamp1 = formatter.format(Instant.now()); + final String timestamp = formatter.format(Instant.now()); // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp1); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 0aa65bbef..f15ab28b1 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -4,13 +4,19 @@ // search bar. public class SearchResultInputData { - private static final String city; + private String city; + private final String date; public SearchResultInputData(String cityName, String date) { this.city = cityName; + this.date = date; } - public static String getCity() { - return city; + public String getCity() { + return this.city; + } + + public String getDate() { + return this.date; } } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index f2a6ab4c5..5c8b0fcb7 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -7,10 +7,10 @@ public class SearchResultOutputData { private final String location; - private final Map weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, Map weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; From 81773e73f1e9073be38fb69f331692a6d5c443c0 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 14 Nov 2024 14:54:09 -0800 Subject: [PATCH 050/267] Adding ActionListener to temperature convertor button. --- src/main/java/view/WeatherPanelView.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 5c5441d0a..98963d98e 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,8 +1,10 @@ package view; import interface_adapter.note.WeatherViewModel; +import WeatherController; import javax.swing.*; +import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Observer; @@ -12,7 +14,7 @@ * of LabelTextPanel that displays varies weather information. * This part of view will have to change based on the output, so it depends on the view model */ -public class WeatherPanelView extends JPanel implements PropertyChangeListener { +public class WeatherPanelView extends JPanel implements PropertyChangeListener, ActionListener { private final WeatherViewModel weatherViewModel; private final LabelTextPanel weatherfincitypanel; @@ -25,6 +27,8 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener { private final JLabel emptylabel = new JLabel(""); private final int weatherpanelwidth = 370; private final int weatherpanelheight = 400; + private final JButton temperatureconverter; + private WeatherController weatherController; public WeatherPanelView(WeatherViewModel weatherViewModel) { this.weatherViewModel = weatherViewModel; @@ -33,7 +37,13 @@ public WeatherPanelView(WeatherViewModel weatherViewModel) { this.setSize(weatherpanelwidth, weatherpanelheight); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); - // Note we might want to add a convertor here. + // Note we want to add a convertor here.The button needs an action listenser. + this.temperatureconverter = new JButton("Temperature Converter"); + temperatureconverter.addActionListener( event -> { + // if the event is coming from cityinput field, execute controller + if (event.getSource() == temperatureconverter) {WeatherController.excute(temperatureconverter.getText()); + }); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); @@ -41,6 +51,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel) { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherfincitypanel); this.add(temperaturepanel); + this.add(temperatureconverter); this.add(skyconditionpanel); this.add(humiditypanel); this.add(windspeedpanel); From 77ceff0bac428acd2f5511b043eed5a710ccaa93 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 02:22:04 -0500 Subject: [PATCH 051/267] finished weather controller and presenter, renamed related files from 'note' to 'weather' --- src/main/java/app/NoteAppBuilder.java | 10 ++--- .../note/NoteController.java | 28 -------------- .../interface_adapter/note/NotePresenter.java | 38 ------------------- .../weather/WeatherController.java | 25 ++++++++++++ .../weather/WeatherPresenter.java | 38 +++++++++++++++++++ .../{note => weather}/WeatherState.java | 2 +- .../{note => weather}/WeatherViewModel.java | 2 +- .../pin_weather/PinWeatherInputBoundary.java | 2 +- .../search_result/SearchResultInputData.java | 8 +--- src/main/java/view/MainView.java | 2 +- src/main/java/view/MapPanelView.java | 9 ++--- src/main/java/view/WeatherPanelView.java | 3 +- src/main/java/view/mappanelpreview.java | 2 +- 13 files changed, 78 insertions(+), 91 deletions(-) delete mode 100644 src/main/java/interface_adapter/note/NoteController.java delete mode 100644 src/main/java/interface_adapter/note/NotePresenter.java create mode 100644 src/main/java/interface_adapter/weather/WeatherController.java create mode 100644 src/main/java/interface_adapter/weather/WeatherPresenter.java rename src/main/java/interface_adapter/{note => weather}/WeatherState.java (93%) rename src/main/java/interface_adapter/{note => weather}/WeatherViewModel.java (87%) diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index 652884732..ea2a3a58a 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -3,9 +3,9 @@ import javax.swing.JFrame; import javax.swing.WindowConstants; -import interface_adapter.note.NoteController; -import interface_adapter.note.NotePresenter; -import interface_adapter.note.NoteViewModel; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherPresenter; +import interface_adapter.weather.WeatherViewModel; import use_case.note.WeatherDataAccessInterface; import use_case.note.NoteInteractor; import use_case.note.NoteOutputBoundary; @@ -40,11 +40,11 @@ public NoteAppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { * @throws RuntimeException if this method is called before addNoteView */ public NoteAppBuilder addNoteUseCase() { - final NoteOutputBoundary noteOutputBoundary = new NotePresenter(noteViewModel); + final NoteOutputBoundary noteOutputBoundary = new WeatherPresenter(noteViewModel); noteInteractor = new NoteInteractor( noteDAO, noteOutputBoundary); - final NoteController controller = new NoteController(noteInteractor); + final WeatherController controller = new WeatherController(noteInteractor); if (noteView == null) { throw new RuntimeException("addNoteView must be called before addNoteUseCase"); } diff --git a/src/main/java/interface_adapter/note/NoteController.java b/src/main/java/interface_adapter/note/NoteController.java deleted file mode 100644 index e3e5dfb32..000000000 --- a/src/main/java/interface_adapter/note/NoteController.java +++ /dev/null @@ -1,28 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteInputBoundary; - -/** - * Controller for our Note related Use Cases. - */ -public class NoteController { - - private final NoteInputBoundary noteInteractor; - - public NoteController(NoteInputBoundary noteInteractor) { - this.noteInteractor = noteInteractor; - } - - /** - * Executes the Note related Use Cases. - * @param note the note to be recorded - */ - public void execute(String note) { - if (note != null) { - noteInteractor.executeSave(note); - } - else { - noteInteractor.executeRefresh(); - } - } -} diff --git a/src/main/java/interface_adapter/note/NotePresenter.java b/src/main/java/interface_adapter/note/NotePresenter.java deleted file mode 100644 index d4e416165..000000000 --- a/src/main/java/interface_adapter/note/NotePresenter.java +++ /dev/null @@ -1,38 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteOutputBoundary; - -/** - * The presenter for our Note viewing and editing program. - */ -public class NotePresenter implements NoteOutputBoundary { - - private final NoteViewModel noteViewModel; - - public NotePresenter(NoteViewModel noteViewModel) { - this.noteViewModel = noteViewModel; - } - - /** - * Prepares the success view for the Note related Use Cases. - * - * @param note the output data - */ - @Override - public void prepareSuccessView(String note) { - noteViewModel.getState().setNote(note); - noteViewModel.getState().setError(null); - noteViewModel.firePropertyChanged(); - } - - /** - * Prepares the failure view for the Note related Use Cases. - * - * @param errorMessage the explanation of the failure - */ - @Override - public void prepareFailView(String errorMessage) { - noteViewModel.getState().setError(errorMessage); - noteViewModel.firePropertyChanged(); - } -} diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java new file mode 100644 index 000000000..299ebd86e --- /dev/null +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -0,0 +1,25 @@ +package interface_adapter.weather; + +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; + +/** + * Controller for our Note related Use Cases. + */ +public class WeatherController { + + private final SearchResultInputBoundary searchInteractor; + + public WeatherController(SearchResultInputBoundary searchInteractor) { + this.searchInteractor = searchInteractor; + } + + /** + * Execute the weather use case. + * @param cityName the city to find the weather for + */ + public void execute(String cityName) { + final SearchResultInputData searchInputData = new SearchResultInputData(cityName); + searchInteractor.execute(searchInputData); + } +} diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java new file mode 100644 index 000000000..5cc8a4fed --- /dev/null +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -0,0 +1,38 @@ +package interface_adapter.weather; + +import use_case.note.NoteOutputBoundary; + +/** + * The presenter for our Note viewing and editing program. + */ +public class WeatherPresenter implements NoteOutputBoundary { + + private final WeatherViewModel weatherViewModel; + + public WeatherPresenter(WeatherViewModel weatherViewModel) { + this.weatherViewModel = weatherViewModel; + } + + /** + * Prepares the success view for the Weather related Use Cases. + * + * @param weather the output data + */ + @Override + public void prepareSuccessView(String weather) { + weatherViewModel.getState().setWeather(weather); + weatherViewModel.getState().setError(null); + weatherViewModel.firePropertyChanged(); + } + + /** + * Prepares the failure view for the Weather related Use Cases. + * + * @param errorMessage the explanation of the failure + */ + @Override + public void prepareFailView(String errorMessage) { + weatherViewModel.getState().setError(errorMessage); + weatherViewModel.firePropertyChanged(); + } +} diff --git a/src/main/java/interface_adapter/note/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java similarity index 93% rename from src/main/java/interface_adapter/note/WeatherState.java rename to src/main/java/interface_adapter/weather/WeatherState.java index 1d2bf9657..426fb8437 100644 --- a/src/main/java/interface_adapter/note/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -1,4 +1,4 @@ -package interface_adapter.note; +package interface_adapter.weather; /** * The State for a weather. diff --git a/src/main/java/interface_adapter/note/WeatherViewModel.java b/src/main/java/interface_adapter/weather/WeatherViewModel.java similarity index 87% rename from src/main/java/interface_adapter/note/WeatherViewModel.java rename to src/main/java/interface_adapter/weather/WeatherViewModel.java index 7d10ebde8..9cffe3889 100644 --- a/src/main/java/interface_adapter/note/WeatherViewModel.java +++ b/src/main/java/interface_adapter/weather/WeatherViewModel.java @@ -1,4 +1,4 @@ -package interface_adapter.note; +package interface_adapter.weather; import interface_adapter.ViewModel; diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java index 77475633d..2e267e172 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java @@ -3,5 +3,5 @@ // Input is a click on "pin." public interface PinWeatherInputBoundary { - void execute(PinWeatherInputData pinWeatherInputData) + void execute(PinWeatherInputData pinWeatherInputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index f15ab28b1..296c5bcb9 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -5,18 +5,12 @@ public class SearchResultInputData { private String city; - private final String date; - public SearchResultInputData(String cityName, String date) { + public SearchResultInputData(String cityName) { this.city = cityName; - this.date = date; } public String getCity() { return this.city; } - - public String getDate() { - return this.date; - } } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index e689a9197..7b4887e8e 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,6 +1,6 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.JFrame; import java.awt.GridLayout; diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index ef31154ff..fc08a81f8 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,15 +1,12 @@ package view; -import interface_adapter.note.NoteController; -import interface_adapter.note.WeatherState; -import interface_adapter.note.WeatherViewModel; -import WeatherController; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: @@ -33,7 +30,7 @@ public MapPanelView() { cityinputfield.addActionListener( event -> { // if the event is coming from cityinput field, execute controller - if (event.getSource() == cityinputfield) {WeatherController.excute(cityinputfield.getText()); + if (event.getSource() == cityinputfield) {WeatherController.execute(cityinputfield.getText()); } } ); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 5c5441d0a..79580c43c 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,11 +1,10 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Observer; /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java index 232391e1f..55fbe9866 100644 --- a/src/main/java/view/mappanelpreview.java +++ b/src/main/java/view/mappanelpreview.java @@ -1,6 +1,6 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; From 069d89deff3519ff9b2732da87e870b340f9ef4f Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 02:41:16 -0500 Subject: [PATCH 052/267] re-added imports that somehow got deleted --- src/main/java/view/MapPanelView.java | 2 ++ src/main/java/view/WeatherPanelView.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index fc08a81f8..69776eb1f 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -2,11 +2,13 @@ import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherState; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 79580c43c..578342a5b 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -5,6 +5,7 @@ import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Observer; /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch From 09d0f1b7251197edcb103d6ba911194d7dec33a7 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 03:18:31 -0500 Subject: [PATCH 053/267] fixed WeatherPresenter, updated README --- README.md | 2 +- .../weather/WeatherController.java | 2 +- .../weather/WeatherPresenter.java | 15 ++++++++------- .../interface_adapter/weather/WeatherState.java | 3 +-- .../weather/WeatherViewModel.java | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e03030fe2..d808a0220 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Person wants a quick overview of the weather in nearby areas. They can view a li Person wants to compare the weather in 2 different locations. They can pin the weather of a certain place to the ui to make it easier to compare it to the weather in other places. -Person wants to see what the weather was yesterday. They can select any hour from the past 24 hours to see what the weather was then. +Person checks the weather of a certain location often. They can view their search history and select that location to avoid having to repeatedly search for the same city. ## API The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 299ebd86e..11c3644f7 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -4,7 +4,7 @@ import use_case.note.search_result.SearchResultInputData; /** - * Controller for our Note related Use Cases. + * Controller for our weather related Use Cases. */ public class WeatherController { diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 5cc8a4fed..cf75eebb8 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,11 +1,12 @@ package interface_adapter.weather; -import use_case.note.NoteOutputBoundary; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; /** - * The presenter for our Note viewing and editing program. + * The presenter for the */ -public class WeatherPresenter implements NoteOutputBoundary { +public class WeatherPresenter implements SearchResultOutputBoundary { private final WeatherViewModel weatherViewModel; @@ -16,11 +17,11 @@ public WeatherPresenter(WeatherViewModel weatherViewModel) { /** * Prepares the success view for the Weather related Use Cases. * - * @param weather the output data + * @param response the output data */ @Override - public void prepareSuccessView(String weather) { - weatherViewModel.getState().setWeather(weather); + public void presentSuccessView(SearchResultOutputData response) { + weatherViewModel.getState().setWeather(response.getWeather()); weatherViewModel.getState().setError(null); weatherViewModel.firePropertyChanged(); } @@ -31,7 +32,7 @@ public void prepareSuccessView(String weather) { * @param errorMessage the explanation of the failure */ @Override - public void prepareFailView(String errorMessage) { + public void presentFailView(String errorMessage) { weatherViewModel.getState().setError(errorMessage); weatherViewModel.firePropertyChanged(); } diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index 426fb8437..c5547e531 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -1,8 +1,7 @@ package interface_adapter.weather; /** - * The State for a weather. - *

For this example, a note is simplay a string.

+ * The state information for the weather view model. */ public class WeatherState { private String weather = ""; diff --git a/src/main/java/interface_adapter/weather/WeatherViewModel.java b/src/main/java/interface_adapter/weather/WeatherViewModel.java index 9cffe3889..5bc58f127 100644 --- a/src/main/java/interface_adapter/weather/WeatherViewModel.java +++ b/src/main/java/interface_adapter/weather/WeatherViewModel.java @@ -3,7 +3,7 @@ import interface_adapter.ViewModel; /** - * The ViewModel for the NoteView. + * The ViewModel for the WeatherView. */ public class WeatherViewModel extends ViewModel { public WeatherViewModel() { From 2f9cedd77334a45f4631caf081b924075e60d2b9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Fri, 15 Nov 2024 10:48:14 -0500 Subject: [PATCH 054/267] modified some minor bugs. Presenter implemented --- .../note/SearchResultCountroller.java | 5 ++++ .../note/SearchResultPresenter.java | 24 +++++++++++++++++++ .../interface_adapter/note/WeatherState.java | 8 ++++--- .../pin_weather/PinWeatherInputBoundary.java | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/main/java/interface_adapter/note/SearchResultCountroller.java create mode 100644 src/main/java/interface_adapter/note/SearchResultPresenter.java diff --git a/src/main/java/interface_adapter/note/SearchResultCountroller.java b/src/main/java/interface_adapter/note/SearchResultCountroller.java new file mode 100644 index 000000000..94abb7f7c --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultCountroller.java @@ -0,0 +1,5 @@ +package interface_adapter.note; + +public class SearchResultCountroller { + +} diff --git a/src/main/java/interface_adapter/note/SearchResultPresenter.java b/src/main/java/interface_adapter/note/SearchResultPresenter.java new file mode 100644 index 000000000..243f736a7 --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultPresenter.java @@ -0,0 +1,24 @@ +package interface_adapter.note; + +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; + + +public class SearchResultPresenter implements SearchResultOutputBoundary { + + private final WeatherViewModel viewModel; + + public SearchResultPresenter(WeatherViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void presentSuccessView(SearchResultOutputData searchResultOutputData) { + viewModel.getState().setWeather(searchResultOutputData.getWeather()); + } + + @Override + public void presentFailView(String errorMessage) { + viewModel.getState().setError(errorMessage); + } +} diff --git a/src/main/java/interface_adapter/note/WeatherState.java b/src/main/java/interface_adapter/note/WeatherState.java index 1d2bf9657..51103bd35 100644 --- a/src/main/java/interface_adapter/note/WeatherState.java +++ b/src/main/java/interface_adapter/note/WeatherState.java @@ -1,18 +1,20 @@ package interface_adapter.note; +import entity.Weather; + /** * The State for a weather. *

For this example, a note is simplay a string.

*/ public class WeatherState { - private String weather = ""; + private Weather weather; private String error; - public String getWeather() { + public Weather getWeather() { return weather; } - public void setWeather(String weather) { + public void setWeather(Weather weather) { this.weather = weather; } diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java index 77475633d..2e267e172 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java @@ -3,5 +3,5 @@ // Input is a click on "pin." public interface PinWeatherInputBoundary { - void execute(PinWeatherInputData pinWeatherInputData) + void execute(PinWeatherInputData pinWeatherInputData); } From f34c0ca61b5b0b493dab281914f94369f5fc71fe Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 16 Nov 2024 04:31:23 -0500 Subject: [PATCH 055/267] changed weather variable to be the weather entity instead of a string, changed interface adapter to use the searchreturn use case instead of the searchresult --- .../weather/WeatherController.java | 10 +++++----- .../interface_adapter/weather/WeatherPresenter.java | 10 +++++----- .../interface_adapter/weather/WeatherState.java | 8 +++++--- .../note/search_result/SearchResultInputData.java | 6 ++++++ .../note/search_return/SearchReturnInputData.java | 13 ++++++++++++- .../note/search_return/SearchReturnOutputData.java | 8 +++++--- 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 11c3644f7..526c4e607 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -1,16 +1,16 @@ package interface_adapter.weather; -import use_case.note.search_result.SearchResultInputBoundary; -import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; /** * Controller for our weather related Use Cases. */ public class WeatherController { - private final SearchResultInputBoundary searchInteractor; + private final SearchReturnInputBoundary searchInteractor; - public WeatherController(SearchResultInputBoundary searchInteractor) { + public WeatherController(SearchReturnInputBoundary searchInteractor) { this.searchInteractor = searchInteractor; } @@ -19,7 +19,7 @@ public WeatherController(SearchResultInputBoundary searchInteractor) { * @param cityName the city to find the weather for */ public void execute(String cityName) { - final SearchResultInputData searchInputData = new SearchResultInputData(cityName); + final SearchReturnInputData searchInputData = new SearchReturnInputData(cityName); searchInteractor.execute(searchInputData); } } diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index cf75eebb8..523bd3e9c 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,12 +1,12 @@ package interface_adapter.weather; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; /** * The presenter for the */ -public class WeatherPresenter implements SearchResultOutputBoundary { +public class WeatherPresenter implements SearchReturnOutputBoundary { private final WeatherViewModel weatherViewModel; @@ -20,7 +20,7 @@ public WeatherPresenter(WeatherViewModel weatherViewModel) { * @param response the output data */ @Override - public void presentSuccessView(SearchResultOutputData response) { + public void presentSuccessView(SearchReturnOutputData response) { weatherViewModel.getState().setWeather(response.getWeather()); weatherViewModel.getState().setError(null); weatherViewModel.firePropertyChanged(); @@ -32,7 +32,7 @@ public void presentSuccessView(SearchResultOutputData response) { * @param errorMessage the explanation of the failure */ @Override - public void presentFailView(String errorMessage) { + public void prepareFailView(String errorMessage) { weatherViewModel.getState().setError(errorMessage); weatherViewModel.firePropertyChanged(); } diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index c5547e531..2055b23ee 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -1,17 +1,19 @@ package interface_adapter.weather; +import entity.Weather; + /** * The state information for the weather view model. */ public class WeatherState { - private String weather = ""; + private Weather weather = new Weather("", 0, 0, 0, "", "", 0, 0); private String error; - public String getWeather() { + public Weather getWeather() { return weather; } - public void setWeather(String weather) { + public void setWeather(Weather weather) { this.weather = weather; } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 296c5bcb9..3fcc1fa2d 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -5,12 +5,18 @@ public class SearchResultInputData { private String city; + private final String date; public SearchResultInputData(String cityName) { this.city = cityName; + this.date = date; } public String getCity() { return this.city; } + + public String getDate() { + return this.date; + } } diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputData.java b/src/main/java/use_case/note/search_return/SearchReturnInputData.java index 626e3ad64..4c892875c 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputData.java @@ -1,5 +1,16 @@ package use_case.note.search_return; -// Input is one click on "return." +/** + * // Input is one click on "return." + */ public class SearchReturnInputData { + private final String city; + + public SearchReturnInputData(String cityName) { + this.city = cityName; + } + + public String getCity() { + return this.city; + } } diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java index c787226d2..f48d43f72 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -1,12 +1,14 @@ package use_case.note.search_return; +import entity.Weather; + public class SearchReturnOutputData { private final String location; - private final String weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchReturnOutputData(String location, String weather, boolean useCaseFailed) { + public SearchReturnOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; @@ -16,7 +18,7 @@ public String getLocation() { return location; } - public String getWeather() {return weather;} + public Weather getWeather() {return weather;} public boolean isUseCaseFailed() { return useCaseFailed; From 58eb21b0703cf0c5de63485651d1b441c489a86a Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 16 Nov 2024 04:34:08 -0500 Subject: [PATCH 056/267] re-added date variable to searchresultinputdata --- .../java/use_case/note/search_result/SearchResultInputData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 3fcc1fa2d..f15ab28b1 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -7,7 +7,7 @@ public class SearchResultInputData { private String city; private final String date; - public SearchResultInputData(String cityName) { + public SearchResultInputData(String cityName, String date) { this.city = cityName; this.date = date; } From ecd02fa34f375856c79c50ea489800cd61d70d40 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 16 Nov 2024 04:39:16 -0500 Subject: [PATCH 057/267] changed weather variable declaration in weatherstate --- src/main/java/interface_adapter/weather/WeatherState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index 2055b23ee..d61a08aa4 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -6,7 +6,7 @@ * The state information for the weather view model. */ public class WeatherState { - private Weather weather = new Weather("", 0, 0, 0, "", "", 0, 0); + private Weather weather; private String error; public Weather getWeather() { From b737bccf2d79a213b469b39c1949b080faf3e73b Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 16 Nov 2024 10:08:23 -0500 Subject: [PATCH 058/267] presenter controller, view and view model implemented --- .../SearchResultViewModel.java | 9 +++++ .../interface_adapter/WeatherController.java | 4 ++ .../interface_adapter/note/NotePresenter.java | 38 ------------------- .../note/SearchResultState.java | 28 ++++++++++++++ .../use_case/note/SearchResultInteractor.java | 3 -- 5 files changed, 41 insertions(+), 41 deletions(-) create mode 100644 src/main/java/interface_adapter/SearchResultViewModel.java create mode 100644 src/main/java/interface_adapter/WeatherController.java delete mode 100644 src/main/java/interface_adapter/note/NotePresenter.java create mode 100644 src/main/java/interface_adapter/note/SearchResultState.java diff --git a/src/main/java/interface_adapter/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResultViewModel.java new file mode 100644 index 000000000..65796da11 --- /dev/null +++ b/src/main/java/interface_adapter/SearchResultViewModel.java @@ -0,0 +1,9 @@ +package interface_adapter; +import interface_adapter.note.SearchResultState; + +public class SearchResultViewModel extends ViewModel { + public SearchResultViewModel() { + super("searchResult"); + setState(new SearchResultState()); + } +} diff --git a/src/main/java/interface_adapter/WeatherController.java b/src/main/java/interface_adapter/WeatherController.java new file mode 100644 index 000000000..133efb33d --- /dev/null +++ b/src/main/java/interface_adapter/WeatherController.java @@ -0,0 +1,4 @@ +package interface_adapter; + +public class WeatherController { +} diff --git a/src/main/java/interface_adapter/note/NotePresenter.java b/src/main/java/interface_adapter/note/NotePresenter.java deleted file mode 100644 index d4e416165..000000000 --- a/src/main/java/interface_adapter/note/NotePresenter.java +++ /dev/null @@ -1,38 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteOutputBoundary; - -/** - * The presenter for our Note viewing and editing program. - */ -public class NotePresenter implements NoteOutputBoundary { - - private final NoteViewModel noteViewModel; - - public NotePresenter(NoteViewModel noteViewModel) { - this.noteViewModel = noteViewModel; - } - - /** - * Prepares the success view for the Note related Use Cases. - * - * @param note the output data - */ - @Override - public void prepareSuccessView(String note) { - noteViewModel.getState().setNote(note); - noteViewModel.getState().setError(null); - noteViewModel.firePropertyChanged(); - } - - /** - * Prepares the failure view for the Note related Use Cases. - * - * @param errorMessage the explanation of the failure - */ - @Override - public void prepareFailView(String errorMessage) { - noteViewModel.getState().setError(errorMessage); - noteViewModel.firePropertyChanged(); - } -} diff --git a/src/main/java/interface_adapter/note/SearchResultState.java b/src/main/java/interface_adapter/note/SearchResultState.java new file mode 100644 index 000000000..c779f11c2 --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultState.java @@ -0,0 +1,28 @@ +package interface_adapter.note; + +import entity.Weather; + +/** + * The State for a search result. + *

For this example, a note is simplay a string.

+ */ +public class SearchResultState { + private Weather weather; + private String error; + + public Weather getWeather() { + return weather; + } + + public void setWeather(Weather weather) { + this.weather = weather; + } + + public void setError(String errorMessage) { + this.error = errorMessage; + } + + public String getError() { + return error; + } +} diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index e0ca7370b..3ed852d83 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -6,9 +6,6 @@ import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import entity.Weather; import use_case.note.search_result.SearchResultInputBoundary; From e4b503b61824129d799e1b79c1c53e29b8cb7ce4 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 16 Nov 2024 16:27:09 -0500 Subject: [PATCH 059/267] controller implemented --- .../note/SearchResultController.java | 30 +++++++++++++++++++ .../note/SearchResultCountroller.java | 5 ---- src/main/java/view/WeatherPanelView.java | 8 ++++- 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 src/main/java/interface_adapter/note/SearchResultController.java delete mode 100644 src/main/java/interface_adapter/note/SearchResultCountroller.java diff --git a/src/main/java/interface_adapter/note/SearchResultController.java b/src/main/java/interface_adapter/note/SearchResultController.java new file mode 100644 index 000000000..9bbaf631f --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultController.java @@ -0,0 +1,30 @@ +package interface_adapter.note; + +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; + +/** + * Controller class that handles the search result use case. + */ +public class SearchResultController { + + private final SearchResultInputBoundary searchResultInteractor; + + // Constructor that injects the use case's input boundary + public SearchResultController(SearchResultInputBoundary searchResultInteractor) { + this.searchResultInteractor = searchResultInteractor; + } + + /** + * Executes the search result use case. + * @param cityName the name of the city to search for + * @param date the date to search for + */ + public void execute(String cityName, String date) { + // Create a SearchResultInputData object to encapsulate the input data + final SearchResultInputData inputData = new SearchResultInputData(cityName, date); + // Call the use case's execute method with the input data + searchResultInteractor.execute(inputData); + } +} + diff --git a/src/main/java/interface_adapter/note/SearchResultCountroller.java b/src/main/java/interface_adapter/note/SearchResultCountroller.java deleted file mode 100644 index 94abb7f7c..000000000 --- a/src/main/java/interface_adapter/note/SearchResultCountroller.java +++ /dev/null @@ -1,5 +0,0 @@ -package interface_adapter.note; - -public class SearchResultCountroller { - -} diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 5c5441d0a..b512b87eb 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,5 +1,6 @@ package view; +import interface_adapter.SearchResultViewModel; import interface_adapter.note.WeatherViewModel; import javax.swing.*; @@ -14,6 +15,7 @@ */ public class WeatherPanelView extends JPanel implements PropertyChangeListener { private final WeatherViewModel weatherViewModel; + private final SearchResultViewModel searchResultViewModel; private final LabelTextPanel weatherfincitypanel; private final LabelTextPanel temperaturepanel; @@ -21,14 +23,18 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener { private final LabelTextPanel humiditypanel; private final LabelTextPanel windspeedpanel; private final LabelTextPanel visibilitypanel; + private final LabelTextPanel searchresultpanel; private final JLabel emptylabel = new JLabel(""); private final int weatherpanelwidth = 370; private final int weatherpanelheight = 400; - public WeatherPanelView(WeatherViewModel weatherViewModel) { + public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel) { this.weatherViewModel = weatherViewModel; this.weatherViewModel.addPropertyChangeListener(this); + // Users can search for weather at a given time + this.searchResultViewModel = searchResultViewModel; + this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(weatherpanelwidth, weatherpanelheight); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); From 8e8e4690754063d116955b7c307cd9a7602ded8a Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 16 Nov 2024 16:33:31 -0500 Subject: [PATCH 060/267] controller implemented --- .../SearchResultController.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/interface_adapter/SearchResultController.java diff --git a/src/main/java/interface_adapter/SearchResultController.java b/src/main/java/interface_adapter/SearchResultController.java new file mode 100644 index 000000000..8bc814614 --- /dev/null +++ b/src/main/java/interface_adapter/SearchResultController.java @@ -0,0 +1,31 @@ +package interface_adapter; + +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; + +/** + * The controller for the search result view. It is responsible for executing the search result use case. + */ +public class SearchResultController { + + private final SearchResultInputBoundary searchResultInteractor; + + // Constructor that injects the use case's input boundary + public SearchResultController(SearchResultInputBoundary searchResultInteractor) { + this.searchResultInteractor = searchResultInteractor; + } + + /** + * Executes the search result use case with the given city name and date. + * + * @param cityName the name of the city to search for + * @param date the date to search for + */ + public void execute(String cityName, String date) { + // Create a SearchResultInputData object to encapsulate the input data + final SearchResultInputData inputData = new SearchResultInputData(cityName, date); + // Call the use case's execute method with the input data + searchResultInteractor.execute(inputData); + } +} + From 30868d17a5db55b63a79ff94f76919ce726e89cd Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sat, 16 Nov 2024 23:23:30 -0500 Subject: [PATCH 061/267] Resolved conflict in ConverterPresenter.java --- .../converter/ConverterPresenter.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/interface_adapter/converter/ConverterPresenter.java diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java new file mode 100644 index 000000000..a5679cb95 --- /dev/null +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -0,0 +1,27 @@ +package interface_adapter.converter; + +import interface_adapter.weather.WeatherViewModel; +import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; +import use_case.note.convert_farenheit.ConvertFarenheitOutputData; + +public class ConverterPresenter implements ConvertFarenheitOutputBoundary { + private final WeatherViewModel viewModel; + + public ConverterPresenter(WeatherViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void prepareFailView(String errorMessage) { + viewModel.getState().setError(errorMessage); + viewModel.firePropertyChanged(); + } + + @Override + public void prepareSuccessView(ConvertFarenheitOutputData outputData) { + final String weather = viewModel.getState().getWeather(); + viewModel.getState().setWeather(weather); + viewModel.getState().setError(null); + viewModel.firePropertyChanged(); + } +} From 9362e2069e2d4fd267b5b879eaf45cd4bcc0b8ee Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 11 Nov 2024 21:41:38 -0500 Subject: [PATCH 062/267] SearchResultInteractor implemented. --- src/main/java/use_case/note/SearchResultInteractor.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 16630ba91..12cecce16 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -13,9 +13,6 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; -/** - * The interactor for the search result use case.. - */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; From ddc23545b9b090b966ef98e10099a5ce829621c9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 11:49:20 -0500 Subject: [PATCH 063/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 12cecce16..b598748ff 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -13,6 +13,9 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; +/** + * The interactor for the search result use case. + */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; From 5387ed9bd976ea1c7672dc50dd29159c0e09a9e2 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 12:16:22 -0500 Subject: [PATCH 064/267] null tag added --- src/main/java/use_case/note/SearchResultInteractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index b598748ff..16630ba91 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -14,7 +14,7 @@ import use_case.note.search_result.SearchResultOutputData; /** - * The interactor for the search result use case. + * The interactor for the search result use case.. */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; From 535e26ecdbb62396b386fc8cd45a06280509760c Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 21:05:59 -0500 Subject: [PATCH 065/267] null tag added --- .../use_case/note/SearchReturnInteractor.java | 31 +++++++++++++++++++ .../SearchReturnInputBoundary.java | 11 +++++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/main/java/use_case/note/SearchReturnInteractor.java diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java new file mode 100644 index 000000000..bb67cc4c2 --- /dev/null +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -0,0 +1,31 @@ +import entity.Weather; +import use_case.note.WeatherDataAccessInterface; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class SearchReturnInteractor implements SearchReturnInputBoundary { + private final SearchResultOutputBoundary outputBoundary; + private final WeatherDataAccessInterface weatherDataAccess; + private final Map historicalWeatherData; + + public SearchReturnInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + this.outputBoundary = outputBoundary; + this.weatherDataAccess = weatherDataAccess; + this.historicalWeatherData = new HashMap<>(); + } + + @Override + public void execute(SearchReturnInputData searchReturnInputData) { + + } +} \ No newline at end of file diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java index 654457ce1..ac47665d0 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java @@ -1,7 +1,14 @@ package use_case.note.search_return; -// Input is one click on "return." +/** + * The input boundary for the search return use case. + */ public interface SearchReturnInputBoundary { - void execute(SearchReturnInputData searchReturnInputData) + /** + * Execute the search return use case. + * + * @param searchReturnInputData The input data for the search return use case. + */ + void execute(SearchReturnInputData searchReturnInputData); } From b77969b30392d15fe2df1a9e8b3ca65056d46767 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 12 Nov 2024 23:05:15 -0500 Subject: [PATCH 066/267] correct mistakes being sent to the SearchResultOutputData --- src/main/java/use_case/note/SearchResultInteractor.java | 4 +++- src/main/java/use_case/note/WeatherDataAccessInterface.java | 3 ++- .../use_case/note/search_result/SearchResultOutputData.java | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 16630ba91..e11801a68 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -39,6 +39,7 @@ public void execute(SearchResultInputData searchReturnInputData) { scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); } + private void fetchWeatherData() { try { final String city = SearchResultInputData.getCity(); @@ -51,7 +52,8 @@ private void fetchWeatherData() { // Send it to the output boundary final SearchResultOutputData outputData = - new SearchResultOutputData(city, weatherData, false); + new SearchResultOutputData(city, historicalWeatherData, false); + weatherDataAccess.saveWeather(city, historicalWeatherData) outputBoundary.presentSuccessView(outputData); } catch (IOException exception) { diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index e1c13927a..1dab1f0ea 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -2,6 +2,7 @@ import entity.Weather; import java.io.IOException; +import java.util.Map; /** * Interface for the WeatherDAO. It consists of methods for @@ -17,5 +18,5 @@ public interface WeatherDataAccessInterface { */ Weather getWeather(String city) throws IOException; - + Map saveWeather(String city, Map weather) throws IOException; } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index 310ed041c..f2a6ab4c5 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -2,13 +2,15 @@ import entity.Weather; +import java.util.Map; + public class SearchResultOutputData { private final String location; - private final Weather weather; + private final Map weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Map weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; From a6e7b65eb04adaede3a7b90c34b1babd8ef4d4f9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Wed, 13 Nov 2024 23:51:41 -0500 Subject: [PATCH 067/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- pom.xml | 6 ++ .../HistoricalWeatherDataAccessObject.java | 95 +++++++++++++++++++ .../data_access/WeatherDataAccessObject.java | 11 ++- .../HistoricalWeatherDataAccessInterface.java | 27 ++++++ .../use_case/note/SearchResultInteractor.java | 12 ++- .../note/WeatherDataAccessInterface.java | 2 - 6 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 src/main/java/data_access/HistoricalWeatherDataAccessObject.java create mode 100644 src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java diff --git a/pom.xml b/pom.xml index e86052a71..63e13760c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,12 @@ 2.8 + + com.googlecode.json-simple + json-simple + 1.1 + + diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java new file mode 100644 index 000000000..0bc5c6e33 --- /dev/null +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -0,0 +1,95 @@ +package data_access; + +import java.io.FileWriter; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Objects; + +import org.json.JSONArray; +import org.json.JSONObject; + +import entity.Weather; +import use_case.note.HistoricalWeatherDataAccessInterface; + +/** + * This class provides the service of saving and getting historical weather data. + */ +public class HistoricalWeatherDataAccessObject implements HistoricalWeatherDataAccessInterface { + @Override + public void saveWeather(Weather weather, String timeStamp) { + + // Save the weather data to the database + // Convert the Weather object to JSON + final String nextLine = "\",\n"; + final StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder.append("{\n"); + jsonBuilder.append(" \"timeStamp\": \"" + timeStamp + nextLine); + jsonBuilder.append(" \"city\": \"" + weather.getCity() + nextLine); + jsonBuilder.append(" \"longitude\": " + weather.getLongitude() + nextLine); + jsonBuilder.append(" \"latitude\": ").append(weather.getLatitude()).append(nextLine); + jsonBuilder.append(" \"temperature\": ").append(weather.getTemperature()).append(nextLine); + jsonBuilder.append(" \"looks\": \"").append(weather.getLooks()).append(nextLine); + jsonBuilder.append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append(nextLine); + jsonBuilder.append(" \"humidity\": " + weather.getHumidity() + nextLine); + jsonBuilder.append(" \"windSpeed\": " + weather.getWindSpeed() + nextLine); + jsonBuilder.append("}"); + + // Convert StringBuilder to String + final String weatherJson = jsonBuilder.toString(); + + // Write JSON to a file + try (FileWriter fileWriter = new FileWriter("weather.json")) { + fileWriter.write(weatherJson); + System.out.println("Successfully wrote weather data to weather.json"); + } + catch (IOException excep) { + excep.printStackTrace(); + } + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + // Get the weather data from the database + // Read the JSON from the file + final String filePath = "weather.json"; + try { + // Reading the content of the JSON file into a String + final String jsonString = Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader() + .getResource(filePath)).toURI())); + // Converting the JSON String to a JSONArray + final JSONArray weatherArray = new JSONArray(jsonString); + // Iterating over the JSONArray + for (int i = 0; i < weatherArray.length(); i++) { + // Getting the JSONObject at the index i + final JSONObject weatherObject = weatherArray.getJSONObject(i); + // Getting the city from the JSONObject + final String cityNameCall = weatherObject.getString("city"); + // Getting the timestamp from the JSONObject + final String timeStamp = weatherObject.getString("timeStamp"); + // Checking if the city and timestamp match the input + if (cityNameCall.equals(cityNameCall) && timeStamp.equals(timestamp)) { + // Create weather object + final Weather weather = new Weather( + cityNameCall, + weatherObject.getInt("longitude"), + weatherObject.getInt("latitude"), + weatherObject.getInt("temperature"), + weatherObject.getString("looks"), + weatherObject.getString("alertDescription"), + weatherObject.getInt("humidity"), + weatherObject.getInt("windSpeed") + ); + return weather; + } + + } + } + catch (IOException | URISyntaxException exe) { + exe.printStackTrace(); + } + throw new IOException("Weather data not found"); + } + +} diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 9e56b8c45..2ed681744 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -9,6 +9,8 @@ import org.json.JSONArray; import use_case.note.WeatherDataAccessInterface; + + import java.io.IOException; @@ -16,7 +18,7 @@ * This class runs the API and creates a weather DAO. **/ -public class WeatherDataAccessObject implements WeatherDataAccessInterface { +public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; private static String city; @@ -27,14 +29,14 @@ public class WeatherDataAccessObject implements WeatherDataAccessInterface { private static final String MESSAGE = "message"; @Override - public Weather getWeather(String city) throws IOException { + public Weather getWeather(String citySearch) throws IOException { // Make an API call to get the user object. final OkHttpClient client = new OkHttpClient().newBuilder().build(); // creating file final Request request = new Request.Builder() .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=" - + API_KEY + "&units=metric", city)) + + API_KEY + "&units=metric", citySearch)) .addHeader("Content-Type", CONTENT_TYPE_JSON) .build(); try { @@ -61,7 +63,7 @@ public Weather getWeather(String city) throws IOException { } } - return new Weather(city, lon, lat, temp, looks, alertDescription, humidity, windspeed); + return new Weather(citySearch, lon, lat, temp, looks, alertDescription, humidity, windspeed); } else { @@ -72,5 +74,6 @@ public Weather getWeather(String city) throws IOException { throw new IOException(ex); } } + } diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java new file mode 100644 index 000000000..ee92c1262 --- /dev/null +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -0,0 +1,27 @@ +package use_case.note; + +import entity.Weather; + +import java.io.IOException; +import java.util.Map; + +/** + * Interface for the HistoricalWeatherDataAccessObject. It consists of methods for + * saving the weather. + */ +public interface HistoricalWeatherDataAccessInterface { + /** + * Saves the weather data. + * @param weather the weather data to save + * @throws IOException if there is an error saving the weather data + */ + void saveWeather(Weather weather, String timstamp) throws IOException; + + /** + * Gets the weather data. + * @param city the city to get the weather data for + * @param timestamp the timestamp of the weather data + * @throws IOException if there is an error getting the weather data + */ + Weather getWeather(String city, String timestamp) throws IOException; +} diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index e11801a68..241c4af63 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -12,6 +12,7 @@ import use_case.note.search_result.SearchResultInputData; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; +import use_case.note.HistoricalWeatherDataAccessInterface; /** * The interactor for the search result use case.. @@ -20,11 +21,14 @@ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; private final Map historicalWeatherData; + private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; - public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess, + HistoricalWeatherDataAccessInterface historicalDataInterface ) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherData = new HashMap<>(); + this.historicalWeatherDataAccessInterface = historicalDataInterface } @Override @@ -47,14 +51,14 @@ private void fetchWeatherData() { final Weather weatherData = weatherDataAccess.getWeather(city); // Store it in historical data - final String timestamp = String.valueOf(System.currentTimeMillis()); - historicalWeatherData.put(timestamp, weatherData); + final String timestamp = String.valueOf(System.currentTimeMillis());; // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - weatherDataAccess.saveWeather(city, historicalWeatherData) + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); outputBoundary.presentSuccessView(outputData); + } catch (IOException exception) { // Handle exception if weather data retrieval fails and send failure view diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index 1dab1f0ea..163d40981 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -2,7 +2,6 @@ import entity.Weather; import java.io.IOException; -import java.util.Map; /** * Interface for the WeatherDAO. It consists of methods for @@ -18,5 +17,4 @@ public interface WeatherDataAccessInterface { */ Weather getWeather(String city) throws IOException; - Map saveWeather(String city, Map weather) throws IOException; } From b2f1a740432fdeb10bcd6102e40dc23976314603 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:22:31 -0500 Subject: [PATCH 068/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- pom.xml | 5 ----- .../use_case/note/HistoricalWeatherDataAccessInterface.java | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 63e13760c..c181fb0f6 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,6 @@ 2.8 - - com.googlecode.json-simple - json-simple - 1.1 - diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index ee92c1262..904670ccf 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -1,9 +1,8 @@ package use_case.note; -import entity.Weather; - import java.io.IOException; -import java.util.Map; + +import entity.Weather; /** * Interface for the HistoricalWeatherDataAccessObject. It consists of methods for @@ -13,6 +12,7 @@ public interface HistoricalWeatherDataAccessInterface { /** * Saves the weather data. * @param weather the weather data to save + * @param timstamp the timestamp of the weather data * @throws IOException if there is an error saving the weather data */ void saveWeather(Weather weather, String timstamp) throws IOException; From b3bf870e5b018e59cd74aa795a6afb1d398181c5 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:25:48 -0500 Subject: [PATCH 069/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- src/main/java/use_case/note/SearchResultInteractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 241c4af63..91b9fdb5c 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -28,7 +28,7 @@ public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, Weather this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherData = new HashMap<>(); - this.historicalWeatherDataAccessInterface = historicalDataInterface + this.historicalWeatherDataAccessInterface = historicalDataInterface; } @Override From 8b389b28b2c8c7e4d4ddfc784ebb61b6bcc34542 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 00:32:30 -0500 Subject: [PATCH 070/267] implemented the database for saving data, interface connecting dao and getting data from the database and modified the search result interactor --- src/main/java/use_case/note/SearchResultInteractor.java | 9 ++++++--- .../note/search_result/SearchResultInputData.java | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 91b9fdb5c..f15698cb6 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -1,6 +1,9 @@ package use_case.note; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; @@ -12,7 +15,6 @@ import use_case.note.search_result.SearchResultInputData; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; -import use_case.note.HistoricalWeatherDataAccessInterface; /** * The interactor for the search result use case.. @@ -51,12 +53,13 @@ private void fetchWeatherData() { final Weather weatherData = weatherDataAccess.getWeather(city); // Store it in historical data - final String timestamp = String.valueOf(System.currentTimeMillis());; + final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); + final String timestamp1 = formatter.format(Instant.now()); // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp1); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 63e213ef5..0aa65bbef 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -6,7 +6,7 @@ public class SearchResultInputData { private static final String city; - public SearchResultInputData(String cityName) { + public SearchResultInputData(String cityName, String date) { this.city = cityName; } From d72d9aa437fca2aa241d35e40aa891fa7d3e39e5 Mon Sep 17 00:00:00 2001 From: harman Date: Wed, 13 Nov 2024 19:21:51 -0500 Subject: [PATCH 071/267] Updated README.md --- README.md | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 8aa6d8de8..e03030fe2 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,11 @@ -# Note Application - -This is a minimal example demonstrating usage of the -password-protected user part of the API used in lab 5. - -You can find more information about the API endpoints in -[the documentation](https://www.postman.com/cloudy-astronaut-813156/csc207-grade-apis-demo/documentation/fg3zkjm/5-password-protected-user). - -If your team is considering an application for which it would be convenient to -store data in something like a database, you may find that the API calls demonstrated -here will be useful in your project, as this will allow you to store -an arbitrary JSON object associated with a username and password. - -In this application, a single note has a name (the "username" in terms of the API) and the note -can be read by anyone who knows the name — but only edited by someone who -knows the password for it. - - -You can see the documentation in the various files for more information. +# WeatherWizard +The purpose of our Code is to create a Weather Application that is User friendly and can display several features. ## User Stories Person wants to search for a specific location. They type that location in the search bar and the map moves to that location and displays the weather. If they search for a place that doesnt exist, the software displays an error message. +Person does not understand metric units so they convert to imperial. + Person wants to view weather alerts in a certain area. They see that displayed somewhere. Person wants a quick overview of the weather in nearby areas. They can view a list of major nearby locations and select one. @@ -29,21 +14,17 @@ Person wants to compare the weather in 2 different locations. They can pin the w Person wants to see what the weather was yesterday. They can select any hour from the past 24 hours to see what the weather was then. +## API +The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. + https://openweathermap.org/api/one-call-3 +The JXMAP library is used to produce a map in which the user can drag and drop pins on cities. + msteiger/jxmapviewer2: JXMapViewer2 ## Testing +[To be added] -The repo also includes an example of a use case interactor test, as well as -an example of an end-to-end test which automates button clicks and inspects -the contents of the actual views. This is something we discussed in the lectures -about testing in CA but had not provided a code example of before. Note, one -could also inspect the contents of the ViewModel objects instead when testing -CA to make a similar test which would be less dependent on the details of the -specific UI implementation. - -## Project Starter Code +## Want to know more? +If you would like to know more please check out our presentation. +[Link to be added] -Your team may choose to use this repo as starter code for your project. You could -also use the lab 5 code — or start from an empty repo if your team prefers. -If you choose to use one of the repositories we have provided, you can either make -a fork of it or copy the subset of code you want into a completely new repository. From 39fd5e1fc757e5c59215f94ecbeb9058526c2ef2 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:40:29 -0800 Subject: [PATCH 072/267] Updating WeatherState and WeatherViewModel, this 2 classes will be used in MapPanelView.java --- .../java/interface_adapter/note/NoteViewModel.java | 13 ------------- .../note/{NoteState.java => WeatherState.java} | 14 +++++++------- .../interface_adapter/note/WeatherViewModel.java | 13 +++++++++++++ 3 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/interface_adapter/note/NoteViewModel.java rename src/main/java/interface_adapter/note/{NoteState.java => WeatherState.java} (56%) create mode 100644 src/main/java/interface_adapter/note/WeatherViewModel.java diff --git a/src/main/java/interface_adapter/note/NoteViewModel.java b/src/main/java/interface_adapter/note/NoteViewModel.java deleted file mode 100644 index 6e185d0fa..000000000 --- a/src/main/java/interface_adapter/note/NoteViewModel.java +++ /dev/null @@ -1,13 +0,0 @@ -package interface_adapter.note; - -import interface_adapter.ViewModel; - -/** - * The ViewModel for the NoteView. - */ -public class NoteViewModel extends ViewModel { - public NoteViewModel() { - super("note"); - setState(new NoteState()); - } -} diff --git a/src/main/java/interface_adapter/note/NoteState.java b/src/main/java/interface_adapter/note/WeatherState.java similarity index 56% rename from src/main/java/interface_adapter/note/NoteState.java rename to src/main/java/interface_adapter/note/WeatherState.java index c5b2234d6..1d2bf9657 100644 --- a/src/main/java/interface_adapter/note/NoteState.java +++ b/src/main/java/interface_adapter/note/WeatherState.java @@ -1,19 +1,19 @@ package interface_adapter.note; /** - * The State for a note. + * The State for a weather. *

For this example, a note is simplay a string.

*/ -public class NoteState { - private String note = ""; +public class WeatherState { + private String weather = ""; private String error; - public String getNote() { - return note; + public String getWeather() { + return weather; } - public void setNote(String note) { - this.note = note; + public void setWeather(String weather) { + this.weather = weather; } public void setError(String errorMessage) { diff --git a/src/main/java/interface_adapter/note/WeatherViewModel.java b/src/main/java/interface_adapter/note/WeatherViewModel.java new file mode 100644 index 000000000..7d10ebde8 --- /dev/null +++ b/src/main/java/interface_adapter/note/WeatherViewModel.java @@ -0,0 +1,13 @@ +package interface_adapter.note; + +import interface_adapter.ViewModel; + +/** + * The ViewModel for the NoteView. + */ +public class WeatherViewModel extends ViewModel { + public WeatherViewModel() { + super("weather"); + setState(new WeatherState()); + } +} From 9c88ecb0279e37146539d58152b5c87b4000d8ac Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:42:28 -0800 Subject: [PATCH 073/267] This is a example picture from the Jxmap API --- src/main/java/view/MapImage.png | Bin 0 -> 99551 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/view/MapImage.png diff --git a/src/main/java/view/MapImage.png b/src/main/java/view/MapImage.png new file mode 100644 index 0000000000000000000000000000000000000000..699acf98433a5cf50e999c8739b330f117ce1dd5 GIT binary patch literal 99551 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%0DCTEt#o_SWHJ-&&Ivj5zb@Jh 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 Date: Tue, 12 Nov 2024 12:47:59 -0800 Subject: [PATCH 074/267] Those classes are responsible for building the GUI, this should give the JFrame after implementingWeatherController and WeatherPresenter. --- src/main/java/view/MainView.java | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/view/MainView.java diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java new file mode 100644 index 000000000..3fdcb1a41 --- /dev/null +++ b/src/main/java/view/MainView.java @@ -0,0 +1,33 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; +import java.awt.*; + +public class MainView extends JFrame { + private MapPanelView mapPanelView; + private WeatherPanelView weatherPanelView; + private final int frameWidth = 1200; + private final int frameHeight = 1000; + + public MainView(WeatherViewModel weatherViewModel) { + mapPanelView = new MapPanelView(weatherViewModel); + weatherPanelView = new WeatherPanelView(); + this.setTitle("Weather Wizard"); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setSize(frameWidth, frameHeight); + // I choose to use 1X2 gridlayout so we can have both panel side by side + this.setLayout(new GridLayout(1, 2)); + this.add(mapPanelView); + this.add(weatherPanelView); + // pack() optimize window size + this.pack(); + this.setVisible(true); + + } + public static void main(String[] args) { + new MainView(); + } + +} From 66c3e19b006875619aa261faef79c5d772cdf69f Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 12:48:56 -0800 Subject: [PATCH 075/267] 2 simple preview act like tests for map Jpanel --- src/main/java/view/mapimagepreview.java | 12 ++++++++++++ src/main/java/view/mappanelpreview.java | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/main/java/view/mapimagepreview.java create mode 100644 src/main/java/view/mappanelpreview.java diff --git a/src/main/java/view/mapimagepreview.java b/src/main/java/view/mapimagepreview.java new file mode 100644 index 000000000..44d9edb57 --- /dev/null +++ b/src/main/java/view/mapimagepreview.java @@ -0,0 +1,12 @@ +package view; + +import javax.swing.*; + +public class mapimagepreview { + public static void main(String[] args) { + // Create the JPanel and add components to it + JPanel panel = new MapImagepanel(); + // Display the JPanel in a JOptionPane dialog + JOptionPane.showMessageDialog(null, panel, "map image preview", JOptionPane.PLAIN_MESSAGE); + } +} diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java new file mode 100644 index 000000000..232391e1f --- /dev/null +++ b/src/main/java/view/mappanelpreview.java @@ -0,0 +1,18 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; + +/* +* this class give a preview on MapPanelview. + */ +public class mappanelpreview { + public static void main(String[] args) { + // Create the JPanel and add components to it + final MapPanelView panel = new MapPanelView(new WeatherViewModel()); + + // Display the JPanel in a JOptionPane dialog + JOptionPane.showMessageDialog(null, panel, "JPanel Preview", JOptionPane.PLAIN_MESSAGE); + } +} \ No newline at end of file From 78d024eb024d533e9623c3363ecf7bc8f5b8bd8f Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:48:39 -0800 Subject: [PATCH 076/267] Add method setoutput to LabelTextPanel.java so it takes a String and convert it to JLabel --- src/main/java/view/LabelTextPanel.java | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/view/LabelTextPanel.java diff --git a/src/main/java/view/LabelTextPanel.java b/src/main/java/view/LabelTextPanel.java new file mode 100644 index 000000000..e17a8efe8 --- /dev/null +++ b/src/main/java/view/LabelTextPanel.java @@ -0,0 +1,30 @@ +package view; + +import javax.swing.*; + +/** + * A panel containing a label and a text field. + */ +public class LabelTextPanel extends JPanel { + private JLabel output; + + public LabelTextPanel(JLabel label, JTextField textField) { + this.output = null; + this.add(label); + this.add(textField); + } + + public LabelTextPanel(JLabel label, String output) { + this.output = null; + this.add(label); + this.add(this.output); + } + + public JLabel getoutput() { + return this.output; + } + + public void setoutput(String outputstring) { + this.output = new JLabel(outputstring); + } +} From 1bb683637a826cbb7e8966d9f888badb7677824e Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:57:07 -0800 Subject: [PATCH 077/267] Add another constructor that takes in two JLabel --- src/main/java/view/LabelTextPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/LabelTextPanel.java b/src/main/java/view/LabelTextPanel.java index e17a8efe8..00b67c912 100644 --- a/src/main/java/view/LabelTextPanel.java +++ b/src/main/java/view/LabelTextPanel.java @@ -14,10 +14,10 @@ public LabelTextPanel(JLabel label, JTextField textField) { this.add(textField); } - public LabelTextPanel(JLabel label, String output) { + public LabelTextPanel(JLabel label, JLabel info) { this.output = null; this.add(label); - this.add(this.output); + this.add(info); } public JLabel getoutput() { From 9f047f234d08655bfc8075bceaff0af67ecbc849 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 15:58:34 -0800 Subject: [PATCH 078/267] Class MainView intergrate and conbine class MapPanelView and WeatherPanelView. --- src/main/java/view/MainView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 3fdcb1a41..786a235a7 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -12,8 +12,8 @@ public class MainView extends JFrame { private final int frameHeight = 1000; public MainView(WeatherViewModel weatherViewModel) { - mapPanelView = new MapPanelView(weatherViewModel); - weatherPanelView = new WeatherPanelView(); + mapPanelView = new MapPanelView(); + weatherPanelView = new WeatherPanelView(weatherViewModel); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); @@ -26,7 +26,7 @@ public MainView(WeatherViewModel weatherViewModel) { this.setVisible(true); } - public static void main(String[] args) { + public static void man(String[] args) { new MainView(); } From 76da47744e5b368c98ab4e0de042d2b5da6c96ae Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:00:17 -0800 Subject: [PATCH 079/267] Remove PropertyChangeListener part of the code because I realize with a fixed map, we don't need change anything. --- src/main/java/view/MapPanelView.java | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/main/java/view/MapPanelView.java diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java new file mode 100644 index 000000000..ef31154ff --- /dev/null +++ b/src/main/java/view/MapPanelView.java @@ -0,0 +1,74 @@ +package view; + +import interface_adapter.note.NoteController; +import interface_adapter.note.WeatherState; +import interface_adapter.note.WeatherViewModel; +import WeatherController; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/* +* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: +* 1. search panel where user can type the city name. This is connected to a Action Lisenter, which pass information +* to our Input Class. +* 2. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. + */ +public class MapPanelView extends JPanel implements ActionListener { + private final LabelTextPanel searchpanel; + private final MapImagepanel mapimagepanel; + private final JTextField cityinputfield = new JTextField(15); + private final int mappanelwidth = 370; + private final int mappanelheight = 400; + + private WeatherController weatherController; + + public MapPanelView() { + + + mapimagepanel = new MapImagepanel(); + cityinputfield.addActionListener( + event -> { + // if the event is coming from cityinput field, execute controller + if (event.getSource() == cityinputfield) {WeatherController.excute(cityinputfield.getText()); + } + } + ); + searchpanel = new LabelTextPanel(new JLabel("search bar"), cityinputfield); +// this.setSize(mappanelwidth, mappanelheight); + this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(searchpanel); + // adding a Jlabel + this.add(mapimagepanel.getDisplayfield()); + + } + + @Override + /* + * prints a message to the console when an action event occurs. Will look something like "Enter city name" + */ + public void actionPerformed(ActionEvent event) { + System.out.println("Enter" + event.getActionCommand()); + + } + public void propertyChange(PropertyChangeEvent evt) { + final WeatherState state = (WeatherState) evt.getNewValue(); + setFields(state); + if (state.getError() != null) { + JOptionPane.showMessageDialog(this, state.getError(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + private void setFields(WeatherState state) { + cityinputfield.setText(state.getWeather()); + } + + public void setWeatherController(WeatherController controller) { + this.weatherController = controller; + } +} + From 89a1aff1c909131eb7f765e9cf0967b04eadc403 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:01:25 -0800 Subject: [PATCH 080/267] MapImagepanel.java can take a file name, and turn it into a JLabel. --- src/main/java/view/MapImagepanel.java | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/view/MapImagepanel.java diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java new file mode 100644 index 000000000..b61fa74c9 --- /dev/null +++ b/src/main/java/view/MapImagepanel.java @@ -0,0 +1,46 @@ +package view; + +import javax.swing.*; +import java.awt.*; + +/* +* the MapImagePanel is responsible for displaying the map file. + */ +public class MapImagepanel extends JPanel { + private ImageIcon imagemap; + private String filename; + private JLabel displayfield; + + // if no arg given, use the example MapImage.png + public MapImagepanel() { + // this is a local image + this.filename = "/Users/sophie/IdeaProjects/WeatherWizard/src/main/java/view/MapImage.png"; + try { + imagemap = new ImageIcon(this.filename); + displayfield = new JLabel(imagemap); + this.add(displayfield); + this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); + + } catch (Exception e) { + System.out.println("image cannot be found"); + } + } + + // or pass a filename as an argument + public MapImagepanel(String filename) { + this.filename = filename; + try { + imagemap = new ImageIcon(this.filename); + displayfield = new JLabel(imagemap); + this.add(displayfield); + this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); + + } catch (Exception e) { + System.out.println("image cannot be found"); + } + } + + public JLabel getDisplayfield() { + return displayfield; + } +} From 1b0b92a5d34c28567f121254785ec5309daf0c21 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:02:24 -0800 Subject: [PATCH 081/267] Delete the NoteView.java --- src/main/java/view/NoteView.java | 95 -------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 src/main/java/view/NoteView.java diff --git a/src/main/java/view/NoteView.java b/src/main/java/view/NoteView.java deleted file mode 100644 index 331d76493..000000000 --- a/src/main/java/view/NoteView.java +++ /dev/null @@ -1,95 +0,0 @@ -package view; - -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextArea; - -import interface_adapter.note.NoteController; -import interface_adapter.note.NoteState; -import interface_adapter.note.NoteViewModel; - -/** - * The View for when the user is viewing a note in the program. - */ -public class NoteView extends JPanel implements ActionListener, PropertyChangeListener { - - private final NoteViewModel noteViewModel; - - private final JLabel noteName = new JLabel("note for jonathan_calver2"); - private final JTextArea noteInputField = new JTextArea(); - - private final JButton saveButton = new JButton("Save"); - private final JButton refreshButton = new JButton("Refresh"); - private NoteController noteController; - - public NoteView(NoteViewModel noteViewModel) { - - noteName.setAlignmentX(Component.CENTER_ALIGNMENT); - this.noteViewModel = noteViewModel; - this.noteViewModel.addPropertyChangeListener(this); - - final JPanel buttons = new JPanel(); - buttons.add(saveButton); - buttons.add(refreshButton); - - saveButton.addActionListener( - evt -> { - if (evt.getSource().equals(saveButton)) { - noteController.execute(noteInputField.getText()); - - } - } - ); - - refreshButton.addActionListener( - evt -> { - if (evt.getSource().equals(refreshButton)) { - noteController.execute(null); - - } - } - ); - - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - this.add(noteName); - this.add(noteInputField); - this.add(buttons); - } - - /** - * React to a button click that results in evt. - * @param evt the ActionEvent to react to - */ - public void actionPerformed(ActionEvent evt) { - System.out.println("Click " + evt.getActionCommand()); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - final NoteState state = (NoteState) evt.getNewValue(); - setFields(state); - if (state.getError() != null) { - JOptionPane.showMessageDialog(this, state.getError(), - "Error", JOptionPane.ERROR_MESSAGE); - } - } - - private void setFields(NoteState state) { - noteInputField.setText(state.getNote()); - } - - public void setNoteController(NoteController controller) { - this.noteController = controller; - } -} - From 61304cdc7494feea71793ceff8b45c2952a73d50 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:03:29 -0800 Subject: [PATCH 082/267] WeatherPanelView.java implements PropertyChangeListener. Updates weather information. --- src/main/java/view/WeatherPanelView.java | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/main/java/view/WeatherPanelView.java diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java new file mode 100644 index 000000000..215284763 --- /dev/null +++ b/src/main/java/view/WeatherPanelView.java @@ -0,0 +1,78 @@ +package view; + +import interface_adapter.note.WeatherViewModel; + +import javax.swing.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Observer; + +/* + * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch + * of LabelTextPanel that displays varies weather information. + * This part of view will have to change based on the output, so it depends on the view model. + */ +public class WeatherPanelView extends JPanel implements PropertyChangeListener { + private final WeatherViewModel weatherViewModel; + + private final LabelTextPanel weatherfincitypanel; + private final LabelTextPanel temperaturepanel; + private final LabelTextPanel skyconditionpanel; + private final LabelTextPanel humiditypanel; + private final LabelTextPanel windspeedpanel; + private final LabelTextPanel visibilitypanel; + + private final JLabel emptylabel = new JLabel(""); + private final int weatherpanelwidth = 370; + private final int weatherpanelheight = 400; + + public WeatherPanelView(WeatherViewModel weatherViewModel) { + this.weatherViewModel = weatherViewModel; + this.weatherViewModel.addPropertyChangeListener(this); + + this.setSize(weatherpanelwidth, weatherpanelheight); + weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(weatherfincitypanel); + this.add(temperaturepanel); + this.add(skyconditionpanel); + this.add(humiditypanel); + this.add(windspeedpanel); + this.add(visibilitypanel); + } + /* + * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. + */ + public void propertyChange(PropertyChangeEvent evt) { + final String propertyName = evt.getPropertyName(); + final String newValue = (String) evt.getNewValue(); + + SwingUtilities.invokeLater(() -> { + switch (propertyName) { + case "city": + weatherfincitypanel.setoutput(newValue); + break; + case "temperature": + temperaturepanel.setoutput(newValue); + break; + case "skyCondition": + skyconditionpanel.setoutput(newValue); + break; + case "humidity": + humiditypanel.setoutput(newValue); + break; + case "windSpeed": + windspeedpanel.setoutput(newValue); + break; + case "visibility": + visibilitypanel.setoutput(newValue); + break; + } + }); + } +} From 38f761592b357a930343008e5691cf3bfa00b2b5 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:22:32 -0800 Subject: [PATCH 083/267] Note we might want to add a convertor here. --- src/main/java/view/WeatherPanelView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 215284763..b4f1fdc1f 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -33,6 +33,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel) { this.setSize(weatherpanelwidth, weatherpanelheight); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + // Note we might want to add a convertor here. skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); From ac0dfe7423293bbcb0f9cc0f8f230e565d03f7f3 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:37:12 -0800 Subject: [PATCH 084/267] Fix Checkstyle for import --- src/main/java/view/MainView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 786a235a7..9f2dda417 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -2,8 +2,8 @@ import interface_adapter.note.WeatherViewModel; -import javax.swing.*; -import java.awt.*; +import javax.swing.JFrame; +import java.awt.GridLayout; public class MainView extends JFrame { private MapPanelView mapPanelView; From 25c02661bac5a58e81be994da45d3c3540d71081 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 12 Nov 2024 16:42:02 -0800 Subject: [PATCH 085/267] // psvm --- src/main/java/view/MainView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 9f2dda417..e689a9197 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -26,8 +26,8 @@ public MainView(WeatherViewModel weatherViewModel) { this.setVisible(true); } - public static void man(String[] args) { - new MainView(); - } +// public static void man(String[] args) { +// new MainView(); +// } } From c114d0db0603211a1a5f8b945511231ebc46d980 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 13 Nov 2024 12:15:42 -0800 Subject: [PATCH 086/267] / --- src/main/java/view/WeatherPanelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index b4f1fdc1f..5c5441d0a 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -10,7 +10,7 @@ /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch * of LabelTextPanel that displays varies weather information. - * This part of view will have to change based on the output, so it depends on the view model. + * This part of view will have to change based on the output, so it depends on the view model */ public class WeatherPanelView extends JPanel implements PropertyChangeListener { private final WeatherViewModel weatherViewModel; From f540f9444ea108dac5e66e3be87b8acf7d78ef1e Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 9 Nov 2024 06:56:32 -0800 Subject: [PATCH 087/267] i forgot --- src/main/java/entity/Weather.java | 70 +++++++++++++------------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index ec99bba68..b0be05c1f 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -1,69 +1,55 @@ package entity; /** - * The representation of a Weather Information Package. + * The representation of a password-protected user for our program. */ public class Weather { - private final String city; - private final int longitude; - private final int latitude; - private int temperature; - private final String looks; - private final String alertDescription; + private final float temperature; + private final String weather; + private final String description; + private final String icon; + private final float windSpeed; private final int humidity; - private int windSpeed; + private final int visibility; - public Weather(String city, int longitude, int latitude, int temperature, String looks, String alertDescription, int humidity, int windSpeed) { - this.city = city; - this.longitude = longitude; - this.latitude = latitude; + + public Weather(float temperature, String weather, String description, String icon, float windSpeed, int humidity, + int visibility) { this.temperature = temperature; - this.looks = looks; - this.alertDescription = alertDescription; - this.humidity = humidity; + this.weather = weather; + this.description = description; + this.icon = icon; this.windSpeed = windSpeed; - - } - - public int getHumidity() { - return humidity; - } - - public int getWindSpeed() { - return windSpeed; - } - - public void setWindSpeed(int newSpeed) { - windSpeed = newSpeed; + this.humidity = humidity; + this.visibility = visibility; } - public String getCity() { - return city; + public String getIcon() { + return icon; } - public int getLongitude() { - return longitude; + public String getDescription() { + return description; } - public int getLatitude() { - return latitude; + public String getWeather() { + return weather; } - public int getTemperature() { + public float getTemperature() { return temperature; } - public void setTemperature(int temperature) { - this.temperature = temperature; + public float getWindSpeed() { + return windSpeed; } - public String getLooks() { - return looks; + public int getHumidity() { + return humidity; } - public String getAlertDescription() { - return alertDescription; + public int getVisibility() { + return visibility; } - } From 31c1ea09dc070898dfc18a811b8bd137f0f303bd Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 14 Nov 2024 15:45:50 -0500 Subject: [PATCH 088/267] interactor and output boundary finished --- .../java/use_case/note/SearchResultInteractor.java | 14 +++----------- .../note/search_result/SearchResultInputData.java | 12 +++++++++--- .../note/search_result/SearchResultOutputData.java | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index f15698cb6..e0ca7370b 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -35,17 +35,9 @@ public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, Weather @Override public void execute(SearchResultInputData searchReturnInputData) { - final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - final Runnable weatherTask = () -> { - fetchWeatherData(); - }; - - // Schedule the task to run every hour - scheduler.scheduleAtFixedRate(weatherTask, 0, 1, TimeUnit.HOURS); + fetchWeatherData(); } - private void fetchWeatherData() { try { final String city = SearchResultInputData.getCity(); @@ -54,12 +46,12 @@ private void fetchWeatherData() { // Store it in historical data final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); - final String timestamp1 = formatter.format(Instant.now()); + final String timestamp = formatter.format(Instant.now()); // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(city, historicalWeatherData, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp1); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 0aa65bbef..f15ab28b1 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -4,13 +4,19 @@ // search bar. public class SearchResultInputData { - private static final String city; + private String city; + private final String date; public SearchResultInputData(String cityName, String date) { this.city = cityName; + this.date = date; } - public static String getCity() { - return city; + public String getCity() { + return this.city; + } + + public String getDate() { + return this.date; } } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index f2a6ab4c5..5c8b0fcb7 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -7,10 +7,10 @@ public class SearchResultOutputData { private final String location; - private final Map weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, Map weather, boolean useCaseFailed) { + public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; From 963005d931b3e2ada6878d0d4755c370f594ec82 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sat, 16 Nov 2024 22:59:04 -0500 Subject: [PATCH 089/267] Implemented the Unit Conversion Use Case between Farenheit and Celcius. --- .../data_access/DBNoteDataAccessObject.java | 111 ------------------ src/main/java/entity/Converter.java | 13 -- .../converter/ConverterController.java | 22 ++++ .../note/NoteController.java | 6 +- .../java/use_case/note/NoteInputBoundary.java | 19 --- .../use_case/note/NoteOutputBoundary.java | 18 --- .../use_case/note/SearchResultInteractor.java | 2 +- .../ConvertFarenheitInputBoundary.java | 4 +- .../ConvertFarenheitInputData.java | 7 ++ .../ConvertFarenheitOutputBoundary.java | 4 +- .../ConvertFarenheitOutputData.java | 10 +- .../convert_farenheit/ConvertInteractor.java | 43 +++++++ src/main/java/view/MainView.java | 4 + 13 files changed, 94 insertions(+), 169 deletions(-) delete mode 100644 src/main/java/data_access/DBNoteDataAccessObject.java delete mode 100644 src/main/java/entity/Converter.java create mode 100644 src/main/java/interface_adapter/converter/ConverterController.java delete mode 100644 src/main/java/use_case/note/NoteInputBoundary.java delete mode 100644 src/main/java/use_case/note/NoteOutputBoundary.java create mode 100644 src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java diff --git a/src/main/java/data_access/DBNoteDataAccessObject.java b/src/main/java/data_access/DBNoteDataAccessObject.java deleted file mode 100644 index 0bb066aaf..000000000 --- a/src/main/java/data_access/DBNoteDataAccessObject.java +++ /dev/null @@ -1,111 +0,0 @@ -package data_access; - -import java.io.IOException; - -import org.json.JSONException; -import org.json.JSONObject; - -import entity.Weather; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import use_case.note.DataAccessException; -import use_case.note.WeatherDataAccessInterface; - -/** - * The DAO for accessing notes stored in the database. - *

This class demonstrates how your group can use the password-protected user - * endpoints of the API used in lab 5 to store persistent data in your program. - *

- *

You can also refer to the lab 5 code for signing up a new user and other use cases. - *

- * See - *
- * the documentation - * of the API for more details. - * implements NoteDataAccessInterface - */ -public class DBNoteDataAccessObject { - private static final int SUCCESS_CODE = 200; - private static final int CREDENTIAL_ERROR = 401; - private static final String CONTENT_TYPE_LABEL = "Content-Type"; - private static final String CONTENT_TYPE_JSON = "application/json"; - private static final String STATUS_CODE_LABEL = "status_code"; - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - private static final String MESSAGE = "message"; - - @Override - public String saveNote(Weather weather, String note) throws DataAccessException { - final OkHttpClient client = new OkHttpClient().newBuilder() - .build(); - - // POST METHOD - final MediaType mediaType = MediaType.parse(CONTENT_TYPE_JSON); - final JSONObject requestBody = new JSONObject(); - requestBody.put(USERNAME, weather.getCity()); - requestBody.put(PASSWORD, weather.getLongitude()); - requestBody.put(USERNAME, weather.getLatitude()); - requestBody.put(USERNAME, weather.getTemperature()); - requestBody.put(USERNAME, weather.getLooks()); - final JSONObject extra = new JSONObject(); - extra.put("note", note); - requestBody.put("info", extra); - final RequestBody body = RequestBody.create(requestBody.toString(), mediaType); - final Request request = new Request.Builder() - .url("http://vm003.teach.cs.toronto.edu:20112/modifyUserInfo") - .method("PUT", body) - .addHeader(CONTENT_TYPE_LABEL, CONTENT_TYPE_JSON) - .build(); - try { - final Response response = client.newCall(request).execute(); - - final JSONObject responseBody = new JSONObject(response.body().string()); - - if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - return loadNote(weather); - } - else if (responseBody.getInt(STATUS_CODE_LABEL) == CREDENTIAL_ERROR) { - throw new DataAccessException("message could not be found or password was incorrect"); - } - else { - throw new DataAccessException("database error: " + responseBody.getString(MESSAGE)); - } - } - catch (IOException | JSONException ex) { - throw new DataAccessException(ex.getMessage()); - } - } - - @Override - public String loadNote(Weather weather) throws DataAccessException { - // Make an API call to get the user object. - final String username = weather.getCity(); - final OkHttpClient client = new OkHttpClient().newBuilder().build(); - final Request request = new Request.Builder() - .url(String.format("http://vm003.teach.cs.toronto.edu:20112/user?username=%s", username)) - .addHeader("Content-Type", CONTENT_TYPE_JSON) - .build(); - try { - final Response response = client.newCall(request).execute(); - - final JSONObject responseBody = new JSONObject(response.body().string()); - - if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { - final JSONObject userJSONObject = responseBody.getJSONObject("user"); - final JSONObject data = userJSONObject.getJSONObject("info"); - return data.getString("note"); - } - else { - throw new DataAccessException(responseBody.getString(MESSAGE)); - } - } - catch (IOException | JSONException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/src/main/java/entity/Converter.java b/src/main/java/entity/Converter.java deleted file mode 100644 index cbc21f4a3..000000000 --- a/src/main/java/entity/Converter.java +++ /dev/null @@ -1,13 +0,0 @@ -package entity; - -public class Converter { - public static final double KILOMETERS_MILE = 0.62; - public static final double CELC_FAREN = 1.8; - public static final double FAREN_ADD = 32; - - public Converter(Weather weather) { - weather.setWindSpeed((int) (weather.getWindSpeed() * KILOMETERS_MILE)); - weather.setTemperature((int) ((weather.getTemperature() * CELC_FAREN)+ FAREN_ADD)); - - } -} diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java new file mode 100644 index 000000000..06cc40dff --- /dev/null +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -0,0 +1,22 @@ +package interface_adapter.converter; + +import entity.Weather; +import use_case.note.convert_farenheit.ConvertFarenheitInputBoundary; +import use_case.note.convert_farenheit.ConvertFarenheitInputData; + +public class ConverterController { + private final ConvertFarenheitInputBoundary convertInteractor; + + public ConverterController(ConvertFarenheitInputBoundary cInteractor) { + this.convertInteractor = cInteractor; + } + + /** + * Executes the convert case. + * @param weather the note to be recorded + */ + public void execute(Weather weather) { + final ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); + convertInteractor.executeConvert(inputData); + } +} diff --git a/src/main/java/interface_adapter/note/NoteController.java b/src/main/java/interface_adapter/note/NoteController.java index e3e5dfb32..90df8c8b0 100644 --- a/src/main/java/interface_adapter/note/NoteController.java +++ b/src/main/java/interface_adapter/note/NoteController.java @@ -1,15 +1,15 @@ package interface_adapter.note; -import use_case.note.NoteInputBoundary; +import use_case.note.ConvertInputBoundary; /** * Controller for our Note related Use Cases. */ public class NoteController { - private final NoteInputBoundary noteInteractor; + private final ConvertInputBoundary noteInteractor; - public NoteController(NoteInputBoundary noteInteractor) { + public NoteController(ConvertInputBoundary noteInteractor) { this.noteInteractor = noteInteractor; } diff --git a/src/main/java/use_case/note/NoteInputBoundary.java b/src/main/java/use_case/note/NoteInputBoundary.java deleted file mode 100644 index b41da9bf5..000000000 --- a/src/main/java/use_case/note/NoteInputBoundary.java +++ /dev/null @@ -1,19 +0,0 @@ -package use_case.note; - -/** - * The Input Boundary for our note-related use cases. Since they are closely related, - * we have included them both in the same interface for simplicity. - */ -public interface NoteInputBoundary { - - /** - * Executes the refresh note use case. - */ - void executeRefresh(); - - /** - * Executes the save note use case. - * @param message the input data - */ - void executeSave(String message); -} diff --git a/src/main/java/use_case/note/NoteOutputBoundary.java b/src/main/java/use_case/note/NoteOutputBoundary.java deleted file mode 100644 index c0c2bb1d0..000000000 --- a/src/main/java/use_case/note/NoteOutputBoundary.java +++ /dev/null @@ -1,18 +0,0 @@ -package use_case.note; - -/** - * The output boundary for the Login Use Case. - */ -public interface NoteOutputBoundary { - /** - * Prepares the success view for the Note related Use Cases. - * @param message the output data - */ - void prepareSuccessView(String message); - - /** - * Prepares the failure view for the Note related Use Cases. - * @param errorMessage the explanation of the failure - */ - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index e0ca7370b..8b20fce9e 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -17,7 +17,7 @@ import use_case.note.search_result.SearchResultOutputData; /** - * The interactor for the search result use case.. + * The interactor for the search result use case. */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java index 84670f1b9..8de3c12a4 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java @@ -1,5 +1,7 @@ package use_case.note.convert_farenheit; public interface ConvertFarenheitInputBoundary { - void execute(ConvertFarenheitInputData convertFarenheitInputData); + void executeConvert(ConvertFarenheitInputData convertFarenheitInputData); + + void convert(ConvertFarenheitInputData convertFarenheitInputData); } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java index 97b2827ee..3b463e735 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java @@ -1,4 +1,11 @@ package use_case.note.convert_farenheit; +import entity.Weather; + public class ConvertFarenheitInputData { + public Weather weather; + + public ConvertFarenheitInputData(Weather weather) { + this.weather = weather; + } } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java index dc5d3c646..a2c9f7018 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java @@ -1,7 +1,7 @@ package use_case.note.convert_farenheit; public interface ConvertFarenheitOutputBoundary { - void presentSuccessView(ConvertFarenheitOutputData data); - void prepareFailView(String errorMessage); + + void prepareSuccessView(ConvertFarenheitOutputData outputData); } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java index 1da847392..0f1c7f201 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java @@ -1,13 +1,21 @@ package use_case.note.convert_farenheit; +import entity.Weather; + public class ConvertFarenheitOutputData { private final boolean useCaseFailed; + private final Weather weather; - public ConvertFarenheitOutputData(boolean useCaseFailed) { + public ConvertFarenheitOutputData(Weather weather, boolean useCaseFailed) { this.useCaseFailed = useCaseFailed; + this.weather = weather; } public boolean isUseCaseFailed() { return useCaseFailed; } + + public Weather getWeather() { + return weather; + } } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java new file mode 100644 index 000000000..4ab97f475 --- /dev/null +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -0,0 +1,43 @@ +package use_case.note.convert_farenheit; + +public class ConvertInteractor implements ConvertFarenheitInputBoundary { + public static final double KILOMETERS_MILE = 0.62; + public static final double CELC_FAREN = 1.8; + public static final double FAREN_ADD = 32; + + private final ConvertFarenheitOutputBoundary oBounds; + + public ConvertInteractor(ConvertFarenheitOutputBoundary convertFarenheitOutputBoundary) { + this.oBounds = convertFarenheitOutputBoundary; + } + + @Override + public void executeConvert(ConvertFarenheitInputData cInputData) { + if (cInputData.weather != null) { + + convert(cInputData); + + final ConvertFarenheitOutputData outputData = new ConvertFarenheitOutputData(cInputData.weather, true); + oBounds.prepareSuccessView(outputData); + } + else { + + oBounds.prepareFailView("UNABLE TO CONVERT"); + } + } + + @Override + public void convert(ConvertFarenheitInputData cInputData) { + + if (cInputData.weather.isMetric()) { + cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() * KILOMETERS_MILE)); + cInputData.weather.setTemperature((int) ((cInputData.weather.getTemperature() * CELC_FAREN) + FAREN_ADD)); + } + else { + cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() / KILOMETERS_MILE)); + cInputData.weather.setTemperature((int) ((cInputData.weather.getTemperature() - FAREN_ADD) / CELC_FAREN)); + } + } + +} + diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index e689a9197..faa2ebced 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -26,6 +26,10 @@ public MainView(WeatherViewModel weatherViewModel) { this.setVisible(true); } + + public void firePropertyChanged() { + + } // public static void man(String[] args) { // new MainView(); // } From dc10ff919f3c95cba42c61b5cc7a008e147ed553 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Fri, 15 Nov 2024 10:48:14 -0500 Subject: [PATCH 090/267] modified some minor bugs. Presenter implemented --- .../note/SearchResultCountroller.java | 5 ++++ .../note/SearchResultPresenter.java | 24 +++++++++++++++++++ .../interface_adapter/note/WeatherState.java | 8 ++++--- .../pin_weather/PinWeatherInputBoundary.java | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/main/java/interface_adapter/note/SearchResultCountroller.java create mode 100644 src/main/java/interface_adapter/note/SearchResultPresenter.java diff --git a/src/main/java/interface_adapter/note/SearchResultCountroller.java b/src/main/java/interface_adapter/note/SearchResultCountroller.java new file mode 100644 index 000000000..94abb7f7c --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultCountroller.java @@ -0,0 +1,5 @@ +package interface_adapter.note; + +public class SearchResultCountroller { + +} diff --git a/src/main/java/interface_adapter/note/SearchResultPresenter.java b/src/main/java/interface_adapter/note/SearchResultPresenter.java new file mode 100644 index 000000000..243f736a7 --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultPresenter.java @@ -0,0 +1,24 @@ +package interface_adapter.note; + +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; + + +public class SearchResultPresenter implements SearchResultOutputBoundary { + + private final WeatherViewModel viewModel; + + public SearchResultPresenter(WeatherViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void presentSuccessView(SearchResultOutputData searchResultOutputData) { + viewModel.getState().setWeather(searchResultOutputData.getWeather()); + } + + @Override + public void presentFailView(String errorMessage) { + viewModel.getState().setError(errorMessage); + } +} diff --git a/src/main/java/interface_adapter/note/WeatherState.java b/src/main/java/interface_adapter/note/WeatherState.java index 1d2bf9657..51103bd35 100644 --- a/src/main/java/interface_adapter/note/WeatherState.java +++ b/src/main/java/interface_adapter/note/WeatherState.java @@ -1,18 +1,20 @@ package interface_adapter.note; +import entity.Weather; + /** * The State for a weather. *

For this example, a note is simplay a string.

*/ public class WeatherState { - private String weather = ""; + private Weather weather; private String error; - public String getWeather() { + public Weather getWeather() { return weather; } - public void setWeather(String weather) { + public void setWeather(Weather weather) { this.weather = weather; } diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java index 77475633d..2e267e172 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java @@ -3,5 +3,5 @@ // Input is a click on "pin." public interface PinWeatherInputBoundary { - void execute(PinWeatherInputData pinWeatherInputData) + void execute(PinWeatherInputData pinWeatherInputData); } From 566922a4a4ea7d55cdde461d1d2809e033647a7f Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 16 Nov 2024 10:08:23 -0500 Subject: [PATCH 091/267] presenter controller, view and view model implemented --- .../SearchResultViewModel.java | 9 +++++ .../interface_adapter/WeatherController.java | 4 ++ .../interface_adapter/note/NotePresenter.java | 38 ------------------- .../note/SearchResultState.java | 28 ++++++++++++++ .../use_case/note/SearchResultInteractor.java | 3 -- 5 files changed, 41 insertions(+), 41 deletions(-) create mode 100644 src/main/java/interface_adapter/SearchResultViewModel.java create mode 100644 src/main/java/interface_adapter/WeatherController.java delete mode 100644 src/main/java/interface_adapter/note/NotePresenter.java create mode 100644 src/main/java/interface_adapter/note/SearchResultState.java diff --git a/src/main/java/interface_adapter/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResultViewModel.java new file mode 100644 index 000000000..65796da11 --- /dev/null +++ b/src/main/java/interface_adapter/SearchResultViewModel.java @@ -0,0 +1,9 @@ +package interface_adapter; +import interface_adapter.note.SearchResultState; + +public class SearchResultViewModel extends ViewModel { + public SearchResultViewModel() { + super("searchResult"); + setState(new SearchResultState()); + } +} diff --git a/src/main/java/interface_adapter/WeatherController.java b/src/main/java/interface_adapter/WeatherController.java new file mode 100644 index 000000000..133efb33d --- /dev/null +++ b/src/main/java/interface_adapter/WeatherController.java @@ -0,0 +1,4 @@ +package interface_adapter; + +public class WeatherController { +} diff --git a/src/main/java/interface_adapter/note/NotePresenter.java b/src/main/java/interface_adapter/note/NotePresenter.java deleted file mode 100644 index d4e416165..000000000 --- a/src/main/java/interface_adapter/note/NotePresenter.java +++ /dev/null @@ -1,38 +0,0 @@ -package interface_adapter.note; - -import use_case.note.NoteOutputBoundary; - -/** - * The presenter for our Note viewing and editing program. - */ -public class NotePresenter implements NoteOutputBoundary { - - private final NoteViewModel noteViewModel; - - public NotePresenter(NoteViewModel noteViewModel) { - this.noteViewModel = noteViewModel; - } - - /** - * Prepares the success view for the Note related Use Cases. - * - * @param note the output data - */ - @Override - public void prepareSuccessView(String note) { - noteViewModel.getState().setNote(note); - noteViewModel.getState().setError(null); - noteViewModel.firePropertyChanged(); - } - - /** - * Prepares the failure view for the Note related Use Cases. - * - * @param errorMessage the explanation of the failure - */ - @Override - public void prepareFailView(String errorMessage) { - noteViewModel.getState().setError(errorMessage); - noteViewModel.firePropertyChanged(); - } -} diff --git a/src/main/java/interface_adapter/note/SearchResultState.java b/src/main/java/interface_adapter/note/SearchResultState.java new file mode 100644 index 000000000..c779f11c2 --- /dev/null +++ b/src/main/java/interface_adapter/note/SearchResultState.java @@ -0,0 +1,28 @@ +package interface_adapter.note; + +import entity.Weather; + +/** + * The State for a search result. + *

For this example, a note is simplay a string.

+ */ +public class SearchResultState { + private Weather weather; + private String error; + + public Weather getWeather() { + return weather; + } + + public void setWeather(Weather weather) { + this.weather = weather; + } + + public void setError(String errorMessage) { + this.error = errorMessage; + } + + public String getError() { + return error; + } +} diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 8b20fce9e..33ef27729 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -6,9 +6,6 @@ import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import entity.Weather; import use_case.note.search_result.SearchResultInputBoundary; From a033f944780f8a8e223aa9274a19ca8d38a977d2 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 9 Nov 2024 11:07:40 -0500 Subject: [PATCH 092/267] sample file for map added --- src/test/java/app/Sample3.java | 112 ++++++++++++++++++++++++ src/test/java/app/SelectionAdapter.java | 87 ++++++++++++++++++ src/test/java/app/SelectionPainter.java | 42 +++++++++ 3 files changed, 241 insertions(+) create mode 100644 src/test/java/app/Sample3.java create mode 100644 src/test/java/app/SelectionAdapter.java create mode 100644 src/test/java/app/SelectionPainter.java diff --git a/src/test/java/app/Sample3.java b/src/test/java/app/Sample3.java new file mode 100644 index 000000000..c22666b16 --- /dev/null +++ b/src/test/java/app/Sample3.java @@ -0,0 +1,112 @@ +package app; + +import java.awt.BorderLayout; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.WindowConstants; +import javax.swing.event.MouseInputListener; + +import org.jxmapviewer.JXMapViewer; +import org.jxmapviewer.OSMTileFactoryInfo; +import org.jxmapviewer.cache.FileBasedLocalCache; +import org.jxmapviewer.input.CenterMapListener; +import org.jxmapviewer.input.PanKeyListener; +import org.jxmapviewer.input.PanMouseInputListener; +import org.jxmapviewer.input.ZoomMouseWheelListenerCursor; +import org.jxmapviewer.viewer.DefaultTileFactory; +import org.jxmapviewer.viewer.GeoPosition; +import org.jxmapviewer.viewer.TileFactoryInfo; + +/** + * A simple sample application that shows + * a OSM map of Europe + * @author Martin Steiger + */ +public class Sample3 +{ + /** + * @param args the program args (ignored) + */ + public static void main(String[] args) + { + // Create a TileFactoryInfo for OpenStreetMap + TileFactoryInfo info = new OSMTileFactoryInfo(); + DefaultTileFactory tileFactory = new DefaultTileFactory(info); + + // Setup local file cache + File cacheDir = new File(System.getProperty("user.home") + File.separator + ".jxmapviewer2"); + tileFactory.setLocalCache(new FileBasedLocalCache(cacheDir, false)); + + // Setup JXMapViewer + final JXMapViewer mapViewer = new JXMapViewer(); + mapViewer.setTileFactory(tileFactory); + + GeoPosition frankfurt = new GeoPosition(50.11, 8.68); + + // Set the focus + mapViewer.setZoom(7); + mapViewer.setAddressLocation(frankfurt); + + // Add interactions + MouseInputListener mia = new PanMouseInputListener(mapViewer); + mapViewer.addMouseListener(mia); + mapViewer.addMouseMotionListener(mia); + + mapViewer.addMouseListener(new CenterMapListener(mapViewer)); + + mapViewer.addMouseWheelListener(new ZoomMouseWheelListenerCursor(mapViewer)); + + mapViewer.addKeyListener(new PanKeyListener(mapViewer)); + + // Add a selection painter + SelectionAdapter sa = new SelectionAdapter(mapViewer); + SelectionPainter sp = new SelectionPainter(sa); + mapViewer.addMouseListener(sa); + mapViewer.addMouseMotionListener(sa); + mapViewer.setOverlayPainter(sp); + + // Display the viewer in a JFrame + final JFrame frame = new JFrame(); + frame.setLayout(new BorderLayout()); + String text = "Use left mouse button to pan, mouse wheel to zoom and right mouse to select"; + frame.add(new JLabel(text), BorderLayout.NORTH); + frame.add(mapViewer); + frame.setSize(800, 600); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setVisible(true); + + mapViewer.addPropertyChangeListener("zoom", new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + updateWindowTitle(frame, mapViewer); + } + }); + + mapViewer.addPropertyChangeListener("center", new PropertyChangeListener() + { + @Override + public void propertyChange(PropertyChangeEvent evt) + { + updateWindowTitle(frame, mapViewer); + } + }); + + updateWindowTitle(frame, mapViewer); + } + + protected static void updateWindowTitle(JFrame frame, JXMapViewer mapViewer) + { + double lat = mapViewer.getCenterPosition().getLatitude(); + double lon = mapViewer.getCenterPosition().getLongitude(); + int zoom = mapViewer.getZoom(); + + frame.setTitle(String.format("JXMapviewer2 Example 3 (%.2f / %.2f) - Zoom: %d", lat, lon, zoom)); + } + +} diff --git a/src/test/java/app/SelectionAdapter.java b/src/test/java/app/SelectionAdapter.java new file mode 100644 index 000000000..e5aae17f8 --- /dev/null +++ b/src/test/java/app/SelectionAdapter.java @@ -0,0 +1,87 @@ + +package app; + +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; + +import org.jxmapviewer.JXMapViewer; + +/** + * Creates a selection rectangle based on mouse input + * Also triggers repaint events in the viewer + * @author Martin Steiger + */ +public class SelectionAdapter extends MouseAdapter +{ + private boolean dragging; + private JXMapViewer viewer; + + private Point2D startPos = new Point2D.Double(); + private Point2D endPos = new Point2D.Double(); + + /** + * @param viewer the jxmapviewer + */ + public SelectionAdapter(JXMapViewer viewer) + { + this.viewer = viewer; + } + + @Override + public void mousePressed(MouseEvent e) + { + if (e.getButton() != MouseEvent.BUTTON3) + return; + + startPos.setLocation(e.getX(), e.getY()); + endPos.setLocation(e.getX(), e.getY()); + + dragging = true; + } + + @Override + public void mouseDragged(MouseEvent e) + { + if (!dragging) + return; + + endPos.setLocation(e.getX(), e.getY()); + + viewer.repaint(); + } + + @Override + public void mouseReleased(MouseEvent e) + { + if (!dragging) + return; + + if (e.getButton() != MouseEvent.BUTTON3) + return; + + viewer.repaint(); + + dragging = false; + } + + /** + * @return the selection rectangle + */ + public Rectangle getRectangle() + { + if (dragging) + { + int x1 = (int) Math.min(startPos.getX(), endPos.getX()); + int y1 = (int) Math.min(startPos.getY(), endPos.getY()); + int x2 = (int) Math.max(startPos.getX(), endPos.getX()); + int y2 = (int) Math.max(startPos.getY(), endPos.getY()); + + return new Rectangle(x1, y1, x2-x1, y2-y1); + } + + return null; + } + +} diff --git a/src/test/java/app/SelectionPainter.java b/src/test/java/app/SelectionPainter.java new file mode 100644 index 000000000..be57d652d --- /dev/null +++ b/src/test/java/app/SelectionPainter.java @@ -0,0 +1,42 @@ + +package app; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +import org.jxmapviewer.painter.Painter; + +/** + * Paints a selection rectangle + * @author Martin Steiger + */ +public class SelectionPainter implements Painter +{ + private Color fillColor = new Color(128, 192, 255, 128); + private Color frameColor = new Color(0, 0, 255, 128); + + private SelectionAdapter adapter; + + /** + * @param adapter the selection adapter + */ + public SelectionPainter(SelectionAdapter adapter) + { + this.adapter = adapter; + } + + @Override + public void paint(Graphics2D g, Object t, int width, int height) + { + Rectangle rc = adapter.getRectangle(); + + if (rc != null) + { + g.setColor(frameColor); + g.draw(rc); + g.setColor(fillColor); + g.fill(rc); + } + } +} From 4d3f24be3bde560c50992173f527ccadd2da0f0b Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Tue, 12 Nov 2024 12:49:50 -0500 Subject: [PATCH 093/267] deleted sample files for map --- src/test/java/app/Sample3.java | 112 ------------------------ src/test/java/app/SelectionAdapter.java | 87 ------------------ src/test/java/app/SelectionPainter.java | 42 --------- 3 files changed, 241 deletions(-) delete mode 100644 src/test/java/app/Sample3.java delete mode 100644 src/test/java/app/SelectionAdapter.java delete mode 100644 src/test/java/app/SelectionPainter.java diff --git a/src/test/java/app/Sample3.java b/src/test/java/app/Sample3.java deleted file mode 100644 index c22666b16..000000000 --- a/src/test/java/app/Sample3.java +++ /dev/null @@ -1,112 +0,0 @@ -package app; - -import java.awt.BorderLayout; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; - -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.WindowConstants; -import javax.swing.event.MouseInputListener; - -import org.jxmapviewer.JXMapViewer; -import org.jxmapviewer.OSMTileFactoryInfo; -import org.jxmapviewer.cache.FileBasedLocalCache; -import org.jxmapviewer.input.CenterMapListener; -import org.jxmapviewer.input.PanKeyListener; -import org.jxmapviewer.input.PanMouseInputListener; -import org.jxmapviewer.input.ZoomMouseWheelListenerCursor; -import org.jxmapviewer.viewer.DefaultTileFactory; -import org.jxmapviewer.viewer.GeoPosition; -import org.jxmapviewer.viewer.TileFactoryInfo; - -/** - * A simple sample application that shows - * a OSM map of Europe - * @author Martin Steiger - */ -public class Sample3 -{ - /** - * @param args the program args (ignored) - */ - public static void main(String[] args) - { - // Create a TileFactoryInfo for OpenStreetMap - TileFactoryInfo info = new OSMTileFactoryInfo(); - DefaultTileFactory tileFactory = new DefaultTileFactory(info); - - // Setup local file cache - File cacheDir = new File(System.getProperty("user.home") + File.separator + ".jxmapviewer2"); - tileFactory.setLocalCache(new FileBasedLocalCache(cacheDir, false)); - - // Setup JXMapViewer - final JXMapViewer mapViewer = new JXMapViewer(); - mapViewer.setTileFactory(tileFactory); - - GeoPosition frankfurt = new GeoPosition(50.11, 8.68); - - // Set the focus - mapViewer.setZoom(7); - mapViewer.setAddressLocation(frankfurt); - - // Add interactions - MouseInputListener mia = new PanMouseInputListener(mapViewer); - mapViewer.addMouseListener(mia); - mapViewer.addMouseMotionListener(mia); - - mapViewer.addMouseListener(new CenterMapListener(mapViewer)); - - mapViewer.addMouseWheelListener(new ZoomMouseWheelListenerCursor(mapViewer)); - - mapViewer.addKeyListener(new PanKeyListener(mapViewer)); - - // Add a selection painter - SelectionAdapter sa = new SelectionAdapter(mapViewer); - SelectionPainter sp = new SelectionPainter(sa); - mapViewer.addMouseListener(sa); - mapViewer.addMouseMotionListener(sa); - mapViewer.setOverlayPainter(sp); - - // Display the viewer in a JFrame - final JFrame frame = new JFrame(); - frame.setLayout(new BorderLayout()); - String text = "Use left mouse button to pan, mouse wheel to zoom and right mouse to select"; - frame.add(new JLabel(text), BorderLayout.NORTH); - frame.add(mapViewer); - frame.setSize(800, 600); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setVisible(true); - - mapViewer.addPropertyChangeListener("zoom", new PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - updateWindowTitle(frame, mapViewer); - } - }); - - mapViewer.addPropertyChangeListener("center", new PropertyChangeListener() - { - @Override - public void propertyChange(PropertyChangeEvent evt) - { - updateWindowTitle(frame, mapViewer); - } - }); - - updateWindowTitle(frame, mapViewer); - } - - protected static void updateWindowTitle(JFrame frame, JXMapViewer mapViewer) - { - double lat = mapViewer.getCenterPosition().getLatitude(); - double lon = mapViewer.getCenterPosition().getLongitude(); - int zoom = mapViewer.getZoom(); - - frame.setTitle(String.format("JXMapviewer2 Example 3 (%.2f / %.2f) - Zoom: %d", lat, lon, zoom)); - } - -} diff --git a/src/test/java/app/SelectionAdapter.java b/src/test/java/app/SelectionAdapter.java deleted file mode 100644 index e5aae17f8..000000000 --- a/src/test/java/app/SelectionAdapter.java +++ /dev/null @@ -1,87 +0,0 @@ - -package app; - -import java.awt.Rectangle; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.Point2D; - -import org.jxmapviewer.JXMapViewer; - -/** - * Creates a selection rectangle based on mouse input - * Also triggers repaint events in the viewer - * @author Martin Steiger - */ -public class SelectionAdapter extends MouseAdapter -{ - private boolean dragging; - private JXMapViewer viewer; - - private Point2D startPos = new Point2D.Double(); - private Point2D endPos = new Point2D.Double(); - - /** - * @param viewer the jxmapviewer - */ - public SelectionAdapter(JXMapViewer viewer) - { - this.viewer = viewer; - } - - @Override - public void mousePressed(MouseEvent e) - { - if (e.getButton() != MouseEvent.BUTTON3) - return; - - startPos.setLocation(e.getX(), e.getY()); - endPos.setLocation(e.getX(), e.getY()); - - dragging = true; - } - - @Override - public void mouseDragged(MouseEvent e) - { - if (!dragging) - return; - - endPos.setLocation(e.getX(), e.getY()); - - viewer.repaint(); - } - - @Override - public void mouseReleased(MouseEvent e) - { - if (!dragging) - return; - - if (e.getButton() != MouseEvent.BUTTON3) - return; - - viewer.repaint(); - - dragging = false; - } - - /** - * @return the selection rectangle - */ - public Rectangle getRectangle() - { - if (dragging) - { - int x1 = (int) Math.min(startPos.getX(), endPos.getX()); - int y1 = (int) Math.min(startPos.getY(), endPos.getY()); - int x2 = (int) Math.max(startPos.getX(), endPos.getX()); - int y2 = (int) Math.max(startPos.getY(), endPos.getY()); - - return new Rectangle(x1, y1, x2-x1, y2-y1); - } - - return null; - } - -} diff --git a/src/test/java/app/SelectionPainter.java b/src/test/java/app/SelectionPainter.java deleted file mode 100644 index be57d652d..000000000 --- a/src/test/java/app/SelectionPainter.java +++ /dev/null @@ -1,42 +0,0 @@ - -package app; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Rectangle; - -import org.jxmapviewer.painter.Painter; - -/** - * Paints a selection rectangle - * @author Martin Steiger - */ -public class SelectionPainter implements Painter -{ - private Color fillColor = new Color(128, 192, 255, 128); - private Color frameColor = new Color(0, 0, 255, 128); - - private SelectionAdapter adapter; - - /** - * @param adapter the selection adapter - */ - public SelectionPainter(SelectionAdapter adapter) - { - this.adapter = adapter; - } - - @Override - public void paint(Graphics2D g, Object t, int width, int height) - { - Rectangle rc = adapter.getRectangle(); - - if (rc != null) - { - g.setColor(frameColor); - g.draw(rc); - g.setColor(fillColor); - g.fill(rc); - } - } -} From 51906adabf7e14c82a88711783a2787c0f77f50c Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 02:22:04 -0500 Subject: [PATCH 094/267] fixed some problems --- src/main/java/app/NoteAppBuilder.java | 10 ++--- .../SearchResultCountroller.java | 0 .../SearchResultPresenter.java | 0 .../{note => weather}/SearchResultState.java | 0 .../weather/WeatherController.java | 25 ++++++++++++ .../weather/WeatherPresenter.java | 38 +++++++++++++++++++ .../{note => weather}/WeatherState.java | 2 +- .../{note => weather}/WeatherViewModel.java | 2 +- .../search_result/SearchResultInputData.java | 8 +--- src/main/java/view/MainView.java | 2 +- src/main/java/view/MapPanelView.java | 9 ++--- src/main/java/view/WeatherPanelView.java | 3 +- src/main/java/view/mappanelpreview.java | 2 +- 13 files changed, 77 insertions(+), 24 deletions(-) rename src/main/java/interface_adapter/{note => weather}/SearchResultCountroller.java (100%) rename src/main/java/interface_adapter/{note => weather}/SearchResultPresenter.java (100%) rename src/main/java/interface_adapter/{note => weather}/SearchResultState.java (100%) create mode 100644 src/main/java/interface_adapter/weather/WeatherController.java create mode 100644 src/main/java/interface_adapter/weather/WeatherPresenter.java rename src/main/java/interface_adapter/{note => weather}/WeatherState.java (93%) rename src/main/java/interface_adapter/{note => weather}/WeatherViewModel.java (87%) diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index 652884732..ea2a3a58a 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -3,9 +3,9 @@ import javax.swing.JFrame; import javax.swing.WindowConstants; -import interface_adapter.note.NoteController; -import interface_adapter.note.NotePresenter; -import interface_adapter.note.NoteViewModel; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherPresenter; +import interface_adapter.weather.WeatherViewModel; import use_case.note.WeatherDataAccessInterface; import use_case.note.NoteInteractor; import use_case.note.NoteOutputBoundary; @@ -40,11 +40,11 @@ public NoteAppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { * @throws RuntimeException if this method is called before addNoteView */ public NoteAppBuilder addNoteUseCase() { - final NoteOutputBoundary noteOutputBoundary = new NotePresenter(noteViewModel); + final NoteOutputBoundary noteOutputBoundary = new WeatherPresenter(noteViewModel); noteInteractor = new NoteInteractor( noteDAO, noteOutputBoundary); - final NoteController controller = new NoteController(noteInteractor); + final WeatherController controller = new WeatherController(noteInteractor); if (noteView == null) { throw new RuntimeException("addNoteView must be called before addNoteUseCase"); } diff --git a/src/main/java/interface_adapter/note/SearchResultCountroller.java b/src/main/java/interface_adapter/weather/SearchResultCountroller.java similarity index 100% rename from src/main/java/interface_adapter/note/SearchResultCountroller.java rename to src/main/java/interface_adapter/weather/SearchResultCountroller.java diff --git a/src/main/java/interface_adapter/note/SearchResultPresenter.java b/src/main/java/interface_adapter/weather/SearchResultPresenter.java similarity index 100% rename from src/main/java/interface_adapter/note/SearchResultPresenter.java rename to src/main/java/interface_adapter/weather/SearchResultPresenter.java diff --git a/src/main/java/interface_adapter/note/SearchResultState.java b/src/main/java/interface_adapter/weather/SearchResultState.java similarity index 100% rename from src/main/java/interface_adapter/note/SearchResultState.java rename to src/main/java/interface_adapter/weather/SearchResultState.java diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java new file mode 100644 index 000000000..299ebd86e --- /dev/null +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -0,0 +1,25 @@ +package interface_adapter.weather; + +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; + +/** + * Controller for our Note related Use Cases. + */ +public class WeatherController { + + private final SearchResultInputBoundary searchInteractor; + + public WeatherController(SearchResultInputBoundary searchInteractor) { + this.searchInteractor = searchInteractor; + } + + /** + * Execute the weather use case. + * @param cityName the city to find the weather for + */ + public void execute(String cityName) { + final SearchResultInputData searchInputData = new SearchResultInputData(cityName); + searchInteractor.execute(searchInputData); + } +} diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java new file mode 100644 index 000000000..5cc8a4fed --- /dev/null +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -0,0 +1,38 @@ +package interface_adapter.weather; + +import use_case.note.NoteOutputBoundary; + +/** + * The presenter for our Note viewing and editing program. + */ +public class WeatherPresenter implements NoteOutputBoundary { + + private final WeatherViewModel weatherViewModel; + + public WeatherPresenter(WeatherViewModel weatherViewModel) { + this.weatherViewModel = weatherViewModel; + } + + /** + * Prepares the success view for the Weather related Use Cases. + * + * @param weather the output data + */ + @Override + public void prepareSuccessView(String weather) { + weatherViewModel.getState().setWeather(weather); + weatherViewModel.getState().setError(null); + weatherViewModel.firePropertyChanged(); + } + + /** + * Prepares the failure view for the Weather related Use Cases. + * + * @param errorMessage the explanation of the failure + */ + @Override + public void prepareFailView(String errorMessage) { + weatherViewModel.getState().setError(errorMessage); + weatherViewModel.firePropertyChanged(); + } +} diff --git a/src/main/java/interface_adapter/note/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java similarity index 93% rename from src/main/java/interface_adapter/note/WeatherState.java rename to src/main/java/interface_adapter/weather/WeatherState.java index 51103bd35..ba4b56306 100644 --- a/src/main/java/interface_adapter/note/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -1,4 +1,4 @@ -package interface_adapter.note; +package interface_adapter.weather; import entity.Weather; diff --git a/src/main/java/interface_adapter/note/WeatherViewModel.java b/src/main/java/interface_adapter/weather/WeatherViewModel.java similarity index 87% rename from src/main/java/interface_adapter/note/WeatherViewModel.java rename to src/main/java/interface_adapter/weather/WeatherViewModel.java index 7d10ebde8..9cffe3889 100644 --- a/src/main/java/interface_adapter/note/WeatherViewModel.java +++ b/src/main/java/interface_adapter/weather/WeatherViewModel.java @@ -1,4 +1,4 @@ -package interface_adapter.note; +package interface_adapter.weather; import interface_adapter.ViewModel; diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index f15ab28b1..296c5bcb9 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -5,18 +5,12 @@ public class SearchResultInputData { private String city; - private final String date; - public SearchResultInputData(String cityName, String date) { + public SearchResultInputData(String cityName) { this.city = cityName; - this.date = date; } public String getCity() { return this.city; } - - public String getDate() { - return this.date; - } } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index faa2ebced..4438a0094 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,6 +1,6 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.JFrame; import java.awt.GridLayout; diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index ef31154ff..fc08a81f8 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,15 +1,12 @@ package view; -import interface_adapter.note.NoteController; -import interface_adapter.note.WeatherState; -import interface_adapter.note.WeatherViewModel; -import WeatherController; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: @@ -33,7 +30,7 @@ public MapPanelView() { cityinputfield.addActionListener( event -> { // if the event is coming from cityinput field, execute controller - if (event.getSource() == cityinputfield) {WeatherController.excute(cityinputfield.getText()); + if (event.getSource() == cityinputfield) {WeatherController.execute(cityinputfield.getText()); } } ); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 5c5441d0a..79580c43c 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,11 +1,10 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Observer; /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java index 232391e1f..55fbe9866 100644 --- a/src/main/java/view/mappanelpreview.java +++ b/src/main/java/view/mappanelpreview.java @@ -1,6 +1,6 @@ package view; -import interface_adapter.note.WeatherViewModel; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; From bb3780bcd50b0f9f196b6ad5e7aa9b59007af5cd Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 02:41:16 -0500 Subject: [PATCH 095/267] re-added imports that somehow got deleted --- src/main/java/view/MapPanelView.java | 2 ++ src/main/java/view/WeatherPanelView.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index fc08a81f8..69776eb1f 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -2,11 +2,13 @@ import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherState; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 79580c43c..578342a5b 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -5,6 +5,7 @@ import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Observer; /* * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch From 3dfe4ba5c857c64de4050aa352b5fa49a4746d4a Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 15 Nov 2024 03:18:31 -0500 Subject: [PATCH 096/267] fixed WeatherPresenter, updated README --- README.md | 2 +- .../weather/WeatherController.java | 2 +- .../weather/WeatherPresenter.java | 15 ++++++++------- .../interface_adapter/weather/WeatherState.java | 3 +-- .../weather/WeatherViewModel.java | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e03030fe2..d808a0220 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Person wants a quick overview of the weather in nearby areas. They can view a li Person wants to compare the weather in 2 different locations. They can pin the weather of a certain place to the ui to make it easier to compare it to the weather in other places. -Person wants to see what the weather was yesterday. They can select any hour from the past 24 hours to see what the weather was then. +Person checks the weather of a certain location often. They can view their search history and select that location to avoid having to repeatedly search for the same city. ## API The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 299ebd86e..11c3644f7 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -4,7 +4,7 @@ import use_case.note.search_result.SearchResultInputData; /** - * Controller for our Note related Use Cases. + * Controller for our weather related Use Cases. */ public class WeatherController { diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 5cc8a4fed..cf75eebb8 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,11 +1,12 @@ package interface_adapter.weather; -import use_case.note.NoteOutputBoundary; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; /** - * The presenter for our Note viewing and editing program. + * The presenter for the */ -public class WeatherPresenter implements NoteOutputBoundary { +public class WeatherPresenter implements SearchResultOutputBoundary { private final WeatherViewModel weatherViewModel; @@ -16,11 +17,11 @@ public WeatherPresenter(WeatherViewModel weatherViewModel) { /** * Prepares the success view for the Weather related Use Cases. * - * @param weather the output data + * @param response the output data */ @Override - public void prepareSuccessView(String weather) { - weatherViewModel.getState().setWeather(weather); + public void presentSuccessView(SearchResultOutputData response) { + weatherViewModel.getState().setWeather(response.getWeather()); weatherViewModel.getState().setError(null); weatherViewModel.firePropertyChanged(); } @@ -31,7 +32,7 @@ public void prepareSuccessView(String weather) { * @param errorMessage the explanation of the failure */ @Override - public void prepareFailView(String errorMessage) { + public void presentFailView(String errorMessage) { weatherViewModel.getState().setError(errorMessage); weatherViewModel.firePropertyChanged(); } diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index ba4b56306..d61a08aa4 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -3,8 +3,7 @@ import entity.Weather; /** - * The State for a weather. - *

For this example, a note is simplay a string.

+ * The state information for the weather view model. */ public class WeatherState { private Weather weather; diff --git a/src/main/java/interface_adapter/weather/WeatherViewModel.java b/src/main/java/interface_adapter/weather/WeatherViewModel.java index 9cffe3889..5bc58f127 100644 --- a/src/main/java/interface_adapter/weather/WeatherViewModel.java +++ b/src/main/java/interface_adapter/weather/WeatherViewModel.java @@ -3,7 +3,7 @@ import interface_adapter.ViewModel; /** - * The ViewModel for the NoteView. + * The ViewModel for the WeatherView. */ public class WeatherViewModel extends ViewModel { public WeatherViewModel() { From 026023af55b5e3778bc2fb95fddcff0875346507 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 16 Nov 2024 04:31:23 -0500 Subject: [PATCH 097/267] changed weather variable to be the weather entity instead of a string, changed interface adapter to use the searchreturn use case instead of the searchresult --- .../weather/WeatherController.java | 10 +++++----- .../interface_adapter/weather/WeatherPresenter.java | 10 +++++----- .../note/search_result/SearchResultInputData.java | 6 ++++++ .../note/search_return/SearchReturnInputData.java | 13 ++++++++++++- .../note/search_return/SearchReturnOutputData.java | 8 +++++--- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 11c3644f7..526c4e607 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -1,16 +1,16 @@ package interface_adapter.weather; -import use_case.note.search_result.SearchResultInputBoundary; -import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; /** * Controller for our weather related Use Cases. */ public class WeatherController { - private final SearchResultInputBoundary searchInteractor; + private final SearchReturnInputBoundary searchInteractor; - public WeatherController(SearchResultInputBoundary searchInteractor) { + public WeatherController(SearchReturnInputBoundary searchInteractor) { this.searchInteractor = searchInteractor; } @@ -19,7 +19,7 @@ public WeatherController(SearchResultInputBoundary searchInteractor) { * @param cityName the city to find the weather for */ public void execute(String cityName) { - final SearchResultInputData searchInputData = new SearchResultInputData(cityName); + final SearchReturnInputData searchInputData = new SearchReturnInputData(cityName); searchInteractor.execute(searchInputData); } } diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index cf75eebb8..523bd3e9c 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,12 +1,12 @@ package interface_adapter.weather; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; /** * The presenter for the */ -public class WeatherPresenter implements SearchResultOutputBoundary { +public class WeatherPresenter implements SearchReturnOutputBoundary { private final WeatherViewModel weatherViewModel; @@ -20,7 +20,7 @@ public WeatherPresenter(WeatherViewModel weatherViewModel) { * @param response the output data */ @Override - public void presentSuccessView(SearchResultOutputData response) { + public void presentSuccessView(SearchReturnOutputData response) { weatherViewModel.getState().setWeather(response.getWeather()); weatherViewModel.getState().setError(null); weatherViewModel.firePropertyChanged(); @@ -32,7 +32,7 @@ public void presentSuccessView(SearchResultOutputData response) { * @param errorMessage the explanation of the failure */ @Override - public void presentFailView(String errorMessage) { + public void prepareFailView(String errorMessage) { weatherViewModel.getState().setError(errorMessage); weatherViewModel.firePropertyChanged(); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 296c5bcb9..3fcc1fa2d 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -5,12 +5,18 @@ public class SearchResultInputData { private String city; + private final String date; public SearchResultInputData(String cityName) { this.city = cityName; + this.date = date; } public String getCity() { return this.city; } + + public String getDate() { + return this.date; + } } diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputData.java b/src/main/java/use_case/note/search_return/SearchReturnInputData.java index 626e3ad64..4c892875c 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputData.java @@ -1,5 +1,16 @@ package use_case.note.search_return; -// Input is one click on "return." +/** + * // Input is one click on "return." + */ public class SearchReturnInputData { + private final String city; + + public SearchReturnInputData(String cityName) { + this.city = cityName; + } + + public String getCity() { + return this.city; + } } diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java index c787226d2..f48d43f72 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -1,12 +1,14 @@ package use_case.note.search_return; +import entity.Weather; + public class SearchReturnOutputData { private final String location; - private final String weather; + private final Weather weather; private final boolean useCaseFailed; - public SearchReturnOutputData(String location, String weather, boolean useCaseFailed) { + public SearchReturnOutputData(String location, Weather weather, boolean useCaseFailed) { this.location = location; this.weather = weather; this.useCaseFailed = useCaseFailed; @@ -16,7 +18,7 @@ public String getLocation() { return location; } - public String getWeather() {return weather;} + public Weather getWeather() {return weather;} public boolean isUseCaseFailed() { return useCaseFailed; From db5c42d1f82dc4e1e195c3afae4dc16f4c1d5a8e Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 16 Nov 2024 04:34:08 -0500 Subject: [PATCH 098/267] re-added date variable to searchresultinputdata --- .../java/use_case/note/search_result/SearchResultInputData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index 3fcc1fa2d..f15ab28b1 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -7,7 +7,7 @@ public class SearchResultInputData { private String city; private final String date; - public SearchResultInputData(String cityName) { + public SearchResultInputData(String cityName, String date) { this.city = cityName; this.date = date; } From b595f045b609b35a752bb3f60c331eea1f1a7636 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sat, 16 Nov 2024 23:59:41 -0500 Subject: [PATCH 099/267] Implemented the Unit Conversion Use Case between Farenheit and Celcius. --- src/main/java/entity/Weather.java | 22 +++++++++++++++++-- .../converter/ConverterPresenter.java | 2 -- .../use_case/note/SearchResultInteractor.java | 3 --- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index b0be05c1f..c99616208 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -6,12 +6,13 @@ public class Weather { private final float temperature; - private final String weather; + private String weather; private final String description; private final String icon; - private final float windSpeed; + private float windSpeed; private final int humidity; private final int visibility; + private boolean metric; public Weather(float temperature, String weather, String description, String icon, float windSpeed, int humidity, @@ -23,6 +24,7 @@ public Weather(float temperature, String weather, String description, String ico this.windSpeed = windSpeed; this.humidity = humidity; this.visibility = visibility; + this.metric = false; } public String getIcon() { @@ -33,6 +35,22 @@ public String getDescription() { return description; } + public boolean isMetric() { + return metric; + } + + public void setMetric(boolean metric) { + this.metric = metric; + } + + public void setWeather(double weather) { + this.weather = weather; + } + + public void setWindSpeed(float windSpeed) { + this.windSpeed = windSpeed; + } + public String getWeather() { return weather; } diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java index a5679cb95..c634c2d30 100644 --- a/src/main/java/interface_adapter/converter/ConverterPresenter.java +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -19,8 +19,6 @@ public void prepareFailView(String errorMessage) { @Override public void prepareSuccessView(ConvertFarenheitOutputData outputData) { - final String weather = viewModel.getState().getWeather(); - viewModel.getState().setWeather(weather); viewModel.getState().setError(null); viewModel.firePropertyChanged(); } diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 33ef27729..c25d64a39 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -13,9 +13,6 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; -/** - * The interactor for the search result use case. - */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; From 75a460ed71104e3a94b5fb29108bd55c8d5809be Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 17 Nov 2024 11:58:53 -0500 Subject: [PATCH 100/267] put interface adapters about searchResult into a folder --- .../{ => SearchResult}/SearchResultController.java | 2 +- .../{weather => SearchResult}/SearchResultPresenter.java | 3 ++- .../{weather => SearchResult}/SearchResultState.java | 2 +- .../{ => SearchResult}/SearchResultViewModel.java | 5 +++-- src/main/java/interface_adapter/WeatherController.java | 4 ---- 5 files changed, 7 insertions(+), 9 deletions(-) rename src/main/java/interface_adapter/{ => SearchResult}/SearchResultController.java (96%) rename src/main/java/interface_adapter/{weather => SearchResult}/SearchResultPresenter.java (87%) rename src/main/java/interface_adapter/{weather => SearchResult}/SearchResultState.java (92%) rename src/main/java/interface_adapter/{ => SearchResult}/SearchResultViewModel.java (71%) delete mode 100644 src/main/java/interface_adapter/WeatherController.java diff --git a/src/main/java/interface_adapter/SearchResultController.java b/src/main/java/interface_adapter/SearchResult/SearchResultController.java similarity index 96% rename from src/main/java/interface_adapter/SearchResultController.java rename to src/main/java/interface_adapter/SearchResult/SearchResultController.java index 8bc814614..9d58fd126 100644 --- a/src/main/java/interface_adapter/SearchResultController.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultController.java @@ -1,4 +1,4 @@ -package interface_adapter; +package interface_adapter.SearchResult; import use_case.note.search_result.SearchResultInputBoundary; import use_case.note.search_result.SearchResultInputData; diff --git a/src/main/java/interface_adapter/weather/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java similarity index 87% rename from src/main/java/interface_adapter/weather/SearchResultPresenter.java rename to src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index 243f736a7..78ab05899 100644 --- a/src/main/java/interface_adapter/weather/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -1,5 +1,6 @@ -package interface_adapter.note; +package interface_adapter.SearchResult; +import interface_adapter.weather.WeatherViewModel; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; diff --git a/src/main/java/interface_adapter/weather/SearchResultState.java b/src/main/java/interface_adapter/SearchResult/SearchResultState.java similarity index 92% rename from src/main/java/interface_adapter/weather/SearchResultState.java rename to src/main/java/interface_adapter/SearchResult/SearchResultState.java index c779f11c2..25fa2ddeb 100644 --- a/src/main/java/interface_adapter/weather/SearchResultState.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultState.java @@ -1,4 +1,4 @@ -package interface_adapter.note; +package interface_adapter.SearchResult; import entity.Weather; diff --git a/src/main/java/interface_adapter/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java similarity index 71% rename from src/main/java/interface_adapter/SearchResultViewModel.java rename to src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java index 65796da11..5c3b5886f 100644 --- a/src/main/java/interface_adapter/SearchResultViewModel.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java @@ -1,5 +1,6 @@ -package interface_adapter; -import interface_adapter.note.SearchResultState; +package interface_adapter.SearchResult; + +import interface_adapter.ViewModel; public class SearchResultViewModel extends ViewModel { public SearchResultViewModel() { diff --git a/src/main/java/interface_adapter/WeatherController.java b/src/main/java/interface_adapter/WeatherController.java deleted file mode 100644 index 133efb33d..000000000 --- a/src/main/java/interface_adapter/WeatherController.java +++ /dev/null @@ -1,4 +0,0 @@ -package interface_adapter; - -public class WeatherController { -} From bb1d863a1b1a98c43474f709bcd5b8ac356ef347 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sun, 17 Nov 2024 19:26:02 -0500 Subject: [PATCH 101/267] Updated the metric variable in the Conversion Use Case. --- src/main/java/entity/Weather.java | 23 +++++++++++-------- .../convert_farenheit/ConvertInteractor.java | 4 +++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index c99616208..0453924fc 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -5,7 +5,7 @@ */ public class Weather { - private final float temperature; + private float temperature; private String weather; private final String description; private final String icon; @@ -14,7 +14,6 @@ public class Weather { private final int visibility; private boolean metric; - public Weather(float temperature, String weather, String description, String icon, float windSpeed, int humidity, int visibility) { this.temperature = temperature; @@ -27,14 +26,6 @@ public Weather(float temperature, String weather, String description, String ico this.metric = false; } - public String getIcon() { - return icon; - } - - public String getDescription() { - return description; - } - public boolean isMetric() { return metric; } @@ -43,6 +34,18 @@ public void setMetric(boolean metric) { this.metric = metric; } + public void setTemperature(float temperature) { + this.temperature = temperature; + } + + public String getIcon() { + return icon; + } + + public String getDescription() { + return description; + } + public void setWeather(double weather) { this.weather = weather; } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java index 4ab97f475..0d1891ec9 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -31,11 +31,13 @@ public void convert(ConvertFarenheitInputData cInputData) { if (cInputData.weather.isMetric()) { cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() * KILOMETERS_MILE)); - cInputData.weather.setTemperature((int) ((cInputData.weather.getTemperature() * CELC_FAREN) + FAREN_ADD)); + cInputData.weather.setTemperature((float) ((cInputData.weather.getTemperature() * CELC_FAREN) + FAREN_ADD)); + cInputData.weather.setMetric(false); } else { cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() / KILOMETERS_MILE)); cInputData.weather.setTemperature((int) ((cInputData.weather.getTemperature() - FAREN_ADD) / CELC_FAREN)); + cInputData.weather.setMetric(true); } } From 982ed4f2305b236e6fb8ab572cebf6f73fa625d3 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 17 Nov 2024 23:25:26 -0500 Subject: [PATCH 102/267] SearchResultPanelView and SearchResultState implemented --- .../SearchResult/SearchResultState.java | 9 ++ src/main/java/view/SearchResultPanelView.java | 114 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/main/java/view/SearchResultPanelView.java diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultState.java b/src/main/java/interface_adapter/SearchResult/SearchResultState.java index 25fa2ddeb..3e5a6c04c 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultState.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultState.java @@ -9,6 +9,7 @@ public class SearchResultState { private Weather weather; private String error; + private String date; public Weather getWeather() { return weather; @@ -25,4 +26,12 @@ public void setError(String errorMessage) { public String getError() { return error; } + + public void setDate(String date) { + this.date = date; + } + + public String getDate() { + return date; + } } diff --git a/src/main/java/view/SearchResultPanelView.java b/src/main/java/view/SearchResultPanelView.java new file mode 100644 index 000000000..34003a34e --- /dev/null +++ b/src/main/java/view/SearchResultPanelView.java @@ -0,0 +1,114 @@ +package view; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; + +import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.SearchResult.SearchResultState; +import interface_adapter.SearchResult.SearchResultViewModel; + +/** + * The View for when the user is viewing a note in the program. + */ +public class SearchResultPanelView extends JPanel implements ActionListener, PropertyChangeListener { + + private final SearchResultViewModel searchResultViewModel; + + private final JLabel noteName = new JLabel("search result"); + private final JTextArea cityInputField = new JTextArea(); + private final JTextArea dateInputField = new JTextArea(); + + private final JButton cityButton = new JButton("Searched City"); + private final JButton dateButton = new JButton("Date"); + private final JLabel cityLabel = new JLabel("City:"); + private final JLabel dateLabel = new JLabel("Date:"); + private final JButton searchButton = new JButton("Search"); + private SearchResultController searchResultController; + + public SearchResultView(SearchResultViewModel searchResultViewModel) { + + noteName.setAlignmentX(Component.CENTER_ALIGNMENT); + this.searchResultViewModel = searchResultViewModel; + this.searchResultViewModel.addPropertyChangeListener(this); + + final JPanel buttons = new JPanel(); + buttons.add(searchButton); + + // Creating panels to contain each label and input field + final JPanel cityPanel = new JPanel(); + cityPanel.setLayout(new BoxLayout(cityPanel, BoxLayout.X_AXIS)); + cityPanel.add(cityLabel); + cityPanel.add(cityInputField); + + final JPanel datePanel = new JPanel(); + datePanel.setLayout(new BoxLayout(datePanel, BoxLayout.X_AXIS)); + datePanel.add(dateLabel); + datePanel.add(dateInputField); + + searchButton.addActionListener( + evt -> { + if (evt.getSource().equals(searchButton)) { + searchResultAction(); + } + } + ); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(noteName); + this.add(cityPanel); + this.add(datePanel); + this.add(buttons); + } + + private void searchResultAction() { + final String city = cityInputField.getText(); + final String date = dateInputField.getText(); + + if (city.isEmpty() || date.isEmpty()) { + // Display an error message or simply return + JOptionPane.showMessageDialog( + this, + "Please fill in both the City and Date fields before searching.", + "Input Error", JOptionPane.ERROR_MESSAGE); + } + else { + searchResultController.execute(city, date); + } + } + + /** + * React to a button click that results in evt. + * @param evt the ActionEvent to react to + */ + public void actionPerformed(ActionEvent evt) { + System.out.println("Click " + evt.getActionCommand()); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final SearchResultState state = (SearchResultState) evt.getNewValue(); + setFields(state); + if (state.getError() != null) { + JOptionPane.showMessageDialog(this, state.getError(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + + private void setFields(SearchResultState state) { + cityInputField.setText(state.getWeather().getCity()); + dateInputField.setText(state.getDate()); + } + + public void setSearchResultController(SearchResultController controller) { + this.searchResultController = controller; + } +} \ No newline at end of file From a4411ffcdc61e8ac33f60b40439b054511b1e7ab Mon Sep 17 00:00:00 2001 From: sophie Date: Sun, 17 Nov 2024 21:35:21 -0800 Subject: [PATCH 103/267] Adding Use Case compare cities --- .../CompareCitiesDataAccessInterface.java | 11 ++++++ .../CompareCitiesInputBoundary.java | 4 +++ .../CompareCities/CompareCitiesInputData.java | 20 +++++++++++ .../CompareCitiesOutPutData.java | 22 ++++++++++++ .../CompareCitiesOutputBoundary.java | 15 ++++++++ .../CompareCityiesnteractor.java | 35 +++++++++++++++++++ 6 files changed, 107 insertions(+) create mode 100644 src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java create mode 100644 src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java create mode 100644 src/main/java/use_case/note/CompareCities/CompareCitiesInputData.java create mode 100644 src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java create mode 100644 src/main/java/use_case/note/CompareCities/CompareCitiesOutputBoundary.java create mode 100644 src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java new file mode 100644 index 000000000..9609ad7e2 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -0,0 +1,11 @@ +package use_case.note.CompareCities; + +import entity.Weather; + +public interface CompareCitiesDataAccessInterface { + boolean citynotexist(String cityname); + Weather getWeather(String cityname); + void saveWeather(String cityname); + String getCurrentCity(); + void setCurrentCity(String cityname); +} diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java new file mode 100644 index 000000000..7c3148c97 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java @@ -0,0 +1,4 @@ +package use_case.note.CompareCities; + +public interface CompareCitiesInputBoundary { +} diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInputData.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInputData.java new file mode 100644 index 000000000..6b976f2e4 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInputData.java @@ -0,0 +1,20 @@ +package use_case.note.CompareCities; + +public class CompareCitiesInputData { + + private final String firstcityname; + private final String secondcityname; + + public CompareCitiesInputData(String firstcityname, String secondcityname) { + this.firstcityname = firstcityname; + this.secondcityname = secondcityname; + } + + public String getFirstcityname() { + return firstcityname; + } + + public String getSecondcityname() { + return secondcityname; + } +} diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java new file mode 100644 index 000000000..d66e40946 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java @@ -0,0 +1,22 @@ +package use_case.note.CompareCities; + +public class CompareCitiesOutPutData { + private final String firstCityname; + private final String secondCityname; + private final boolean useCaseFailed; + + public CompareCitiesOutPutData(String firstCityname, String secondCityname, boolean useCaseFailed) { + this.firstCityname = firstCityname; + this.secondCityname = secondCityname; + this.useCaseFailed = useCaseFailed; + } + + + public String getFirstCityname() { + return firstCityname; + } + + public String getSecondCityname() { + return secondCityname; + } +} diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesOutputBoundary.java b/src/main/java/use_case/note/CompareCities/CompareCitiesOutputBoundary.java new file mode 100644 index 000000000..55d49c082 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesOutputBoundary.java @@ -0,0 +1,15 @@ +package use_case.note.CompareCities; + +public interface CompareCitiesOutputBoundary { + /** + * Prepares the success view for the Login Use Case. + * @param outputData the output data + */ + void prepareSuccessView(CompareCitiesOutPutData outputData); + + /** + * Prepares the failure view for the Login Use Case. + * @param errorMessage the explanation of the failure + */ + void prepareFailView(String errorMessage); +} diff --git a/src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java b/src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java new file mode 100644 index 000000000..6ae07bc16 --- /dev/null +++ b/src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java @@ -0,0 +1,35 @@ +package use_case.note.CompareCities; +import entity.Weather; +/* +* The Comparecities Interactor. + */ +public class CompareCityiesnteractor implements CompareCitiesInputBoundary { + private final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface; + private final CompareCitiesOutputBoundary comparecitiesPresenter; + + public CompareCityiesnteractor(CompareCitiesDataAccessInterface compareCitiesDataAccessInterface, + CompareCitiesOutputBoundary comparecitiesPresenter) { + this.comparecitiesPresenter = comparecitiesPresenter; + this.compareCitiesDataAccessInterface = compareCitiesDataAccessInterface; + } + + public void execute(CompareCitiesInputData compareCitiesInputData) { + final String firstcityname = compareCitiesInputData.getFirstcityname(); + final String secondcityname = compareCitiesInputData.getSecondcityname(); + if (firstcityname.equals(secondcityname)) { + comparecitiesPresenter.prepareFailView("Cannot compare the same city"); + } + else { + if ((!compareCitiesDataAccessInterface.citynotexist(firstcityname)) + || (!compareCitiesDataAccessInterface.citynotexist(secondcityname))) { + comparecitiesPresenter.prepareFailView("city not found"); + } + else { + final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); + final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstweather, secondweather, false); + comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); + } + } + } +} From 7f54926e0e4df09fd7ff724bbd4c57a05662c7ed Mon Sep 17 00:00:00 2001 From: sophie Date: Sun, 17 Nov 2024 21:36:59 -0800 Subject: [PATCH 104/267] / --- src/main/java/data_access/WeatherDataAccessObject.java | 9 ++++++++- .../CompareCities/CompareCitiesPresenter.java | 7 +++++++ src/main/java/view/MapPanelView.java | 5 +++-- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 2ed681744..6cf6936b6 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -7,18 +7,21 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONArray; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; import use_case.note.WeatherDataAccessInterface; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * This class runs the API and creates a weather DAO. **/ -public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface { +public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; private static String city; @@ -27,6 +30,7 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private static final String STATUS_CODE_LABEL = "cod"; private static final String WEATHER_LIST = "list"; private static final String MESSAGE = "message"; + public final Map weathers = new HashMap<>(); @Override public Weather getWeather(String citySearch) throws IOException { @@ -75,5 +79,8 @@ public Weather getWeather(String citySearch) throws IOException { } } + public void saveWeather(Weather weather) { + weathers.put(weather.getCity(), weather); + } } diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java new file mode 100644 index 000000000..70fb705c8 --- /dev/null +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -0,0 +1,7 @@ +package interface_adapter.CompareCities; + +import use_case.note.CompareCities.CompareCitiesOutputBoundary; + +public class CompareCitiesPresenter implements CompareCitiesOutputBoundary { + +} diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 69776eb1f..be68ffb43 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -16,6 +16,7 @@ * to our Input Class. * 2. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. */ +@SuppressWarnings("checkstyle:WriteTag") public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel searchpanel; private final MapImagepanel mapimagepanel; @@ -27,12 +28,12 @@ public class MapPanelView extends JPanel implements ActionListener { public MapPanelView() { - mapimagepanel = new MapImagepanel(); cityinputfield.addActionListener( event -> { // if the event is coming from cityinput field, execute controller - if (event.getSource() == cityinputfield) {WeatherController.execute(cityinputfield.getText()); + if (event.getSource() == cityinputfield) { + WeatherController.execute(cityinputfield.getText()); } } ); From 7a5b02bb88895ae668415b5d4ff5d87b87abe45e Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 18 Nov 2024 06:28:47 -0800 Subject: [PATCH 105/267] / --- src/main/java/view/WeatherPanelView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index da4f98c4c..1de1d9a02 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,8 +1,8 @@ package view; -import interface_adapter.SearchResultViewModel; -import interface_adapter.note.WeatherViewModel; -import WeatherController; +import interface_adapter.SearchResult.SearchResultViewModel; +import interface_adapter.weather.WeatherViewModel; +import interface_adapter.weather.WeatherController; import javax.swing.*; import java.awt.event.ActionListener; From 40986524d565c6a57e6e4dbf13503b1e0f12524f Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 18 Nov 2024 06:43:03 -0800 Subject: [PATCH 106/267] Change to ConverterController --- src/main/java/view/WeatherPanelView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 1de1d9a02..29dab6a74 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -3,6 +3,7 @@ import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; import interface_adapter.weather.WeatherController; +import interface_adapter.converter.ConverterController; import javax.swing.*; import java.awt.event.ActionListener; @@ -47,7 +48,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.temperatureconverter = new JButton("Temperature Converter"); temperatureconverter.addActionListener( event -> { // if the event is coming from cityinput field, execute controller - if (event.getSource() == temperatureconverter) {WeatherController.excute(temperatureconverter.getText()); + if (event.getSource() == temperatureconverter) {ConverterController.excute(temperatureconverter.getText()); }); skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); From 4bc61c4d75ae17a56201da45599723c703acbed9 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 10:41:48 -0500 Subject: [PATCH 107/267] renamed a lotta stuff --- src/main/java/app/MainNoteApplication.java | 2 +- src/main/java/app/NoteAppBuilder.java | 3 +-- .../HistoricalWeatherDataAccessObject.java | 2 +- .../java/data_access/WeatherDataAccessObject.java | 2 +- .../converter/ConverterController.java | 4 ++-- .../converter/ConverterPresenter.java | 4 ++-- .../major_cities/MajorCitiesController.java | 4 ++++ .../major_cities/MajorCitiesPresenter.java | 4 ++++ .../major_cities/MajorCitiesState.java | 4 ++++ .../major_cities/MajorCitiesViewModel.java | 4 ++++ .../SearchResultController.java | 6 +++--- .../SearchResultPresenter.java | 6 +++--- .../SearchResultState.java | 2 +- .../SearchResultViewModel.java | 2 +- .../weather/WeatherController.java | 4 ++-- .../weather/WeatherPresenter.java | 4 ++-- .../use_case/{note => }/DataAccessException.java | 2 +- .../HistoricalWeatherDataAccessInterface.java | 2 +- .../{note => }/WeatherDataAccessInterface.java | 2 +- .../alert_pop/AlertPopInputBoundary.java | 2 +- .../{note => }/alert_pop/AlertPopInputData.java | 2 +- .../{note => alert_pop}/AlertPopInteractor.java | 4 ++-- .../alert_pop/AlertPopOutputBoundary.java | 2 +- .../{note => }/alert_pop/AlertPopOutputData.java | 2 +- .../BookmarkReturnInputBoundary.java | 2 +- .../bookmark_return/BookmarkReturnInputData.java | 2 +- .../BookmarkReturnOutputBoundary.java | 2 +- .../bookmark_return/BookmarkReturnOutputData.java | 2 +- .../city_bookmark/CityBookmarkInputBoundary.java | 2 +- .../city_bookmark/CityBookmarkInputData.java | 2 +- .../city_bookmark/CityBookmarkOutputBoundary.java | 2 +- .../city_bookmark/CityBookmarkOutputData.java | 2 +- .../close_list/CloseListInputBoundary.java | 2 +- .../{note => }/close_list/CloseListInputData.java | 2 +- .../close_list/CloseListOutputBoundary.java | 2 +- .../{note => }/close_list/CloseListOutputData.java | 2 +- .../close_pin/ClosePinInputBoundary.java | 2 +- .../{note => }/close_pin/ClosePinInputData.java | 2 +- .../close_pin/ClosePinOutputBoundary.java | 2 +- .../{note => }/close_pin/ClosePinOutputData.java | 2 +- .../close_pop/ClosePopInputBoundary.java | 2 +- .../{note => }/close_pop/ClosePopInputData.java | 2 +- .../close_pop/ClosePopOutputBoundary.java | 2 +- .../{note => }/close_pop/ClosePopOutputData.java | 2 +- .../ConvertFarenheitInputBoundary.java | 2 +- .../ConvertFarenheitInputData.java | 2 +- .../ConvertFarenheitOutputBoundary.java | 2 +- .../ConvertFarenheitOutputData.java | 2 +- .../convert_farenheit/ConvertInteractor.java | 2 +- .../nearby_list/NearbyListInputBoundary.java | 2 +- .../nearby_list/NearbyListInputData.java | 2 +- .../nearby_list/NearbyListOutputBoundary.java | 2 +- .../nearby_list/NearbyListOutputData.java | 2 +- .../pin_weather/PinWeatherInputBoundary.java | 2 +- .../pin_weather/PinWeatherInputData.java | 2 +- .../pin_weather/PinWeatherOutputBoundary.java | 2 +- .../pin_weather/PinWeatherOutputData.java | 2 +- .../return_home/ReturnHomeInputBoundary.java | 2 +- .../return_home/ReturnHomeInputData.java | 2 +- .../return_home/ReturnHomeOutputBoundary.java | 2 +- .../return_home/ReturnHomeOutputData.java | 2 +- .../search_result/SearchResultInputBoundary.java | 2 +- .../search_result/SearchResultInputData.java | 2 +- .../SearchResultInteractor.java | 8 +++----- .../search_result/SearchResultOutputBoundary.java | 2 +- .../search_result/SearchResultOutputData.java | 2 +- .../search_return/SearchReturnInputBoundary.java | 2 +- .../search_return/SearchReturnInputData.java | 2 +- .../SearchReturnInteractor.java | 14 ++++---------- .../search_return/SearchReturnOutputBoundary.java | 2 +- .../search_return/SearchReturnOutputData.java | 2 +- .../select_region/SelectRegionInputBoundary.java | 2 +- .../select_region/SelectRegionInputData.java | 2 +- .../select_region/SelectRegionOutputBoundary.java | 2 +- .../select_region/SelectRegionOutputData.java | 2 +- src/main/java/view/SearchResultPanelView.java | 6 +++--- .../use_case/{note => }/NoteInteractorTest.java | 2 +- 77 files changed, 105 insertions(+), 98 deletions(-) create mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesController.java create mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java create mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesState.java create mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java rename src/main/java/interface_adapter/{SearchResult => search_result}/SearchResultController.java (86%) rename src/main/java/interface_adapter/{SearchResult => search_result}/SearchResultPresenter.java (78%) rename src/main/java/interface_adapter/{SearchResult => search_result}/SearchResultState.java (94%) rename src/main/java/interface_adapter/{SearchResult => search_result}/SearchResultViewModel.java (84%) rename src/main/java/use_case/{note => }/DataAccessException.java (89%) rename src/main/java/use_case/{note => }/HistoricalWeatherDataAccessInterface.java (97%) rename src/main/java/use_case/{note => }/WeatherDataAccessInterface.java (95%) rename src/main/java/use_case/{note => }/alert_pop/AlertPopInputBoundary.java (81%) rename src/main/java/use_case/{note => }/alert_pop/AlertPopInputData.java (89%) rename src/main/java/use_case/{note => alert_pop}/AlertPopInteractor.java (93%) rename src/main/java/use_case/{note => }/alert_pop/AlertPopOutputBoundary.java (83%) rename src/main/java/use_case/{note => }/alert_pop/AlertPopOutputData.java (92%) rename src/main/java/use_case/{note => }/bookmark_return/BookmarkReturnInputBoundary.java (80%) rename src/main/java/use_case/{note => }/bookmark_return/BookmarkReturnInputData.java (67%) rename src/main/java/use_case/{note => }/bookmark_return/BookmarkReturnOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/bookmark_return/BookmarkReturnOutputData.java (87%) rename src/main/java/use_case/{note => }/city_bookmark/CityBookmarkInputBoundary.java (86%) rename src/main/java/use_case/{note => }/city_bookmark/CityBookmarkInputData.java (81%) rename src/main/java/use_case/{note => }/city_bookmark/CityBookmarkOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/city_bookmark/CityBookmarkOutputData.java (92%) rename src/main/java/use_case/{note => }/close_list/CloseListInputBoundary.java (81%) rename src/main/java/use_case/{note => }/close_list/CloseListInputData.java (67%) rename src/main/java/use_case/{note => }/close_list/CloseListOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/close_list/CloseListOutputData.java (88%) rename src/main/java/use_case/{note => }/close_pin/ClosePinInputBoundary.java (81%) rename src/main/java/use_case/{note => }/close_pin/ClosePinInputData.java (70%) rename src/main/java/use_case/{note => }/close_pin/ClosePinOutputBoundary.java (83%) rename src/main/java/use_case/{note => }/close_pin/ClosePinOutputData.java (88%) rename src/main/java/use_case/{note => }/close_pop/ClosePopInputBoundary.java (80%) rename src/main/java/use_case/{note => }/close_pop/ClosePopInputData.java (67%) rename src/main/java/use_case/{note => }/close_pop/ClosePopOutputBoundary.java (83%) rename src/main/java/use_case/{note => }/close_pop/ClosePopOutputData.java (88%) rename src/main/java/use_case/{note => }/convert_farenheit/ConvertFarenheitInputBoundary.java (83%) rename src/main/java/use_case/{note => }/convert_farenheit/ConvertFarenheitInputData.java (82%) rename src/main/java/use_case/{note => }/convert_farenheit/ConvertFarenheitOutputBoundary.java (80%) rename src/main/java/use_case/{note => }/convert_farenheit/ConvertFarenheitOutputData.java (91%) rename src/main/java/use_case/{note => }/convert_farenheit/ConvertInteractor.java (97%) rename src/main/java/use_case/{note => }/nearby_list/NearbyListInputBoundary.java (86%) rename src/main/java/use_case/{note => }/nearby_list/NearbyListInputData.java (81%) rename src/main/java/use_case/{note => }/nearby_list/NearbyListOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/nearby_list/NearbyListOutputData.java (90%) rename src/main/java/use_case/{note => }/pin_weather/PinWeatherInputBoundary.java (79%) rename src/main/java/use_case/{note => }/pin_weather/PinWeatherInputData.java (66%) rename src/main/java/use_case/{note => }/pin_weather/PinWeatherOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/pin_weather/PinWeatherOutputData.java (92%) rename src/main/java/use_case/{note => }/return_home/ReturnHomeInputBoundary.java (80%) rename src/main/java/use_case/{note => }/return_home/ReturnHomeInputData.java (69%) rename src/main/java/use_case/{note => }/return_home/ReturnHomeOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/return_home/ReturnHomeOutputData.java (88%) rename src/main/java/use_case/{note => }/search_result/SearchResultInputBoundary.java (86%) rename src/main/java/use_case/{note => }/search_result/SearchResultInputData.java (92%) rename src/main/java/use_case/{note => search_result}/SearchResultInteractor.java (89%) rename src/main/java/use_case/{note => }/search_result/SearchResultOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/search_result/SearchResultOutputData.java (94%) rename src/main/java/use_case/{note => }/search_return/SearchReturnInputBoundary.java (89%) rename src/main/java/use_case/{note => }/search_return/SearchReturnInputData.java (87%) rename src/main/java/use_case/{note => search_return}/SearchReturnInteractor.java (58%) rename src/main/java/use_case/{note => }/search_return/SearchReturnOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/search_return/SearchReturnOutputData.java (94%) rename src/main/java/use_case/{note => }/select_region/SelectRegionInputBoundary.java (79%) rename src/main/java/use_case/{note => }/select_region/SelectRegionInputData.java (66%) rename src/main/java/use_case/{note => }/select_region/SelectRegionOutputBoundary.java (82%) rename src/main/java/use_case/{note => }/select_region/SelectRegionOutputData.java (93%) rename src/test/java/use_case/{note => }/NoteInteractorTest.java (97%) diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index 9ef9b0693..695ed2380 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -1,7 +1,7 @@ package app; import data_access.WeatherDataAccessObject; -import use_case.note.WeatherDataAccessInterface; +import use_case.WeatherDataAccessInterface; /** * An application where we can view and add to a note stored by a user. diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index ea2a3a58a..53a9773d8 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -5,8 +5,7 @@ import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherPresenter; -import interface_adapter.weather.WeatherViewModel; -import use_case.note.WeatherDataAccessInterface; +import use_case.WeatherDataAccessInterface; import use_case.note.NoteInteractor; import use_case.note.NoteOutputBoundary; import view.NoteView; diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 0bc5c6e33..127bea2e0 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -11,7 +11,7 @@ import org.json.JSONObject; import entity.Weather; -import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.HistoricalWeatherDataAccessInterface; /** * This class provides the service of saving and getting historical weather data. diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 2ed681744..aa838f99d 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -7,7 +7,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONArray; -import use_case.note.WeatherDataAccessInterface; +import use_case.WeatherDataAccessInterface; diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 06cc40dff..5f46f98f1 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -1,8 +1,8 @@ package interface_adapter.converter; import entity.Weather; -import use_case.note.convert_farenheit.ConvertFarenheitInputBoundary; -import use_case.note.convert_farenheit.ConvertFarenheitInputData; +import use_case.convert_farenheit.ConvertFarenheitInputBoundary; +import use_case.convert_farenheit.ConvertFarenheitInputData; public class ConverterController { private final ConvertFarenheitInputBoundary convertInteractor; diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java index c634c2d30..32c8096d6 100644 --- a/src/main/java/interface_adapter/converter/ConverterPresenter.java +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -1,8 +1,8 @@ package interface_adapter.converter; import interface_adapter.weather.WeatherViewModel; -import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; -import use_case.note.convert_farenheit.ConvertFarenheitOutputData; +import use_case.convert_farenheit.ConvertFarenheitOutputBoundary; +import use_case.convert_farenheit.ConvertFarenheitOutputData; public class ConverterPresenter implements ConvertFarenheitOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesController.java b/src/main/java/interface_adapter/major_cities/MajorCitiesController.java new file mode 100644 index 000000000..0df737800 --- /dev/null +++ b/src/main/java/interface_adapter/major_cities/MajorCitiesController.java @@ -0,0 +1,4 @@ +package interface_adapter.major_cities; + +public class MajorCitiesController { +} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java b/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java new file mode 100644 index 000000000..b5dce39a9 --- /dev/null +++ b/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java @@ -0,0 +1,4 @@ +package interface_adapter.major_cities; + +public class MajorCitiesPresenter { +} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesState.java b/src/main/java/interface_adapter/major_cities/MajorCitiesState.java new file mode 100644 index 000000000..023790561 --- /dev/null +++ b/src/main/java/interface_adapter/major_cities/MajorCitiesState.java @@ -0,0 +1,4 @@ +package interface_adapter.major_cities; + +public class MajorCitiesState { +} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java b/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java new file mode 100644 index 000000000..873de3dd6 --- /dev/null +++ b/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java @@ -0,0 +1,4 @@ +package interface_adapter.major_cities; + +public class MajorCitiesViewModel { +} diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultController.java b/src/main/java/interface_adapter/search_result/SearchResultController.java similarity index 86% rename from src/main/java/interface_adapter/SearchResult/SearchResultController.java rename to src/main/java/interface_adapter/search_result/SearchResultController.java index 9d58fd126..c6fbcb099 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultController.java +++ b/src/main/java/interface_adapter/search_result/SearchResultController.java @@ -1,7 +1,7 @@ -package interface_adapter.SearchResult; +package interface_adapter.search_result; -import use_case.note.search_result.SearchResultInputBoundary; -import use_case.note.search_result.SearchResultInputData; +import use_case.search_result.SearchResultInputBoundary; +import use_case.search_result.SearchResultInputData; /** * The controller for the search result view. It is responsible for executing the search result use case. diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/search_result/SearchResultPresenter.java similarity index 78% rename from src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java rename to src/main/java/interface_adapter/search_result/SearchResultPresenter.java index 78ab05899..b4d6d81f8 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/search_result/SearchResultPresenter.java @@ -1,8 +1,8 @@ -package interface_adapter.SearchResult; +package interface_adapter.search_result; import interface_adapter.weather.WeatherViewModel; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; +import use_case.search_result.SearchResultOutputBoundary; +import use_case.search_result.SearchResultOutputData; public class SearchResultPresenter implements SearchResultOutputBoundary { diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultState.java b/src/main/java/interface_adapter/search_result/SearchResultState.java similarity index 94% rename from src/main/java/interface_adapter/SearchResult/SearchResultState.java rename to src/main/java/interface_adapter/search_result/SearchResultState.java index 3e5a6c04c..dda0963c8 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultState.java +++ b/src/main/java/interface_adapter/search_result/SearchResultState.java @@ -1,4 +1,4 @@ -package interface_adapter.SearchResult; +package interface_adapter.search_result; import entity.Weather; diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java b/src/main/java/interface_adapter/search_result/SearchResultViewModel.java similarity index 84% rename from src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java rename to src/main/java/interface_adapter/search_result/SearchResultViewModel.java index 5c3b5886f..2f8f034d7 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java +++ b/src/main/java/interface_adapter/search_result/SearchResultViewModel.java @@ -1,4 +1,4 @@ -package interface_adapter.SearchResult; +package interface_adapter.search_result; import interface_adapter.ViewModel; diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 526c4e607..4012bc1ca 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -1,7 +1,7 @@ package interface_adapter.weather; -import use_case.note.search_return.SearchReturnInputBoundary; -import use_case.note.search_return.SearchReturnInputData; +import use_case.search_return.SearchReturnInputBoundary; +import use_case.search_return.SearchReturnInputData; /** * Controller for our weather related Use Cases. diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 523bd3e9c..72f4f6dfa 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,7 +1,7 @@ package interface_adapter.weather; -import use_case.note.search_return.SearchReturnOutputBoundary; -import use_case.note.search_return.SearchReturnOutputData; +import use_case.search_return.SearchReturnOutputBoundary; +import use_case.search_return.SearchReturnOutputData; /** * The presenter for the diff --git a/src/main/java/use_case/note/DataAccessException.java b/src/main/java/use_case/DataAccessException.java similarity index 89% rename from src/main/java/use_case/note/DataAccessException.java rename to src/main/java/use_case/DataAccessException.java index b8c17920d..59cf779b3 100644 --- a/src/main/java/use_case/note/DataAccessException.java +++ b/src/main/java/use_case/DataAccessException.java @@ -1,4 +1,4 @@ -package use_case.note; +package use_case; /** * Exception thrown when there is an error with accessing data. diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/HistoricalWeatherDataAccessInterface.java similarity index 97% rename from src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java rename to src/main/java/use_case/HistoricalWeatherDataAccessInterface.java index 904670ccf..d945ab8b2 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/HistoricalWeatherDataAccessInterface.java @@ -1,4 +1,4 @@ -package use_case.note; +package use_case; import java.io.IOException; diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/WeatherDataAccessInterface.java similarity index 95% rename from src/main/java/use_case/note/WeatherDataAccessInterface.java rename to src/main/java/use_case/WeatherDataAccessInterface.java index 163d40981..2238d0d65 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/WeatherDataAccessInterface.java @@ -1,4 +1,4 @@ -package use_case.note; +package use_case; import entity.Weather; import java.io.IOException; diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java b/src/main/java/use_case/alert_pop/AlertPopInputBoundary.java similarity index 81% rename from src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java rename to src/main/java/use_case/alert_pop/AlertPopInputBoundary.java index 7d635bfb0..f48f97a87 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java +++ b/src/main/java/use_case/alert_pop/AlertPopInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.alert_pop; +package use_case.alert_pop; // No input because alertpop is automatic. public interface AlertPopInputBoundary { diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputData.java b/src/main/java/use_case/alert_pop/AlertPopInputData.java similarity index 89% rename from src/main/java/use_case/note/alert_pop/AlertPopInputData.java rename to src/main/java/use_case/alert_pop/AlertPopInputData.java index 2bb4bb6e1..82b4161a6 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInputData.java +++ b/src/main/java/use_case/alert_pop/AlertPopInputData.java @@ -1,4 +1,4 @@ -package use_case.note.alert_pop; +package use_case.alert_pop; // No input because alertpop is automatic. public class AlertPopInputData { diff --git a/src/main/java/use_case/note/AlertPopInteractor.java b/src/main/java/use_case/alert_pop/AlertPopInteractor.java similarity index 93% rename from src/main/java/use_case/note/AlertPopInteractor.java rename to src/main/java/use_case/alert_pop/AlertPopInteractor.java index cf8758a8c..8dcc493f4 100644 --- a/src/main/java/use_case/note/AlertPopInteractor.java +++ b/src/main/java/use_case/alert_pop/AlertPopInteractor.java @@ -1,6 +1,6 @@ -package use_case.note.alert_pop; +package use_case.alert_pop; -import use_case.note.WeatherDataAccessInterface; +import use_case.WeatherDataAccessInterface; import entity.Weather; public class AlertPopInteractor implements AlertPopInputBoundary { diff --git a/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java b/src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java similarity index 83% rename from src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java rename to src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java index 4e431ba03..be39182e0 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java +++ b/src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.alert_pop; +package use_case.alert_pop; public interface AlertPopOutputBoundary { diff --git a/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java b/src/main/java/use_case/alert_pop/AlertPopOutputData.java similarity index 92% rename from src/main/java/use_case/note/alert_pop/AlertPopOutputData.java rename to src/main/java/use_case/alert_pop/AlertPopOutputData.java index 50f45b31e..75acbbbd6 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java +++ b/src/main/java/use_case/alert_pop/AlertPopOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.alert_pop; +package use_case.alert_pop; public class AlertPopOutputData { diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java b/src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java similarity index 80% rename from src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java rename to src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java index 4b46cafdd..f54a5f73b 100644 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java +++ b/src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.bookmark_return; +package use_case.bookmark_return; // The input is one click on "return". public interface BookmarkReturnInputBoundary { diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java b/src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java similarity index 67% rename from src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java rename to src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java index e53789e11..11e36d6ae 100644 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java +++ b/src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java @@ -1,4 +1,4 @@ -package use_case.note.bookmark_return; +package use_case.bookmark_return; // The input is one click on "return". public class BookmarkReturnInputData { diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java b/src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java rename to src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java index ce8bdd68d..bd108bc40 100644 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java +++ b/src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.bookmark_return; +package use_case.bookmark_return; public interface BookmarkReturnOutputBoundary { diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java b/src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java similarity index 87% rename from src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java rename to src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java index 688222b79..f0bd0977f 100644 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java +++ b/src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.bookmark_return; +package use_case.bookmark_return; public class BookmarkReturnOutputData { diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java b/src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java similarity index 86% rename from src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java rename to src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java index b8cfda36e..326bdd240 100644 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java +++ b/src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.city_bookmark; +package use_case.city_bookmark; // The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the // InputData. diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java b/src/main/java/use_case/city_bookmark/CityBookmarkInputData.java similarity index 81% rename from src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java rename to src/main/java/use_case/city_bookmark/CityBookmarkInputData.java index 47d6cb8a1..5a45ef969 100644 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java +++ b/src/main/java/use_case/city_bookmark/CityBookmarkInputData.java @@ -1,4 +1,4 @@ -package use_case.note.city_bookmark; +package use_case.city_bookmark; // The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the // InputData. diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java b/src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java rename to src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java index 02f755b2e..900beb5ff 100644 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java +++ b/src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.city_bookmark; +package use_case.city_bookmark; public interface CityBookmarkOutputBoundary { diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java b/src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java similarity index 92% rename from src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java rename to src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java index 55b08fce3..fb1d23e84 100644 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java +++ b/src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.city_bookmark; +package use_case.city_bookmark; import java.util.ArrayList; diff --git a/src/main/java/use_case/note/close_list/CloseListInputBoundary.java b/src/main/java/use_case/close_list/CloseListInputBoundary.java similarity index 81% rename from src/main/java/use_case/note/close_list/CloseListInputBoundary.java rename to src/main/java/use_case/close_list/CloseListInputBoundary.java index be422c7e9..8322e61e4 100644 --- a/src/main/java/use_case/note/close_list/CloseListInputBoundary.java +++ b/src/main/java/use_case/close_list/CloseListInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_list; +package use_case.close_list; // Input is one click on "close". public interface CloseListInputBoundary { diff --git a/src/main/java/use_case/note/close_list/CloseListInputData.java b/src/main/java/use_case/close_list/CloseListInputData.java similarity index 67% rename from src/main/java/use_case/note/close_list/CloseListInputData.java rename to src/main/java/use_case/close_list/CloseListInputData.java index caba5f836..4c47c653e 100644 --- a/src/main/java/use_case/note/close_list/CloseListInputData.java +++ b/src/main/java/use_case/close_list/CloseListInputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_list; +package use_case.close_list; // Input is one click on "close". public class CloseListInputData { diff --git a/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java b/src/main/java/use_case/close_list/CloseListOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/close_list/CloseListOutputBoundary.java rename to src/main/java/use_case/close_list/CloseListOutputBoundary.java index fe3d9a723..92c806a03 100644 --- a/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java +++ b/src/main/java/use_case/close_list/CloseListOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_list; +package use_case.close_list; public interface CloseListOutputBoundary { diff --git a/src/main/java/use_case/note/close_list/CloseListOutputData.java b/src/main/java/use_case/close_list/CloseListOutputData.java similarity index 88% rename from src/main/java/use_case/note/close_list/CloseListOutputData.java rename to src/main/java/use_case/close_list/CloseListOutputData.java index e4a99360d..ec3d8d94d 100644 --- a/src/main/java/use_case/note/close_list/CloseListOutputData.java +++ b/src/main/java/use_case/close_list/CloseListOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_list; +package use_case.close_list; public class CloseListOutputData { diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java b/src/main/java/use_case/close_pin/ClosePinInputBoundary.java similarity index 81% rename from src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java rename to src/main/java/use_case/close_pin/ClosePinInputBoundary.java index 1c679ef8c..5c32427d3 100644 --- a/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java +++ b/src/main/java/use_case/close_pin/ClosePinInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_pin; +package use_case.close_pin; // Input is a click on the "close" button. public interface ClosePinInputBoundary { diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputData.java b/src/main/java/use_case/close_pin/ClosePinInputData.java similarity index 70% rename from src/main/java/use_case/note/close_pin/ClosePinInputData.java rename to src/main/java/use_case/close_pin/ClosePinInputData.java index ba3f16d7c..7ede61f1f 100644 --- a/src/main/java/use_case/note/close_pin/ClosePinInputData.java +++ b/src/main/java/use_case/close_pin/ClosePinInputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_pin; +package use_case.close_pin; // Input is a click on the "close" button. public class ClosePinInputData { diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java b/src/main/java/use_case/close_pin/ClosePinOutputBoundary.java similarity index 83% rename from src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java rename to src/main/java/use_case/close_pin/ClosePinOutputBoundary.java index da4e3b1bc..aad5eb740 100644 --- a/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java +++ b/src/main/java/use_case/close_pin/ClosePinOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_pin; +package use_case.close_pin; public interface ClosePinOutputBoundary { diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputData.java b/src/main/java/use_case/close_pin/ClosePinOutputData.java similarity index 88% rename from src/main/java/use_case/note/close_pin/ClosePinOutputData.java rename to src/main/java/use_case/close_pin/ClosePinOutputData.java index eab6e91f4..38bd3fecd 100644 --- a/src/main/java/use_case/note/close_pin/ClosePinOutputData.java +++ b/src/main/java/use_case/close_pin/ClosePinOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_pin; +package use_case.close_pin; public class ClosePinOutputData { diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java b/src/main/java/use_case/close_pop/ClosePopInputBoundary.java similarity index 80% rename from src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java rename to src/main/java/use_case/close_pop/ClosePopInputBoundary.java index 06cd776d8..fd904a694 100644 --- a/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java +++ b/src/main/java/use_case/close_pop/ClosePopInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_pop; +package use_case.close_pop; // Input is a click on "close". public interface ClosePopInputBoundary { diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputData.java b/src/main/java/use_case/close_pop/ClosePopInputData.java similarity index 67% rename from src/main/java/use_case/note/close_pop/ClosePopInputData.java rename to src/main/java/use_case/close_pop/ClosePopInputData.java index dfeeafa7b..8e8b312db 100644 --- a/src/main/java/use_case/note/close_pop/ClosePopInputData.java +++ b/src/main/java/use_case/close_pop/ClosePopInputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_pop; +package use_case.close_pop; // Input is a click on "close". public class ClosePopInputData { diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java b/src/main/java/use_case/close_pop/ClosePopOutputBoundary.java similarity index 83% rename from src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java rename to src/main/java/use_case/close_pop/ClosePopOutputBoundary.java index 4d881e40f..d5466d25a 100644 --- a/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java +++ b/src/main/java/use_case/close_pop/ClosePopOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.close_pop; +package use_case.close_pop; public interface ClosePopOutputBoundary { diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputData.java b/src/main/java/use_case/close_pop/ClosePopOutputData.java similarity index 88% rename from src/main/java/use_case/note/close_pop/ClosePopOutputData.java rename to src/main/java/use_case/close_pop/ClosePopOutputData.java index 03ffe9913..c772aa6b9 100644 --- a/src/main/java/use_case/note/close_pop/ClosePopOutputData.java +++ b/src/main/java/use_case/close_pop/ClosePopOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.close_pop; +package use_case.close_pop; public class ClosePopOutputData { diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java b/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java similarity index 83% rename from src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java rename to src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java index 8de3c12a4..83121223e 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java +++ b/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.convert_farenheit; +package use_case.convert_farenheit; public interface ConvertFarenheitInputBoundary { void executeConvert(ConvertFarenheitInputData convertFarenheitInputData); diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java b/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java similarity index 82% rename from src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java rename to src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java index 3b463e735..b64a798f7 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java +++ b/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java @@ -1,4 +1,4 @@ -package use_case.note.convert_farenheit; +package use_case.convert_farenheit; import entity.Weather; diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java b/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java similarity index 80% rename from src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java rename to src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java index a2c9f7018..a7598d88e 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java +++ b/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.convert_farenheit; +package use_case.convert_farenheit; public interface ConvertFarenheitOutputBoundary { void prepareFailView(String errorMessage); diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java b/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java similarity index 91% rename from src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java rename to src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java index 0f1c7f201..4d61ede11 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java +++ b/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.convert_farenheit; +package use_case.convert_farenheit; import entity.Weather; diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/convert_farenheit/ConvertInteractor.java similarity index 97% rename from src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java rename to src/main/java/use_case/convert_farenheit/ConvertInteractor.java index 0d1891ec9..116db6ac9 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/convert_farenheit/ConvertInteractor.java @@ -1,4 +1,4 @@ -package use_case.note.convert_farenheit; +package use_case.convert_farenheit; public class ConvertInteractor implements ConvertFarenheitInputBoundary { public static final double KILOMETERS_MILE = 0.62; diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java b/src/main/java/use_case/nearby_list/NearbyListInputBoundary.java similarity index 86% rename from src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java rename to src/main/java/use_case/nearby_list/NearbyListInputBoundary.java index 22407c6b4..cead1cbdb 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java +++ b/src/main/java/use_case/nearby_list/NearbyListInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.nearby_list; +package use_case.nearby_list; // This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. public interface NearbyListInputBoundary { diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java b/src/main/java/use_case/nearby_list/NearbyListInputData.java similarity index 81% rename from src/main/java/use_case/note/nearby_list/NearbyListInputData.java rename to src/main/java/use_case/nearby_list/NearbyListInputData.java index 5e6e7aa29..8a3e3532e 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java +++ b/src/main/java/use_case/nearby_list/NearbyListInputData.java @@ -1,4 +1,4 @@ -package use_case.note.nearby_list; +package use_case.nearby_list; // This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. public class NearbyListInputData { diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java b/src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java rename to src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java index 4ac7b4bd4..50a1fba3c 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java +++ b/src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.nearby_list; +package use_case.nearby_list; public interface NearbyListOutputBoundary { diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java b/src/main/java/use_case/nearby_list/NearbyListOutputData.java similarity index 90% rename from src/main/java/use_case/note/nearby_list/NearbyListOutputData.java rename to src/main/java/use_case/nearby_list/NearbyListOutputData.java index e6256e43f..d71c9528b 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java +++ b/src/main/java/use_case/nearby_list/NearbyListOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.nearby_list; +package use_case.nearby_list; public class NearbyListOutputData { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java similarity index 79% rename from src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java rename to src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java index 2e267e172..7b1f9360a 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ b/src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.pin_weather; +package use_case.pin_weather; // Input is a click on "pin." public interface PinWeatherInputBoundary { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java b/src/main/java/use_case/pin_weather/PinWeatherInputData.java similarity index 66% rename from src/main/java/use_case/note/pin_weather/PinWeatherInputData.java rename to src/main/java/use_case/pin_weather/PinWeatherInputData.java index 623290d9f..dc35d03f5 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java +++ b/src/main/java/use_case/pin_weather/PinWeatherInputData.java @@ -1,4 +1,4 @@ -package use_case.note.pin_weather; +package use_case.pin_weather; // Input is a click on "pin." public class PinWeatherInputData { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java b/src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java rename to src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java index 6eac48913..6f4751ad5 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java +++ b/src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.pin_weather; +package use_case.pin_weather; public interface PinWeatherOutputBoundary { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java b/src/main/java/use_case/pin_weather/PinWeatherOutputData.java similarity index 92% rename from src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java rename to src/main/java/use_case/pin_weather/PinWeatherOutputData.java index cc0446619..5050e5c50 100644 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java +++ b/src/main/java/use_case/pin_weather/PinWeatherOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.pin_weather; +package use_case.pin_weather; public class PinWeatherOutputData { diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java b/src/main/java/use_case/return_home/ReturnHomeInputBoundary.java similarity index 80% rename from src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java rename to src/main/java/use_case/return_home/ReturnHomeInputBoundary.java index 93b43e15b..b62d0c326 100644 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java +++ b/src/main/java/use_case/return_home/ReturnHomeInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.return_home; +package use_case.return_home; // Input is a click on the home button. public interface ReturnHomeInputBoundary { diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java b/src/main/java/use_case/return_home/ReturnHomeInputData.java similarity index 69% rename from src/main/java/use_case/note/return_home/ReturnHomeInputData.java rename to src/main/java/use_case/return_home/ReturnHomeInputData.java index 27162a91e..04aff31e9 100644 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java +++ b/src/main/java/use_case/return_home/ReturnHomeInputData.java @@ -1,4 +1,4 @@ -package use_case.note.return_home; +package use_case.return_home; // Input is a click on the home button. public class ReturnHomeInputData { diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java b/src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java rename to src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java index 258573eb3..63db3b752 100644 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java +++ b/src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.return_home; +package use_case.return_home; public interface ReturnHomeOutputBoundary { diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java b/src/main/java/use_case/return_home/ReturnHomeOutputData.java similarity index 88% rename from src/main/java/use_case/note/return_home/ReturnHomeOutputData.java rename to src/main/java/use_case/return_home/ReturnHomeOutputData.java index 49f1ba0c4..774760fa4 100644 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java +++ b/src/main/java/use_case/return_home/ReturnHomeOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.return_home; +package use_case.return_home; public class ReturnHomeOutputData { diff --git a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java b/src/main/java/use_case/search_result/SearchResultInputBoundary.java similarity index 86% rename from src/main/java/use_case/note/search_result/SearchResultInputBoundary.java rename to src/main/java/use_case/search_result/SearchResultInputBoundary.java index 99054de87..307ffa93f 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java +++ b/src/main/java/use_case/search_result/SearchResultInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.search_result; +package use_case.search_result; // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/search_result/SearchResultInputData.java similarity index 92% rename from src/main/java/use_case/note/search_result/SearchResultInputData.java rename to src/main/java/use_case/search_result/SearchResultInputData.java index f15ab28b1..228d37b69 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/search_result/SearchResultInputData.java @@ -1,4 +1,4 @@ -package use_case.note.search_result; +package use_case.search_result; // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/search_result/SearchResultInteractor.java similarity index 89% rename from src/main/java/use_case/note/SearchResultInteractor.java rename to src/main/java/use_case/search_result/SearchResultInteractor.java index 3ed852d83..0d85f7421 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/search_result/SearchResultInteractor.java @@ -1,4 +1,4 @@ -package use_case.note; +package use_case.search_result; import java.io.IOException; import java.time.Instant; @@ -8,10 +8,8 @@ import java.util.Map; import entity.Weather; -import use_case.note.search_result.SearchResultInputBoundary; -import use_case.note.search_result.SearchResultInputData; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; +import use_case.HistoricalWeatherDataAccessInterface; +import use_case.WeatherDataAccessInterface; /** * The interactor for the search result use case.. diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java b/src/main/java/use_case/search_result/SearchResultOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java rename to src/main/java/use_case/search_result/SearchResultOutputBoundary.java index cee8789c9..e0081252c 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java +++ b/src/main/java/use_case/search_result/SearchResultOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.search_result; +package use_case.search_result; public interface SearchResultOutputBoundary { diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/search_result/SearchResultOutputData.java similarity index 94% rename from src/main/java/use_case/note/search_result/SearchResultOutputData.java rename to src/main/java/use_case/search_result/SearchResultOutputData.java index 5c8b0fcb7..ac1fb94ee 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/search_result/SearchResultOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.search_result; +package use_case.search_result; import entity.Weather; diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java b/src/main/java/use_case/search_return/SearchReturnInputBoundary.java similarity index 89% rename from src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java rename to src/main/java/use_case/search_return/SearchReturnInputBoundary.java index ac47665d0..58e18a2fe 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java +++ b/src/main/java/use_case/search_return/SearchReturnInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.search_return; +package use_case.search_return; /** * The input boundary for the search return use case. diff --git a/src/main/java/use_case/note/search_return/SearchReturnInputData.java b/src/main/java/use_case/search_return/SearchReturnInputData.java similarity index 87% rename from src/main/java/use_case/note/search_return/SearchReturnInputData.java rename to src/main/java/use_case/search_return/SearchReturnInputData.java index 4c892875c..919005971 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInputData.java +++ b/src/main/java/use_case/search_return/SearchReturnInputData.java @@ -1,4 +1,4 @@ -package use_case.note.search_return; +package use_case.search_return; /** * // Input is one click on "return." diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/search_return/SearchReturnInteractor.java similarity index 58% rename from src/main/java/use_case/note/SearchReturnInteractor.java rename to src/main/java/use_case/search_return/SearchReturnInteractor.java index bb67cc4c2..a95698d39 100644 --- a/src/main/java/use_case/note/SearchReturnInteractor.java +++ b/src/main/java/use_case/search_return/SearchReturnInteractor.java @@ -1,17 +1,11 @@ +package use_case.search_return; + import entity.Weather; -import use_case.note.WeatherDataAccessInterface; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_return.SearchReturnInputBoundary; -import use_case.note.search_return.SearchReturnInputData; -import use_case.note.search_return.SearchReturnOutputBoundary; -import use_case.note.search_return.SearchReturnOutputData; +import use_case.WeatherDataAccessInterface; +import use_case.search_result.SearchResultOutputBoundary; -import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; public class SearchReturnInteractor implements SearchReturnInputBoundary { private final SearchResultOutputBoundary outputBoundary; diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java b/src/main/java/use_case/search_return/SearchReturnOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java rename to src/main/java/use_case/search_return/SearchReturnOutputBoundary.java index 90e7ca950..516e7f5f4 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java +++ b/src/main/java/use_case/search_return/SearchReturnOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.search_return; +package use_case.search_return; public interface SearchReturnOutputBoundary { diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/search_return/SearchReturnOutputData.java similarity index 94% rename from src/main/java/use_case/note/search_return/SearchReturnOutputData.java rename to src/main/java/use_case/search_return/SearchReturnOutputData.java index f48d43f72..237664c43 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/search_return/SearchReturnOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.search_return; +package use_case.search_return; import entity.Weather; diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java b/src/main/java/use_case/select_region/SelectRegionInputBoundary.java similarity index 79% rename from src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java rename to src/main/java/use_case/select_region/SelectRegionInputBoundary.java index 17c3d0394..24349e8b9 100644 --- a/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java +++ b/src/main/java/use_case/select_region/SelectRegionInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.select_region; +package use_case.select_region; // Input is a click on the region. public interface SelectRegionInputBoundary { diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputData.java b/src/main/java/use_case/select_region/SelectRegionInputData.java similarity index 66% rename from src/main/java/use_case/note/select_region/SelectRegionInputData.java rename to src/main/java/use_case/select_region/SelectRegionInputData.java index 9d72aadd3..94c16b33e 100644 --- a/src/main/java/use_case/note/select_region/SelectRegionInputData.java +++ b/src/main/java/use_case/select_region/SelectRegionInputData.java @@ -1,4 +1,4 @@ -package use_case.note.select_region; +package use_case.select_region; // Input is a click on the region. public class SelectRegionInputData { diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java b/src/main/java/use_case/select_region/SelectRegionOutputBoundary.java similarity index 82% rename from src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java rename to src/main/java/use_case/select_region/SelectRegionOutputBoundary.java index eca8cecf5..ee462c67b 100644 --- a/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java +++ b/src/main/java/use_case/select_region/SelectRegionOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.note.select_region; +package use_case.select_region; public interface SelectRegionOutputBoundary { diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputData.java b/src/main/java/use_case/select_region/SelectRegionOutputData.java similarity index 93% rename from src/main/java/use_case/note/select_region/SelectRegionOutputData.java rename to src/main/java/use_case/select_region/SelectRegionOutputData.java index a8fe7a631..e9ef88712 100644 --- a/src/main/java/use_case/note/select_region/SelectRegionOutputData.java +++ b/src/main/java/use_case/select_region/SelectRegionOutputData.java @@ -1,4 +1,4 @@ -package use_case.note.select_region; +package use_case.select_region; public class SelectRegionOutputData { private final String location; diff --git a/src/main/java/view/SearchResultPanelView.java b/src/main/java/view/SearchResultPanelView.java index 34003a34e..380255252 100644 --- a/src/main/java/view/SearchResultPanelView.java +++ b/src/main/java/view/SearchResultPanelView.java @@ -13,9 +13,9 @@ import javax.swing.JPanel; import javax.swing.JTextArea; -import interface_adapter.SearchResult.SearchResultController; -import interface_adapter.SearchResult.SearchResultState; -import interface_adapter.SearchResult.SearchResultViewModel; +import interface_adapter.search_result.SearchResultController; +import interface_adapter.search_result.SearchResultState; +import interface_adapter.search_result.SearchResultViewModel; /** * The View for when the user is viewing a note in the program. diff --git a/src/test/java/use_case/note/NoteInteractorTest.java b/src/test/java/use_case/NoteInteractorTest.java similarity index 97% rename from src/test/java/use_case/note/NoteInteractorTest.java rename to src/test/java/use_case/NoteInteractorTest.java index a3ed466b6..4b3933e4c 100644 --- a/src/test/java/use_case/note/NoteInteractorTest.java +++ b/src/test/java/use_case/NoteInteractorTest.java @@ -1,4 +1,4 @@ -package use_case.note; +package use_case; import entity.User; import org.junit.Test; From 5abf8dda9c5fc5ddef09bd7e6d67a88b3375735c Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 18 Nov 2024 10:45:49 -0500 Subject: [PATCH 108/267] bug fixed --- .../java/data_access/HistoricalWeatherDataAccessObject.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 0bc5c6e33..c6bead637 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -67,9 +67,9 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Getting the city from the JSONObject final String cityNameCall = weatherObject.getString("city"); // Getting the timestamp from the JSONObject - final String timeStamp = weatherObject.getString("timeStamp"); + final String timeStamp1 = weatherObject.getString("timeStamp"); // Checking if the city and timestamp match the input - if (cityNameCall.equals(cityNameCall) && timeStamp.equals(timestamp)) { + if (cityNameCall.equals(city) && timeStamp1.equals(timestamp)) { // Create weather object final Weather weather = new Weather( cityNameCall, From 3b7e60fa7eef78b112fae9706f2875963e604de1 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 10:46:31 -0500 Subject: [PATCH 109/267] Revert "renamed a lotta stuff" This reverts commit 4bc61c4d75ae17a56201da45599723c703acbed9. --- src/main/java/app/MainNoteApplication.java | 2 +- src/main/java/app/NoteAppBuilder.java | 3 ++- .../HistoricalWeatherDataAccessObject.java | 2 +- .../java/data_access/WeatherDataAccessObject.java | 2 +- .../SearchResultController.java | 6 +++--- .../SearchResultPresenter.java | 6 +++--- .../SearchResultState.java | 2 +- .../SearchResultViewModel.java | 2 +- .../converter/ConverterController.java | 4 ++-- .../converter/ConverterPresenter.java | 4 ++-- .../major_cities/MajorCitiesController.java | 4 ---- .../major_cities/MajorCitiesPresenter.java | 4 ---- .../major_cities/MajorCitiesState.java | 4 ---- .../major_cities/MajorCitiesViewModel.java | 4 ---- .../weather/WeatherController.java | 4 ++-- .../weather/WeatherPresenter.java | 4 ++-- .../{alert_pop => note}/AlertPopInteractor.java | 4 ++-- .../use_case/{ => note}/DataAccessException.java | 2 +- .../HistoricalWeatherDataAccessInterface.java | 2 +- .../SearchResultInteractor.java | 8 +++++--- .../SearchReturnInteractor.java | 14 ++++++++++---- .../{ => note}/WeatherDataAccessInterface.java | 2 +- .../alert_pop/AlertPopInputBoundary.java | 2 +- .../{ => note}/alert_pop/AlertPopInputData.java | 2 +- .../alert_pop/AlertPopOutputBoundary.java | 2 +- .../{ => note}/alert_pop/AlertPopOutputData.java | 2 +- .../BookmarkReturnInputBoundary.java | 2 +- .../bookmark_return/BookmarkReturnInputData.java | 2 +- .../BookmarkReturnOutputBoundary.java | 2 +- .../bookmark_return/BookmarkReturnOutputData.java | 2 +- .../city_bookmark/CityBookmarkInputBoundary.java | 2 +- .../city_bookmark/CityBookmarkInputData.java | 2 +- .../city_bookmark/CityBookmarkOutputBoundary.java | 2 +- .../city_bookmark/CityBookmarkOutputData.java | 2 +- .../close_list/CloseListInputBoundary.java | 2 +- .../{ => note}/close_list/CloseListInputData.java | 2 +- .../close_list/CloseListOutputBoundary.java | 2 +- .../{ => note}/close_list/CloseListOutputData.java | 2 +- .../close_pin/ClosePinInputBoundary.java | 2 +- .../{ => note}/close_pin/ClosePinInputData.java | 2 +- .../close_pin/ClosePinOutputBoundary.java | 2 +- .../{ => note}/close_pin/ClosePinOutputData.java | 2 +- .../close_pop/ClosePopInputBoundary.java | 2 +- .../{ => note}/close_pop/ClosePopInputData.java | 2 +- .../close_pop/ClosePopOutputBoundary.java | 2 +- .../{ => note}/close_pop/ClosePopOutputData.java | 2 +- .../ConvertFarenheitInputBoundary.java | 2 +- .../ConvertFarenheitInputData.java | 2 +- .../ConvertFarenheitOutputBoundary.java | 2 +- .../ConvertFarenheitOutputData.java | 2 +- .../convert_farenheit/ConvertInteractor.java | 2 +- .../nearby_list/NearbyListInputBoundary.java | 2 +- .../nearby_list/NearbyListInputData.java | 2 +- .../nearby_list/NearbyListOutputBoundary.java | 2 +- .../nearby_list/NearbyListOutputData.java | 2 +- .../pin_weather/PinWeatherInputBoundary.java | 2 +- .../pin_weather/PinWeatherInputData.java | 2 +- .../pin_weather/PinWeatherOutputBoundary.java | 2 +- .../pin_weather/PinWeatherOutputData.java | 2 +- .../return_home/ReturnHomeInputBoundary.java | 2 +- .../return_home/ReturnHomeInputData.java | 2 +- .../return_home/ReturnHomeOutputBoundary.java | 2 +- .../return_home/ReturnHomeOutputData.java | 2 +- .../search_result/SearchResultInputBoundary.java | 2 +- .../search_result/SearchResultInputData.java | 2 +- .../search_result/SearchResultOutputBoundary.java | 2 +- .../search_result/SearchResultOutputData.java | 2 +- .../search_return/SearchReturnInputBoundary.java | 2 +- .../search_return/SearchReturnInputData.java | 2 +- .../search_return/SearchReturnOutputBoundary.java | 2 +- .../search_return/SearchReturnOutputData.java | 2 +- .../select_region/SelectRegionInputBoundary.java | 2 +- .../select_region/SelectRegionInputData.java | 2 +- .../select_region/SelectRegionOutputBoundary.java | 2 +- .../select_region/SelectRegionOutputData.java | 2 +- src/main/java/view/SearchResultPanelView.java | 6 +++--- .../use_case/{ => note}/NoteInteractorTest.java | 2 +- 77 files changed, 98 insertions(+), 105 deletions(-) rename src/main/java/interface_adapter/{search_result => SearchResult}/SearchResultController.java (86%) rename src/main/java/interface_adapter/{search_result => SearchResult}/SearchResultPresenter.java (78%) rename src/main/java/interface_adapter/{search_result => SearchResult}/SearchResultState.java (94%) rename src/main/java/interface_adapter/{search_result => SearchResult}/SearchResultViewModel.java (84%) delete mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesController.java delete mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java delete mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesState.java delete mode 100644 src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java rename src/main/java/use_case/{alert_pop => note}/AlertPopInteractor.java (93%) rename src/main/java/use_case/{ => note}/DataAccessException.java (89%) rename src/main/java/use_case/{ => note}/HistoricalWeatherDataAccessInterface.java (97%) rename src/main/java/use_case/{search_result => note}/SearchResultInteractor.java (89%) rename src/main/java/use_case/{search_return => note}/SearchReturnInteractor.java (58%) rename src/main/java/use_case/{ => note}/WeatherDataAccessInterface.java (95%) rename src/main/java/use_case/{ => note}/alert_pop/AlertPopInputBoundary.java (81%) rename src/main/java/use_case/{ => note}/alert_pop/AlertPopInputData.java (89%) rename src/main/java/use_case/{ => note}/alert_pop/AlertPopOutputBoundary.java (83%) rename src/main/java/use_case/{ => note}/alert_pop/AlertPopOutputData.java (92%) rename src/main/java/use_case/{ => note}/bookmark_return/BookmarkReturnInputBoundary.java (80%) rename src/main/java/use_case/{ => note}/bookmark_return/BookmarkReturnInputData.java (67%) rename src/main/java/use_case/{ => note}/bookmark_return/BookmarkReturnOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/bookmark_return/BookmarkReturnOutputData.java (87%) rename src/main/java/use_case/{ => note}/city_bookmark/CityBookmarkInputBoundary.java (86%) rename src/main/java/use_case/{ => note}/city_bookmark/CityBookmarkInputData.java (81%) rename src/main/java/use_case/{ => note}/city_bookmark/CityBookmarkOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/city_bookmark/CityBookmarkOutputData.java (92%) rename src/main/java/use_case/{ => note}/close_list/CloseListInputBoundary.java (81%) rename src/main/java/use_case/{ => note}/close_list/CloseListInputData.java (67%) rename src/main/java/use_case/{ => note}/close_list/CloseListOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/close_list/CloseListOutputData.java (88%) rename src/main/java/use_case/{ => note}/close_pin/ClosePinInputBoundary.java (81%) rename src/main/java/use_case/{ => note}/close_pin/ClosePinInputData.java (70%) rename src/main/java/use_case/{ => note}/close_pin/ClosePinOutputBoundary.java (83%) rename src/main/java/use_case/{ => note}/close_pin/ClosePinOutputData.java (88%) rename src/main/java/use_case/{ => note}/close_pop/ClosePopInputBoundary.java (80%) rename src/main/java/use_case/{ => note}/close_pop/ClosePopInputData.java (67%) rename src/main/java/use_case/{ => note}/close_pop/ClosePopOutputBoundary.java (83%) rename src/main/java/use_case/{ => note}/close_pop/ClosePopOutputData.java (88%) rename src/main/java/use_case/{ => note}/convert_farenheit/ConvertFarenheitInputBoundary.java (83%) rename src/main/java/use_case/{ => note}/convert_farenheit/ConvertFarenheitInputData.java (82%) rename src/main/java/use_case/{ => note}/convert_farenheit/ConvertFarenheitOutputBoundary.java (80%) rename src/main/java/use_case/{ => note}/convert_farenheit/ConvertFarenheitOutputData.java (91%) rename src/main/java/use_case/{ => note}/convert_farenheit/ConvertInteractor.java (97%) rename src/main/java/use_case/{ => note}/nearby_list/NearbyListInputBoundary.java (86%) rename src/main/java/use_case/{ => note}/nearby_list/NearbyListInputData.java (81%) rename src/main/java/use_case/{ => note}/nearby_list/NearbyListOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/nearby_list/NearbyListOutputData.java (90%) rename src/main/java/use_case/{ => note}/pin_weather/PinWeatherInputBoundary.java (79%) rename src/main/java/use_case/{ => note}/pin_weather/PinWeatherInputData.java (66%) rename src/main/java/use_case/{ => note}/pin_weather/PinWeatherOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/pin_weather/PinWeatherOutputData.java (92%) rename src/main/java/use_case/{ => note}/return_home/ReturnHomeInputBoundary.java (80%) rename src/main/java/use_case/{ => note}/return_home/ReturnHomeInputData.java (69%) rename src/main/java/use_case/{ => note}/return_home/ReturnHomeOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/return_home/ReturnHomeOutputData.java (88%) rename src/main/java/use_case/{ => note}/search_result/SearchResultInputBoundary.java (86%) rename src/main/java/use_case/{ => note}/search_result/SearchResultInputData.java (92%) rename src/main/java/use_case/{ => note}/search_result/SearchResultOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/search_result/SearchResultOutputData.java (94%) rename src/main/java/use_case/{ => note}/search_return/SearchReturnInputBoundary.java (89%) rename src/main/java/use_case/{ => note}/search_return/SearchReturnInputData.java (87%) rename src/main/java/use_case/{ => note}/search_return/SearchReturnOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/search_return/SearchReturnOutputData.java (94%) rename src/main/java/use_case/{ => note}/select_region/SelectRegionInputBoundary.java (79%) rename src/main/java/use_case/{ => note}/select_region/SelectRegionInputData.java (66%) rename src/main/java/use_case/{ => note}/select_region/SelectRegionOutputBoundary.java (82%) rename src/main/java/use_case/{ => note}/select_region/SelectRegionOutputData.java (93%) rename src/test/java/use_case/{ => note}/NoteInteractorTest.java (97%) diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index 695ed2380..9ef9b0693 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -1,7 +1,7 @@ package app; import data_access.WeatherDataAccessObject; -import use_case.WeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; /** * An application where we can view and add to a note stored by a user. diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java index 53a9773d8..ea2a3a58a 100644 --- a/src/main/java/app/NoteAppBuilder.java +++ b/src/main/java/app/NoteAppBuilder.java @@ -5,7 +5,8 @@ import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherPresenter; -import use_case.WeatherDataAccessInterface; +import interface_adapter.weather.WeatherViewModel; +import use_case.note.WeatherDataAccessInterface; import use_case.note.NoteInteractor; import use_case.note.NoteOutputBoundary; import view.NoteView; diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 127bea2e0..0bc5c6e33 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -11,7 +11,7 @@ import org.json.JSONObject; import entity.Weather; -import use_case.HistoricalWeatherDataAccessInterface; +import use_case.note.HistoricalWeatherDataAccessInterface; /** * This class provides the service of saving and getting historical weather data. diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index aa838f99d..2ed681744 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -7,7 +7,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONArray; -import use_case.WeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; diff --git a/src/main/java/interface_adapter/search_result/SearchResultController.java b/src/main/java/interface_adapter/SearchResult/SearchResultController.java similarity index 86% rename from src/main/java/interface_adapter/search_result/SearchResultController.java rename to src/main/java/interface_adapter/SearchResult/SearchResultController.java index c6fbcb099..9d58fd126 100644 --- a/src/main/java/interface_adapter/search_result/SearchResultController.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultController.java @@ -1,7 +1,7 @@ -package interface_adapter.search_result; +package interface_adapter.SearchResult; -import use_case.search_result.SearchResultInputBoundary; -import use_case.search_result.SearchResultInputData; +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; /** * The controller for the search result view. It is responsible for executing the search result use case. diff --git a/src/main/java/interface_adapter/search_result/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java similarity index 78% rename from src/main/java/interface_adapter/search_result/SearchResultPresenter.java rename to src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index b4d6d81f8..78ab05899 100644 --- a/src/main/java/interface_adapter/search_result/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -1,8 +1,8 @@ -package interface_adapter.search_result; +package interface_adapter.SearchResult; import interface_adapter.weather.WeatherViewModel; -import use_case.search_result.SearchResultOutputBoundary; -import use_case.search_result.SearchResultOutputData; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; public class SearchResultPresenter implements SearchResultOutputBoundary { diff --git a/src/main/java/interface_adapter/search_result/SearchResultState.java b/src/main/java/interface_adapter/SearchResult/SearchResultState.java similarity index 94% rename from src/main/java/interface_adapter/search_result/SearchResultState.java rename to src/main/java/interface_adapter/SearchResult/SearchResultState.java index dda0963c8..3e5a6c04c 100644 --- a/src/main/java/interface_adapter/search_result/SearchResultState.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultState.java @@ -1,4 +1,4 @@ -package interface_adapter.search_result; +package interface_adapter.SearchResult; import entity.Weather; diff --git a/src/main/java/interface_adapter/search_result/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java similarity index 84% rename from src/main/java/interface_adapter/search_result/SearchResultViewModel.java rename to src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java index 2f8f034d7..5c3b5886f 100644 --- a/src/main/java/interface_adapter/search_result/SearchResultViewModel.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java @@ -1,4 +1,4 @@ -package interface_adapter.search_result; +package interface_adapter.SearchResult; import interface_adapter.ViewModel; diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 5f46f98f1..06cc40dff 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -1,8 +1,8 @@ package interface_adapter.converter; import entity.Weather; -import use_case.convert_farenheit.ConvertFarenheitInputBoundary; -import use_case.convert_farenheit.ConvertFarenheitInputData; +import use_case.note.convert_farenheit.ConvertFarenheitInputBoundary; +import use_case.note.convert_farenheit.ConvertFarenheitInputData; public class ConverterController { private final ConvertFarenheitInputBoundary convertInteractor; diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java index 32c8096d6..c634c2d30 100644 --- a/src/main/java/interface_adapter/converter/ConverterPresenter.java +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -1,8 +1,8 @@ package interface_adapter.converter; import interface_adapter.weather.WeatherViewModel; -import use_case.convert_farenheit.ConvertFarenheitOutputBoundary; -import use_case.convert_farenheit.ConvertFarenheitOutputData; +import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; +import use_case.note.convert_farenheit.ConvertFarenheitOutputData; public class ConverterPresenter implements ConvertFarenheitOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesController.java b/src/main/java/interface_adapter/major_cities/MajorCitiesController.java deleted file mode 100644 index 0df737800..000000000 --- a/src/main/java/interface_adapter/major_cities/MajorCitiesController.java +++ /dev/null @@ -1,4 +0,0 @@ -package interface_adapter.major_cities; - -public class MajorCitiesController { -} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java b/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java deleted file mode 100644 index b5dce39a9..000000000 --- a/src/main/java/interface_adapter/major_cities/MajorCitiesPresenter.java +++ /dev/null @@ -1,4 +0,0 @@ -package interface_adapter.major_cities; - -public class MajorCitiesPresenter { -} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesState.java b/src/main/java/interface_adapter/major_cities/MajorCitiesState.java deleted file mode 100644 index 023790561..000000000 --- a/src/main/java/interface_adapter/major_cities/MajorCitiesState.java +++ /dev/null @@ -1,4 +0,0 @@ -package interface_adapter.major_cities; - -public class MajorCitiesState { -} diff --git a/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java b/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java deleted file mode 100644 index 873de3dd6..000000000 --- a/src/main/java/interface_adapter/major_cities/MajorCitiesViewModel.java +++ /dev/null @@ -1,4 +0,0 @@ -package interface_adapter.major_cities; - -public class MajorCitiesViewModel { -} diff --git a/src/main/java/interface_adapter/weather/WeatherController.java b/src/main/java/interface_adapter/weather/WeatherController.java index 4012bc1ca..526c4e607 100644 --- a/src/main/java/interface_adapter/weather/WeatherController.java +++ b/src/main/java/interface_adapter/weather/WeatherController.java @@ -1,7 +1,7 @@ package interface_adapter.weather; -import use_case.search_return.SearchReturnInputBoundary; -import use_case.search_return.SearchReturnInputData; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; /** * Controller for our weather related Use Cases. diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 72f4f6dfa..523bd3e9c 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -1,7 +1,7 @@ package interface_adapter.weather; -import use_case.search_return.SearchReturnOutputBoundary; -import use_case.search_return.SearchReturnOutputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; /** * The presenter for the diff --git a/src/main/java/use_case/alert_pop/AlertPopInteractor.java b/src/main/java/use_case/note/AlertPopInteractor.java similarity index 93% rename from src/main/java/use_case/alert_pop/AlertPopInteractor.java rename to src/main/java/use_case/note/AlertPopInteractor.java index 8dcc493f4..cf8758a8c 100644 --- a/src/main/java/use_case/alert_pop/AlertPopInteractor.java +++ b/src/main/java/use_case/note/AlertPopInteractor.java @@ -1,6 +1,6 @@ -package use_case.alert_pop; +package use_case.note.alert_pop; -import use_case.WeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; import entity.Weather; public class AlertPopInteractor implements AlertPopInputBoundary { diff --git a/src/main/java/use_case/DataAccessException.java b/src/main/java/use_case/note/DataAccessException.java similarity index 89% rename from src/main/java/use_case/DataAccessException.java rename to src/main/java/use_case/note/DataAccessException.java index 59cf779b3..b8c17920d 100644 --- a/src/main/java/use_case/DataAccessException.java +++ b/src/main/java/use_case/note/DataAccessException.java @@ -1,4 +1,4 @@ -package use_case; +package use_case.note; /** * Exception thrown when there is an error with accessing data. diff --git a/src/main/java/use_case/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java similarity index 97% rename from src/main/java/use_case/HistoricalWeatherDataAccessInterface.java rename to src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index d945ab8b2..904670ccf 100644 --- a/src/main/java/use_case/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -1,4 +1,4 @@ -package use_case; +package use_case.note; import java.io.IOException; diff --git a/src/main/java/use_case/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java similarity index 89% rename from src/main/java/use_case/search_result/SearchResultInteractor.java rename to src/main/java/use_case/note/SearchResultInteractor.java index 0d85f7421..3ed852d83 100644 --- a/src/main/java/use_case/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -1,4 +1,4 @@ -package use_case.search_result; +package use_case.note; import java.io.IOException; import java.time.Instant; @@ -8,8 +8,10 @@ import java.util.Map; import entity.Weather; -import use_case.HistoricalWeatherDataAccessInterface; -import use_case.WeatherDataAccessInterface; +import use_case.note.search_result.SearchResultInputBoundary; +import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; /** * The interactor for the search result use case.. diff --git a/src/main/java/use_case/search_return/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java similarity index 58% rename from src/main/java/use_case/search_return/SearchReturnInteractor.java rename to src/main/java/use_case/note/SearchReturnInteractor.java index a95698d39..bb67cc4c2 100644 --- a/src/main/java/use_case/search_return/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -1,11 +1,17 @@ -package use_case.search_return; - import entity.Weather; -import use_case.WeatherDataAccessInterface; -import use_case.search_result.SearchResultOutputBoundary; +import use_case.note.WeatherDataAccessInterface; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnInputData; +import use_case.note.search_return.SearchReturnOutputBoundary; +import use_case.note.search_return.SearchReturnOutputData; +import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class SearchReturnInteractor implements SearchReturnInputBoundary { private final SearchResultOutputBoundary outputBoundary; diff --git a/src/main/java/use_case/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java similarity index 95% rename from src/main/java/use_case/WeatherDataAccessInterface.java rename to src/main/java/use_case/note/WeatherDataAccessInterface.java index 2238d0d65..163d40981 100644 --- a/src/main/java/use_case/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -1,4 +1,4 @@ -package use_case; +package use_case.note; import entity.Weather; import java.io.IOException; diff --git a/src/main/java/use_case/alert_pop/AlertPopInputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java similarity index 81% rename from src/main/java/use_case/alert_pop/AlertPopInputBoundary.java rename to src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java index f48f97a87..7d635bfb0 100644 --- a/src/main/java/use_case/alert_pop/AlertPopInputBoundary.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.alert_pop; +package use_case.note.alert_pop; // No input because alertpop is automatic. public interface AlertPopInputBoundary { diff --git a/src/main/java/use_case/alert_pop/AlertPopInputData.java b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java similarity index 89% rename from src/main/java/use_case/alert_pop/AlertPopInputData.java rename to src/main/java/use_case/note/alert_pop/AlertPopInputData.java index 82b4161a6..2bb4bb6e1 100644 --- a/src/main/java/use_case/alert_pop/AlertPopInputData.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputData.java @@ -1,4 +1,4 @@ -package use_case.alert_pop; +package use_case.note.alert_pop; // No input because alertpop is automatic. public class AlertPopInputData { diff --git a/src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java similarity index 83% rename from src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java rename to src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java index be39182e0..4e431ba03 100644 --- a/src/main/java/use_case/alert_pop/AlertPopOutputBoundary.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.alert_pop; +package use_case.note.alert_pop; public interface AlertPopOutputBoundary { diff --git a/src/main/java/use_case/alert_pop/AlertPopOutputData.java b/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java similarity index 92% rename from src/main/java/use_case/alert_pop/AlertPopOutputData.java rename to src/main/java/use_case/note/alert_pop/AlertPopOutputData.java index 75acbbbd6..50f45b31e 100644 --- a/src/main/java/use_case/alert_pop/AlertPopOutputData.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopOutputData.java @@ -1,4 +1,4 @@ -package use_case.alert_pop; +package use_case.note.alert_pop; public class AlertPopOutputData { diff --git a/src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java similarity index 80% rename from src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java rename to src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java index f54a5f73b..4b46cafdd 100644 --- a/src/main/java/use_case/bookmark_return/BookmarkReturnInputBoundary.java +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.bookmark_return; +package use_case.note.bookmark_return; // The input is one click on "return". public interface BookmarkReturnInputBoundary { diff --git a/src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java similarity index 67% rename from src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java rename to src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java index 11e36d6ae..e53789e11 100644 --- a/src/main/java/use_case/bookmark_return/BookmarkReturnInputData.java +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java @@ -1,4 +1,4 @@ -package use_case.bookmark_return; +package use_case.note.bookmark_return; // The input is one click on "return". public class BookmarkReturnInputData { diff --git a/src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java similarity index 82% rename from src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java rename to src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java index bd108bc40..ce8bdd68d 100644 --- a/src/main/java/use_case/bookmark_return/BookmarkReturnOutputBoundary.java +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.bookmark_return; +package use_case.note.bookmark_return; public interface BookmarkReturnOutputBoundary { diff --git a/src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java similarity index 87% rename from src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java rename to src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java index f0bd0977f..688222b79 100644 --- a/src/main/java/use_case/bookmark_return/BookmarkReturnOutputData.java +++ b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java @@ -1,4 +1,4 @@ -package use_case.bookmark_return; +package use_case.note.bookmark_return; public class BookmarkReturnOutputData { diff --git a/src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java similarity index 86% rename from src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java rename to src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java index 326bdd240..b8cfda36e 100644 --- a/src/main/java/use_case/city_bookmark/CityBookmarkInputBoundary.java +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.city_bookmark; +package use_case.note.city_bookmark; // The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the // InputData. diff --git a/src/main/java/use_case/city_bookmark/CityBookmarkInputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java similarity index 81% rename from src/main/java/use_case/city_bookmark/CityBookmarkInputData.java rename to src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java index 5a45ef969..47d6cb8a1 100644 --- a/src/main/java/use_case/city_bookmark/CityBookmarkInputData.java +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java @@ -1,4 +1,4 @@ -package use_case.city_bookmark; +package use_case.note.city_bookmark; // The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the // InputData. diff --git a/src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java similarity index 82% rename from src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java rename to src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java index 900beb5ff..02f755b2e 100644 --- a/src/main/java/use_case/city_bookmark/CityBookmarkOutputBoundary.java +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.city_bookmark; +package use_case.note.city_bookmark; public interface CityBookmarkOutputBoundary { diff --git a/src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java similarity index 92% rename from src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java rename to src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java index fb1d23e84..55b08fce3 100644 --- a/src/main/java/use_case/city_bookmark/CityBookmarkOutputData.java +++ b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java @@ -1,4 +1,4 @@ -package use_case.city_bookmark; +package use_case.note.city_bookmark; import java.util.ArrayList; diff --git a/src/main/java/use_case/close_list/CloseListInputBoundary.java b/src/main/java/use_case/note/close_list/CloseListInputBoundary.java similarity index 81% rename from src/main/java/use_case/close_list/CloseListInputBoundary.java rename to src/main/java/use_case/note/close_list/CloseListInputBoundary.java index 8322e61e4..be422c7e9 100644 --- a/src/main/java/use_case/close_list/CloseListInputBoundary.java +++ b/src/main/java/use_case/note/close_list/CloseListInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_list; +package use_case.note.close_list; // Input is one click on "close". public interface CloseListInputBoundary { diff --git a/src/main/java/use_case/close_list/CloseListInputData.java b/src/main/java/use_case/note/close_list/CloseListInputData.java similarity index 67% rename from src/main/java/use_case/close_list/CloseListInputData.java rename to src/main/java/use_case/note/close_list/CloseListInputData.java index 4c47c653e..caba5f836 100644 --- a/src/main/java/use_case/close_list/CloseListInputData.java +++ b/src/main/java/use_case/note/close_list/CloseListInputData.java @@ -1,4 +1,4 @@ -package use_case.close_list; +package use_case.note.close_list; // Input is one click on "close". public class CloseListInputData { diff --git a/src/main/java/use_case/close_list/CloseListOutputBoundary.java b/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java similarity index 82% rename from src/main/java/use_case/close_list/CloseListOutputBoundary.java rename to src/main/java/use_case/note/close_list/CloseListOutputBoundary.java index 92c806a03..fe3d9a723 100644 --- a/src/main/java/use_case/close_list/CloseListOutputBoundary.java +++ b/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_list; +package use_case.note.close_list; public interface CloseListOutputBoundary { diff --git a/src/main/java/use_case/close_list/CloseListOutputData.java b/src/main/java/use_case/note/close_list/CloseListOutputData.java similarity index 88% rename from src/main/java/use_case/close_list/CloseListOutputData.java rename to src/main/java/use_case/note/close_list/CloseListOutputData.java index ec3d8d94d..e4a99360d 100644 --- a/src/main/java/use_case/close_list/CloseListOutputData.java +++ b/src/main/java/use_case/note/close_list/CloseListOutputData.java @@ -1,4 +1,4 @@ -package use_case.close_list; +package use_case.note.close_list; public class CloseListOutputData { diff --git a/src/main/java/use_case/close_pin/ClosePinInputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java similarity index 81% rename from src/main/java/use_case/close_pin/ClosePinInputBoundary.java rename to src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java index 5c32427d3..1c679ef8c 100644 --- a/src/main/java/use_case/close_pin/ClosePinInputBoundary.java +++ b/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_pin; +package use_case.note.close_pin; // Input is a click on the "close" button. public interface ClosePinInputBoundary { diff --git a/src/main/java/use_case/close_pin/ClosePinInputData.java b/src/main/java/use_case/note/close_pin/ClosePinInputData.java similarity index 70% rename from src/main/java/use_case/close_pin/ClosePinInputData.java rename to src/main/java/use_case/note/close_pin/ClosePinInputData.java index 7ede61f1f..ba3f16d7c 100644 --- a/src/main/java/use_case/close_pin/ClosePinInputData.java +++ b/src/main/java/use_case/note/close_pin/ClosePinInputData.java @@ -1,4 +1,4 @@ -package use_case.close_pin; +package use_case.note.close_pin; // Input is a click on the "close" button. public class ClosePinInputData { diff --git a/src/main/java/use_case/close_pin/ClosePinOutputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java similarity index 83% rename from src/main/java/use_case/close_pin/ClosePinOutputBoundary.java rename to src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java index aad5eb740..da4e3b1bc 100644 --- a/src/main/java/use_case/close_pin/ClosePinOutputBoundary.java +++ b/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_pin; +package use_case.note.close_pin; public interface ClosePinOutputBoundary { diff --git a/src/main/java/use_case/close_pin/ClosePinOutputData.java b/src/main/java/use_case/note/close_pin/ClosePinOutputData.java similarity index 88% rename from src/main/java/use_case/close_pin/ClosePinOutputData.java rename to src/main/java/use_case/note/close_pin/ClosePinOutputData.java index 38bd3fecd..eab6e91f4 100644 --- a/src/main/java/use_case/close_pin/ClosePinOutputData.java +++ b/src/main/java/use_case/note/close_pin/ClosePinOutputData.java @@ -1,4 +1,4 @@ -package use_case.close_pin; +package use_case.note.close_pin; public class ClosePinOutputData { diff --git a/src/main/java/use_case/close_pop/ClosePopInputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java similarity index 80% rename from src/main/java/use_case/close_pop/ClosePopInputBoundary.java rename to src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java index fd904a694..06cd776d8 100644 --- a/src/main/java/use_case/close_pop/ClosePopInputBoundary.java +++ b/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_pop; +package use_case.note.close_pop; // Input is a click on "close". public interface ClosePopInputBoundary { diff --git a/src/main/java/use_case/close_pop/ClosePopInputData.java b/src/main/java/use_case/note/close_pop/ClosePopInputData.java similarity index 67% rename from src/main/java/use_case/close_pop/ClosePopInputData.java rename to src/main/java/use_case/note/close_pop/ClosePopInputData.java index 8e8b312db..dfeeafa7b 100644 --- a/src/main/java/use_case/close_pop/ClosePopInputData.java +++ b/src/main/java/use_case/note/close_pop/ClosePopInputData.java @@ -1,4 +1,4 @@ -package use_case.close_pop; +package use_case.note.close_pop; // Input is a click on "close". public class ClosePopInputData { diff --git a/src/main/java/use_case/close_pop/ClosePopOutputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java similarity index 83% rename from src/main/java/use_case/close_pop/ClosePopOutputBoundary.java rename to src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java index d5466d25a..4d881e40f 100644 --- a/src/main/java/use_case/close_pop/ClosePopOutputBoundary.java +++ b/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.close_pop; +package use_case.note.close_pop; public interface ClosePopOutputBoundary { diff --git a/src/main/java/use_case/close_pop/ClosePopOutputData.java b/src/main/java/use_case/note/close_pop/ClosePopOutputData.java similarity index 88% rename from src/main/java/use_case/close_pop/ClosePopOutputData.java rename to src/main/java/use_case/note/close_pop/ClosePopOutputData.java index c772aa6b9..03ffe9913 100644 --- a/src/main/java/use_case/close_pop/ClosePopOutputData.java +++ b/src/main/java/use_case/note/close_pop/ClosePopOutputData.java @@ -1,4 +1,4 @@ -package use_case.close_pop; +package use_case.note.close_pop; public class ClosePopOutputData { diff --git a/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java similarity index 83% rename from src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java rename to src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java index 83121223e..8de3c12a4 100644 --- a/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputBoundary.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.convert_farenheit; +package use_case.note.convert_farenheit; public interface ConvertFarenheitInputBoundary { void executeConvert(ConvertFarenheitInputData convertFarenheitInputData); diff --git a/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java similarity index 82% rename from src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java rename to src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java index b64a798f7..3b463e735 100644 --- a/src/main/java/use_case/convert_farenheit/ConvertFarenheitInputData.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitInputData.java @@ -1,4 +1,4 @@ -package use_case.convert_farenheit; +package use_case.note.convert_farenheit; import entity.Weather; diff --git a/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java similarity index 80% rename from src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java rename to src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java index a7598d88e..a2c9f7018 100644 --- a/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputBoundary.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.convert_farenheit; +package use_case.note.convert_farenheit; public interface ConvertFarenheitOutputBoundary { void prepareFailView(String errorMessage); diff --git a/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java similarity index 91% rename from src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java rename to src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java index 4d61ede11..0f1c7f201 100644 --- a/src/main/java/use_case/convert_farenheit/ConvertFarenheitOutputData.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertFarenheitOutputData.java @@ -1,4 +1,4 @@ -package use_case.convert_farenheit; +package use_case.note.convert_farenheit; import entity.Weather; diff --git a/src/main/java/use_case/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java similarity index 97% rename from src/main/java/use_case/convert_farenheit/ConvertInteractor.java rename to src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java index 116db6ac9..0d1891ec9 100644 --- a/src/main/java/use_case/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -1,4 +1,4 @@ -package use_case.convert_farenheit; +package use_case.note.convert_farenheit; public class ConvertInteractor implements ConvertFarenheitInputBoundary { public static final double KILOMETERS_MILE = 0.62; diff --git a/src/main/java/use_case/nearby_list/NearbyListInputBoundary.java b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java similarity index 86% rename from src/main/java/use_case/nearby_list/NearbyListInputBoundary.java rename to src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java index cead1cbdb..22407c6b4 100644 --- a/src/main/java/use_case/nearby_list/NearbyListInputBoundary.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.nearby_list; +package use_case.note.nearby_list; // This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. public interface NearbyListInputBoundary { diff --git a/src/main/java/use_case/nearby_list/NearbyListInputData.java b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java similarity index 81% rename from src/main/java/use_case/nearby_list/NearbyListInputData.java rename to src/main/java/use_case/note/nearby_list/NearbyListInputData.java index 8a3e3532e..5e6e7aa29 100644 --- a/src/main/java/use_case/nearby_list/NearbyListInputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java @@ -1,4 +1,4 @@ -package use_case.nearby_list; +package use_case.note.nearby_list; // This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. public class NearbyListInputData { diff --git a/src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java similarity index 82% rename from src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java rename to src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java index 50a1fba3c..4ac7b4bd4 100644 --- a/src/main/java/use_case/nearby_list/NearbyListOutputBoundary.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.nearby_list; +package use_case.note.nearby_list; public interface NearbyListOutputBoundary { diff --git a/src/main/java/use_case/nearby_list/NearbyListOutputData.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java similarity index 90% rename from src/main/java/use_case/nearby_list/NearbyListOutputData.java rename to src/main/java/use_case/note/nearby_list/NearbyListOutputData.java index d71c9528b..e6256e43f 100644 --- a/src/main/java/use_case/nearby_list/NearbyListOutputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java @@ -1,4 +1,4 @@ -package use_case.nearby_list; +package use_case.note.nearby_list; public class NearbyListOutputData { diff --git a/src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java similarity index 79% rename from src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java rename to src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java index 7b1f9360a..2e267e172 100644 --- a/src/main/java/use_case/pin_weather/PinWeatherInputBoundary.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.pin_weather; +package use_case.note.pin_weather; // Input is a click on "pin." public interface PinWeatherInputBoundary { diff --git a/src/main/java/use_case/pin_weather/PinWeatherInputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java similarity index 66% rename from src/main/java/use_case/pin_weather/PinWeatherInputData.java rename to src/main/java/use_case/note/pin_weather/PinWeatherInputData.java index dc35d03f5..623290d9f 100644 --- a/src/main/java/use_case/pin_weather/PinWeatherInputData.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java @@ -1,4 +1,4 @@ -package use_case.pin_weather; +package use_case.note.pin_weather; // Input is a click on "pin." public class PinWeatherInputData { diff --git a/src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java similarity index 82% rename from src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java rename to src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java index 6f4751ad5..6eac48913 100644 --- a/src/main/java/use_case/pin_weather/PinWeatherOutputBoundary.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.pin_weather; +package use_case.note.pin_weather; public interface PinWeatherOutputBoundary { diff --git a/src/main/java/use_case/pin_weather/PinWeatherOutputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java similarity index 92% rename from src/main/java/use_case/pin_weather/PinWeatherOutputData.java rename to src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java index 5050e5c50..cc0446619 100644 --- a/src/main/java/use_case/pin_weather/PinWeatherOutputData.java +++ b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java @@ -1,4 +1,4 @@ -package use_case.pin_weather; +package use_case.note.pin_weather; public class PinWeatherOutputData { diff --git a/src/main/java/use_case/return_home/ReturnHomeInputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java similarity index 80% rename from src/main/java/use_case/return_home/ReturnHomeInputBoundary.java rename to src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java index b62d0c326..93b43e15b 100644 --- a/src/main/java/use_case/return_home/ReturnHomeInputBoundary.java +++ b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.return_home; +package use_case.note.return_home; // Input is a click on the home button. public interface ReturnHomeInputBoundary { diff --git a/src/main/java/use_case/return_home/ReturnHomeInputData.java b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java similarity index 69% rename from src/main/java/use_case/return_home/ReturnHomeInputData.java rename to src/main/java/use_case/note/return_home/ReturnHomeInputData.java index 04aff31e9..27162a91e 100644 --- a/src/main/java/use_case/return_home/ReturnHomeInputData.java +++ b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java @@ -1,4 +1,4 @@ -package use_case.return_home; +package use_case.note.return_home; // Input is a click on the home button. public class ReturnHomeInputData { diff --git a/src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java similarity index 82% rename from src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java rename to src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java index 63db3b752..258573eb3 100644 --- a/src/main/java/use_case/return_home/ReturnHomeOutputBoundary.java +++ b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.return_home; +package use_case.note.return_home; public interface ReturnHomeOutputBoundary { diff --git a/src/main/java/use_case/return_home/ReturnHomeOutputData.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java similarity index 88% rename from src/main/java/use_case/return_home/ReturnHomeOutputData.java rename to src/main/java/use_case/note/return_home/ReturnHomeOutputData.java index 774760fa4..49f1ba0c4 100644 --- a/src/main/java/use_case/return_home/ReturnHomeOutputData.java +++ b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java @@ -1,4 +1,4 @@ -package use_case.return_home; +package use_case.note.return_home; public class ReturnHomeOutputData { diff --git a/src/main/java/use_case/search_result/SearchResultInputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java similarity index 86% rename from src/main/java/use_case/search_result/SearchResultInputBoundary.java rename to src/main/java/use_case/note/search_result/SearchResultInputBoundary.java index 307ffa93f..99054de87 100644 --- a/src/main/java/use_case/search_result/SearchResultInputBoundary.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.search_result; +package use_case.note.search_result; // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. diff --git a/src/main/java/use_case/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java similarity index 92% rename from src/main/java/use_case/search_result/SearchResultInputData.java rename to src/main/java/use_case/note/search_result/SearchResultInputData.java index 228d37b69..f15ab28b1 100644 --- a/src/main/java/use_case/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -1,4 +1,4 @@ -package use_case.search_result; +package use_case.note.search_result; // Didn't implement the use case for past 24 hours. Undecided between a separate use case or putting it inside // search bar. diff --git a/src/main/java/use_case/search_result/SearchResultOutputBoundary.java b/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java similarity index 82% rename from src/main/java/use_case/search_result/SearchResultOutputBoundary.java rename to src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java index e0081252c..cee8789c9 100644 --- a/src/main/java/use_case/search_result/SearchResultOutputBoundary.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.search_result; +package use_case.note.search_result; public interface SearchResultOutputBoundary { diff --git a/src/main/java/use_case/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java similarity index 94% rename from src/main/java/use_case/search_result/SearchResultOutputData.java rename to src/main/java/use_case/note/search_result/SearchResultOutputData.java index ac1fb94ee..5c8b0fcb7 100644 --- a/src/main/java/use_case/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -1,4 +1,4 @@ -package use_case.search_result; +package use_case.note.search_result; import entity.Weather; diff --git a/src/main/java/use_case/search_return/SearchReturnInputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java similarity index 89% rename from src/main/java/use_case/search_return/SearchReturnInputBoundary.java rename to src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java index 58e18a2fe..ac47665d0 100644 --- a/src/main/java/use_case/search_return/SearchReturnInputBoundary.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.search_return; +package use_case.note.search_return; /** * The input boundary for the search return use case. diff --git a/src/main/java/use_case/search_return/SearchReturnInputData.java b/src/main/java/use_case/note/search_return/SearchReturnInputData.java similarity index 87% rename from src/main/java/use_case/search_return/SearchReturnInputData.java rename to src/main/java/use_case/note/search_return/SearchReturnInputData.java index 919005971..4c892875c 100644 --- a/src/main/java/use_case/search_return/SearchReturnInputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInputData.java @@ -1,4 +1,4 @@ -package use_case.search_return; +package use_case.note.search_return; /** * // Input is one click on "return." diff --git a/src/main/java/use_case/search_return/SearchReturnOutputBoundary.java b/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java similarity index 82% rename from src/main/java/use_case/search_return/SearchReturnOutputBoundary.java rename to src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java index 516e7f5f4..90e7ca950 100644 --- a/src/main/java/use_case/search_return/SearchReturnOutputBoundary.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.search_return; +package use_case.note.search_return; public interface SearchReturnOutputBoundary { diff --git a/src/main/java/use_case/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java similarity index 94% rename from src/main/java/use_case/search_return/SearchReturnOutputData.java rename to src/main/java/use_case/note/search_return/SearchReturnOutputData.java index 237664c43..f48d43f72 100644 --- a/src/main/java/use_case/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -1,4 +1,4 @@ -package use_case.search_return; +package use_case.note.search_return; import entity.Weather; diff --git a/src/main/java/use_case/select_region/SelectRegionInputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java similarity index 79% rename from src/main/java/use_case/select_region/SelectRegionInputBoundary.java rename to src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java index 24349e8b9..17c3d0394 100644 --- a/src/main/java/use_case/select_region/SelectRegionInputBoundary.java +++ b/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java @@ -1,4 +1,4 @@ -package use_case.select_region; +package use_case.note.select_region; // Input is a click on the region. public interface SelectRegionInputBoundary { diff --git a/src/main/java/use_case/select_region/SelectRegionInputData.java b/src/main/java/use_case/note/select_region/SelectRegionInputData.java similarity index 66% rename from src/main/java/use_case/select_region/SelectRegionInputData.java rename to src/main/java/use_case/note/select_region/SelectRegionInputData.java index 94c16b33e..9d72aadd3 100644 --- a/src/main/java/use_case/select_region/SelectRegionInputData.java +++ b/src/main/java/use_case/note/select_region/SelectRegionInputData.java @@ -1,4 +1,4 @@ -package use_case.select_region; +package use_case.note.select_region; // Input is a click on the region. public class SelectRegionInputData { diff --git a/src/main/java/use_case/select_region/SelectRegionOutputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java similarity index 82% rename from src/main/java/use_case/select_region/SelectRegionOutputBoundary.java rename to src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java index ee462c67b..eca8cecf5 100644 --- a/src/main/java/use_case/select_region/SelectRegionOutputBoundary.java +++ b/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java @@ -1,4 +1,4 @@ -package use_case.select_region; +package use_case.note.select_region; public interface SelectRegionOutputBoundary { diff --git a/src/main/java/use_case/select_region/SelectRegionOutputData.java b/src/main/java/use_case/note/select_region/SelectRegionOutputData.java similarity index 93% rename from src/main/java/use_case/select_region/SelectRegionOutputData.java rename to src/main/java/use_case/note/select_region/SelectRegionOutputData.java index e9ef88712..a8fe7a631 100644 --- a/src/main/java/use_case/select_region/SelectRegionOutputData.java +++ b/src/main/java/use_case/note/select_region/SelectRegionOutputData.java @@ -1,4 +1,4 @@ -package use_case.select_region; +package use_case.note.select_region; public class SelectRegionOutputData { private final String location; diff --git a/src/main/java/view/SearchResultPanelView.java b/src/main/java/view/SearchResultPanelView.java index 380255252..34003a34e 100644 --- a/src/main/java/view/SearchResultPanelView.java +++ b/src/main/java/view/SearchResultPanelView.java @@ -13,9 +13,9 @@ import javax.swing.JPanel; import javax.swing.JTextArea; -import interface_adapter.search_result.SearchResultController; -import interface_adapter.search_result.SearchResultState; -import interface_adapter.search_result.SearchResultViewModel; +import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.SearchResult.SearchResultState; +import interface_adapter.SearchResult.SearchResultViewModel; /** * The View for when the user is viewing a note in the program. diff --git a/src/test/java/use_case/NoteInteractorTest.java b/src/test/java/use_case/note/NoteInteractorTest.java similarity index 97% rename from src/test/java/use_case/NoteInteractorTest.java rename to src/test/java/use_case/note/NoteInteractorTest.java index 4b3933e4c..a3ed466b6 100644 --- a/src/test/java/use_case/NoteInteractorTest.java +++ b/src/test/java/use_case/note/NoteInteractorTest.java @@ -1,4 +1,4 @@ -package use_case; +package use_case.note; import entity.User; import org.junit.Test; From 9f6a8bbc9ec160c11495a0adfb1ab86d12056321 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 13:53:48 -0500 Subject: [PATCH 110/267] Initial interface adapter for nearby cities use case --- .../nearby_list/NearbyListController.java | 26 +++++++++++++ .../nearby_list/NearbyListPresenter.java | 38 +++++++++++++++++++ .../nearby_list/NearbyListState.java | 28 ++++++++++++++ .../nearby_list/NearbyListViewModel.java | 13 +++++++ .../weather/WeatherPresenter.java | 2 +- .../note/nearby_list/NearbyListInputData.java | 19 +++++++++- .../nearby_list/NearbyListInteractor.java | 9 +++++ .../nearby_list/NearbyListOutputData.java | 13 +++++-- 8 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 src/main/java/interface_adapter/nearby_list/NearbyListController.java create mode 100644 src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java create mode 100644 src/main/java/interface_adapter/nearby_list/NearbyListState.java create mode 100644 src/main/java/interface_adapter/nearby_list/NearbyListViewModel.java create mode 100644 src/main/java/use_case/note/nearby_list/NearbyListInteractor.java diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListController.java b/src/main/java/interface_adapter/nearby_list/NearbyListController.java new file mode 100644 index 000000000..38704e16e --- /dev/null +++ b/src/main/java/interface_adapter/nearby_list/NearbyListController.java @@ -0,0 +1,26 @@ +package interface_adapter.nearby_list; + +import use_case.note.nearby_list.NearbyListInputBoundary; +import use_case.note.nearby_list.NearbyListInputData; + +public class NearbyListController { + private final NearbyListInputBoundary nearbyListInteractor; + + // Constructor that injects the use case's input boundary + public NearbyListController(NearbyListInputBoundary nearbyListInteractor) { + this.nearbyListInteractor = nearbyListInteractor; + } + + /** + * Executes the find nearby cities use case given the longitude and latitude of the current location. + * + * @param longitude the name of the city to search for + * @param latitude the date to search for + */ + public void execute(float longitude, float latitude) { + // Create a NearbyListInputData object to encapsulate the input data + final NearbyListInputData inputData = new NearbyListInputData(longitude, latitude); + // Call the use case's execute method with the input data + nearbyListInteractor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java b/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java new file mode 100644 index 000000000..c1bd7054d --- /dev/null +++ b/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java @@ -0,0 +1,38 @@ +package interface_adapter.nearby_list; + +import use_case.note.nearby_list.NearbyListOutputBoundary; +import use_case.note.nearby_list.NearbyListOutputData; + +/** + * The presenter for the nearby cities use case. + */ +public class NearbyListPresenter implements NearbyListOutputBoundary { + private final NearbyListViewModel nearbyListViewModel; + + public NearbyListPresenter(NearbyListViewModel nearbyListViewModel) { + this.nearbyListViewModel = nearbyListViewModel; + } + + /** + * Prepares the success view for the NearbyList related Use Cases. + * + * @param response the output data + */ + @Override + public void presentSuccessView(NearbyListOutputData response) { + nearbyListViewModel.getState().setCities(response.getCities()); + nearbyListViewModel.getState().setError(null); + nearbyListViewModel.firePropertyChanged(); + } + + /** + * Prepares the failure view for the NearbyList related Use Cases. + * + * @param errorMessage the explanation of the failure + */ + @Override + public void prepareFailView(String errorMessage) { + nearbyListViewModel.getState().setError(errorMessage); + nearbyListViewModel.firePropertyChanged(); + } +} diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListState.java b/src/main/java/interface_adapter/nearby_list/NearbyListState.java new file mode 100644 index 000000000..f29ce145b --- /dev/null +++ b/src/main/java/interface_adapter/nearby_list/NearbyListState.java @@ -0,0 +1,28 @@ +package interface_adapter.nearby_list; + +import java.util.ArrayList; +import java.util.List; + +/** + * The state information for the nearby list view model. + */ +public class NearbyListState { + private ArrayList cities; + private String error; + + public List getCities() { + return cities; + } + + public void setCities(List cities) { + this.cities = (ArrayList) cities; + } + + public void setError(String error) { + this.error = error; + } + + public String getError() { + return error; + } +} diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListViewModel.java b/src/main/java/interface_adapter/nearby_list/NearbyListViewModel.java new file mode 100644 index 000000000..6bcf53628 --- /dev/null +++ b/src/main/java/interface_adapter/nearby_list/NearbyListViewModel.java @@ -0,0 +1,13 @@ +package interface_adapter.nearby_list; + +import interface_adapter.ViewModel; + +/** + * The view model for the nearby list view. + */ +public class NearbyListViewModel extends ViewModel { + public NearbyListViewModel() { + super("nearbyList"); + setState(new NearbyListState()); + } +} diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 523bd3e9c..489c49f01 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -4,7 +4,7 @@ import use_case.note.search_return.SearchReturnOutputData; /** - * The presenter for the + * The presenter for the weather use case. */ public class WeatherPresenter implements SearchReturnOutputBoundary { diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java index 5e6e7aa29..8e3958263 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java @@ -1,5 +1,22 @@ package use_case.note.nearby_list; -// This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. +/** + * This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. + */ public class NearbyListInputData { + private final float longitude; + private final float latitude; + + public NearbyListInputData(float longitude, float latitude) { + this.longitude = longitude; + this.latitude = latitude; + } + + public float getLongitude() { + return longitude; + } + + public float getLatitude() { + return latitude; + } } diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java new file mode 100644 index 000000000..fa863ef7b --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java @@ -0,0 +1,9 @@ +package use_case.note.nearby_list; + +public class NearbyListInteractor implements NearbyListInputBoundary { + + @Override + public void execute(NearbyListInputData nearbyListInputData) { + + } +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java index e6256e43f..100b26de8 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java @@ -1,16 +1,23 @@ package use_case.note.nearby_list; +import java.util.ArrayList; +import java.util.List; + public class NearbyListOutputData { - private final String[] cities; + private final ArrayList cities; private final boolean useCaseFailed; - public NearbyListOutputData(String[] cities, boolean useCaseFailed) { - this.cities = cities; + public NearbyListOutputData(List cities, boolean useCaseFailed) { + this.cities = (ArrayList) cities; this.useCaseFailed = useCaseFailed; } public boolean isUseCaseFailed() { return useCaseFailed; } + + public List getCities() { + return cities; + } } From 486ae43283377db2225eaf4506d2e20b53f34a2e Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 14:10:38 -0500 Subject: [PATCH 111/267] Initial interface for nearby cities use case --- .../NearbyCitiesAccessInterface.java | 15 ++++++++++++ .../nearby_list/NearbyListInteractor.java | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java diff --git a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java new file mode 100644 index 000000000..c128d1db3 --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java @@ -0,0 +1,15 @@ +package use_case.note.nearby_list; + +import java.io.IOException; +import java.util.List; + +public interface NearbyCitiesAccessInterface { + /** + * + * @param latitude + * @param longitude + * @return + * @throws IOException + */ + List getNearbyCities(Float latitude, Float longitude) throws IOException; +} diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java index fa863ef7b..5dfc90dfd 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java @@ -1,9 +1,32 @@ package use_case.note.nearby_list; +import java.io.IOException; +import java.util.ArrayList; + +/** + * The interactor for the nearby cities use case. + */ public class NearbyListInteractor implements NearbyListInputBoundary { + private final NearbyListOutputBoundary outputBoundary; + private final NearbyCitiesAccessInterface cityDataAccess; + + public NearbyListInteractor(NearbyListOutputBoundary outputBoundary, NearbyCitiesAccessInterface cityDataAccess) { + this.outputBoundary = outputBoundary; + this.cityDataAccess = cityDataAccess; + } @Override public void execute(NearbyListInputData nearbyListInputData) { + try { + final Float latitude = nearbyListInputData.getLatitude(); + final Float longitude = nearbyListInputData.getLongitude(); + final ArrayList cities = (ArrayList) cityDataAccess.getNearbyCities(latitude, longitude); + final NearbyListOutputData outputData = new NearbyListOutputData(cities, false); + outputBoundary.presentSuccessView(outputData); + } + catch (IOException exception) { + outputBoundary.prepareFailView("Error: " + exception.getMessage()); + } } } From 2ffaed38886519d4d933dacaac93f9df232a3f53 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 18:22:33 -0500 Subject: [PATCH 112/267] Finished interface + object for cities list, added data file for cities --- .../NearbyCitiesAccessInterface.java | 10 +- .../nearby_list/NearbyCitiesAccessObject.java | 51 + src/main/resources/cities_list.json | 2228 +++++++++++++++++ 3 files changed, 2282 insertions(+), 7 deletions(-) create mode 100644 src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java create mode 100644 src/main/resources/cities_list.json diff --git a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java index c128d1db3..a588d62fc 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java +++ b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java @@ -3,13 +3,9 @@ import java.io.IOException; import java.util.List; +/** + * Interface for generating list of nearby cities. + */ public interface NearbyCitiesAccessInterface { - /** - * - * @param latitude - * @param longitude - * @return - * @throws IOException - */ List getNearbyCities(Float latitude, Float longitude) throws IOException; } diff --git a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java new file mode 100644 index 000000000..4cdf09a56 --- /dev/null +++ b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java @@ -0,0 +1,51 @@ +package use_case.note.nearby_list; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public abstract class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { + private static final Float LOWER_LAT = -90.0f; + private static final Float UPPER_LAT = 90.0f; + private static final Float LOWER_LON = -180.0f; + private static final Float UPPER_LON = 180.0f; + private static final Float COMPARE_DIFF = 10.0f; + + @Override + public List getNearbyCities(Float latitude, Float longitude) throws IOException { + if (latitude == null || longitude == null || latitude < LOWER_LAT || latitude > UPPER_LAT || longitude < LOWER_LON || longitude > UPPER_LON) { + throw new IOException(); + } + try { + final String jsonString = Files + .readString(Paths.get(getClass().getClassLoader().getResource("cities_list.json").toURI())); + return getCityNames(latitude, longitude, jsonString); + } + catch (IOException | URISyntaxException ex) { + throw new IOException(); + } + } + + @NotNull + private static ArrayList getCityNames(Float latitude, Float longitude, String jsonString) { + final JSONArray jsonArray = new JSONArray(jsonString); + + final ArrayList nearbyCities = new ArrayList<>(); + + for (int i = 0; i < jsonArray.length(); i++) { + final JSONObject city = jsonArray.getJSONObject(i); + if (Math.abs(city.getInt("lat") - latitude) < COMPARE_DIFF + && Math.abs(city.getInt("lon") - longitude) < COMPARE_DIFF) { + nearbyCities.add(city.getString("name")); + } + } + return nearbyCities; + } +} diff --git a/src/main/resources/cities_list.json b/src/main/resources/cities_list.json new file mode 100644 index 000000000..391b7cb98 --- /dev/null +++ b/src/main/resources/cities_list.json @@ -0,0 +1,2228 @@ +[ + { + "name": "Abidjan", + "lon": -4.00167, + "lat": 5.35444, + "country": "Ivory Coast" + }, + { + "name": "Abu Dhabi", + "lon": 54.39696, + "lat": 24.45118, + "country": "United Arab Emirates" + }, + { + "name": "Abuja", + "lon": 7.49508, + "lat": 9.05785, + "country": "Nigeria" + }, + { + "name": "Accra", + "lon": -0.1969, + "lat": 5.55602, + "country": "Ghana" + }, + { + "name": "Addis Ababa", + "lon": 38.74689, + "lat": 9.02497, + "country": "Ethiopia" + }, + { + "name": "Ahmedabad", + "lon": 72.58727, + "lat": 23.02579, + "country": "India" + }, + { + "name": "Aleppo", + "lon": 37.16117, + "lat": 36.20124, + "country": "Syria" + }, + { + "name": "Alexandria", + "lon": 29.91582, + "lat": 31.20176, + "country": "Egypt" + }, + { + "name": "Algiers", + "lon": 3.08746, + "lat": 36.73225, + "country": "Algeria" + }, + { + "name": "Almaty", + "lon": 76.92861, + "lat": 43.25667, + "country": "Kazakhstan" + }, + { + "name": "Amman", + "lon": 35.94503, + "lat": 31.95522, + "country": "Jordan" + }, + { + "name": "Amsterdam", + "lon": 4.88969, + "lat": 52.37403, + "country": "Netherlands" + }, + { + "name": "Anchorage", + "lon": -149.90028, + "lat": 61.21806, + "country": "United States" + }, + { + "name": "Andorra la Vella", + "lon": 1.52109, + "lat": 42.50779, + "country": "Andorra" + }, + { + "name": "Ankara", + "lon": 32.85427, + "lat": 39.91987, + "country": "Turkey" + }, + { + "name": "Antananarivo", + "lon": 47.53613, + "lat": -18.91368, + "country": "Madagascar" + }, + { + "name": "Apia", + "lon": -171.76666, + "lat": -13.83333, + "country": "Samoa" + }, + { + "name": "Arnold", + "lon": -120.351935, + "lat": 38.255366, + "country": "United States" + }, + { + "name": "Ashgabat", + "lon": 58.38333, + "lat": 37.95, + "country": "Turkmenistan" + }, + { + "name": "Asmara", + "lon": 38.93184, + "lat": 15.33805, + "country": "Eritrea" + }, + { + "name": "Asuncion", + "lon": -57.647, + "lat": -25.28646, + "country": "Paraguay" + }, + { + "name": "Athens", + "lon": 23.72784, + "lat": 37.98376, + "country": "Greece" + }, + { + "name": "Auckland", + "lon": 174.76349, + "lat": -36.84853, + "country": "New Zealand" + }, + { + "name": "Avarua", + "lon": -159.77545, + "lat": -21.2075, + "country": "Cook Islands" + }, + { + "name": "Baghdad", + "lon": 44.40088, + "lat": 33.34058, + "country": "Iraq" + }, + { + "name": "Baku", + "lon": 49.89201, + "lat": 40.37767, + "country": "Azerbaijan" + }, + { + "name": "Bamako", + "lon": -8, + "lat": 12.65, + "country": "Mali" + }, + { + "name": "Banda Aceh", + "lon": 95.33333, + "lat": 5.54167, + "country": "Indonesia" + }, + { + "name": "Bandar Seri Begawan", + "lon": 114.94006, + "lat": 4.89035, + "country": "Brunei" + }, + { + "name": "Bandung", + "lon": 107.60694, + "lat": -6.92222, + "country": "Indonesia" + }, + { + "name": "Bangkok", + "lon": 100.50144, + "lat": 13.75398, + "country": "Thailand" + }, + { + "name": "Bangui", + "lon": 18.55496, + "lat": 4.36122, + "country": "Central African Republic" + }, + { + "name": "Banjul", + "lon": -16.57803, + "lat": 13.45274, + "country": "Gambia" + }, + { + "name": "Barcelona", + "lon": 2.15899, + "lat": 41.38879, + "country": "Spain" + }, + { + "name": "Barranquilla", + "lon": -74.78132, + "lat": 10.96854, + "country": "Colombia" + }, + { + "name": "Basrah", + "lon": 47.7804, + "lat": 30.50852, + "country": "Iraq" + }, + { + "name": "Basse-Terre", + "lon": -61.73214, + "lat": 15.99714, + "country": "Guadeloupe" + }, + { + "name": "Basseterre", + "lon": -62.72499, + "lat": 17.2955, + "country": "Saint Kitts and Nevis" + }, + { + "name": "Beijing", + "lon": 116.39723, + "lat": 39.9075, + "country": "China" + }, + { + "name": "Beirut", + "lon": 35.50157, + "lat": 33.89332, + "country": "Lebanon" + }, + { + "name": "Bekasi", + "lon": 106.9896, + "lat": -6.2349, + "country": "Indonesia" + }, + { + "name": "Belem", + "lon": -48.50444, + "lat": -1.45583, + "country": "Brazil" + }, + { + "name": "Belgrade", + "lon": 20.46513, + "lat": 44.80401, + "country": "Serbia" + }, + { + "name": "Belmopan", + "lon": -88.76667, + "lat": 17.25, + "country": "Belize" + }, + { + "name": "Belo Horizonte", + "lon": -43.93778, + "lat": -19.92083, + "country": "Brazil" + }, + { + "name": "Bengaluru", + "lon": 77.59369, + "lat": 12.97194, + "country": "India" + }, + { + "name": "Berlin", + "lon": 13.41053, + "lat": 52.52437, + "country": "Germany" + }, + { + "name": "Bern", + "lon": 7.44744, + "lat": 46.94809, + "country": "Switzerland" + }, + { + "name": "Bishkek", + "lon": 74.59, + "lat": 42.87, + "country": "Kyrgyzstan" + }, + { + "name": "Bissau", + "lon": -15.59767, + "lat": 11.86357, + "country": "Guinea-Bissau" + }, + { + "name": "Bogota", + "lon": -74.08175, + "lat": 4.60971, + "country": "Colombia" + }, + { + "name": "Brasilia", + "lon": -47.92972, + "lat": -15.77972, + "country": "Brazil" + }, + { + "name": "Bratislava", + "lon": 17.10674, + "lat": 48.14816, + "country": "Slovakia" + }, + { + "name": "Brazzaville", + "lon": 15.28318, + "lat": -4.26613, + "country": "Republic of the Congo" + }, + { + "name": "Bridgetown", + "lon": -59.62021, + "lat": 13.10732, + "country": "Barbados" + }, + { + "name": "Brisbane", + "lon": 153.02809, + "lat": -27.46794, + "country": "Australia" + }, + { + "name": "Brussels", + "lon": 4.34878, + "lat": 50.85045, + "country": "Belgium" + }, + { + "name": "Bucharest", + "lon": 26.10626, + "lat": 44.43225, + "country": "Romania" + }, + { + "name": "Budapest", + "lon": 19.04045, + "lat": 47.49835, + "country": "Hungary" + }, + { + "name": "Buenos Aires", + "lon": -58.37723, + "lat": -34.61315, + "country": "Argentina" + }, + { + "name": "Bujumbura", + "lon": 29.36142, + "lat": -3.38193, + "country": "Burundi" + }, + { + "name": "Bursa", + "lon": 29.06013, + "lat": 40.19559, + "country": "Turkey" + }, + { + "name": "Busan", + "lon": 129.03004, + "lat": 35.10168, + "country": "South Korea" + }, + { + "name": "Cairo", + "lon": 31.24967, + "lat": 30.06263, + "country": "Egypt" + }, + { + "name": "Cali", + "lon": -76.5225, + "lat": 3.43722, + "country": "Colombia" + }, + { + "name": "Caloocan", + "lon": 120.96788, + "lat": 14.64953, + "country": "Philippines" + }, + { + "name": "Camayenne", + "lon": -13.68778, + "lat": 9.535, + "country": "Guinea" + }, + { + "name": "Canberra", + "lon": 149.12807, + "lat": -35.28346, + "country": "Australia" + }, + { + "name": "Cape Town", + "lon": 18.42322, + "lat": -33.92584, + "country": "South Africa" + }, + { + "name": "Caracas", + "lon": -66.87919, + "lat": 10.48801, + "country": "Venezuela" + }, + { + "name": "Casablanca", + "lon": -7.61138, + "lat": 33.58831, + "country": "Morocco" + }, + { + "name": "Castries", + "lon": -61.00614, + "lat": 13.9957, + "country": "Saint Lucia" + }, + { + "name": "Cayenne", + "lon": -52.33333, + "lat": 4.93333, + "country": "French Guiana" + }, + { + "name": "Charlotte Amalie", + "lon": -64.9307, + "lat": 18.3419, + "country": "U.S. Virgin Islands" + }, + { + "name": "Chengdu", + "lon": 104.06667, + "lat": 30.66667, + "country": "China" + }, + { + "name": "Chennai", + "lon": 80.27847, + "lat": 13.08784, + "country": "India" + }, + { + "name": "Chicago", + "lon": -87.65005, + "lat": 41.85003, + "country": "United States" + }, + { + "name": "Chisinau", + "lon": 28.8575, + "lat": 47.00556, + "country": "Moldova" + }, + { + "name": "Chittagong", + "lon": 91.83168, + "lat": 22.3384, + "country": "Bangladesh" + }, + { + "name": "Chongqing", + "lon": 106.55278, + "lat": 29.56278, + "country": "China" + }, + { + "name": "Colombo", + "lon": 79.84868, + "lat": 6.93548, + "country": "Sri Lanka" + }, + { + "name": "Conakry", + "lon": -13.67729, + "lat": 9.53795, + "country": "Guinea" + }, + { + "name": "Copenhagen", + "lon": 12.56553, + "lat": 55.67594, + "country": "Denmark" + }, + { + "name": "Cordoba", + "lon": -64.18105, + "lat": -31.4135, + "country": "Argentina" + }, + { + "name": "Curitiba", + "lon": -49.27306, + "lat": -25.42778, + "country": "Brazil" + }, + { + "name": "Daegu", + "lon": 128.59111, + "lat": 35.87028, + "country": "South Korea" + }, + { + "name": "Daejeon", + "lon": 127.38493, + "lat": 36.34913, + "country": "South Korea" + }, + { + "name": "Dakar", + "lon": -17.44406, + "lat": 14.6937, + "country": "Senegal" + }, + { + "name": "Dallas", + "lon": -96.80667, + "lat": 32.78306, + "country": "United States" + }, + { + "name": "Damascus", + "lon": 36.29128, + "lat": 33.5102, + "country": "Syria" + }, + { + "name": "Dar es Salaam", + "lon": 39.26951, + "lat": -6.82349, + "country": "Tanzania" + }, + { + "name": "Delhi", + "lon": 77.23149, + "lat": 28.65195, + "country": "India" + }, + { + "name": "Denver", + "lon": -104.9847, + "lat": 39.73915, + "country": "United States" + }, + { + "name": "Dhaka", + "lon": 90.40744, + "lat": 23.7104, + "country": "Bangladesh" + }, + { + "name": "Dili", + "lon": 125.57361, + "lat": -8.55861, + "country": "Timor Leste" + }, + { + "name": "Djibouti", + "lon": 43.14503, + "lat": 11.58901, + "country": "Djibouti" + }, + { + "name": "Dodoma", + "lon": 35.73947, + "lat": -6.17221, + "country": "Tanzania" + }, + { + "name": "Doha", + "lon": 51.53096, + "lat": 25.28545, + "country": "Qatar" + }, + { + "name": "Dongguan", + "lon": 113.74866, + "lat": 23.01797, + "country": "China" + }, + { + "name": "Douala", + "lon": 9.70428, + "lat": 4.04827, + "country": "Cameroon" + }, + { + "name": "Douglas", + "lon": -4.48333, + "lat": 54.15, + "country": "Isle of Man" + }, + { + "name": "Dubai", + "lon": 55.30927, + "lat": 25.07725, + "country": "United Arab Emirates" + }, + { + "name": "Dublin", + "lon": -6.24889, + "lat": 53.33306, + "country": "Ireland" + }, + { + "name": "Durban", + "lon": 31.0292, + "lat": -29.8579, + "country": "South Africa" + }, + { + "name": "Dushanbe", + "lon": 68.77905, + "lat": 38.53575, + "country": "Tajikistan" + }, + { + "name": "Faisalabad", + "lon": 73.08969, + "lat": 31.41554, + "country": "Pakistan" + }, + { + "name": "Fort-de-France", + "lon": -61.07418, + "lat": 14.60365, + "country": "Martinique" + }, + { + "name": "Fortaleza", + "lon": -38.54306, + "lat": -3.71722, + "country": "Brazil" + }, + { + "name": "Freetown", + "lon": -13.2356, + "lat": 8.48714, + "country": "Sierra Leone" + }, + { + "name": "Fukuoka", + "lon": 130.41667, + "lat": 33.6, + "country": "Japan" + }, + { + "name": "Funafuti", + "lon": 179.19417, + "lat": -8.52425, + "country": "Tuvalu" + }, + { + "name": "Gaborone", + "lon": 25.90859, + "lat": -24.65451, + "country": "Botswana" + }, + { + "name": "George Town", + "lon": -81.37436, + "lat": 19.2866, + "country": "Malaysia" + }, + { + "name": "Georgetown", + "lon": -58.15527, + "lat": 6.80448, + "country": "Guyana" + }, + { + "name": "Gibraltar", + "lon": -5.35257, + "lat": 36.14474, + "country": "Gibraltar" + }, + { + "name": "Gitega", + "lon": 29.92463, + "lat": -3.42708, + "country": "Burundi" + }, + { + "name": "Giza", + "lon": 31.20861, + "lat": 30.00944, + "country": "Egypt" + }, + { + "name": "Guadalajara", + "lon": -103.39182, + "lat": 20.66682, + "country": "Mexico" + }, + { + "name": "Guangzhou", + "lon": 113.25, + "lat": 23.11667, + "country": "China" + }, + { + "name": "Guatemala City", + "lon": -90.51327, + "lat": 14.64072, + "country": "Guatemala" + }, + { + "name": "Guayaquil", + "lon": -79.88621, + "lat": -2.19616, + "country": "Ecuador" + }, + { + "name": "Gujranwala", + "lon": 74.18705, + "lat": 32.15567, + "country": "Pakistan" + }, + { + "name": "Gustavia", + "lon": -62.84978, + "lat": 17.89618, + "country": "Saint Barthelemy" + }, + { + "name": "Gwangju", + "lon": 126.91556, + "lat": 35.15472, + "country": "South Korea" + }, + { + "name": "Hamburg", + "lon": 9.99302, + "lat": 53.55073, + "country": "Germany" + }, + { + "name": "Hanoi", + "lon": 105.84117, + "lat": 21.0245, + "country": "Vietnam" + }, + { + "name": "Harare", + "lon": 31.05337, + "lat": -17.82772, + "country": "Zimbabwe" + }, + { + "name": "Havana", + "lon": -82.38304, + "lat": 23.13302, + "country": "Cuba" + }, + { + "name": "Helsinki", + "lon": 24.93545, + "lat": 60.16952, + "country": "Finland" + }, + { + "name": "Ho Chi Minh City", + "lon": 106.62965, + "lat": 10.82302, + "country": "Vietnam" + }, + { + "name": "Hong Kong", + "lon": 114.17469, + "lat": 22.27832, + "country": "Hong Kong" + }, + { + "name": "Honiara", + "lon": 159.95, + "lat": -9.43333, + "country": "Solomon Islands" + }, + { + "name": "Honolulu", + "lon": -157.85833, + "lat": 21.30694, + "country": "United States" + }, + { + "name": "Houston", + "lon": -95.36327, + "lat": 29.76328, + "country": "United States" + }, + { + "name": "Hyderabad", + "lon": 78.45636, + "lat": 17.38405, + "country": "India" + }, + { + "name": "Hyderabad", + "lon": 68.37366, + "lat": 25.39242, + "country": "Pakistan" + }, + { + "name": "Ibadan", + "lon": 3.90591, + "lat": 7.37756, + "country": "Nigeria" + }, + { + "name": "Incheon", + "lon": 126.70515, + "lat": 37.45646, + "country": "South Korea" + }, + { + "name": "Isfahan", + "lon": 51.67462, + "lat": 32.65246, + "country": "Iran" + }, + { + "name": "Islamabad", + "lon": 73.04329, + "lat": 33.72148, + "country": "Pakistan" + }, + { + "name": "Istanbul", + "lon": 28.94966, + "lat": 41.01384, + "country": "Turkey" + }, + { + "name": "Izmir", + "lon": 27.13838, + "lat": 38.41273, + "country": "Turkey" + }, + { + "name": "Jaipur", + "lon": 75.78781, + "lat": 26.91962, + "country": "India" + }, + { + "name": "Jakarta", + "lon": 106.84513, + "lat": -6.21462, + "country": "Indonesia" + }, + { + "name": "Jeddah", + "lon": 39.18624, + "lat": 21.49012, + "country": "Saudi Arabia" + }, + { + "name": "Jerusalem", + "lon": 35.21633, + "lat": 31.76904, + "country": "Israel" + }, + { + "name": "Johannesburg", + "lon": 28.04363, + "lat": -26.20227, + "country": "South Africa" + }, + { + "name": "Juarez", + "lon": -106.46084, + "lat": 31.72024, + "country": "Mexico" + }, + { + "name": "Juba", + "lon": 31.58247, + "lat": 4.85165, + "country": "South Sudan" + }, + { + "name": "Kabul", + "lon": 69.17233, + "lat": 34.52813, + "country": "Afghanistan" + }, + { + "name": "Kaduna", + "lon": 7.43879, + "lat": 10.52641, + "country": "Nigeria" + }, + { + "name": "Kampala", + "lon": 32.58219, + "lat": 0.31628, + "country": "Uganda" + }, + { + "name": "Kano", + "lon": 8.51672, + "lat": 12.00012, + "country": "Nigeria" + }, + { + "name": "Kanpur", + "lon": 80.34975, + "lat": 26.46523, + "country": "India" + }, + { + "name": "Kaohsiung", + "lon": 120.31333, + "lat": 22.61626, + "country": "Taiwan" + }, + { + "name": "Karachi", + "lon": 67.0104, + "lat": 24.8608, + "country": "Pakistan" + }, + { + "name": "Karaj", + "lon": 50.99155, + "lat": 35.83266, + "country": "Iran" + }, + { + "name": "Kathmandu", + "lon": 85.3206, + "lat": 27.70169, + "country": "Nepal" + }, + { + "name": "Kawasaki", + "lon": 139.71722, + "lat": 35.52056, + "country": "Japan" + }, + { + "name": "Kharkiv", + "lon": 36.25272, + "lat": 49.98081, + "country": "Ukraine" + }, + { + "name": "Khartoum", + "lon": 32.53241, + "lat": 15.55177, + "country": "Sudan" + }, + { + "name": "Khulna", + "lon": 89.56439, + "lat": 22.80979, + "country": "Bangladesh" + }, + { + "name": "Kigali", + "lon": 30.05885, + "lat": -1.94995, + "country": "Rwanda" + }, + { + "name": "Kingsburg", + "lon": -119.554, + "lat": 36.5138, + "country": "United States" + }, + { + "name": "Kingston", + "lon": -76.79358, + "lat": 17.99702, + "country": "Jamaica" + }, + { + "name": "Kingstown", + "lon": -61.22742, + "lat": 13.15527, + "country": "Saint Vincent and the Grenadines" + }, + { + "name": "Kinshasa", + "lon": 15.31357, + "lat": -4.32758, + "country": "Democratic Republic of the Congo" + }, + { + "name": "Kobe", + "lon": 135.183, + "lat": 34.6913, + "country": "Japan" + }, + { + "name": "Kolkata", + "lon": 88.36304, + "lat": 22.56263, + "country": "India" + }, + { + "name": "Kota Bharu", + "lon": 102.24333, + "lat": 6.12361, + "country": "Malaysia" + }, + { + "name": "Kowloon", + "lon": 114.18333, + "lat": 22.31667, + "country": "Hong Kong" + }, + { + "name": "Kuala Lumpur", + "lon": 101.68653, + "lat": 3.1412, + "country": "Malaysia" + }, + { + "name": "Kumasi", + "lon": -1.62443, + "lat": 6.68848, + "country": "Ghana" + }, + { + "name": "Kuwait", + "lon": 47.97833, + "lat": 29.36972, + "country": "Kuwait" + }, + { + "name": "Kyiv", + "lon": 30.5238, + "lat": 50.45466, + "country": "Ukraine" + }, + { + "name": "Kyoto", + "lon": 135.75385, + "lat": 35.02107, + "country": "Japan" + }, + { + "name": "La Paz", + "lon": -68.15, + "lat": -16.5, + "country": "Bolivia" + }, + { + "name": "Lagos", + "lon": 3.39467, + "lat": 6.45407, + "country": "Nigeria" + }, + { + "name": "Lahore", + "lon": 74.35071, + "lat": 31.558, + "country": "Pakistan" + }, + { + "name": "Libreville", + "lon": 9.45356, + "lat": 0.39241, + "country": "Gabon" + }, + { + "name": "Lilongwe", + "lon": 33.78725, + "lat": -13.96692, + "country": "Malawi" + }, + { + "name": "Lima", + "lon": -77.02824, + "lat": -12.04318, + "country": "Peru" + }, + { + "name": "Lisbon", + "lon": -9.13333, + "lat": 38.71667, + "country": "Portugal" + }, + { + "name": "Ljubljana", + "lon": 14.50513, + "lat": 46.05108, + "country": "Slovenia" + }, + { + "name": "Lome", + "lon": 1.22154, + "lat": 6.12874, + "country": "Togo" + }, + { + "name": "London", + "lon": -0.12574, + "lat": 51.50853, + "country": "United Kingdom" + }, + { + "name": "Los Angeles", + "lon": -118.24368, + "lat": 34.05223, + "country": "United States" + }, + { + "name": "Luanda", + "lon": 13.23432, + "lat": -8.83682, + "country": "Angola" + }, + { + "name": "Lubumbashi", + "lon": 27.47938, + "lat": -11.66089, + "country": "Democratic Republic of the Congo" + }, + { + "name": "Lusaka", + "lon": 28.28713, + "lat": -15.40669, + "country": "Zambia" + }, + { + "name": "Luxembourg", + "lon": 6.13, + "lat": 49.61167, + "country": "Luxembourg" + }, + { + "name": "Macau", + "lon": 113.54611, + "lat": 22.20056, + "country": "Macao" + }, + { + "name": "Madrid", + "lon": -3.70256, + "lat": 40.4165, + "country": "Spain" + }, + { + "name": "Majuro", + "lon": 171.38027, + "lat": 7.08971, + "country": "Marshall Islands" + }, + { + "name": "Makassar", + "lon": 119.43194, + "lat": -5.14861, + "country": "Indonesia" + }, + { + "name": "Malabo", + "lon": 8.78166, + "lat": 3.75578, + "country": "Equatorial Guinea" + }, + { + "name": "Male", + "lon": 73.50916, + "lat": 4.17521, + "country": "Maldives" + }, + { + "name": "Mamoudzou", + "lon": 45.22878, + "lat": -12.78234, + "country": "Mayotte" + }, + { + "name": "Managua", + "lon": -86.2504, + "lat": 12.13282, + "country": "Nicaragua" + }, + { + "name": "Manama", + "lon": 50.58565, + "lat": 26.22787, + "country": "Bahrain" + }, + { + "name": "Manaus", + "lon": -60.025, + "lat": -3.10194, + "country": "Brazil" + }, + { + "name": "Manila", + "lon": 120.9822, + "lat": 14.6042, + "country": "Philippines" + }, + { + "name": "Maputo", + "lon": 32.58322, + "lat": -25.96553, + "country": "Mozambique" + }, + { + "name": "Maracaibo", + "lon": -71.61245, + "lat": 10.66663, + "country": "Venezuela" + }, + { + "name": "Maracay", + "lon": -67.59113, + "lat": 10.23535, + "country": "Venezuela" + }, + { + "name": "Mariehamn", + "lon": 19.93481, + "lat": 60.09726, + "country": "Aland Islands" + }, + { + "name": "Marigot", + "lon": -63.08302, + "lat": 18.06819, + "country": "Saint Martin" + }, + { + "name": "Maseru", + "lon": 27.48333, + "lat": -29.31667, + "country": "Lesotho" + }, + { + "name": "Mashhad", + "lon": 59.56796, + "lat": 36.31559, + "country": "Iran" + }, + { + "name": "Mbabane", + "lon": 31.13333, + "lat": -26.31667, + "country": "Eswatini" + }, + { + "name": "Mecca", + "lon": 39.82563, + "lat": 21.42664, + "country": "Saudi Arabia" + }, + { + "name": "Medan", + "lon": 98.66667, + "lat": 3.58333, + "country": "Indonesia" + }, + { + "name": "Medellin", + "lon": -75.56359, + "lat": 6.25184, + "country": "Colombia" + }, + { + "name": "Medina", + "lon": 39.61417, + "lat": 24.46861, + "country": "Saudi Arabia" + }, + { + "name": "Melbourne", + "lon": 144.96332, + "lat": -37.814, + "country": "Australia" + }, + { + "name": "Mexico City", + "lon": -99.12766, + "lat": 19.42847, + "country": "Mexico" + }, + { + "name": "Miami", + "lon": -80.19366, + "lat": 25.77427, + "country": "United States" + }, + { + "name": "Minsk", + "lon": 27.56667, + "lat": 53.9, + "country": "Belarus" + }, + { + "name": "Mogadishu", + "lon": 45.34375, + "lat": 2.03711, + "country": "Somalia" + }, + { + "name": "Monaco", + "lon": 7.41667, + "lat": 43.73333, + "country": "Monaco" + }, + { + "name": "Monrovia", + "lon": -10.7969, + "lat": 6.30054, + "country": "Liberia" + }, + { + "name": "Montevideo", + "lon": -56.18816, + "lat": -34.90328, + "country": "Uruguay" + }, + { + "name": "Montreal", + "lon": -73.58781, + "lat": 45.50884, + "country": "Canada" + }, + { + "name": "Moroni", + "lon": 43.25506, + "lat": -11.70216, + "country": "Comoros" + }, + { + "name": "Moscow", + "lon": 37.61556, + "lat": 55.75222, + "country": "Russia" + }, + { + "name": "Mosul", + "lon": 43.11889, + "lat": 36.335, + "country": "Iraq" + }, + { + "name": "Multan", + "lon": 71.47824, + "lat": 30.19679, + "country": "Pakistan" + }, + { + "name": "Mumbai", + "lon": 72.88261, + "lat": 19.07283, + "country": "India" + }, + { + "name": "Muscat", + "lon": 58.40778, + "lat": 23.58413, + "country": "Oman" + }, + { + "name": "N'Djamena", + "lon": 15.0444, + "lat": 12.10672, + "country": "Chad" + }, + { + "name": "Nagoya", + "lon": 136.90641, + "lat": 35.18147, + "country": "Japan" + }, + { + "name": "Nairobi", + "lon": 36.81667, + "lat": -1.28333, + "country": "Kenya" + }, + { + "name": "Nanchong", + "lon": 106.08473, + "lat": 30.79508, + "country": "China" + }, + { + "name": "Nanjing", + "lon": 118.77778, + "lat": 32.06167, + "country": "China" + }, + { + "name": "Nassau", + "lon": -77.34306, + "lat": 25.05823, + "country": "Bahamas" + }, + { + "name": "Nay Pyi Taw", + "lon": 96.12972, + "lat": 19.745, + "country": "Myanmar" + }, + { + "name": "New York", + "lon": -74.00597, + "lat": 40.71427, + "country": "United States" + }, + { + "name": "Niamey", + "lon": 2.1098, + "lat": 13.51366, + "country": "Niger" + }, + { + "name": "Nicosia", + "lon": 33.3642, + "lat": 35.17531, + "country": "Cyprus" + }, + { + "name": "Nouakchott", + "lon": -15.9785, + "lat": 18.08581, + "country": "Mauritania" + }, + { + "name": "Noumea", + "lon": 166.44884, + "lat": -22.27407, + "country": "New Caledonia" + }, + { + "name": "Novosibirsk", + "lon": 82.9346, + "lat": 55.0415, + "country": "Russia" + }, + { + "name": "Nuku'alofa", + "lon": -175.2018, + "lat": -21.13938, + "country": "Tonga" + }, + { + "name": "Nur-Sultan", + "lon": 71.44598, + "lat": 51.1801, + "country": "Kazakhstan" + }, + { + "name": "Nuuk", + "lon": -51.72157, + "lat": 64.18347, + "country": "Greenland" + }, + { + "name": "Oranjestad", + "lon": -70.02703, + "lat": 12.52398, + "country": "Aruba" + }, + { + "name": "Osaka", + "lon": 135.50218, + "lat": 34.69374, + "country": "Japan" + }, + { + "name": "Oslo", + "lon": 10.74609, + "lat": 59.91273, + "country": "Norway" + }, + { + "name": "Ottawa", + "lon": -75.69812, + "lat": 45.41117, + "country": "Canada" + }, + { + "name": "Ouagadougou", + "lon": -1.53388, + "lat": 12.36566, + "country": "Burkina Faso" + }, + { + "name": "Pago Pago", + "lon": -170.7025, + "lat": -14.27806, + "country": "American Samoa" + }, + { + "name": "Palembang", + "lon": 104.7458, + "lat": -2.91673, + "country": "Indonesia" + }, + { + "name": "Palo Alto", + "lon": -122.14302, + "lat": 37.44188, + "country": "United States" + }, + { + "name": "Panama", + "lon": -79.51973, + "lat": 8.9936, + "country": "Panama" + }, + { + "name": "Papeete", + "lon": -149.5665, + "lat": -17.53733, + "country": "French Polynesia" + }, + { + "name": "Paramaribo", + "lon": -55.16682, + "lat": 5.86638, + "country": "Suriname" + }, + { + "name": "Paris", + "lon": 2.3488, + "lat": 48.85341, + "country": "France" + }, + { + "name": "Perth", + "lon": 115.8614, + "lat": -31.95224, + "country": "Australia" + }, + { + "name": "Philadelphia", + "lon": -75.16379, + "lat": 39.95233, + "country": "United States" + }, + { + "name": "Phnom Penh", + "lon": 104.91601, + "lat": 11.56245, + "country": "Cambodia" + }, + { + "name": "Phoenix", + "lon": -112.07404, + "lat": 33.44838, + "country": "United States" + }, + { + "name": "Podgorica", + "lon": 19.26361, + "lat": 42.44111, + "country": "Montenegro" + }, + { + "name": "Port Louis", + "lon": 57.49889, + "lat": -20.16194, + "country": "Mauritius" + }, + { + "name": "Port Moresby", + "lon": 147.15089, + "lat": -9.47723, + "country": "Papua New Guinea" + }, + { + "name": "Port of Spain", + "lon": -61.51889, + "lat": 10.66668, + "country": "Trinidad and Tobago" + }, + { + "name": "Port-Vila", + "lon": 168.31366, + "lat": -17.73648, + "country": "Vanuatu" + }, + { + "name": "Port-au-Prince", + "lon": -72.33881, + "lat": 18.54349, + "country": "Haiti" + }, + { + "name": "Porto Alegre", + "lon": -51.23019, + "lat": -30.03283, + "country": "Brazil" + }, + { + "name": "Porto-Novo", + "lon": 2.60359, + "lat": 6.49646, + "country": "Benin" + }, + { + "name": "Prague", + "lon": 14.42076, + "lat": 50.08804, + "country": "Czechia" + }, + { + "name": "Praia", + "lon": -23.51254, + "lat": 14.93152, + "country": "Cabo Verde" + }, + { + "name": "Pretoria", + "lon": 28.18783, + "lat": -25.74486, + "country": "South Africa" + }, + { + "name": "Pristina", + "lon": 21.16688, + "lat": 42.67272, + "country": "Kosovo" + }, + { + "name": "Puebla", + "lon": -98.20346, + "lat": 19.03793, + "country": "Mexico" + }, + { + "name": "Pune", + "lon": 73.85535, + "lat": 18.51957, + "country": "India" + }, + { + "name": "Pyongyang", + "lon": 125.75432, + "lat": 39.03385, + "country": "North Korea" + }, + { + "name": "Quezon City", + "lon": 121.0509, + "lat": 14.6488, + "country": "Philippines" + }, + { + "name": "Quito", + "lon": -78.52495, + "lat": -0.22985, + "country": "Ecuador" + }, + { + "name": "Rabat", + "lon": -6.83255, + "lat": 34.01325, + "country": "Morocco" + }, + { + "name": "Rawalpindi", + "lon": 73.0479, + "lat": 33.59733, + "country": "Pakistan" + }, + { + "name": "Recife", + "lon": -34.88111, + "lat": -8.05389, + "country": "Brazil" + }, + { + "name": "Reykjavik", + "lon": -21.89541, + "lat": 64.13548, + "country": "Iceland" + }, + { + "name": "Riga", + "lon": 24.10589, + "lat": 56.946, + "country": "Latvia" + }, + { + "name": "Rio de Janeiro", + "lon": -43.18223, + "lat": -22.90642, + "country": "Brazil" + }, + { + "name": "Riyadh", + "lon": 46.72185, + "lat": 24.68773, + "country": "Saudi Arabia" + }, + { + "name": "Road Town", + "lon": -64.62079, + "lat": 18.42693, + "country": "British Virgin Islands" + }, + { + "name": "Rome", + "lon": 12.51133, + "lat": 41.89193, + "country": "Italy" + }, + { + "name": "Roseau", + "lon": -61.38808, + "lat": 15.30174, + "country": "Dominica" + }, + { + "name": "Saint George's", + "lon": -61.75226, + "lat": 12.05288, + "country": "Grenada" + }, + { + "name": "Saint Helier", + "lon": -2.10491, + "lat": 49.18804, + "country": "Jersey" + }, + { + "name": "Saint John's", + "lon": -61.84329, + "lat": 17.12096, + "country": "Antigua and Barbuda" + }, + { + "name": "Saint Peter Port", + "lon": -2.53527, + "lat": 49.45981, + "country": "Guernsey" + }, + { + "name": "Saint Petersburg", + "lon": 30.31413, + "lat": 59.93863, + "country": "Russia" + }, + { + "name": "Saint-Denis", + "lon": 55.4504, + "lat": -20.88231, + "country": "Reunion" + }, + { + "name": "Saint-Pierre", + "lon": -56.1773, + "lat": 46.77914, + "country": "Reunion" + }, + { + "name": "Saipan", + "lon": 145.7545, + "lat": 15.21233, + "country": "Northern Mariana Islands" + }, + { + "name": "Salvador", + "lon": -38.51083, + "lat": -12.97111, + "country": "Brazil" + }, + { + "name": "San Antonio", + "lon": -98.49363, + "lat": 29.42412, + "country": "United States" + }, + { + "name": "San Diego", + "lon": -117.16472, + "lat": 32.71571, + "country": "United States" + }, + { + "name": "San Francisco", + "lon": -122.41942, + "lat": 37.77493, + "country": "United States" + }, + { + "name": "San Jose", + "lon": -84.08333, + "lat": 9.93333, + "country": "United States" + }, + { + "name": "San Juan", + "lon": -66.10572, + "lat": 18.46633, + "country": "Argentina" + }, + { + "name": "San Marino", + "lon": 12.44639, + "lat": 43.93667, + "country": "United States" + }, + { + "name": "San Salvador", + "lon": -89.18718, + "lat": 13.68935, + "country": "El Salvador" + }, + { + "name": "Sanaa", + "lon": 44.20667, + "lat": 15.35472, + "country": "Yemen" + }, + { + "name": "Santa Cruz de la Sierra", + "lon": -63.18117, + "lat": -17.78629, + "country": "Bolivia" + }, + { + "name": "Santiago", + "lon": -70.64827, + "lat": -33.45694, + "country": "Chile" + }, + { + "name": "Santo Domingo", + "lon": -69.89232, + "lat": 18.47186, + "country": "Dominican Republic" + }, + { + "name": "Sao Paulo", + "lon": -46.63611, + "lat": -23.5475, + "country": "Brazil" + }, + { + "name": "Sao Tome", + "lon": 6.72732, + "lat": 0.33654, + "country": "Sao Tome and Principe" + }, + { + "name": "Sapporo", + "lon": 141.35, + "lat": 43.06667, + "country": "Japan" + }, + { + "name": "Sarajevo", + "lon": 18.35644, + "lat": 43.84864, + "country": "Bosnia and Herzegovina" + }, + { + "name": "Seattle", + "lon": -122.33207, + "lat": 47.60621, + "country": "United States" + }, + { + "name": "Semarang", + "lon": 110.42083, + "lat": -6.99306, + "country": "Indonesia" + }, + { + "name": "Seoul", + "lon": 126.9784, + "lat": 37.566, + "country": "South Korea" + }, + { + "name": "Shanghai", + "lon": 121.45806, + "lat": 31.22222, + "country": "China" + }, + { + "name": "Sharjah", + "lon": 55.41206, + "lat": 25.33737, + "country": "United Arab Emirates" + }, + { + "name": "Shenzhen", + "lon": 114.0683, + "lat": 22.54554, + "country": "China" + }, + { + "name": "Singapore", + "lon": 103.85007, + "lat": 1.28967, + "country": "Singapore" + }, + { + "name": "Skopje", + "lon": 21.43141, + "lat": 41.99646, + "country": "North Macedonia" + }, + { + "name": "Sofia", + "lon": 23.32415, + "lat": 42.69751, + "country": "Bulgaria" + }, + { + "name": "South Tangerang", + "lon": 106.71789, + "lat": -6.28862, + "country": "Indonesia" + }, + { + "name": "Soweto", + "lon": 27.85849, + "lat": -26.26781, + "country": "South Africa" + }, + { + "name": "Stockholm", + "lon": 18.06871, + "lat": 59.32938, + "country": "Sweden" + }, + { + "name": "Sucre", + "lon": -65.26274, + "lat": -19.03332, + "country": "Bolivia" + }, + { + "name": "Surabaya", + "lon": 112.75083, + "lat": -7.24917, + "country": "Indonesia" + }, + { + "name": "Surat", + "lon": 72.83023, + "lat": 21.19594, + "country": "India" + }, + { + "name": "Suva", + "lon": 178.44149, + "lat": -18.14161, + "country": "Fiji" + }, + { + "name": "Sydney", + "lon": 151.20732, + "lat": -33.86785, + "country": "Australia" + }, + { + "name": "Tabriz", + "lon": 46.2919, + "lat": 38.08, + "country": "Iran" + }, + { + "name": "Taipei", + "lon": 121.53185, + "lat": 25.04776, + "country": "Taiwan" + }, + { + "name": "Tallinn", + "lon": 24.75353, + "lat": 59.43696, + "country": "Estonia" + }, + { + "name": "Tangerang", + "lon": 106.63, + "lat": -6.17806, + "country": "Indonesia" + }, + { + "name": "Tarawa", + "lon": 172.97696, + "lat": 1.3278, + "country": "Kiribati" + }, + { + "name": "Tashkent", + "lon": 69.21627, + "lat": 41.26465, + "country": "Uzbekistan" + }, + { + "name": "Tbilisi", + "lon": 44.83368, + "lat": 41.69411, + "country": "Georgia" + }, + { + "name": "Tegucigalpa", + "lon": -87.20681, + "lat": 14.0818, + "country": "Honduras" + }, + { + "name": "Tehran", + "lon": 51.42151, + "lat": 35.69439, + "country": "Iran" + }, + { + "name": "Tel Aviv", + "lon": 34.78057, + "lat": 32.08088, + "country": "Israel" + }, + { + "name": "Thimphu", + "lon": 89.64191, + "lat": 27.46609, + "country": "Bhutan" + }, + { + "name": "Tianjin", + "lon": 117.17667, + "lat": 39.14222, + "country": "China" + }, + { + "name": "Tijuana", + "lon": -117.00371, + "lat": 32.5027, + "country": "Mexico" + }, + { + "name": "Tirana", + "lon": 19.81889, + "lat": 41.3275, + "country": "Albania" + }, + { + "name": "Tokyo", + "lon": 139.69171, + "lat": 35.6895, + "country": "Japan" + }, + { + "name": "Toronto", + "lon": -79.4163, + "lat": 43.70011, + "country": "Canada" + }, + { + "name": "Torshavn", + "lon": -6.77164, + "lat": 62.00973, + "country": "Faroe Islands" + }, + { + "name": "Tripoli", + "lon": 13.18733, + "lat": 32.88743, + "country": "Libya" + }, + { + "name": "Tunis", + "lon": 10.16579, + "lat": 36.81897, + "country": "Tunisia" + }, + { + "name": "Ulan Bator", + "lon": 106.88324, + "lat": 47.90771, + "country": "Mongolia" + }, + { + "name": "Vaduz", + "lon": 9.52154, + "lat": 47.14151, + "country": "Liechtenstein" + }, + { + "name": "Valencia", + "lon": -68.00765, + "lat": 10.16202, + "country": "Venezuela" + }, + { + "name": "Valletta", + "lon": 14.5148, + "lat": 35.89968, + "country": "Malta" + }, + { + "name": "Vancouver", + "lon": -123.11934, + "lat": 49.24966, + "country": "Canada" + }, + { + "name": "Victoria", + "lon": 55.45501, + "lat": -4.62001, + "country": "Canada" + }, + { + "name": "Vienna", + "lon": 16.37208, + "lat": 48.20849, + "country": "Austria" + }, + { + "name": "Vientiane", + "lon": 102.6, + "lat": 17.96667, + "country": "Laos" + }, + { + "name": "Vilnius", + "lon": 25.2798, + "lat": 54.68916, + "country": "Lithuania" + }, + { + "name": "Warsaw", + "lon": 21.01178, + "lat": 52.22977, + "country": "Poland" + }, + { + "name": "Washington", + "lon": -77.03637, + "lat": 38.89511, + "country": "United States" + }, + { + "name": "Wellington", + "lon": 174.77557, + "lat": -41.28664, + "country": "New Zealand" + }, + { + "name": "Willemstad", + "lon": -68.93354, + "lat": 12.1084, + "country": "Curacao" + }, + { + "name": "Windhoek", + "lon": 17.08323, + "lat": -22.55941, + "country": "Namibia" + }, + { + "name": "Wuhan", + "lon": 114.26667, + "lat": 30.58333, + "country": "China" + }, + { + "name": "Xi'an", + "lon": 108.92861, + "lat": 34.25833, + "country": "China" + }, + { + "name": "Yamoussoukro", + "lon": -5.27674, + "lat": 6.82055, + "country": "Ivory Coast" + }, + { + "name": "Yangon", + "lon": 96.15611, + "lat": 16.80528, + "country": "Myanmar" + }, + { + "name": "Yaounde", + "lon": 11.51667, + "lat": 3.86667, + "country": "Cameroon" + }, + { + "name": "Yekaterinburg", + "lon": 60.6122, + "lat": 56.8519, + "country": "Russia" + }, + { + "name": "Yerevan", + "lon": 44.51361, + "lat": 40.18111, + "country": "Armenia" + }, + { + "name": "Yokohama", + "lon": 139.65, + "lat": 35.43333, + "country": "Japan" + }, + { + "name": "Zagreb", + "lon": 15.97798, + "lat": 45.81444, + "country": "Croatia" + } +] \ No newline at end of file From 5e185fef48a239ac490bbc19f86540bcf499ecbf Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 18 Nov 2024 23:21:30 -0500 Subject: [PATCH 113/267] Added a base test for the nearby list interactor --- .../nearby_list/NearbyListInteractor.java | 1 - .../note/NearbyListInteractorTest.java | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/java/use_case/note/NearbyListInteractorTest.java diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java index 5dfc90dfd..612679209 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java @@ -23,7 +23,6 @@ public void execute(NearbyListInputData nearbyListInputData) { final ArrayList cities = (ArrayList) cityDataAccess.getNearbyCities(latitude, longitude); final NearbyListOutputData outputData = new NearbyListOutputData(cities, false); outputBoundary.presentSuccessView(outputData); - } catch (IOException exception) { outputBoundary.prepareFailView("Error: " + exception.getMessage()); diff --git a/src/test/java/use_case/note/NearbyListInteractorTest.java b/src/test/java/use_case/note/NearbyListInteractorTest.java new file mode 100644 index 000000000..2044d0891 --- /dev/null +++ b/src/test/java/use_case/note/NearbyListInteractorTest.java @@ -0,0 +1,36 @@ +package use_case.note; + +import org.junit.Test; +import use_case.note.nearby_list.*; + +import java.io.IOException; +import java.util.List; + +public class NearbyListInteractorTest { + + @Test + public void testOutput() { + NearbyCitiesAccessInterface cityDAO = new NearbyCitiesAccessInterface() { + @Override + public List getNearbyCities(Float latitude, Float longitude) throws IOException { + return List.of(); + } + }; + + NearbyListOutputBoundary cityOB = new NearbyListOutputBoundary() { + @Override + public void presentSuccessView(NearbyListOutputData nearbyListOutputData) { + + } + + @Override + public void prepareFailView(String errorMessage) { + + } + }; + + NearbyListInteractor cityInteractor = new NearbyListInteractor(cityOB, cityDAO); + NearbyListInputData input = new NearbyListInputData(0.0f, 0.0f); + cityInteractor.execute(input); + } +} From 9fd08e0048c8f26bb9f87c9dc76beaec6a474fb8 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Tue, 19 Nov 2024 20:29:03 -0500 Subject: [PATCH 114/267] Controller --- .../alert_pop/AlertPopController.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/interface_adapter/alert_pop/AlertPopController.java diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopController.java b/src/main/java/interface_adapter/alert_pop/AlertPopController.java new file mode 100644 index 000000000..60911b4a4 --- /dev/null +++ b/src/main/java/interface_adapter/alert_pop/AlertPopController.java @@ -0,0 +1,22 @@ +package interface_adapter.alert_pop; + +import use_case.note.alert_pop.AlertPopInputBoundary; +import use_case.note.alert_pop.AlertPopInputData; + +public class AlertPopController { + private final AlertPopInputBoundary alertPopInputInteractor; + + public alertPopController(AlertPopInputBoundary alertPopInputInteractor) { + this.alertPopInputInteractor = alertPopInputInteractor; + } + + /** + * Executes the Alert Pop Use Case. + * @param cityName the name of the user's city. + */ + public void execute(String cityName) { + final AlertPopInputData alertPopInputData = new AlertPopInputData(cityName); + + alertPopInputInteractor.execute(alertPopInputData); + } +} From d6aeca860198dafb2d9bdf1a86895d1ff6f2cb14 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Tue, 19 Nov 2024 20:32:40 -0500 Subject: [PATCH 115/267] Alert Pop Controller --- .../alert_pop/AlertPopController.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopController.java b/src/main/java/interface_adapter/alert_pop/AlertPopController.java index 60911b4a4..a29efa893 100644 --- a/src/main/java/interface_adapter/alert_pop/AlertPopController.java +++ b/src/main/java/interface_adapter/alert_pop/AlertPopController.java @@ -3,11 +3,14 @@ import use_case.note.alert_pop.AlertPopInputBoundary; import use_case.note.alert_pop.AlertPopInputData; +/** + * The controller for the Alert Pop Use Case. + */ public class AlertPopController { - private final AlertPopInputBoundary alertPopInputInteractor; + private final AlertPopInputBoundary alertPopInteractor; - public alertPopController(AlertPopInputBoundary alertPopInputInteractor) { - this.alertPopInputInteractor = alertPopInputInteractor; + public AlertPopController(AlertPopInputBoundary alertPopInteractor) { + this.alertPopInteractor = alertPopInteractor; } /** @@ -17,6 +20,6 @@ public alertPopController(AlertPopInputBoundary alertPopInputInteractor) { public void execute(String cityName) { final AlertPopInputData alertPopInputData = new AlertPopInputData(cityName); - alertPopInputInteractor.execute(alertPopInputData); + alertPopInteractor.execute(alertPopInputData); } } From 6ceab770626999c2cee8f8fb1081e6f6e649c0f6 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Wed, 20 Nov 2024 23:56:32 -0500 Subject: [PATCH 116/267] Updated SearchResult and AddConvert UseCases. --- src/main/java/app/AppBuilder.java | 161 +++++++++++++++++++++ src/main/java/app/MainNoteApplication.java | 8 +- src/main/java/app/NoteAppBuilder.java | 136 ----------------- 3 files changed, 165 insertions(+), 140 deletions(-) create mode 100644 src/main/java/app/AppBuilder.java delete mode 100644 src/main/java/app/NoteAppBuilder.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java new file mode 100644 index 000000000..bdaa15573 --- /dev/null +++ b/src/main/java/app/AppBuilder.java @@ -0,0 +1,161 @@ +package app; + +import javax.swing.JFrame; +import javax.swing.WindowConstants; + +import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.SearchResult.SearchResultPresenter; +import interface_adapter.converter.ConverterController; +import interface_adapter.converter.ConverterPresenter; +import interface_adapter.weather.WeatherViewModel; +import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.note.SearchResultInteractor; +import use_case.note.WeatherDataAccessInterface; +import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; +import use_case.note.convert_farenheit.ConvertInteractor; +import use_case.note.search_result.SearchResultOutputBoundary; +import view.MainView; + +/** + * Builder for the Note Application. + */ +public class AppBuilder { + public static final int HEIGHT = 750; + public static final int WIDTH = 1500; + private WeatherDataAccessInterface weatherDAO; + private HistoricalWeatherDataAccessInterface historyDAO; + private WeatherViewModel weatherViewModel = new WeatherViewModel(); + private MainView mainView; + private NoteInteractor interactor; + + /** + * Sets the DAO to be used in this application. + * @param weatherDataAccess the DAO to use + * @return this builder + */ + public AppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { + weatherDAO = weatherDataAccess; + return this; + } + + /** + * Builds the application. + * @return the JFrame for the application + */ + public JFrame build() { + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setTitle("Note Application"); + frame.setSize(WIDTH, HEIGHT); + + frame.add(mainView); + + // refresh so that the note will be visible when we start the program + interactor.executeRefresh(); + + return frame; + + } + + /** + * Creates the objects for the Note Use Case and connects the NoteView to its + * controller. + *

This method must be called after addNoteView!

+ * @return this builder + * @throws RuntimeException if this method is called before addNoteView + + */ + + public AppBuilder addSearchResultUseCase() { + final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(weatherViewModel); + final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); + + final SearchResultController controller = new SearchResultController(interactor); + if (mainView == null) { + throw new RuntimeException("addNoteView must be called before addSearchResultUseCase"); + } + mainView.setController(controller); + return this; + } + + public AppBuilder addAlertPopUseCase() { + // no presenter + } + + public AppBuilder addSearchReturnUseCase() { + // no presenter / controller + } + + public AppBuilder addSelectRegionUseCase() { + // no presenter / controller + } + + public AppBuilder addNearbyListUseCase() { + // no presenter / controller + } + + public AppBuilder addCompareCitiesUseCase() { + // no controller + } + + public AppBuilder addConvertUseCase() { + final ConvertFarenheitOutputBoundary outputBoundary = new ConverterPresenter(weatherViewModel); + final ConvertInteractor interactor = new ConvertInteractor(outputBoundary); + + final ConverterController controller = new ConverterController(interactor); + if (mainView == null) { + throw new RuntimeException("addNoteView must be called before addConvertUseCase"); + } + mainView.setController(controller); + return this; + } + + public AppBuilder addCloseListUseCase() { + // no presenter / controller + } + + public AppBuilder addPinWeatherUseCase() { + // no presenter / controller + } + + public AppBuilder addClosePinUseCase() { + // no presenter / controller + } + + public AppBuilder addClosePopUseCase() { + // no presenter / controller + } + + public AppBuilder addBookmarkReturnCase() { + // no presenter / controller + } + + public AppBuilder addCityBookmarkUseCase() { + // no presenter / controller + } + + // add stuff for all the views + public AppBuilder addSearchResultView() { + } + + public AppBuilder addSelectRegionView() { + } + + public AppBuilder addNearbyListView() { + } + + public AppBuilder addPinWeatherView() { + } + + public AppBuilder addAlertPopView() { + } + + public AppBuilder addCityBookmarkView() { + } + + public AppBuilder addMainView() { + weatherViewModel = new WeatherViewModel(); + mainView = new MainView(weatherViewModel); + return this; + } +} diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index 9ef9b0693..047a69fa2 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -48,9 +48,10 @@ public static void main(String[] args) { // create the data access and inject it into our builder! final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); - final NoteAppBuilder builder = new NoteAppBuilder(); + final AppBuilder builder = new AppBuilder(); builder.addNoteDAO(noteDataAccess) - .addNoteView() + .addMainView() + .addConvertUseCase() .addSearchResultView() .addSelectRegionView() .addNearbyListView() @@ -67,8 +68,7 @@ public static void main(String[] args) { .addAlertPopUseCase() .addClosePopUseCase() .addCityBookmarkUseCase() - .addBookmarkReturnCase() - .addNoteUseCase().build().setVisible(true); + .addBookmarkReturnCase().build().setVisible(true); // Annie: What should I do with the last line? First, I don't know if I need to add setVisible to all methods. // Second, I assume noteView to be default view, and noteUseCase be return to the default view with empty // search bar. diff --git a/src/main/java/app/NoteAppBuilder.java b/src/main/java/app/NoteAppBuilder.java deleted file mode 100644 index ea2a3a58a..000000000 --- a/src/main/java/app/NoteAppBuilder.java +++ /dev/null @@ -1,136 +0,0 @@ -package app; - -import javax.swing.JFrame; -import javax.swing.WindowConstants; - -import interface_adapter.weather.WeatherController; -import interface_adapter.weather.WeatherPresenter; -import interface_adapter.weather.WeatherViewModel; -import use_case.note.WeatherDataAccessInterface; -import use_case.note.NoteInteractor; -import use_case.note.NoteOutputBoundary; -import view.NoteView; - -/** - * Builder for the Note Application. - */ -public class NoteAppBuilder { - public static final int HEIGHT = 750; - public static final int WIDTH = 1500; - private WeatherDataAccessInterface noteDAO; - private NoteViewModel noteViewModel = new NoteViewModel(); - private NoteView noteView; - private NoteInteractor noteInteractor; - - /** - * Sets the NoteDAO to be used in this application. - * @param weatherDataAccess the DAO to use - * @return this builder - */ - public NoteAppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { - noteDAO = weatherDataAccess; - return this; - } - - /** - * Creates the objects for the Note Use Case and connects the NoteView to its - * controller. - *

This method must be called after addNoteView!

- * @return this builder - * @throws RuntimeException if this method is called before addNoteView - */ - public NoteAppBuilder addNoteUseCase() { - final NoteOutputBoundary noteOutputBoundary = new WeatherPresenter(noteViewModel); - noteInteractor = new NoteInteractor( - noteDAO, noteOutputBoundary); - - final WeatherController controller = new WeatherController(noteInteractor); - if (noteView == null) { - throw new RuntimeException("addNoteView must be called before addNoteUseCase"); - } - noteView.setNoteController(controller); - return this; - } - - /** - * Creates the NoteView and underlying NoteViewModel. - * @return this builder - */ - public NoteAppBuilder addNoteView() { - noteViewModel = new NoteViewModel(); - noteView = new NoteView(noteViewModel); - return this; - } - - /** - * Builds the application. - * @return the JFrame for the application - */ - public JFrame build() { - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Note Application"); - frame.setSize(WIDTH, HEIGHT); - - frame.add(noteView); - - // refresh so that the note will be visible when we start the program - noteInteractor.executeRefresh(); - - return frame; - - } - - public NoteAppBuilder addSearchResultView() { - } - - public NoteAppBuilder addSelectRegionView() { - return null; - } - - public NoteAppBuilder addNearbyListView() { - } - - public NoteAppBuilder addPinWeatherView() { - } - - public NoteAppBuilder addAlertPopView() { - } - - public NoteAppBuilder addCityBookmarkView() { - } - - public NoteAppBuilder addSearchResultUseCase() { - } - - public NoteAppBuilder addSearchReturnUseCase() { - } - - public NoteAppBuilder addSelectRegionUseCase() { - } - - public NoteAppBuilder addNearbyListUseCase() { - } - - public NoteAppBuilder addCloseListUseCase() { - } - - public NoteAppBuilder addPinWeatherUseCase() { - } - - public NoteAppBuilder addClosePinUseCase() { - } - - public NoteAppBuilder addAlertPopUseCase() { - } - - public NoteAppBuilder addClosePopUseCase() { - } - - public NoteAppBuilder addBookmarkReturnCase() { - } - - public NoteAppBuilder addCityBookmarkUseCase() { - return null; - } -} From 61b770528ac7a586b97632a78471cee6d40f83ba Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 21 Nov 2024 00:40:27 -0500 Subject: [PATCH 117/267] Fixed the Discrepencies in the parameters in HistoricalWeatherDataAccessObject, WeatherDataAccessObject and Weather. Set conclusive parameter and deleted Icons. --- .../HistoricalWeatherDataAccessObject.java | 19 ++++---- .../data_access/WeatherDataAccessObject.java | 8 ++-- src/main/java/entity/Weather.java | 47 ++++++++++++++----- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 0bc5c6e33..65de832a0 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -26,12 +26,12 @@ public void saveWeather(Weather weather, String timeStamp) { final StringBuilder jsonBuilder = new StringBuilder(); jsonBuilder.append("{\n"); jsonBuilder.append(" \"timeStamp\": \"" + timeStamp + nextLine); - jsonBuilder.append(" \"city\": \"" + weather.getCity() + nextLine); - jsonBuilder.append(" \"longitude\": " + weather.getLongitude() + nextLine); - jsonBuilder.append(" \"latitude\": ").append(weather.getLatitude()).append(nextLine); + jsonBuilder.append(" \"city\": \"" + weather.getCityName() + nextLine); + jsonBuilder.append(" \"longitude\": " + weather.getLon() + nextLine); + jsonBuilder.append(" \"latitude\": ").append(weather.getLat()).append(nextLine); jsonBuilder.append(" \"temperature\": ").append(weather.getTemperature()).append(nextLine); - jsonBuilder.append(" \"looks\": \"").append(weather.getLooks()).append(nextLine); - jsonBuilder.append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append(nextLine); + jsonBuilder.append(" \"looks\": \"").append(weather.getWeather()).append(nextLine); + jsonBuilder.append(" \"alertDescription\": \"").append(weather.getDescription()).append(nextLine); jsonBuilder.append(" \"humidity\": " + weather.getHumidity() + nextLine); jsonBuilder.append(" \"windSpeed\": " + weather.getWindSpeed() + nextLine); jsonBuilder.append("}"); @@ -69,17 +69,18 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Getting the timestamp from the JSONObject final String timeStamp = weatherObject.getString("timeStamp"); // Checking if the city and timestamp match the input - if (cityNameCall.equals(cityNameCall) && timeStamp.equals(timestamp)) { + if (cityNameCall.equals(city) && timeStamp.equals(timestamp)) { // Create weather object final Weather weather = new Weather( cityNameCall, - weatherObject.getInt("longitude"), - weatherObject.getInt("latitude"), weatherObject.getInt("temperature"), weatherObject.getString("looks"), weatherObject.getString("alertDescription"), + weatherObject.getInt("windSpeed"), + weatherObject.getInt("longitude"), weatherObject.getInt("humidity"), - weatherObject.getInt("windSpeed") + weatherObject.getInt("longitude"), + weatherObject.getInt("latitude") ); return weather; } diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 6cf6936b6..78fc4dff5 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -59,16 +59,16 @@ public Weather getWeather(String citySearch) throws IOException { final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); - String alertDescription = "No alerts"; + final int visibility = weatherJSON.getInt("visibility"); + String alertDescription = weatherJSON.getJSONObject("weather").getString("description"); if (weatherJSON.has("alerts")) { final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); if (alertsArray.length() > 0) { alertDescription = alertsArray.getJSONObject(0).getString("description"); } } - - return new Weather(citySearch, lon, lat, temp, looks, alertDescription, humidity, windspeed); - + return new Weather(citySearch, temp, looks, alertDescription, windspeed, humidity, + visibility, lon, lat); } else { throw new IOException(responseBody.getString(MESSAGE)); diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 0453924fc..829b5dfd4 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -8,22 +8,54 @@ public class Weather { private float temperature; private String weather; private final String description; - private final String icon; private float windSpeed; private final int humidity; private final int visibility; private boolean metric; + private String cityName; + private int lon; + private int lat; - public Weather(float temperature, String weather, String description, String icon, float windSpeed, int humidity, - int visibility) { + public Weather(String city, float temperature, String weather, String description, + float windSpeed, int humidity, int visibility, int lon, int lat) { this.temperature = temperature; this.weather = weather; this.description = description; - this.icon = icon; this.windSpeed = windSpeed; this.humidity = humidity; this.visibility = visibility; + this.cityName = city; this.metric = false; + this.lon = lon; + this.lat = lat; + } + + public void setWeather(String weather) { + this.weather = weather; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public int getLat() { + return lat; + } + + public void setLat(int lat) { + this.lat = lat; + } + + public int getLon() { + return lon; + } + + public void setLon(int lon) { + this.lon = lon; } public boolean isMetric() { @@ -38,18 +70,11 @@ public void setTemperature(float temperature) { this.temperature = temperature; } - public String getIcon() { - return icon; - } public String getDescription() { return description; } - public void setWeather(double weather) { - this.weather = weather; - } - public void setWindSpeed(float windSpeed) { this.windSpeed = windSpeed; } From a638861a080cba3929218d7bed5e8ad80d820a0a Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 21 Nov 2024 00:52:59 -0500 Subject: [PATCH 118/267] Forgot one little mistake for saveweather --- src/main/java/data_access/WeatherDataAccessObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 78fc4dff5..bcc981e50 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -80,7 +80,7 @@ public Weather getWeather(String citySearch) throws IOException { } public void saveWeather(Weather weather) { - weathers.put(weather.getCity(), weather); + weathers.put(weather.getCityName(), weather); } } From 2f1ccf777470bbf5007d6b0f1e10871b79e040b2 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 21 Nov 2024 01:04:18 -0500 Subject: [PATCH 119/267] Ensured CompareCitiesDataAccessInterface abides by WeatherDataAccessObject --- .../data_access/WeatherDataAccessObject.java | 1 + .../CompareCitiesDataAccessInterface.java | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index bcc981e50..6b135d58c 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -7,6 +7,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONArray; + import use_case.note.CompareCities.CompareCitiesDataAccessInterface; import use_case.note.WeatherDataAccessInterface; diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java index 9609ad7e2..0bba951fd 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -2,10 +2,42 @@ import entity.Weather; +import java.io.IOException; + +/** + * Interface for the Comparing Cities Use case. + */ public interface CompareCitiesDataAccessInterface { + /** + * Check if City exists. + * @param cityname the weather is displayed for + * @return if city exists + */ boolean citynotexist(String cityname); - Weather getWeather(String cityname); + + /** + * Creates the Weather. + * @param cityname the weather is displayed for + * @return the weather information + * @throws IOException if the city does not exist or oi. + */ + Weather getWeather(String cityname) throws IOException; + + /** + * Saves the Weather. + * @param cityname the weather is saved + */ void saveWeather(String cityname); + + /** + * Returns the City. + * @return the city + * */ String getCurrentCity(); + + /** + * Sets city. + * @param cityname the weather is for + */ void setCurrentCity(String cityname); } From afaf70d63ad3d9c6ee379370334a34ec56b03979 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 21 Nov 2024 19:25:20 -0500 Subject: [PATCH 120/267] bug fixed for dao and entity --- src/main/java/entity/Weather.java | 2 +- .../SearchResult/SearchResultController.java | 8 ++++---- .../note/HistoricalWeatherDataAccessInterface.java | 3 ++- src/main/java/use_case/note/SearchResultInteractor.java | 6 ++++-- .../note/search_result/SearchResultInputData.java | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 0453924fc..20baafd93 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -46,7 +46,7 @@ public String getDescription() { return description; } - public void setWeather(double weather) { + public void setWeather(String weather) { this.weather = weather; } diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultController.java b/src/main/java/interface_adapter/SearchResult/SearchResultController.java index 9d58fd126..24c78221a 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultController.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultController.java @@ -8,11 +8,11 @@ */ public class SearchResultController { - private final SearchResultInputBoundary searchResultInteractor; + private final SearchResultInputBoundary searchResultInputBoundary; // Constructor that injects the use case's input boundary - public SearchResultController(SearchResultInputBoundary searchResultInteractor) { - this.searchResultInteractor = searchResultInteractor; + public SearchResultController(SearchResultInputBoundary searchResultInputBoundary) { + this.searchResultInputBoundary = searchResultInputBoundary; } /** @@ -25,7 +25,7 @@ public void execute(String cityName, String date) { // Create a SearchResultInputData object to encapsulate the input data final SearchResultInputData inputData = new SearchResultInputData(cityName, date); // Call the use case's execute method with the input data - searchResultInteractor.execute(inputData); + searchResultInputBoundary.execute(inputData); } } diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index 904670ccf..c4c629cdb 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -13,9 +13,10 @@ public interface HistoricalWeatherDataAccessInterface { * Saves the weather data. * @param weather the weather data to save * @param timstamp the timestamp of the weather data + * @param City the city of the weather data * @throws IOException if there is an error saving the weather data */ - void saveWeather(Weather weather, String timstamp) throws IOException; + void saveWeather(Weather weather, String timstamp, String City) throws IOException; /** * Gets the weather data. diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 3ed852d83..4239fbf58 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -45,10 +45,12 @@ private void fetchWeatherData() { final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); final String timestamp = formatter.format(Instant.now()); + final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city, timestamp); + // Send it to the output boundary final SearchResultOutputData outputData = - new SearchResultOutputData(city, historicalWeatherData, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); + new SearchResultOutputData(city, historicalWeather, false); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp, city); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index f15ab28b1..b21ced456 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -12,7 +12,7 @@ public SearchResultInputData(String cityName, String date) { this.date = date; } - public String getCity() { + public static String getCity() { return this.city; } From 578a4eb1ef456faf71762cc2b81217a935615c45 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Thu, 21 Nov 2024 20:22:30 -0500 Subject: [PATCH 121/267] deleted some use cases --- src/main/java/app/MainNoteApplication.java | 12 ++-------- .../alert_pop/AlertPopPresenter.java | 8 +++++++ .../BookmarkReturnInputBoundary.java | 7 ------ .../BookmarkReturnInputData.java | 5 ---- .../BookmarkReturnOutputBoundary.java | 8 ------- .../BookmarkReturnOutputData.java | 14 ----------- .../CityBookmarkInputBoundary.java | 8 ------- .../city_bookmark/CityBookmarkInputData.java | 6 ----- .../CityBookmarkOutputBoundary.java | 8 ------- .../city_bookmark/CityBookmarkOutputData.java | 22 ------------------ .../close_list/CloseListInputBoundary.java | 7 ------ .../note/close_list/CloseListInputData.java | 5 ---- .../close_list/CloseListOutputBoundary.java | 8 ------- .../note/close_list/CloseListOutputData.java | 14 ----------- .../note/close_pin/ClosePinInputBoundary.java | 7 ------ .../note/close_pin/ClosePinInputData.java | 5 ---- .../close_pin/ClosePinOutputBoundary.java | 8 ------- .../note/close_pin/ClosePinOutputData.java | 14 ----------- .../note/close_pop/ClosePopInputBoundary.java | 7 ------ .../note/close_pop/ClosePopInputData.java | 5 ---- .../close_pop/ClosePopOutputBoundary.java | 8 ------- .../note/close_pop/ClosePopOutputData.java | 14 ----------- .../SelectRegionInputBoundary.java | 7 ------ .../select_region/SelectRegionInputData.java | 5 ---- .../SelectRegionOutputBoundary.java | 8 ------- .../select_region/SelectRegionOutputData.java | 23 ------------------- 26 files changed, 10 insertions(+), 233 deletions(-) create mode 100644 src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java delete mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java delete mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java delete mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java delete mode 100644 src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java delete mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java delete mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java delete mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java delete mode 100644 src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java delete mode 100644 src/main/java/use_case/note/close_list/CloseListInputBoundary.java delete mode 100644 src/main/java/use_case/note/close_list/CloseListInputData.java delete mode 100644 src/main/java/use_case/note/close_list/CloseListOutputBoundary.java delete mode 100644 src/main/java/use_case/note/close_list/CloseListOutputData.java delete mode 100644 src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java delete mode 100644 src/main/java/use_case/note/close_pin/ClosePinInputData.java delete mode 100644 src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java delete mode 100644 src/main/java/use_case/note/close_pin/ClosePinOutputData.java delete mode 100644 src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java delete mode 100644 src/main/java/use_case/note/close_pop/ClosePopInputData.java delete mode 100644 src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java delete mode 100644 src/main/java/use_case/note/close_pop/ClosePopOutputData.java delete mode 100644 src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java delete mode 100644 src/main/java/use_case/note/select_region/SelectRegionInputData.java delete mode 100644 src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java delete mode 100644 src/main/java/use_case/note/select_region/SelectRegionOutputData.java diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java index 047a69fa2..4553283f1 100644 --- a/src/main/java/app/MainNoteApplication.java +++ b/src/main/java/app/MainNoteApplication.java @@ -51,24 +51,16 @@ public static void main(String[] args) { final AppBuilder builder = new AppBuilder(); builder.addNoteDAO(noteDataAccess) .addMainView() - .addConvertUseCase() + .addConvertUseCase() .addSearchResultView() - .addSelectRegionView() .addNearbyListView() .addPinWeatherView() .addAlertPopView() - .addCityBookmarkView() .addSearchResultUseCase() .addSearchReturnUseCase() - .addSelectRegionUseCase() .addNearbyListUseCase() - .addCloseListUseCase() .addPinWeatherUseCase() - .addClosePinUseCase() - .addAlertPopUseCase() - .addClosePopUseCase() - .addCityBookmarkUseCase() - .addBookmarkReturnCase().build().setVisible(true); + .addAlertPopUseCase().build().setVisible(true); // Annie: What should I do with the last line? First, I don't know if I need to add setVisible to all methods. // Second, I assume noteView to be default view, and noteUseCase be return to the default view with empty // search bar. diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java new file mode 100644 index 000000000..c65e176b1 --- /dev/null +++ b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java @@ -0,0 +1,8 @@ +package interface_adapter.alert_pop; + +import interface_adapter.weather.WeatherViewModel; +import use_case.note.alert_pop.AlertPopOutputBoundary; + +public class AlertPopPresenter implements AlertPopOutputBoundary { + private final WeatherViewModel +} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java deleted file mode 100644 index 4b46cafdd..000000000 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.bookmark_return; - -// The input is one click on "return". -public interface BookmarkReturnInputBoundary { - - void execute(BookmarkReturnInputData bookmarkReturnInputData); -} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java deleted file mode 100644 index e53789e11..000000000 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.bookmark_return; - -// The input is one click on "return". -public class BookmarkReturnInputData { -} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java deleted file mode 100644 index ce8bdd68d..000000000 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.bookmark_return; - -public interface BookmarkReturnOutputBoundary { - - void prepareSuccessView(BookmarkReturnOutputData bookmarkReturnOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java b/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java deleted file mode 100644 index 688222b79..000000000 --- a/src/main/java/use_case/note/bookmark_return/BookmarkReturnOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.bookmark_return; - -public class BookmarkReturnOutputData { - - private final boolean useCaseFailed; - - public BookmarkReturnOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java deleted file mode 100644 index b8cfda36e..000000000 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.city_bookmark; - -// The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the -// InputData. -public interface CityBookmarkInputBoundary { - - void execute(CityBookmarkInputBoundary cityBookmarkInputBoundary); -} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java deleted file mode 100644 index 47d6cb8a1..000000000 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkInputData.java +++ /dev/null @@ -1,6 +0,0 @@ -package use_case.note.city_bookmark; - -// The input only involves clicking open the bookmark tab, so I don't know if we need this, or how to write the -// InputData. -public class CityBookmarkInputData { -} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java deleted file mode 100644 index 02f755b2e..000000000 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.city_bookmark; - -public interface CityBookmarkOutputBoundary { - - void presentSuccessView(CityBookmarkOutputData cityBookmarkOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java b/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java deleted file mode 100644 index 55b08fce3..000000000 --- a/src/main/java/use_case/note/city_bookmark/CityBookmarkOutputData.java +++ /dev/null @@ -1,22 +0,0 @@ -package use_case.note.city_bookmark; - -import java.util.ArrayList; - -public class CityBookmarkOutputData { - - private final String[] cities; - private final boolean useCaseFailed; - - public CityBookmarkOutputData(String[] cities, boolean useCaseFailed) { - this.cities = cities; - this.useCaseFailed = useCaseFailed; - } - - public String getCities() { - return cities; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/close_list/CloseListInputBoundary.java b/src/main/java/use_case/note/close_list/CloseListInputBoundary.java deleted file mode 100644 index be422c7e9..000000000 --- a/src/main/java/use_case/note/close_list/CloseListInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.close_list; - -// Input is one click on "close". -public interface CloseListInputBoundary { - - void execute(CloseListInputBoundary closeListInputBoundary); -} diff --git a/src/main/java/use_case/note/close_list/CloseListInputData.java b/src/main/java/use_case/note/close_list/CloseListInputData.java deleted file mode 100644 index caba5f836..000000000 --- a/src/main/java/use_case/note/close_list/CloseListInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.close_list; - -// Input is one click on "close". -public class CloseListInputData { -} diff --git a/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java b/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java deleted file mode 100644 index fe3d9a723..000000000 --- a/src/main/java/use_case/note/close_list/CloseListOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.close_list; - -public interface CloseListOutputBoundary { - - void presentSuccessView(CloseListOutputData closeListOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/close_list/CloseListOutputData.java b/src/main/java/use_case/note/close_list/CloseListOutputData.java deleted file mode 100644 index e4a99360d..000000000 --- a/src/main/java/use_case/note/close_list/CloseListOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.close_list; - -public class CloseListOutputData { - - private final boolean useCaseFailed; - - public CloseListOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java deleted file mode 100644 index 1c679ef8c..000000000 --- a/src/main/java/use_case/note/close_pin/ClosePinInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.close_pin; - -// Input is a click on the "close" button. -public interface ClosePinInputBoundary { - - void execute(ClosePinInputData closePinInputData); -} diff --git a/src/main/java/use_case/note/close_pin/ClosePinInputData.java b/src/main/java/use_case/note/close_pin/ClosePinInputData.java deleted file mode 100644 index ba3f16d7c..000000000 --- a/src/main/java/use_case/note/close_pin/ClosePinInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.close_pin; - -// Input is a click on the "close" button. -public class ClosePinInputData { -} diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java b/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java deleted file mode 100644 index da4e3b1bc..000000000 --- a/src/main/java/use_case/note/close_pin/ClosePinOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.close_pin; - -public interface ClosePinOutputBoundary { - - void presentSuccessView(ClosePinOutputData closePinOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/close_pin/ClosePinOutputData.java b/src/main/java/use_case/note/close_pin/ClosePinOutputData.java deleted file mode 100644 index eab6e91f4..000000000 --- a/src/main/java/use_case/note/close_pin/ClosePinOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.close_pin; - -public class ClosePinOutputData { - - private final boolean useCaseFailed; - - public ClosePinOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java deleted file mode 100644 index 06cd776d8..000000000 --- a/src/main/java/use_case/note/close_pop/ClosePopInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.close_pop; - -// Input is a click on "close". -public interface ClosePopInputBoundary { - - void execute(ClosePopInputData closePopInputData); -} diff --git a/src/main/java/use_case/note/close_pop/ClosePopInputData.java b/src/main/java/use_case/note/close_pop/ClosePopInputData.java deleted file mode 100644 index dfeeafa7b..000000000 --- a/src/main/java/use_case/note/close_pop/ClosePopInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.close_pop; - -// Input is a click on "close". -public class ClosePopInputData { -} diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java b/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java deleted file mode 100644 index 4d881e40f..000000000 --- a/src/main/java/use_case/note/close_pop/ClosePopOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.close_pop; - -public interface ClosePopOutputBoundary { - - void presentSuccessView(ClosePopOutputData closePopOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/close_pop/ClosePopOutputData.java b/src/main/java/use_case/note/close_pop/ClosePopOutputData.java deleted file mode 100644 index 03ffe9913..000000000 --- a/src/main/java/use_case/note/close_pop/ClosePopOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.close_pop; - -public class ClosePopOutputData { - - private final boolean useCaseFailed; - - public ClosePopOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java deleted file mode 100644 index 17c3d0394..000000000 --- a/src/main/java/use_case/note/select_region/SelectRegionInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.select_region; - -// Input is a click on the region. -public interface SelectRegionInputBoundary { - - void execute(SelectRegionInputData selectRegionInputData); -} diff --git a/src/main/java/use_case/note/select_region/SelectRegionInputData.java b/src/main/java/use_case/note/select_region/SelectRegionInputData.java deleted file mode 100644 index 9d72aadd3..000000000 --- a/src/main/java/use_case/note/select_region/SelectRegionInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.select_region; - -// Input is a click on the region. -public class SelectRegionInputData { -} diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java b/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java deleted file mode 100644 index eca8cecf5..000000000 --- a/src/main/java/use_case/note/select_region/SelectRegionOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.select_region; - -public interface SelectRegionOutputBoundary { - - void presentSuccessView(SelectRegionOutputData selectRegionOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/select_region/SelectRegionOutputData.java b/src/main/java/use_case/note/select_region/SelectRegionOutputData.java deleted file mode 100644 index a8fe7a631..000000000 --- a/src/main/java/use_case/note/select_region/SelectRegionOutputData.java +++ /dev/null @@ -1,23 +0,0 @@ -package use_case.note.select_region; - -public class SelectRegionOutputData { - private final String location; - private final String weather; - private final boolean useCaseFailed; - - public SelectRegionOutputData(String location, String weather, boolean useCaseFailed) { - this.location = location; - this.weather = weather; - this.useCaseFailed = useCaseFailed; - } - - public String getLocation() { - return location; - } - - public String getWeather() {return weather;} - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} From eb226bbee46d660285353596431d475817477f9f Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 21 Nov 2024 20:29:55 -0500 Subject: [PATCH 122/267] Fixed the parameter for ConverterController.execute((Weather) evt.getSource()); --- src/main/java/view/WeatherPanelView.java | 81 ++++++++++++++---------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 29dab6a74..cf3158a72 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,72 +1,83 @@ package view; +import entity.Weather; +import interface_adapter.converter.ConverterController; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; import interface_adapter.weather.WeatherController; -import interface_adapter.converter.ConverterController; -import javax.swing.*; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Observer; -/* +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +/** * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch * of LabelTextPanel that displays varies weather information. * This part of view will have to change based on the output, so it depends on the view model - */ + **/ public class WeatherPanelView extends JPanel implements PropertyChangeListener, ActionListener { private final WeatherViewModel weatherViewModel; - private final SearchResultViewModel searchResultViewModel; + private SearchResultViewModel searchResultViewModel; private final LabelTextPanel weatherfincitypanel; private final LabelTextPanel temperaturepanel; - private final LabelTextPanel skyconditionpanel; - private final LabelTextPanel humiditypanel; - private final LabelTextPanel windspeedpanel; - private final LabelTextPanel visibilitypanel; - private final LabelTextPanel searchresultpanel; + private LabelTextPanel skyconditionpanel; + private LabelTextPanel humiditypanel; + private LabelTextPanel windspeedpanel; + private LabelTextPanel visibilitypanel; + private LabelTextPanel searchresultpanel; private final JLabel emptylabel = new JLabel(""); - private final int weatherpanelwidth = 370; - private final int weatherpanelheight = 400; private final JButton temperatureconverter; private WeatherController weatherController; + private static final int WEATHER_PANEL_WIDTH = 370; + public static final int WEATHERPANELHEIGHT = 400; - public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel) { + public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, + PropertyChangeEvent evt) { this.weatherViewModel = weatherViewModel; this.weatherViewModel.addPropertyChangeListener(this); // Users can search for weather at a given time this.searchResultViewModel = searchResultViewModel; this.searchResultViewModel.addPropertyChangeListener(this); - this.setSize(weatherpanelwidth, weatherpanelheight); + this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); - // Note we want to add a convertor here.The button needs an action listenser. + // Note we want to add a convertor here.The button needs an action listener. this.temperatureconverter = new JButton("Temperature Converter"); - temperatureconverter.addActionListener( event -> { - // if the event is coming from cityinput field, execute controller - if (event.getSource() == temperatureconverter) {ConverterController.excute(temperatureconverter.getText()); - }); + temperatureconverter.addActionListener(event -> { + // if the event is coming from cityinput field, execute controller + if (event.getSource() == temperatureconverter) { + ConverterController.execute((Weather) evt.getSource()); + } + + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(weatherfincitypanel); + this.add(temperaturepanel); + this.add(temperatureconverter); + this.add(skyconditionpanel); + this.add(humiditypanel); + this.add(windspeedpanel); + this.add(visibilitypanel); + }); + /* + * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. + */ - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.add(weatherfincitypanel); - this.add(temperaturepanel); - this.add(temperatureconverter); - this.add(skyconditionpanel); - this.add(humiditypanel); - this.add(windspeedpanel); - this.add(visibilitypanel); } - /* - * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. - */ + + @Override public void propertyChange(PropertyChangeEvent evt) { final String propertyName = evt.getPropertyName(); final String newValue = (String) evt.getNewValue(); From dba4d83796d962748b69ba95932a7b61bc6a3fd4 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 18 Nov 2024 09:48:42 -0800 Subject: [PATCH 123/267] implement CompareCitiesInputBoundary --- .../use_case/note/CompareCities/CompareCitiesInputBoundary.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java index 7c3148c97..38a0d6435 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInputBoundary.java @@ -1,4 +1,5 @@ package use_case.note.CompareCities; public interface CompareCitiesInputBoundary { + void execute(CompareCitiesInputData compareCitiesInputData); } From 11c58a47f0c61ae37223362a078a0b6f1c27d7db Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 18 Nov 2024 09:49:09 -0800 Subject: [PATCH 124/267] implement CompareCities Controller and Presenter --- .../CompareCities/CompareCitiesController.java | 15 +++++++++++++++ .../CompareCities/CompareCitiesPresenter.java | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/main/java/interface_adapter/CompareCities/CompareCitiesController.java diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java new file mode 100644 index 000000000..2f799237e --- /dev/null +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java @@ -0,0 +1,15 @@ +package interface_adapter.CompareCities; + +import use_case.note.CompareCities.CompareCitiesInputBoundary; +import use_case.note.CompareCities.CompareCitiesInputData; + +public class CompareCitiesController { + private final CompareCitiesInputBoundary interactor; + public CompareCitiesController(CompareCitiesInputBoundary interactor) { + this.interactor = interactor; + } + public void execute(String firstcityName, String secondcityName) { + final CompareCitiesInputData compareCitiesInputData = new CompareCitiesInputData(firstcityName, secondcityName); + interactor.execute(compareCitiesInputData); + } +} diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java index 70fb705c8..1b8a5ff40 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -1,7 +1,23 @@ package interface_adapter.CompareCities; +import interface_adapter.weather.WeatherViewModel; +import use_case.note.CompareCities.CompareCitiesOutPutData; import use_case.note.CompareCities.CompareCitiesOutputBoundary; public class CompareCitiesPresenter implements CompareCitiesOutputBoundary { + private final WeatherViewModel viewModel; + public CompareCitiesPresenter(WeatherViewModel viewModel) { + this.viewModel = viewModel; + } + @Override + public void prepareFailView(String errorMessage) { + viewModel.getState().setError(errorMessage); + viewModel.firePropertyChanged(); + } + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + viewModel.getState().setError(null); + viewModel.firePropertyChanged(); + } } From 44c8b75ce67e4506216bf913a7b93ec51b1bc8d0 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 21 Nov 2024 11:34:27 -0800 Subject: [PATCH 125/267] Adding CompareCitiesState and CompareCitiesViewModel --- .../CompareCities/CompareCitiesState.java | 40 +++++++++++++++++++ .../CompareCities/CompareCitiesViewModel.java | 10 +++++ 2 files changed, 50 insertions(+) create mode 100644 src/main/java/interface_adapter/CompareCities/CompareCitiesState.java create mode 100644 src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java new file mode 100644 index 000000000..b742b0519 --- /dev/null +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java @@ -0,0 +1,40 @@ +package interface_adapter.CompareCities; + +public class CompareCitiesState { + private String error; + private String firstCityName; + private String secondCityName; + + public CompareCitiesState(CompareCitiesState copy) { + this.error = copy.error; + this.firstCityName = copy.firstCityName; + this.secondCityName = copy.secondCityName; + } + + public CompareCitiesState() { + } + + public String getError() { + return error; + } + + public String getFirstCityName() { + return firstCityName; + } + + public String getSecondCityName() { + return secondCityName; + } + + public void setError(String error) { + this.error = error; + } + + public void setFirstCityName(String firstCityName) { + this.firstCityName = firstCityName; + } + + public void setSecondCityName(String secondCityName) { + this.secondCityName = secondCityName; + } +} diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java new file mode 100644 index 000000000..c5cb586e5 --- /dev/null +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java @@ -0,0 +1,10 @@ +package interface_adapter.CompareCities; + +import interface_adapter.ViewModel; + +public class CompareCitiesViewModel extends ViewModel { + public CompareCityViewModel() { + super("CompareCities"); + setState(new CompareCitiesState()); + } +} From ba02ff7a79b2de63e192fe401d451b788c9459f5 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 21 Nov 2024 11:42:12 -0800 Subject: [PATCH 126/267] A bit refactor (rename to make the file look consist with other classes) --- ...nteractor.java => CompareCitiesInteractor.java} | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) rename src/main/java/use_case/note/CompareCities/{CompareCityiesnteractor.java => CompareCitiesInteractor.java} (67%) diff --git a/src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java similarity index 67% rename from src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java rename to src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index 6ae07bc16..06dbd0512 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCityiesnteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -1,18 +1,22 @@ package use_case.note.CompareCities; + import entity.Weather; + /* * The Comparecities Interactor. */ -public class CompareCityiesnteractor implements CompareCitiesInputBoundary { +public class CompareCitiesInteractor implements CompareCitiesInputBoundary { private final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface; private final CompareCitiesOutputBoundary comparecitiesPresenter; - public CompareCityiesnteractor(CompareCitiesDataAccessInterface compareCitiesDataAccessInterface, + public CompareCitiesInteractor(CompareCitiesDataAccessInterface compareCitiesDataAccessInterface, CompareCitiesOutputBoundary comparecitiesPresenter) { this.comparecitiesPresenter = comparecitiesPresenter; this.compareCitiesDataAccessInterface = compareCitiesDataAccessInterface; } + // when execute by controller, call presenter to prepare fail or success view. If success, make a new a outputdata + // and put it into presenter public void execute(CompareCitiesInputData compareCitiesInputData) { final String firstcityname = compareCitiesInputData.getFirstcityname(); final String secondcityname = compareCitiesInputData.getSecondcityname(); @@ -25,9 +29,9 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("city not found"); } else { - final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); - final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); - final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstweather, secondweather, false); + final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); + final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstweather, secondweather, false); comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); } } From 4eae0cb420953cb42a52de83ec38991d52f61e12 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 14:39:49 -0800 Subject: [PATCH 127/267] Fix method prepareSuccessView, add varable (2 weather objects) into class CompareCitiesState and CompareCitiesOutPutData --- .../CompareCities/CompareCitiesPresenter.java | 15 ++++++++--- .../CompareCities/CompareCitiesState.java | 22 ++++++++++++++++ .../CompareCitiesInteractor.java | 3 ++- .../CompareCitiesOutPutData.java | 25 ++++++++++++++++++- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java index 1b8a5ff40..34364a325 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -1,23 +1,30 @@ package interface_adapter.CompareCities; -import interface_adapter.weather.WeatherViewModel; import use_case.note.CompareCities.CompareCitiesOutPutData; import use_case.note.CompareCities.CompareCitiesOutputBoundary; public class CompareCitiesPresenter implements CompareCitiesOutputBoundary { - private final WeatherViewModel viewModel; - public CompareCitiesPresenter(WeatherViewModel viewModel) { + private final CompareCitiesViewModel viewModel; + + public CompareCitiesPresenter(CompareCitiesViewModel viewModel) { this.viewModel = viewModel; } @Override public void prepareFailView(String errorMessage) { + // viewModel.getState will provide a CompareCitiesState viewModel.getState().setError(errorMessage); viewModel.firePropertyChanged(); } + @Override public void prepareSuccessView(CompareCitiesOutPutData outputData) { viewModel.getState().setError(null); - viewModel.firePropertyChanged(); + viewModel.getState().setFirstCityName(outputData.getFirstCityname()); + viewModel.getState().setSecondCityName(outputData.getSecondCityname()); + viewModel.getState().setFirstWeather(outputData.getFirstWeather()); + viewModel.getState().setSecondWeather(outputData.getSecondWeather()); + viewModel.firePropertyChanged("City"); } } + diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java index b742b0519..e78eec510 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java @@ -1,14 +1,20 @@ package interface_adapter.CompareCities; +import entity.Weather; + public class CompareCitiesState { private String error; private String firstCityName; private String secondCityName; + private Weather firstWeather; + private Weather secondWeather; public CompareCitiesState(CompareCitiesState copy) { this.error = copy.error; this.firstCityName = copy.firstCityName; this.secondCityName = copy.secondCityName; + this.setFirstWeather(copy.getFirstWeather()); + this.setSecondWeather(copy.getSecondWeather()); } public CompareCitiesState() { @@ -37,4 +43,20 @@ public void setFirstCityName(String firstCityName) { public void setSecondCityName(String secondCityName) { this.secondCityName = secondCityName; } + + public Weather getFirstWeather() { + return firstWeather; + } + + public void setFirstWeather(Weather firstWeather) { + this.firstWeather = firstWeather; + } + + public Weather getSecondWeather() { + return secondWeather; + } + + public void setSecondWeather(Weather secondWeather) { + this.secondWeather = secondWeather; + } } diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index 06dbd0512..dcd58e837 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -31,7 +31,8 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { else { final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); - final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstweather, secondweather, false); + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, + firstweather, secondcityname, secondweather, false); comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); } } diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java index d66e40946..738b15309 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java @@ -1,13 +1,20 @@ package use_case.note.CompareCities; +import entity.Weather; + public class CompareCitiesOutPutData { private final String firstCityname; private final String secondCityname; + private Weather firstWeather; + private Weather secondWeather; private final boolean useCaseFailed; - public CompareCitiesOutPutData(String firstCityname, String secondCityname, boolean useCaseFailed) { + public CompareCitiesOutPutData(String firstCityname, Weather firstWeather, + String secondCityname, Weather secondWeather, boolean useCaseFailed) { this.firstCityname = firstCityname; this.secondCityname = secondCityname; + this.setFirstWeather(firstWeather); + this.setSecondWeather(secondWeather); this.useCaseFailed = useCaseFailed; } @@ -19,4 +26,20 @@ public String getFirstCityname() { public String getSecondCityname() { return secondCityname; } + + public Weather getFirstWeather() { + return firstWeather; + } + + public void setFirstWeather(Weather firstWeather) { + this.firstWeather = firstWeather; + } + + public Weather getSecondWeather() { + return secondWeather; + } + + public void setSecondWeather(Weather secondWeather) { + this.secondWeather = secondWeather; + } } From 62f533ef116dbaec4eeb51127ccad34152261288 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 16:57:52 -0800 Subject: [PATCH 128/267] Add new method saveweather and getcitytoweather (this change doesn't influence any pre-existing function in weather DAO) --- .../java/data_access/WeatherDataAccessObject.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 6b135d58c..73bd14800 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -31,7 +31,7 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private static final String STATUS_CODE_LABEL = "cod"; private static final String WEATHER_LIST = "list"; private static final String MESSAGE = "message"; - public final Map weathers = new HashMap<>(); + public final Map citytoweather = new HashMap<>(); @Override public Weather getWeather(String citySearch) throws IOException { @@ -70,18 +70,20 @@ public Weather getWeather(String citySearch) throws IOException { } return new Weather(citySearch, temp, looks, alertDescription, windspeed, humidity, visibility, lon, lat); - } - else { + } else { throw new IOException(responseBody.getString(MESSAGE)); } - } - catch (IOException | JSONException ex) { + } catch (IOException | JSONException ex) { throw new IOException(ex); } } public void saveWeather(Weather weather) { - weathers.put(weather.getCityName(), weather); + citytoweather.put(weather.getCityName(), weather); + } + + public Map getcitytoweather(){ + return this.citytoweather; } } From 4a94e0baec83b7c94e1249eb338637a3ed11e19e Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 17:36:33 -0800 Subject: [PATCH 129/267] Change method name (new name isCityexist, saveWeatherifor)to make it more clear and also avoid potential double naming issue, adding new method clearcitytoweather --- .../CompareCitiesDataAccessInterface.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java index 0bba951fd..de387089c 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -3,6 +3,7 @@ import entity.Weather; import java.io.IOException; +import java.util.Map; /** * Interface for the Comparing Cities Use case. @@ -13,7 +14,7 @@ public interface CompareCitiesDataAccessInterface { * @param cityname the weather is displayed for * @return if city exists */ - boolean citynotexist(String cityname); + boolean isCityexist(String cityname); /** * Creates the Weather. @@ -25,19 +26,25 @@ public interface CompareCitiesDataAccessInterface { /** * Saves the Weather. - * @param cityname the weather is saved + * @param weather save weather infor of a city to a map. since there is method getCityname in Weather Object. + * this method can work without have cityname as its input. */ - void saveWeather(String cityname); + void saveWeatherinfor(Weather weather); /** * Returns the City. * @return the city * */ - String getCurrentCity(); + Map getcitytoweather(); /** * Sets city. - * @param cityname the weather is for + * @param cityname check if the cityname is valid or not */ - void setCurrentCity(String cityname); + boolean isCityExist(String cityname); + + /** + * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. + */ + void clearcitytoweather(); } From 0369041b78be23bb7c85499321306804a60161d5 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 17:40:48 -0800 Subject: [PATCH 130/267] update CompareCitiesInteractor --- .../CompareCities/CompareCitiesInteractor.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index dcd58e837..f9012b3ba 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -15,8 +15,11 @@ public CompareCitiesInteractor(CompareCitiesDataAccessInterface compareCitiesDat this.compareCitiesDataAccessInterface = compareCitiesDataAccessInterface; } - // when execute by controller, call presenter to prepare fail or success view. If success, make a new a outputdata - // and put it into presenter + /** + * @param compareCitiesInputData this input data has 2 city names inside it. + * When execute by controller, call presenter to prepare fail or success view. If success, make a new an output data + * and put it into presenter. + * */ public void execute(CompareCitiesInputData compareCitiesInputData) { final String firstcityname = compareCitiesInputData.getFirstcityname(); final String secondcityname = compareCitiesInputData.getSecondcityname(); @@ -24,16 +27,20 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("Cannot compare the same city"); } else { - if ((!compareCitiesDataAccessInterface.citynotexist(firstcityname)) - || (!compareCitiesDataAccessInterface.citynotexist(secondcityname))) { + if (!compareCitiesDataAccessInterface.isCityexist(firstcityname) + || !compareCitiesDataAccessInterface.isCityexist(secondcityname)) { comparecitiesPresenter.prepareFailView("city not found"); } else { final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); + compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, firstweather, secondcityname, secondweather, false); comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); + // After each round of execution, clear map in DAO. + compareCitiesDataAccessInterface.clearcitytoweather(); } } } From f306d8a2c43b0ba3c2ae1940a01516f9b49eb208 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 17:41:32 -0800 Subject: [PATCH 131/267] remove extra space --- .../use_case/note/CompareCities/CompareCitiesOutPutData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java index 738b15309..2104db263 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesOutPutData.java @@ -18,7 +18,6 @@ public CompareCitiesOutPutData(String firstCityname, Weather firstWeather, this.useCaseFailed = useCaseFailed; } - public String getFirstCityname() { return firstCityname; } From 10af7043e409954c0fb3481045e0bcd34d7485ef Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 17:44:02 -0800 Subject: [PATCH 132/267] add instant variable cityexist, default to be flase. --- .../data_access/WeatherDataAccessObject.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 73bd14800..073db4a77 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -31,6 +31,7 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private static final String STATUS_CODE_LABEL = "cod"; private static final String WEATHER_LIST = "list"; private static final String MESSAGE = "message"; + private boolean cityexist = false; public final Map citytoweather = new HashMap<>(); @Override @@ -78,12 +79,26 @@ public Weather getWeather(String citySearch) throws IOException { } } - public void saveWeather(Weather weather) { + @Override + public void saveWeatherinfor(Weather weather) { citytoweather.put(weather.getCityName(), weather); } - public Map getcitytoweather(){ + @Override + public Map getcitytoweather() { return this.citytoweather; } + + /* + * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. + */ + @Override + public void clearcitytoweather() { + this.citytoweather.clear(); + } + + public boolean isCityexist() { + return cityexist; + } } From 20893eedf3fe30a402c26855bc414ba29a3b973b Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 19:44:40 -0800 Subject: [PATCH 133/267] add date input panel and its coresponding action listener. Add new method setSearchResultController. Comment out method protertyChange because we move that responsibility to WeatherPanelView and Historical panel --- src/main/java/view/MapPanelView.java | 66 ++++++++++++++++++---------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index be68ffb43..eb5d35932 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,47 +1,61 @@ package view; +import interface_adapter.SearchResult.SearchResultController; import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherState; -import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; /* -* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 2 parts: -* 1. search panel where user can type the city name. This is connected to a Action Lisenter, which pass information -* to our Input Class. -* 2. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. +* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 3 parts: +* 1. city input panel where user can type the city name. This is connected to an Action Lisenter, which pass infor +* to our weatherContoller Class. +* 2. date input panel +* 3. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. */ @SuppressWarnings("checkstyle:WriteTag") public class MapPanelView extends JPanel implements ActionListener { - private final LabelTextPanel searchpanel; + private final LabelTextPanel cityinputpanel; + private final LabelTextPanel dateinputpanel; private final MapImagepanel mapimagepanel; + private final JTextField cityinputfield = new JTextField(15); + private final JTextField dateinputfield = new JTextField(15); private final int mappanelwidth = 370; private final int mappanelheight = 400; + private SearchResultController searchResultController; private WeatherController weatherController; public MapPanelView() { mapimagepanel = new MapImagepanel(); + cityinputfield.addActionListener( event -> { - // if the event is coming from cityinput field, execute controller + // if the event is coming from cityinput field, execute weather controller if (event.getSource() == cityinputfield) { - WeatherController.execute(cityinputfield.getText()); + weatherController.execute(cityinputfield.getText()); } } ); - searchpanel = new LabelTextPanel(new JLabel("search bar"), cityinputfield); + cityinputpanel = new LabelTextPanel(new JLabel("search bar"), cityinputfield); + dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); + dateinputfield.addActionListener( + // if this event is coming from dateinput field, execute searchresult contoller + event -> { + if (event.getSource() == dateinputfield) { + searchResultController.execute(cityinputfield.getText(), dateinputfield.getText()); + } + }); // this.setSize(mappanelwidth, mappanelheight); this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.add(searchpanel); + this.add(cityinputpanel); + this.add(dateinputpanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); @@ -55,20 +69,24 @@ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); } - public void propertyChange(PropertyChangeEvent evt) { - final WeatherState state = (WeatherState) evt.getNewValue(); - setFields(state); - if (state.getError() != null) { - JOptionPane.showMessageDialog(this, state.getError(), - "Error", JOptionPane.ERROR_MESSAGE); - } - } - private void setFields(WeatherState state) { - cityinputfield.setText(state.getWeather()); - } +// public void propertyChange(PropertyChangeEvent evt) { +// final WeatherState state = (WeatherState) evt.getNewValue(); +// setFields(state); +// if (state.getError() != null) { +// JOptionPane.showMessageDialog(this, state.getError(), +// "Error", JOptionPane.ERROR_MESSAGE); +// } +// } +// +// private void setFields(WeatherState state) { +// cityinputfield.setText(state.getWeather()); +// } - public void setWeatherController(WeatherController controller) { - this.weatherController = controller; + public void setWeatherController(WeatherController weathercontroller) { + this.weatherController = weathercontroller; } + + public void setSearchResultController(SearchResultController searchresultcontroller) { + this.searchResultController = searchresultcontroller; } } From bf17fd2a09b3df9c5c8f7585e2b1cc0b4f1b61eb Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 19:45:47 -0800 Subject: [PATCH 134/267] construct cityexist. Change MESSAGE to more meaningful string --- src/main/java/data_access/WeatherDataAccessObject.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 073db4a77..d8dce44cb 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -30,9 +30,9 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private static final String CONTENT_TYPE_JSON = "application/json"; private static final String STATUS_CODE_LABEL = "cod"; private static final String WEATHER_LIST = "list"; - private static final String MESSAGE = "message"; - private boolean cityexist = false; - public final Map citytoweather = new HashMap<>(); + private static final String MESSAGE = "This city is not found"; + private boolean cityexist; + private final Map citytoweather = new HashMap<>(); @Override public Weather getWeather(String citySearch) throws IOException { @@ -52,7 +52,7 @@ public Weather getWeather(String citySearch) throws IOException { if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); - + this.cityexist = true; // get individual items from the json object final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); From c8ba5f838b9952fbf926a0ae16d4e39f1ad1e2d4 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 19:48:41 -0800 Subject: [PATCH 135/267] Add method actionperformed, fix (partually) the converter button. --- src/main/java/view/WeatherPanelView.java | 34 ++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index cf3158a72..8d64760a8 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -1,11 +1,6 @@ package view; -import entity.Weather; -import interface_adapter.converter.ConverterController; -import interface_adapter.SearchResult.SearchResultViewModel; -import interface_adapter.weather.WeatherViewModel; -import interface_adapter.weather.WeatherController; - +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -16,6 +11,12 @@ import javax.swing.JPanel; import javax.swing.SwingUtilities; +import entity.Weather; +import interface_adapter.SearchResult.SearchResultViewModel; +import interface_adapter.converter.ConverterController; +//import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherViewModel; + /** * This class responsible for creating the Weather Subpanel of the main. The Weather subpanel itself contains a bunch * of LabelTextPanel that displays varies weather information. @@ -35,7 +36,8 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final JLabel emptylabel = new JLabel(""); private final JButton temperatureconverter; - private WeatherController weatherController; + + private ConverterController convertorController; private static final int WEATHER_PANEL_WIDTH = 370; public static final int WEATHERPANELHEIGHT = 400; @@ -50,12 +52,17 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); - // Note we want to add a convertor here.The button needs an action listener. + // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, + // or the opposite.The button needs an action listener that pass the change to a ConverterController. this.temperatureconverter = new JButton("Temperature Converter"); temperatureconverter.addActionListener(event -> { - // if the event is coming from cityinput field, execute controller + // if the event is coming from temperature converter button, execute convertor controller if (event.getSource() == temperatureconverter) { - ConverterController.execute((Weather) evt.getSource()); + // todo: right now evt.getSource() return String "Temperature Converter", which is not a weather. But + // the method execute in class ConverterController takes Weather object as input, need fix this. + // a potential solution is change evt.getSource() to city name, and in ConverterController, turn + // cityname into Weather(call DAO). + convertorController.execute((Weather) evt.getSource()); } skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); @@ -65,11 +72,11 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherfincitypanel); this.add(temperaturepanel); - this.add(temperatureconverter); this.add(skyconditionpanel); this.add(humiditypanel); this.add(windspeedpanel); this.add(visibilitypanel); + this.add(temperatureconverter); }); /* * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. @@ -105,4 +112,9 @@ public void propertyChange(PropertyChangeEvent evt) { } }); } + + public void actionPerformed(ActionEvent event) { + System.out.println("Enter" + event.getActionCommand()); + + } } From 310b40c3069dcfde4d5400caef87f6ecb8f381a7 Mon Sep 17 00:00:00 2001 From: sophie Date: Fri, 22 Nov 2024 19:49:03 -0800 Subject: [PATCH 136/267] fix typo --- .../interface_adapter/CompareCities/CompareCitiesViewModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java index c5cb586e5..baf04b02b 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java @@ -3,7 +3,7 @@ import interface_adapter.ViewModel; public class CompareCitiesViewModel extends ViewModel { - public CompareCityViewModel() { + public CompareCitiesViewModel() { super("CompareCities"); setState(new CompareCitiesState()); } From 4dd9ab60367dfed7fa99abdd273430f13ad6e643 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Fri, 22 Nov 2024 23:18:06 -0500 Subject: [PATCH 137/267] HistoricalSearchedWeatherView implemented --- .../view/HistoricalSearchedWeatherView.java | 95 +++++++++++++++ src/main/java/view/SearchResultPanelView.java | 114 ------------------ 2 files changed, 95 insertions(+), 114 deletions(-) create mode 100644 src/main/java/view/HistoricalSearchedWeatherView.java delete mode 100644 src/main/java/view/SearchResultPanelView.java diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java new file mode 100644 index 000000000..3042e3f1e --- /dev/null +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -0,0 +1,95 @@ +package view; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.*; + +import interface_adapter.SearchResult.SearchResultState; +import interface_adapter.SearchResult.SearchResultViewModel; + +/** + * The View for when the user is viewing a note in the program. + */ +public class HistoricalSearchedWeatherView extends JPanel implements PropertyChangeListener { + + private final SearchResultViewModel searchResultViewModel; + private LabelTextPanel weatherfincitypanel; + private LabelTextPanel temperaturepanel; + private LabelTextPanel skyconditionpanel; + private LabelTextPanel humiditypanel; + private LabelTextPanel windspeedpanel; + private LabelTextPanel visibilitypanel; + private LabelTextPanel citypanel; + + private final JLabel emptylabel = new JLabel(""); + + private final JLabel noteName = new JLabel("search result"); + private final JTextArea cityInputField = new JTextArea(); + private final JTextArea dateInputField = new JTextArea(); + private static final int HISTORICALPANELWIDTH = 370; + public static final int HISTORICALPANELHEIGHT = 400; + + // private final JButton cityButton = new JButton("Searched City"); +// private final JButton dateButton = new JButton("Date"); +// private final JLabel cityLabel = new JLabel("City:"); +// private final JLabel dateLabel = new JLabel("Date:"); +// private final JButton searchButton = new JButton("Search"); + public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel, + PropertyChangeEvent evt) { + this.searchResultViewModel = searchResultViewModel; + // Users can search for weather at a given time + this.searchResultViewModel.addPropertyChangeListener(this); + + this.setSize(HISTORICALPANELWIDTH, HISTORICALPANELHEIGHT); + weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + // Note we want to add a convertor here.The button needs an action listener. + citypanel = new LabelTextPanel(new JLabel("City"), emptylabel); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(weatherfincitypanel); + this.add(temperaturepanel); + this.add(skyconditionpanel); + this.add(humiditypanel); + this.add(windspeedpanel); + this.add(visibilitypanel); + this.add(citypanel); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final String propertyName = evt.getPropertyName(); + final String newValue = (String) evt.getNewValue(); + + SwingUtilities.invokeLater(() -> { + switch (propertyName) { + case "city": + weatherfincitypanel.setoutput(newValue); + break; + case "temperature": + temperaturepanel.setoutput(newValue); + break; + case "skyCondition": + skyconditionpanel.setoutput(newValue); + break; + case "humidity": + humiditypanel.setoutput(newValue); + break; + case "windSpeed": + windspeedpanel.setoutput(newValue); + break; + case "visibility": + visibilitypanel.setoutput(newValue); + break; + } + } + +// private void setFields(SearchResultState state) { +// temperaturepanel.setText(state.getWeather().getTemperature()); +// } + +} diff --git a/src/main/java/view/SearchResultPanelView.java b/src/main/java/view/SearchResultPanelView.java deleted file mode 100644 index 34003a34e..000000000 --- a/src/main/java/view/SearchResultPanelView.java +++ /dev/null @@ -1,114 +0,0 @@ -package view; - -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextArea; - -import interface_adapter.SearchResult.SearchResultController; -import interface_adapter.SearchResult.SearchResultState; -import interface_adapter.SearchResult.SearchResultViewModel; - -/** - * The View for when the user is viewing a note in the program. - */ -public class SearchResultPanelView extends JPanel implements ActionListener, PropertyChangeListener { - - private final SearchResultViewModel searchResultViewModel; - - private final JLabel noteName = new JLabel("search result"); - private final JTextArea cityInputField = new JTextArea(); - private final JTextArea dateInputField = new JTextArea(); - - private final JButton cityButton = new JButton("Searched City"); - private final JButton dateButton = new JButton("Date"); - private final JLabel cityLabel = new JLabel("City:"); - private final JLabel dateLabel = new JLabel("Date:"); - private final JButton searchButton = new JButton("Search"); - private SearchResultController searchResultController; - - public SearchResultView(SearchResultViewModel searchResultViewModel) { - - noteName.setAlignmentX(Component.CENTER_ALIGNMENT); - this.searchResultViewModel = searchResultViewModel; - this.searchResultViewModel.addPropertyChangeListener(this); - - final JPanel buttons = new JPanel(); - buttons.add(searchButton); - - // Creating panels to contain each label and input field - final JPanel cityPanel = new JPanel(); - cityPanel.setLayout(new BoxLayout(cityPanel, BoxLayout.X_AXIS)); - cityPanel.add(cityLabel); - cityPanel.add(cityInputField); - - final JPanel datePanel = new JPanel(); - datePanel.setLayout(new BoxLayout(datePanel, BoxLayout.X_AXIS)); - datePanel.add(dateLabel); - datePanel.add(dateInputField); - - searchButton.addActionListener( - evt -> { - if (evt.getSource().equals(searchButton)) { - searchResultAction(); - } - } - ); - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.add(noteName); - this.add(cityPanel); - this.add(datePanel); - this.add(buttons); - } - - private void searchResultAction() { - final String city = cityInputField.getText(); - final String date = dateInputField.getText(); - - if (city.isEmpty() || date.isEmpty()) { - // Display an error message or simply return - JOptionPane.showMessageDialog( - this, - "Please fill in both the City and Date fields before searching.", - "Input Error", JOptionPane.ERROR_MESSAGE); - } - else { - searchResultController.execute(city, date); - } - } - - /** - * React to a button click that results in evt. - * @param evt the ActionEvent to react to - */ - public void actionPerformed(ActionEvent evt) { - System.out.println("Click " + evt.getActionCommand()); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - final SearchResultState state = (SearchResultState) evt.getNewValue(); - setFields(state); - if (state.getError() != null) { - JOptionPane.showMessageDialog(this, state.getError(), - "Error", JOptionPane.ERROR_MESSAGE); - } - } - - private void setFields(SearchResultState state) { - cityInputField.setText(state.getWeather().getCity()); - dateInputField.setText(state.getDate()); - } - - public void setSearchResultController(SearchResultController controller) { - this.searchResultController = controller; - } -} \ No newline at end of file From 9ade6e9654510932189fa08974c92efc2b2e8f69 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Sat, 23 Nov 2024 00:04:42 -0500 Subject: [PATCH 138/267] Alert Pop Presenter --- .../alert_pop/AlertPopPresenter.java | 15 ++++++++++++++- .../java/use_case/note/AlertPopInteractor.java | 6 +++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java index c65e176b1..72874a294 100644 --- a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java +++ b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java @@ -2,7 +2,20 @@ import interface_adapter.weather.WeatherViewModel; import use_case.note.alert_pop.AlertPopOutputBoundary; +import use_case.note.alert_pop.AlertPopOutputData; public class AlertPopPresenter implements AlertPopOutputBoundary { - private final WeatherViewModel + private final WeatherViewModel viewModel; + + public AlertPopPresenter(WeatherViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void prepareSuccessView(AlertPopOutputData alertPopOutputData) { + + viewModel.getState().setAlert(alertPopOutputData.getAlert()); + viewModel.firePropertyChanged(); + } + } diff --git a/src/main/java/use_case/note/AlertPopInteractor.java b/src/main/java/use_case/note/AlertPopInteractor.java index cf8758a8c..74eb14aac 100644 --- a/src/main/java/use_case/note/AlertPopInteractor.java +++ b/src/main/java/use_case/note/AlertPopInteractor.java @@ -18,13 +18,13 @@ public void execute(AlertPopInputData alertPopInputData) { String cityName = alertPopInputData.getCityName(); Weather weather = weatherAccess.getWeather(cityName); String alert = weather.getAlertDescription(); - String noAlert = "no alerts"; + String noAlert = "no weather alert"; if (noAlert.equals(alert)) { - AlertPopOutputData outputData = new AlertPopOutputData(noAlert); + AlertPopOutputData outputData = new AlertPopOutputData(noAlert, false); outputBoundary.prepareSuccessView(outputData); } else { - AlertPopOutputData outputData = new AlertPopOutputData(alert); + AlertPopOutputData outputData = new AlertPopOutputData(alert, false); outputBoundary.prepareSuccessView(outputData); } } catch (Exception e) { From da09e4c92bbd718ea1f9cbce897132f1506fe340 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 15:38:54 -0500 Subject: [PATCH 139/267] HistoricalSearchedWeatherView implemented --- .../SearchResult/SearchResultPresenter.java | 5 ++-- .../SearchResult/SearchResultState.java | 9 ++++++ .../view/HistoricalSearchedWeatherView.java | 30 ++++++++++++++----- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index 78ab05899..a648ba624 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -7,15 +7,16 @@ public class SearchResultPresenter implements SearchResultOutputBoundary { - private final WeatherViewModel viewModel; + private final SearchResultViewModel viewModel; - public SearchResultPresenter(WeatherViewModel viewModel) { + public SearchResultPresenter(SearchResultViewModel viewModel) { this.viewModel = viewModel; } @Override public void presentSuccessView(SearchResultOutputData searchResultOutputData) { viewModel.getState().setWeather(searchResultOutputData.getWeather()); + viewModel.getState().setCityName(searchResultOutputData.getWeather().getCityName()); } @Override diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultState.java b/src/main/java/interface_adapter/SearchResult/SearchResultState.java index 3e5a6c04c..c42cf7716 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultState.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultState.java @@ -10,11 +10,20 @@ public class SearchResultState { private Weather weather; private String error; private String date; + private String cityName; public Weather getWeather() { return weather; } + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + public void setWeather(Weather weather) { this.weather = weather; } diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 3042e3f1e..0949d32d1 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -5,6 +5,7 @@ import javax.swing.*; +import entity.Weather; import interface_adapter.SearchResult.SearchResultState; import interface_adapter.SearchResult.SearchResultViewModel; @@ -21,6 +22,7 @@ public class HistoricalSearchedWeatherView extends JPanel implements PropertyCha private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; private LabelTextPanel citypanel; +// private LabelTextPanel metrixPanel; private final JLabel emptylabel = new JLabel(""); @@ -46,6 +48,7 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); // Note we want to add a convertor here.The button needs an action listener. citypanel = new LabelTextPanel(new JLabel("City"), emptylabel); +// metrixPanel = new LabelTextPanel(new JLabel("Metrix"), emptylabel); skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); @@ -58,35 +61,46 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.add(windspeedpanel); this.add(visibilitypanel); this.add(citypanel); +// this.add(metrixPanel); } @Override public void propertyChange(PropertyChangeEvent evt) { final String propertyName = evt.getPropertyName(); - final String newValue = (String) evt.getNewValue(); + final SearchResultState state = (SearchResultState) evt.getNewValue(); + final Weather searchedWeather = state.getWeather(); + SwingUtilities.invokeLater(() -> { switch (propertyName) { case "city": - weatherfincitypanel.setoutput(newValue); + weatherfincitypanel.setoutput(searchedWeather.getCityName()); break; case "temperature": - temperaturepanel.setoutput(newValue); + float temperature = searchedWeather.getTemperature(); + String temperatureString = String.valueOf(temperature); + temperaturepanel.setoutput(temperatureString); break; case "skyCondition": - skyconditionpanel.setoutput(newValue); + skyconditionpanel.setoutput(searchedWeather.getDescription()); break; case "humidity": - humiditypanel.setoutput(newValue); + int humidity = searchedWeather.getHumidity(); + String humidityString = String.valueOf(humidity); + humiditypanel.setoutput(humidityString);); break; case "windSpeed": - windspeedpanel.setoutput(newValue); + float windSpeed = searchedWeather.getWindSpeed(); + String windSpeedString = String.valueOf(windSpeed); + windspeedpanel.setoutput(windSpeedString); break; case "visibility": - visibilitypanel.setoutput(newValue); + int visibility = searchedWeather.getVisibility(); + String visibilityString = String.valueOf(visibility); + visibilitypanel.setoutput(visibilityString); break; } - } + }); // private void setFields(SearchResultState state) { // temperaturepanel.setText(state.getWeather().getTemperature()); From 4770abc0f3963e9cbac099dc995017dfe800c886 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 16:20:15 -0500 Subject: [PATCH 140/267] HistoricalSearchedWeatherView implemented --- .../view/HistoricalSearchedWeatherView.java | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 0949d32d1..3ce1e5d78 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -3,7 +3,11 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.*; +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; import entity.Weather; import interface_adapter.SearchResult.SearchResultState; @@ -14,6 +18,8 @@ */ public class HistoricalSearchedWeatherView extends JPanel implements PropertyChangeListener { + private static final int HISTORICALPANELWIDTH = 370; + private static final int HISTORICALPANELHEIGHT = 400; private final SearchResultViewModel searchResultViewModel; private LabelTextPanel weatherfincitypanel; private LabelTextPanel temperaturepanel; @@ -22,23 +28,15 @@ public class HistoricalSearchedWeatherView extends JPanel implements PropertyCha private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; private LabelTextPanel citypanel; -// private LabelTextPanel metrixPanel; private final JLabel emptylabel = new JLabel(""); private final JLabel noteName = new JLabel("search result"); private final JTextArea cityInputField = new JTextArea(); private final JTextArea dateInputField = new JTextArea(); - private static final int HISTORICALPANELWIDTH = 370; - public static final int HISTORICALPANELHEIGHT = 400; - // private final JButton cityButton = new JButton("Searched City"); -// private final JButton dateButton = new JButton("Date"); -// private final JLabel cityLabel = new JLabel("City:"); -// private final JLabel dateLabel = new JLabel("Date:"); -// private final JButton searchButton = new JButton("Search"); public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel, - PropertyChangeEvent evt) { + PropertyChangeEvent evt) { this.searchResultViewModel = searchResultViewModel; // Users can search for weather at a given time this.searchResultViewModel.addPropertyChangeListener(this); @@ -48,7 +46,6 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); // Note we want to add a convertor here.The button needs an action listener. citypanel = new LabelTextPanel(new JLabel("City"), emptylabel); -// metrixPanel = new LabelTextPanel(new JLabel("Metrix"), emptylabel); skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); @@ -61,8 +58,7 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.add(windspeedpanel); this.add(visibilitypanel); this.add(citypanel); -// this.add(metrixPanel); - } + } @Override public void propertyChange(PropertyChangeEvent evt) { @@ -70,40 +66,43 @@ public void propertyChange(PropertyChangeEvent evt) { final SearchResultState state = (SearchResultState) evt.getNewValue(); final Weather searchedWeather = state.getWeather(); - SwingUtilities.invokeLater(() -> { - switch (propertyName) { - case "city": - weatherfincitypanel.setoutput(searchedWeather.getCityName()); - break; - case "temperature": - float temperature = searchedWeather.getTemperature(); - String temperatureString = String.valueOf(temperature); - temperaturepanel.setoutput(temperatureString); - break; - case "skyCondition": - skyconditionpanel.setoutput(searchedWeather.getDescription()); - break; - case "humidity": - int humidity = searchedWeather.getHumidity(); - String humidityString = String.valueOf(humidity); - humiditypanel.setoutput(humidityString);); - break; - case "windSpeed": - float windSpeed = searchedWeather.getWindSpeed(); - String windSpeedString = String.valueOf(windSpeed); - windspeedpanel.setoutput(windSpeedString); - break; - case "visibility": - int visibility = searchedWeather.getVisibility(); - String visibilityString = String.valueOf(visibility); - visibilitypanel.setoutput(visibilityString); - break; - } - }); + changeProperty(propertyName, searchedWeather); + }); -// private void setFields(SearchResultState state) { -// temperaturepanel.setText(state.getWeather().getTemperature()); -// } + } + private void changeProperty(String propertyName, Weather searchedWeather) { + switch (propertyName) { + case "city": + weatherfincitypanel.setoutput(searchedWeather.getCityName()); + break; + case "temperature": + final float temperature = searchedWeather.getTemperature(); + final String temperatureString = String.valueOf(temperature); + temperaturepanel.setoutput(temperatureString); + break; + case "skyCondition": + skyconditionpanel.setoutput(searchedWeather.getDescription()); + break; + case "humidity": + final int humidity = searchedWeather.getHumidity(); + final String humidityString = String.valueOf(humidity); + humiditypanel.setoutput(humidityString); + break; + case "windSpeed": + final float windSpeed = searchedWeather.getWindSpeed(); + final String windSpeedString = String.valueOf(windSpeed); + windspeedpanel.setoutput(windSpeedString); + break; + case "visibility": + final int visibility = searchedWeather.getVisibility(); + final String visibilityString = String.valueOf(visibility); + visibilitypanel.setoutput(visibilityString); + break; + default: + System.out.println("Unknown property: " + propertyName); + break; + } + } } From a0f20d0b2e24ec2aef797027f2e5cd71c6b322b1 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 16:49:18 -0500 Subject: [PATCH 141/267] some checkstyle issues --- .../data_access/WeatherDataAccessObject.java | 26 +++++++++---------- .../HistoricalWeatherDataAccessInterface.java | 3 +-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 6b135d58c..fe6db9620 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -1,27 +1,23 @@ package data_access; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import entity.Weather; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONArray; - import use_case.note.CompareCities.CompareCitiesDataAccessInterface; import use_case.note.WeatherDataAccessInterface; - - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - - /** * This class runs the API and creates a weather DAO. **/ - public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; @@ -31,7 +27,7 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private static final String STATUS_CODE_LABEL = "cod"; private static final String WEATHER_LIST = "list"; private static final String MESSAGE = "message"; - public final Map weathers = new HashMap<>(); + private final Map weathers = new HashMap<>(); @Override public Weather getWeather(String citySearch) throws IOException { @@ -80,6 +76,10 @@ public Weather getWeather(String citySearch) throws IOException { } } + /** + * Saves the weather data to the DAO. + * @param weather the weather data to save + */ public void saveWeather(Weather weather) { weathers.put(weather.getCityName(), weather); } diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index c4c629cdb..904670ccf 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -13,10 +13,9 @@ public interface HistoricalWeatherDataAccessInterface { * Saves the weather data. * @param weather the weather data to save * @param timstamp the timestamp of the weather data - * @param City the city of the weather data * @throws IOException if there is an error saving the weather data */ - void saveWeather(Weather weather, String timstamp, String City) throws IOException; + void saveWeather(Weather weather, String timstamp) throws IOException; /** * Gets the weather data. From 91235510174bd6e1469094ab990f9493d1ad02ec Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 23 Nov 2024 16:57:18 -0500 Subject: [PATCH 142/267] Updated comments --- .../nearby_list/NearbyListController.java | 8 +++++--- .../note/nearby_list/NearbyListInputBoundary.java | 9 ++++++++- .../use_case/note/nearby_list/NearbyListInputData.java | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListController.java b/src/main/java/interface_adapter/nearby_list/NearbyListController.java index 38704e16e..92d4a21f3 100644 --- a/src/main/java/interface_adapter/nearby_list/NearbyListController.java +++ b/src/main/java/interface_adapter/nearby_list/NearbyListController.java @@ -3,10 +3,12 @@ import use_case.note.nearby_list.NearbyListInputBoundary; import use_case.note.nearby_list.NearbyListInputData; +/** + * Controller for the nearby list use case. + */ public class NearbyListController { private final NearbyListInputBoundary nearbyListInteractor; - // Constructor that injects the use case's input boundary public NearbyListController(NearbyListInputBoundary nearbyListInteractor) { this.nearbyListInteractor = nearbyListInteractor; } @@ -14,8 +16,8 @@ public NearbyListController(NearbyListInputBoundary nearbyListInteractor) { /** * Executes the find nearby cities use case given the longitude and latitude of the current location. * - * @param longitude the name of the city to search for - * @param latitude the date to search for + * @param longitude the current longitude + * @param latitude the current latitude */ public void execute(float longitude, float latitude) { // Create a NearbyListInputData object to encapsulate the input data diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java index 22407c6b4..a52c201a0 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputBoundary.java @@ -1,7 +1,14 @@ package use_case.note.nearby_list; -// This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. +/** + * An input is when the map moves. + */ public interface NearbyListInputBoundary { + /** + * Executes the nearby list use case. + * + * @param nearbyListInputData the input data for the nearby list use case. + */ void execute(NearbyListInputData nearbyListInputData); } diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java index 8e3958263..eef8830d5 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java @@ -1,7 +1,7 @@ package use_case.note.nearby_list; /** - * This one only has the input of clicking "open list," whereas the centre of the location is chosen prior to that. + * An input is when the map moves. */ public class NearbyListInputData { private final float longitude; From 124a7209ab2c290d10c3f9ff570a558e7a46972b Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 23 Nov 2024 16:58:18 -0500 Subject: [PATCH 143/267] Moved nearbycitiesaccessobject to data_access folder --- .../NearbyCitiesAccessObject.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename src/main/java/{use_case/note/nearby_list => data_access}/NearbyCitiesAccessObject.java (92%) diff --git a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java similarity index 92% rename from src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java rename to src/main/java/data_access/NearbyCitiesAccessObject.java index 4cdf09a56..0c8f0afba 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -1,8 +1,9 @@ -package use_case.note.nearby_list; +package data_access; import org.jetbrains.annotations.NotNull; import org.json.JSONArray; import org.json.JSONObject; +import use_case.note.nearby_list.NearbyCitiesAccessInterface; import java.io.IOException; import java.net.URISyntaxException; @@ -11,6 +12,9 @@ import java.util.ArrayList; import java.util.List; +/** + * This class provides the service of getting nearby cities. + */ public abstract class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { private static final Float LOWER_LAT = -90.0f; private static final Float UPPER_LAT = 90.0f; From 3612364c53ec928b71c388cd0d5494f37c4c452e Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 17:07:53 -0500 Subject: [PATCH 144/267] fixing conflict --- src/main/java/data_access/WeatherDataAccessObject.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index d8dce44cb..d0ef29247 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -11,8 +11,6 @@ import use_case.note.CompareCities.CompareCitiesDataAccessInterface; import use_case.note.WeatherDataAccessInterface; - - import java.io.IOException; import java.util.HashMap; import java.util.Map; From d4e6a5bcaf8ef7bef24871db01275fcf47548a0e Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 18:42:34 -0500 Subject: [PATCH 145/267] implemented classes for searching weather in the db --- .../SearchResult/SearchResultPresenter.java | 1 - .../use_case/note/SearchResultInteractor.java | 16 ++++------------ .../search_result/SearchResultInputData.java | 2 +- .../search_result/SearchResultOutputData.java | 10 +--------- 4 files changed, 6 insertions(+), 23 deletions(-) diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index a648ba624..40253631a 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -16,7 +16,6 @@ public SearchResultPresenter(SearchResultViewModel viewModel) { @Override public void presentSuccessView(SearchResultOutputData searchResultOutputData) { viewModel.getState().setWeather(searchResultOutputData.getWeather()); - viewModel.getState().setCityName(searchResultOutputData.getWeather().getCityName()); } @Override diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 4239fbf58..80bb53392 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -4,8 +4,6 @@ import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.HashMap; -import java.util.Map; import entity.Weather; import use_case.note.search_result.SearchResultInputBoundary; @@ -14,30 +12,24 @@ import use_case.note.search_result.SearchResultOutputData; /** - * The interactor for the search result use case.. + * The interactor for the search result use case. */ public class SearchResultInteractor implements SearchResultInputBoundary { private final SearchResultOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; - private final Map historicalWeatherData; private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess, HistoricalWeatherDataAccessInterface historicalDataInterface ) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; - this.historicalWeatherData = new HashMap<>(); this.historicalWeatherDataAccessInterface = historicalDataInterface; } @Override public void execute(SearchResultInputData searchReturnInputData) { - fetchWeatherData(); - } - - private void fetchWeatherData() { try { - final String city = SearchResultInputData.getCity(); + final String city = searchReturnInputData.getCity(); // Simulate reading weather data final Weather weatherData = weatherDataAccess.getWeather(city); @@ -49,8 +41,8 @@ private void fetchWeatherData() { // Send it to the output boundary final SearchResultOutputData outputData = - new SearchResultOutputData(city, historicalWeather, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp, city); + new SearchResultOutputData(historicalWeather, false); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_result/SearchResultInputData.java b/src/main/java/use_case/note/search_result/SearchResultInputData.java index b21ced456..f15ab28b1 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultInputData.java @@ -12,7 +12,7 @@ public SearchResultInputData(String cityName, String date) { this.date = date; } - public static String getCity() { + public String getCity() { return this.city; } diff --git a/src/main/java/use_case/note/search_result/SearchResultOutputData.java b/src/main/java/use_case/note/search_result/SearchResultOutputData.java index 5c8b0fcb7..beb08b3b7 100644 --- a/src/main/java/use_case/note/search_result/SearchResultOutputData.java +++ b/src/main/java/use_case/note/search_result/SearchResultOutputData.java @@ -2,24 +2,16 @@ import entity.Weather; -import java.util.Map; - public class SearchResultOutputData { - private final String location; private final Weather weather; private final boolean useCaseFailed; - public SearchResultOutputData(String location, Weather weather, boolean useCaseFailed) { - this.location = location; + public SearchResultOutputData(Weather weather, boolean useCaseFailed) { this.weather = weather; this.useCaseFailed = useCaseFailed; } - public String getLocation() { - return location; - } - public Weather getWeather() { return weather; } From ff6841694aa395df5ddefcf6d74c381df948fe1f Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 23 Nov 2024 19:16:29 -0500 Subject: [PATCH 146/267] searchReturnInteractor, SearchResultInteractor and SearchReturnOutputData implemented --- .../use_case/note/SearchResultInteractor.java | 5 +-- .../use_case/note/SearchReturnInteractor.java | 39 ++++++++++++++++--- .../search_return/SearchReturnOutputData.java | 11 ++++-- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index 80bb53392..b33b9a07f 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -30,13 +30,10 @@ public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, Weather public void execute(SearchResultInputData searchReturnInputData) { try { final String city = searchReturnInputData.getCity(); + final String timestamp = searchReturnInputData.getDate(); // Simulate reading weather data final Weather weatherData = weatherDataAccess.getWeather(city); - // Store it in historical data - final DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.of("UTC")); - final String timestamp = formatter.format(Instant.now()); - final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city, timestamp); // Send it to the output boundary diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java index bb67cc4c2..07fbd8d43 100644 --- a/src/main/java/use_case/note/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -1,31 +1,60 @@ +package use_case.note; + import entity.Weather; import use_case.note.WeatherDataAccessInterface; -import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnInputData; import use_case.note.search_return.SearchReturnOutputBoundary; import use_case.note.search_return.SearchReturnOutputData; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +/** + * The interactor for the search return use case. + */ public class SearchReturnInteractor implements SearchReturnInputBoundary { - private final SearchResultOutputBoundary outputBoundary; + private final SearchReturnOutputBoundary outputBoundary; private final WeatherDataAccessInterface weatherDataAccess; - private final Map historicalWeatherData; + private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; - public SearchReturnInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess) { + public SearchReturnInteractor(SearchReturnOutputBoundary outputBoundary, + WeatherDataAccessInterface weatherDataAccess, + HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; - this.historicalWeatherData = new HashMap<>(); + this.historicalWeatherDataAccessInterface = historicalWeatherDataAccessInterface; } @Override public void execute(SearchReturnInputData searchReturnInputData) { + try { + final String city = searchReturnInputData.getCity(); + // Simulate reading weather data + final Weather weatherData = weatherDataAccess.getWeather(city); + + // Store it in historical data + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC); + final String timestamp = formatter.format(Instant.now()); + historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); + // Send it to the output boundary + final SearchReturnOutputData outputData = + new SearchReturnOutputData(weatherData, false); + outputBoundary.presentSuccessView(outputData); + + } catch (IOException exception) { + // Handle exception if weather data retrieval fails and send failure view + outputBoundary.prepareFailView("Failed to retrieve weather data: " + exception.getMessage()); + } } } \ No newline at end of file diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java index f48d43f72..7890dce33 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -2,14 +2,17 @@ import entity.Weather; +/** + * Output data for the search return use case. + */ public class SearchReturnOutputData { private final String location; private final Weather weather; private final boolean useCaseFailed; - public SearchReturnOutputData(String location, Weather weather, boolean useCaseFailed) { - this.location = location; + public SearchReturnOutputData(Weather weather, boolean useCaseFailed) { + this.location = weather.getCityName(); this.weather = weather; this.useCaseFailed = useCaseFailed; } @@ -18,7 +21,9 @@ public String getLocation() { return location; } - public Weather getWeather() {return weather;} + public Weather getWeather() { + return weather; + } public boolean isUseCaseFailed() { return useCaseFailed; From 9799ba611a813eb58594fabadeb4e96fab11e438 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 15:02:00 -0800 Subject: [PATCH 147/267] . --- src/main/java/view/MainView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 4438a0094..eb746bc37 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,9 +1,11 @@ package view; +import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; import javax.swing.JFrame; import java.awt.GridLayout; +import java.beans.PropertyChangeEvent; public class MainView extends JFrame { private MapPanelView mapPanelView; @@ -11,9 +13,9 @@ public class MainView extends JFrame { private final int frameWidth = 1200; private final int frameHeight = 1000; - public MainView(WeatherViewModel weatherViewModel) { + public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { mapPanelView = new MapPanelView(); - weatherPanelView = new WeatherPanelView(weatherViewModel); + weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); From 7da03ba125131dc2e0991946d3fb7bd036567b96 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 15:59:17 -0800 Subject: [PATCH 148/267] fixing the propertychange listener. # Conflicts: # src/main/java/view/SearchResultPanelView.java --- src/main/java/view/WeatherPanelView.java | 56 ++++++++++-------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 8d64760a8..0a43b2bf6 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -15,6 +15,7 @@ import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.converter.ConverterController; //import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherState; import interface_adapter.weather.WeatherViewModel; /** @@ -32,9 +33,13 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private LabelTextPanel humiditypanel; private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; - private LabelTextPanel searchresultpanel; - private final JLabel emptylabel = new JLabel(""); + private final JLabel city = new JLabel(""); + private final JLabel temp = new JLabel(""); + private final JLabel skycondition = new JLabel(""); + private final JLabel humidity = new JLabel(""); + private final JLabel windspeed = new JLabel(""); + private final JLabel visibility = new JLabel(""); private final JButton temperatureconverter; private ConverterController convertorController; @@ -50,8 +55,8 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); - weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); - temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), city); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, // or the opposite.The button needs an action listener that pass the change to a ConverterController. this.temperatureconverter = new JButton("Temperature Converter"); @@ -65,10 +70,10 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel convertorController.execute((Weather) evt.getSource()); } - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherfincitypanel); this.add(temperaturepanel); @@ -86,33 +91,18 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { - final String propertyName = evt.getPropertyName(); - final String newValue = (String) evt.getNewValue(); - - SwingUtilities.invokeLater(() -> { - switch (propertyName) { - case "city": - weatherfincitypanel.setoutput(newValue); - break; - case "temperature": - temperaturepanel.setoutput(newValue); - break; - case "skyCondition": - skyconditionpanel.setoutput(newValue); - break; - case "humidity": - humiditypanel.setoutput(newValue); - break; - case "windSpeed": - windspeedpanel.setoutput(newValue); - break; - case "visibility": - visibilitypanel.setoutput(newValue); - break; - } - }); + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + setfield(weatherState); } + public void setfield(WeatherState weatherState) { + city.setText(weatherState.getWeather().getCityName()); + temp.setText(String.valueOf(weatherState.getWeather().getTemperature())); + skycondition.setText(weatherState.getWeather().getWeather()); + humidity.setText(String.valueOf(weatherState.getWeather().getHumidity())); + windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); + visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); + } public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); From 0ff68fd9e0e095fed7fca54c101e651896d48add Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 15:59:55 -0800 Subject: [PATCH 149/267] adding property name when calling firepropertychange --- src/main/java/interface_adapter/weather/WeatherPresenter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/interface_adapter/weather/WeatherPresenter.java b/src/main/java/interface_adapter/weather/WeatherPresenter.java index 489c49f01..9a610d8ff 100644 --- a/src/main/java/interface_adapter/weather/WeatherPresenter.java +++ b/src/main/java/interface_adapter/weather/WeatherPresenter.java @@ -23,7 +23,7 @@ public WeatherPresenter(WeatherViewModel weatherViewModel) { public void presentSuccessView(SearchReturnOutputData response) { weatherViewModel.getState().setWeather(response.getWeather()); weatherViewModel.getState().setError(null); - weatherViewModel.firePropertyChanged(); + weatherViewModel.firePropertyChanged("Weather"); } /** From ffcc9fa9f95678cc17fb4e82a2195610bc2aec1d Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:00:29 -0800 Subject: [PATCH 150/267] add SearchResultPanelView into MainView --- src/main/java/view/MainView.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index eb746bc37..566c3c377 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -10,7 +10,9 @@ public class MainView extends JFrame { private MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; - private final int frameWidth = 1200; + private SearchResultPanelView searchResultPanelView; + + private final int frameWidth = 1500; private final int frameHeight = 1000; public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { @@ -20,18 +22,16 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); // I choose to use 1X2 gridlayout so we can have both panel side by side - this.setLayout(new GridLayout(1, 2)); + this.setLayout(new GridLayout(1, 3)); this.add(mapPanelView); this.add(weatherPanelView); + this.add(searchResultPanelView); // pack() optimize window size this.pack(); this.setVisible(true); } - public void firePropertyChanged() { - - } // public static void man(String[] args) { // new MainView(); // } From c500e3a152ebe7aff80d150d117355507e20a522 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:01:19 -0800 Subject: [PATCH 151/267] rename the property name --- .../CompareCities/CompareCitiesPresenter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java index 34364a325..7586935dd 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -24,7 +24,8 @@ public void prepareSuccessView(CompareCitiesOutPutData outputData) { viewModel.getState().setSecondCityName(outputData.getSecondCityname()); viewModel.getState().setFirstWeather(outputData.getFirstWeather()); viewModel.getState().setSecondWeather(outputData.getSecondWeather()); - viewModel.firePropertyChanged("City"); + + viewModel.firePropertyChanged("CompareCity"); } } From 2ab02bd0d555b5fbc6a16a78139476ec1f9a22c0 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:18:26 -0800 Subject: [PATCH 152/267] change text that repersent the converter --- src/main/java/view/WeatherPanelView.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 0a43b2bf6..c6e94041a 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -9,7 +9,6 @@ import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.SwingUtilities; import entity.Weather; import interface_adapter.SearchResult.SearchResultViewModel; @@ -40,7 +39,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final JLabel humidity = new JLabel(""); private final JLabel windspeed = new JLabel(""); private final JLabel visibility = new JLabel(""); - private final JButton temperatureconverter; + private final JButton unitconverter; private ConverterController convertorController; private static final int WEATHER_PANEL_WIDTH = 370; @@ -55,14 +54,14 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); - weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), city); + weatherfincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, // or the opposite.The button needs an action listener that pass the change to a ConverterController. - this.temperatureconverter = new JButton("Temperature Converter"); - temperatureconverter.addActionListener(event -> { + this.unitconverter = new JButton("Unit Converter"); + unitconverter.addActionListener(event -> { // if the event is coming from temperature converter button, execute convertor controller - if (event.getSource() == temperatureconverter) { + if (event.getSource() == unitconverter) { // todo: right now evt.getSource() return String "Temperature Converter", which is not a weather. But // the method execute in class ConverterController takes Weather object as input, need fix this. // a potential solution is change evt.getSource() to city name, and in ConverterController, turn @@ -81,7 +80,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.add(humiditypanel); this.add(windspeedpanel); this.add(visibilitypanel); - this.add(temperatureconverter); + this.add(unitconverter); }); /* * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. From d8566b72b873a06cd2d528ef7939d30e7771b9a1 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:36:39 -0800 Subject: [PATCH 153/267] add compareto panel for comparecities use case --- src/main/java/view/MapPanelView.java | 39 ++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index eb5d35932..842fb0ccb 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,54 +1,66 @@ package view; +import interface_adapter.CompareCities.CompareCitiesController; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.weather.WeatherController; -import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; /* -* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 3 parts: +* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: * 1. city input panel where user can type the city name. This is connected to an Action Lisenter, which pass infor * to our weatherContoller Class. * 2. date input panel +* 4. compare to button * 3. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. */ @SuppressWarnings("checkstyle:WriteTag") public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel cityinputpanel; private final LabelTextPanel dateinputpanel; + private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private final JTextField cityinputfield = new JTextField(15); + private final JTextField cityinputfield1 = new JTextField(15); private final JTextField dateinputfield = new JTextField(15); + private final JTextField cityinputfield2 = new JTextField(15); private final int mappanelwidth = 370; - private final int mappanelheight = 400; + private final int mappanelheight = 500; private SearchResultController searchResultController; private WeatherController weatherController; + private CompareCitiesController compareCitiesController; public MapPanelView() { mapimagepanel = new MapImagepanel(); - cityinputfield.addActionListener( + cityinputfield1.addActionListener( event -> { // if the event is coming from cityinput field, execute weather controller - if (event.getSource() == cityinputfield) { - weatherController.execute(cityinputfield.getText()); + if (event.getSource() == cityinputfield1) { + weatherController.execute(cityinputfield1.getText()); } } ); - cityinputpanel = new LabelTextPanel(new JLabel("search bar"), cityinputfield); + cityinputfield2.addActionListener( + event -> { + if (event.getSource() == cityinputfield2) { + compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + } + } + ) + cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); + comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); + dateinputfield.addActionListener( // if this event is coming from dateinput field, execute searchresult contoller event -> { if (event.getSource() == dateinputfield) { - searchResultController.execute(cityinputfield.getText(), dateinputfield.getText()); + searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); } }); // this.setSize(mappanelwidth, mappanelheight); @@ -87,6 +99,11 @@ public void setWeatherController(WeatherController weathercontroller) { } public void setSearchResultController(SearchResultController searchresultcontroller) { - this.searchResultController = searchresultcontroller; } + this.searchResultController = searchresultcontroller; + } + + public void setCompareCitiesController(CompareCitiesController compareCitiesController) { + this.compareCitiesController = compareCitiesController; + } } From dd7bf57bd0cb27e253e2315884c4a3e2cd5a997f Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sun, 24 Nov 2024 03:06:59 -0500 Subject: [PATCH 154/267] Made execute static --- .../java/interface_adapter/converter/ConverterController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 06cc40dff..526e0b180 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -15,7 +15,7 @@ public ConverterController(ConvertFarenheitInputBoundary cInteractor) { * Executes the convert case. * @param weather the note to be recorded */ - public void execute(Weather weather) { + public static void execute(Weather weather) { final ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); convertInteractor.executeConvert(inputData); } From f5313c291524accdb018be18bb007cf6d3e8a4f2 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Sun, 24 Nov 2024 16:22:11 -0500 Subject: [PATCH 155/267] removed assignment of weather description to alertDescription variable --- .../java/data_access/WeatherDataAccessObject.java | 2 +- src/main/java/entity/Weather.java | 11 ++++++----- .../alert_pop/AlertPopPresenter.java | 6 ++++++ .../java/interface_adapter/weather/WeatherState.java | 9 +++++++++ .../note/{ => alert_pop}/AlertPopInteractor.java | 0 5 files changed, 22 insertions(+), 6 deletions(-) rename src/main/java/use_case/note/{ => alert_pop}/AlertPopInteractor.java (100%) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index d0ef29247..23e320359 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -60,7 +60,7 @@ public Weather getWeather(String citySearch) throws IOException { final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); - String alertDescription = weatherJSON.getJSONObject("weather").getString("description"); + String alertDescription = "no weather alert"; if (weatherJSON.has("alerts")) { final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); if (alertsArray.length() > 0) { diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 829b5dfd4..9206e67bc 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -7,7 +7,7 @@ public class Weather { private float temperature; private String weather; - private final String description; + private final String alertDescription; private float windSpeed; private final int humidity; private final int visibility; @@ -16,11 +16,11 @@ public class Weather { private int lon; private int lat; - public Weather(String city, float temperature, String weather, String description, + public Weather(String city, float temperature, String weather, String alertDescription, float windSpeed, int humidity, int visibility, int lon, int lat) { this.temperature = temperature; this.weather = weather; - this.description = description; + this.alertDescription = alertDescription; this.windSpeed = windSpeed; this.humidity = humidity; this.visibility = visibility; @@ -71,8 +71,8 @@ public void setTemperature(float temperature) { } - public String getDescription() { - return description; + public String getAlertDescription() { + return alertDescription; } public void setWindSpeed(float windSpeed) { @@ -98,4 +98,5 @@ public int getHumidity() { public int getVisibility() { return visibility; } + } } diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java index 72874a294..434a47773 100644 --- a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java +++ b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java @@ -18,4 +18,10 @@ public void prepareSuccessView(AlertPopOutputData alertPopOutputData) { viewModel.firePropertyChanged(); } + @Override + public void prepareFailView(String message) { + viewModel.getState().setAlert(message); + viewModel.firePropertyChanged(); + } + } diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index 9eb9815d9..29b6b95a6 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -10,11 +10,16 @@ public class WeatherState { private Weather weather; private String error; + private String alert; public Weather getWeather() { return weather; } + public String getAlert() { + return alert; + } + public void setWeather(Weather weather) { this.weather = weather; } @@ -23,6 +28,10 @@ public void setError(String errorMessage) { this.error = errorMessage; } + public void setAlert(String alert) { + this.alert = alert; + } + public String getError() { return error; } diff --git a/src/main/java/use_case/note/AlertPopInteractor.java b/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java similarity index 100% rename from src/main/java/use_case/note/AlertPopInteractor.java rename to src/main/java/use_case/note/alert_pop/AlertPopInteractor.java From d9201325c77d17b8065bf13ac14110cf5cdca63c Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sun, 24 Nov 2024 16:41:12 -0500 Subject: [PATCH 156/267] Completed the ConvertInteractorTest file to ensure 100% code coverage. --- .../use_case/note/ConvertInteractorTest.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/test/java/use_case/note/ConvertInteractorTest.java diff --git a/src/test/java/use_case/note/ConvertInteractorTest.java b/src/test/java/use_case/note/ConvertInteractorTest.java new file mode 100644 index 000000000..d56676e18 --- /dev/null +++ b/src/test/java/use_case/note/ConvertInteractorTest.java @@ -0,0 +1,117 @@ +package use_case.note; + +import data_access.WeatherDataAccessObject; +import entity.Weather; +import org.junit.Test; +import use_case.note.convert_farenheit.ConvertFarenheitInputData; +import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; +import use_case.note.convert_farenheit.ConvertFarenheitOutputData; +import use_case.note.convert_farenheit.ConvertInteractor; + +import java.io.DataOutput; +import java.io.IOException; + +import static org.junit.Assert.*; + +public class ConvertInteractorTest { + + /** + * Checks Lines 1 - 14. + */ + @Test + public void TestIfWeatherDNE() { + WeatherDataAccessInterface Dao = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + return WeatherDataAccessObject.getWeather(city); + } + }; + ConvertFarenheitOutputBoundary boundary = new ConvertFarenheitOutputBoundary() { + @Override + public void prepareFailView(String errorMessage) { + assertEquals(errorMessage,"UNABLE TO CONVERT"); + } + + @Override + public void prepareSuccessView(ConvertFarenheitOutputData outputData) { + fail("this is unexpected"); + } + }; + Weather weather = Dao.getWeather("trn"); + + ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); + + ConvertInteractor interactor = new ConvertInteractor(boundary); + interactor.executeConvert(inputData); + } + + /** + * Convert to Fahrenheit. + * Checks Lines 28 - 36 and lines 15 - 22. + */ + @Test + public void TestIfMetricConversion() { + WeatherDataAccessInterface Dao = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + return WeatherDataAccessObject.getWeather(city); + } + }; + ConvertFarenheitOutputBoundary boundary = new ConvertFarenheitOutputBoundary() { + @Override + public void prepareFailView(String errorMessage) { + fail(errorMessage); + } + + @Override + public void prepareSuccessView(ConvertFarenheitOutputData outputData) { + assertEquals(false, outputData.getWeather().isMetric()); + + } + }; + + Weather weather = Dao.getWeather("Toronto"); + + ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); + + ConvertInteractor interactor = new ConvertInteractor(boundary); + interactor.executeConvert(inputData); + + + } + + /** + * Convert to Metric. + * Checks Lines 37 - end and lines 15 - 22. + */ + @Test + public void TestIfFahrenheitConversion() { + WeatherDataAccessInterface Dao = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + return WeatherDataAccessObject.getWeather(city); + } + }; + ConvertFarenheitOutputBoundary boundary = new ConvertFarenheitOutputBoundary() { + @Override + public void prepareFailView(String errorMessage) { + fail(errorMessage); + } + + @Override + public void prepareSuccessView(ConvertFarenheitOutputData outputData) { + assertTrue(outputData.getWeather().isMetric()); + + } + }; + + Weather weather = Dao.getWeather("Toronto"); + weather.setMetric(false); + + ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); + + ConvertInteractor interactor = new ConvertInteractor(boundary); + interactor.executeConvert(inputData); + + } +} From 48dbb3b84ccac56799fe82d32b565ae9e42b087b Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sun, 24 Nov 2024 17:52:04 -0500 Subject: [PATCH 157/267] Completed the Main Application file. Make Sure to discusss teh DAO. --- src/main/java/app/MainApplication.java | 44 ++++++++++++ src/main/java/app/MainNoteApplication.java | 68 ------------------- ...tionTest.java => MainApplicationTest.java} | 2 +- 3 files changed, 45 insertions(+), 69 deletions(-) create mode 100644 src/main/java/app/MainApplication.java delete mode 100644 src/main/java/app/MainNoteApplication.java rename src/test/java/app/{MainNoteApplicationTest.java => MainApplicationTest.java} (98%) diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java new file mode 100644 index 000000000..93ac1d099 --- /dev/null +++ b/src/main/java/app/MainApplication.java @@ -0,0 +1,44 @@ +package app; + +import data_access.WeatherDataAccessObject; +import use_case.note.WeatherDataAccessInterface; + +/** + * An application where we can view and add to a note stored by a user. + *

+ * This is a minimal example of using the password-protected user API from lab 5, + * but demonstrating the endpoint allowing you to store an arbitrary JSON object. + * This functionality could be used in any project where your team wants to persist + * data which is then accessible across devices.

+ *

The code is intentionally somewhat incomplete to leave work to be done if your + * team were to choose to work on a project which would require similar functionality. + * For example, we have intentionally not created a full "Note" entity here, but + * rather just represented a note as a string. + *

+ * The ViewManager code has also been removed, since this minimal program only requires a single + * view. Your team may wish to bring back the ViewManager or make your own implementation of supporting + * switching between views depending on your project. + */ +public class MainApplication { + + /** + * The main entry point of the application. + * @param args commandline arguments are ignored. + */ + public static void main(String[] args) { + + // create the data access and inject it into our builder! + final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); + + final AppBuilder builder = new AppBuilder(); + builder.addNoteDAO(noteDataAccess) + .addCompareCitiesUseCase() + .addConvertUseCase() + .addNearbyListUseCase() + .addSearchReturnUseCase() + .addSearchResultUseCase() + .addAlertPopUseCase() + .addMainView().build().setVisible(true); + + } +} diff --git a/src/main/java/app/MainNoteApplication.java b/src/main/java/app/MainNoteApplication.java deleted file mode 100644 index 4553283f1..000000000 --- a/src/main/java/app/MainNoteApplication.java +++ /dev/null @@ -1,68 +0,0 @@ -package app; - -import data_access.WeatherDataAccessObject; -import use_case.note.WeatherDataAccessInterface; - -/** - * An application where we can view and add to a note stored by a user. - *

- * This is a minimal example of using the password-protected user API from lab 5, - * but demonstrating the endpoint allowing you to store an arbitrary JSON object. - * This functionality could be used in any project where your team wants to persist - * data which is then accessible across devices.

- *

The code is intentionally somewhat incomplete to leave work to be done if your - * team were to choose to work on a project which would require similar functionality. - * For example, we have intentionally not created a full "Note" entity here, but - * rather just represented a note as a string. - *

- * The ViewManager code has also been removed, since this minimal program only requires a single - * view. Your team may wish to bring back the ViewManager or make your own implementation of supporting - * switching between views depending on your project. - */ -public class MainNoteApplication { - - /** - * The main entry point of the application. - *

- * The program will show you the note currently saved in the system. - * You are able to edit it and then save it to the system. You can refresh - * to update the note to reflect what was saved most recently. This - * uses the API from lab, so there is one database storing the note, - * which means that if anyone updates the note, that is what you will - * see when you refresh. - *

- * You can generalize the code to allow you to - * specify which "user" to save the note for, which will allow your team - * to store information specific to your team which is password-protected. - * The username and password used in this application are currently for - * user jonathan_calver2, but you can change that. As you did in lab 3, - * you will likely want to store password information locally rather than - * in your repo. Or you can require the user to enter their credentials - * in your application; it just depends on what your program's main - * functionality. - *

- * @param args commandline arguments are ignored - */ - public static void main(String[] args) { - - // create the data access and inject it into our builder! - final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); - - final AppBuilder builder = new AppBuilder(); - builder.addNoteDAO(noteDataAccess) - .addMainView() - .addConvertUseCase() - .addSearchResultView() - .addNearbyListView() - .addPinWeatherView() - .addAlertPopView() - .addSearchResultUseCase() - .addSearchReturnUseCase() - .addNearbyListUseCase() - .addPinWeatherUseCase() - .addAlertPopUseCase().build().setVisible(true); - // Annie: What should I do with the last line? First, I don't know if I need to add setVisible to all methods. - // Second, I assume noteView to be default view, and noteUseCase be return to the default view with empty - // search bar. - } -} diff --git a/src/test/java/app/MainNoteApplicationTest.java b/src/test/java/app/MainApplicationTest.java similarity index 98% rename from src/test/java/app/MainNoteApplicationTest.java rename to src/test/java/app/MainApplicationTest.java index 025d970e2..50109e35e 100644 --- a/src/test/java/app/MainNoteApplicationTest.java +++ b/src/test/java/app/MainApplicationTest.java @@ -11,7 +11,7 @@ import static java.lang.Thread.sleep; import static org.junit.Assert.*; -public class MainNoteApplicationTest { +public class MainApplicationTest { private JFrame app; From af94964cc493f277f9add71e0e77a28bfe67cf9f Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sun, 24 Nov 2024 17:57:15 -0500 Subject: [PATCH 158/267] Completed most of the App Builder but the Search Return Case. Please address the error in MainApplication. --- src/main/java/app/AppBuilder.java | 168 +++++++++++++++---------- src/main/java/app/MainApplication.java | 2 +- 2 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index bdaa15573..f554df367 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -3,19 +3,47 @@ import javax.swing.JFrame; import javax.swing.WindowConstants; +import data_access.WeatherDataAccessObject; +import entity.Weather; +import interface_adapter.CompareCities.CompareCitiesController; +import interface_adapter.CompareCities.CompareCitiesPresenter; +import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.SearchResult.SearchResultPresenter; +import interface_adapter.SearchResult.SearchResultViewModel; +import interface_adapter.alert_pop.AlertPopController; +import interface_adapter.alert_pop.AlertPopPresenter; import interface_adapter.converter.ConverterController; import interface_adapter.converter.ConverterPresenter; +import interface_adapter.nearby_list.NearbyListController; +import interface_adapter.nearby_list.NearbyListPresenter; +import interface_adapter.nearby_list.NearbyListViewModel; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherPresenter; import interface_adapter.weather.WeatherViewModel; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; +import use_case.note.CompareCities.CompareCitiesInteractor; +import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; import use_case.note.SearchResultInteractor; +import use_case.note.SearchReturnInteractor; import use_case.note.WeatherDataAccessInterface; +import use_case.note.alert_pop.AlertPopInteractor; +import use_case.note.alert_pop.AlertPopOutputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; import use_case.note.convert_farenheit.ConvertInteractor; +import use_case.note.nearby_list.NearbyCitiesAccessInterface; +import use_case.note.nearby_list.NearbyListInteractor; +import use_case.note.nearby_list.NearbyListOutputBoundary; import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_return.SearchReturnInputBoundary; +import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; +import java.io.IOException; +import java.util.List; +import java.util.Map; + /** * Builder for the Note Application. */ @@ -25,8 +53,10 @@ public class AppBuilder { private WeatherDataAccessInterface weatherDAO; private HistoricalWeatherDataAccessInterface historyDAO; private WeatherViewModel weatherViewModel = new WeatherViewModel(); + private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); + private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); + private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); private MainView mainView; - private NoteInteractor interactor; /** * Sets the DAO to be used in this application. @@ -50,9 +80,6 @@ public JFrame build() { frame.add(mainView); - // refresh so that the note will be visible when we start the program - interactor.executeRefresh(); - return frame; } @@ -64,38 +91,66 @@ public JFrame build() { * @return this builder * @throws RuntimeException if this method is called before addNoteView - */ + **/ + public AppBuilder addAlertPopUseCase() { + final AlertPopOutputBoundary outputBoundary = new AlertPopPresenter(weatherViewModel); + final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + return WeatherDataAccessObject.getWeather(city); + } + }; - public AppBuilder addSearchResultUseCase() { - final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(weatherViewModel); - final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); + final AlertPopInteractor interactor = new AlertPopInteractor(accessInterface, outputBoundary); - final SearchResultController controller = new SearchResultController(interactor); + final AlertPopController controller = new AlertPopController(interactor); if (mainView == null) { - throw new RuntimeException("addNoteView must be called before addSearchResultUseCase"); + throw new RuntimeException("Error"); } - mainView.setController(controller); return this; } - public AppBuilder addAlertPopUseCase() { - // no presenter - } + public AppBuilder addCompareCitiesUseCase() { + final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); + final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { + @Override + public boolean isCityexist(String cityname) { + return false; + } - public AppBuilder addSearchReturnUseCase() { - // no presenter / controller - } + @Override + public Weather getWeather(String cityname) throws IOException { + return null; + } - public AppBuilder addSelectRegionUseCase() { - // no presenter / controller - } + @Override + public void saveWeatherinfor(Weather weather) { - public AppBuilder addNearbyListUseCase() { - // no presenter / controller - } + } - public AppBuilder addCompareCitiesUseCase() { - // no controller + @Override + public Map getcitytoweather() { + return Map.of(); + } + + @Override + public boolean isCityExist(String cityname) { + return false; + } + + @Override + public void clearcitytoweather() { + + } + }; + + final CompareCitiesInteractor interactor = new CompareCitiesInteractor(dai, outputBoundary); + + final CompareCitiesController controller = new CompareCitiesController(interactor); + if (mainView == null) { + throw new RuntimeException("Error"); + } + return this; } public AppBuilder addConvertUseCase() { @@ -104,55 +159,42 @@ public AppBuilder addConvertUseCase() { final ConverterController controller = new ConverterController(interactor); if (mainView == null) { - throw new RuntimeException("addNoteView must be called before addConvertUseCase"); + throw new RuntimeException("Error"); } - mainView.setController(controller); return this; } + public AppBuilder addNearbyListUseCase() { + final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); + final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { + @Override + public List getNearbyCities(Float latitude, Float longitude) throws IOException { + return List.of(); + } + }; - public AppBuilder addCloseListUseCase() { - // no presenter / controller - } - - public AppBuilder addPinWeatherUseCase() { - // no presenter / controller - } - - public AppBuilder addClosePinUseCase() { - // no presenter / controller - } + final NearbyListInteractor interactor = new NearbyListInteractor(outputBoundary, dai); - public AppBuilder addClosePopUseCase() { - // no presenter / controller + final NearbyListController controller = new NearbyListController(interactor); + if (mainView == null) { + throw new RuntimeException("Error"); + } + return this; } - - public AppBuilder addBookmarkReturnCase() { - // no presenter / controller + public AppBuilder addSearchReturnUseCase() { + // can someone complete this its comfusing me. } + public AppBuilder addSearchResultUseCase() { + final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(searchResultViewModel); + final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); - public AppBuilder addCityBookmarkUseCase() { - // no presenter / controller + final SearchResultController controller = new SearchResultController(interactor); + if (mainView == null) { + throw new RuntimeException("Error"); + } + return this; } // add stuff for all the views - public AppBuilder addSearchResultView() { - } - - public AppBuilder addSelectRegionView() { - } - - public AppBuilder addNearbyListView() { - } - - public AppBuilder addPinWeatherView() { - } - - public AppBuilder addAlertPopView() { - } - - public AppBuilder addCityBookmarkView() { - } - public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); mainView = new MainView(weatherViewModel); diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index 93ac1d099..b596ce135 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -31,7 +31,7 @@ public static void main(String[] args) { final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); final AppBuilder builder = new AppBuilder(); - builder.addNoteDAO(noteDataAccess) + builder.addDAO(noteDataAccess) .addCompareCitiesUseCase() .addConvertUseCase() .addNearbyListUseCase() From d4142df72bce9909434b32bba22a0cc7113d4d26 Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Mon, 25 Nov 2024 01:47:23 -0500 Subject: [PATCH 159/267] added use case to AppBuilder --- pom.xml | 49 ++++++++++++++++++- src/main/java/app/AppBuilder.java | 22 +++++++-- src/main/java/entity/Weather.java | 3 +- src/main/java/view/MainView.java | 1 + src/main/java/view/MapPanelView.java | 2 + .../alert_pop/AlertPopInteractorTest.java | 20 ++++++++ 6 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java diff --git a/pom.xml b/pom.xml index c181fb0f6..230991534 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,54 @@ jxmapviewer2 2.8 - + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index bdaa15573..c0ba4d03e 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -1,25 +1,31 @@ package app; -import javax.swing.JFrame; -import javax.swing.WindowConstants; +import javax.swing.*; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.SearchResult.SearchResultPresenter; +import interface_adapter.alert_pop.AlertPopController; +import interface_adapter.alert_pop.AlertPopPresenter; import interface_adapter.converter.ConverterController; import interface_adapter.converter.ConverterPresenter; import interface_adapter.weather.WeatherViewModel; import use_case.note.HistoricalWeatherDataAccessInterface; import use_case.note.SearchResultInteractor; import use_case.note.WeatherDataAccessInterface; +import use_case.note.alert_pop.AlertPopInteractor; +import use_case.note.alert_pop.AlertPopOutputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; import use_case.note.convert_farenheit.ConvertInteractor; import use_case.note.search_result.SearchResultOutputBoundary; import view.MainView; +import java.awt.*; + /** * Builder for the Note Application. */ public class AppBuilder { + public static final int HEIGHT = 750; public static final int WIDTH = 1500; private WeatherDataAccessInterface weatherDAO; @@ -45,7 +51,7 @@ public AppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { public JFrame build() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Note Application"); + frame.setTitle("Weather Wizard"); frame.setSize(WIDTH, HEIGHT); frame.add(mainView); @@ -79,7 +85,15 @@ public AppBuilder addSearchResultUseCase() { } public AppBuilder addAlertPopUseCase() { - // no presenter + final AlertPopOutputBoundary alertPopOutputBoundary = new AlertPopPresenter(weatherViewModel); + final AlertPopInteractor alertPopInteractor = new AlertPopInteractor(weatherDAO, alertPopOutputBoundary); + + final AlertPopController controller = new AlertPopController(alertPopInteractor); + if (mainView == null) { + throw new RuntimeException("addNoteView must be called before addSearchResultUseCase"); + } + mainView.setAlertPopController(controller); + return this; } public AppBuilder addSearchReturnUseCase() { diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 9206e67bc..eaa2b73cf 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -98,5 +98,4 @@ public int getHumidity() { public int getVisibility() { return visibility; } - } -} +} \ No newline at end of file diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 4438a0094..f4e30f4d3 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -30,6 +30,7 @@ public MainView(WeatherViewModel weatherViewModel) { public void firePropertyChanged() { } + // public static void man(String[] args) { // new MainView(); // } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index eb5d35932..7767cee1a 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -23,7 +23,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final MapImagepanel mapimagepanel; private final JTextField cityinputfield = new JTextField(15); + private final JButton alert; private final JTextField dateinputfield = new JTextField(15); + private final JButton search; private final int mappanelwidth = 370; private final int mappanelheight = 400; diff --git a/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java b/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java new file mode 100644 index 000000000..f31174e7f --- /dev/null +++ b/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java @@ -0,0 +1,20 @@ +package use_case.note.alert_pop; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class AlertPopInteractorTest { + + private AlertPopInteractor interactor; + + @BeforeEach + void init() { + interactor = new AlertPopInteractor(); + } + + @Test + void execute() { + } +} \ No newline at end of file From 485dbf9f3ded70565e0e9ded6a5cd8c70e1104cc Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 05:46:16 -0800 Subject: [PATCH 160/267] add CompareCitiesView --- src/main/java/view/CompareCitiesView.java | 96 +++++++++++++++++++++++ src/main/java/view/WeatherPanelView.java | 32 ++++---- 2 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 src/main/java/view/CompareCitiesView.java diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java new file mode 100644 index 000000000..0c51531e3 --- /dev/null +++ b/src/main/java/view/CompareCitiesView.java @@ -0,0 +1,96 @@ +package view; + +import interface_adapter.CompareCities.CompareCitiesState; +import interface_adapter.CompareCities.CompareCitiesViewModel; +import interface_adapter.weather.WeatherState; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class CompareCitiesView extends JFrame implements PropertyChangeListener { + private final LabelTextPanel weatherincitypanelA; + private final LabelTextPanel temperaturepanelA; + private LabelTextPanel skyconditionpanelA; + private LabelTextPanel humiditypanelA; + private LabelTextPanel windspeedpanelA; + private LabelTextPanel visibilitypanelA; + + private final JLabel cityA = new JLabel(""); + private final JLabel tempA = new JLabel(""); + private final JLabel skyconditionA = new JLabel(""); + private final JLabel humidityA = new JLabel(""); + private final JLabel windspeedA = new JLabel(""); + private final JLabel visibilityA = new JLabel(""); + + private final LabelTextPanel weatherincitypanelB; + private final LabelTextPanel temperaturepanelB; + private LabelTextPanel skyconditionpanelB; + private LabelTextPanel humiditypanelB; + private LabelTextPanel windspeedpanelB; + private LabelTextPanel visibilitypanelB; + + private final JLabel cityB = new JLabel(""); + private final JLabel tempB = new JLabel(""); + private final JLabel skyconditionB = new JLabel(""); + private final JLabel humidityB = new JLabel(""); + private final JLabel windspeedB = new JLabel(""); + private final JLabel visibilityB = new JLabel(""); + + private CompareCitiesViewModel compareCitiesViewModel; + + public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { + this.compareCitiesViewModel = compareCitiesViewModel; + + weatherincitypanelA = new LabelTextPanel(new JLabel("Current Weather in"), cityA); + temperaturepanelA = new LabelTextPanel(new JLabel("Temperature"), tempA); + skyconditionpanelA = new LabelTextPanel(new JLabel("Sky"), skyconditionA); + humiditypanelA = new LabelTextPanel(new JLabel("Humidity"), humidityA); + windspeedpanelA = new LabelTextPanel(new JLabel("Wind"), windspeedA); + visibilitypanelA = new LabelTextPanel(new JLabel("Visibility"), visibilityA); + + weatherincitypanelB = new LabelTextPanel(new JLabel("Current Weather in"), cityB); + temperaturepanelB = new LabelTextPanel(new JLabel("Temperature"), tempB); + skyconditionpanelB = new LabelTextPanel(new JLabel("Sky"), skyconditionB); + humiditypanelB = new LabelTextPanel(new JLabel("Humidity"), humidityB); + windspeedpanelB = new LabelTextPanel(new JLabel("Wind"), windspeedB); + visibilitypanelB = new LabelTextPanel(new JLabel("Visibility"), visibilityB); + + this.setLayout(new GridLayout(2, 6)); + this.add(weatherincitypanelA, BorderLayout.WEST); + this.add(temperaturepanelA, BorderLayout.WEST); + this.add(skyconditionpanelA, BorderLayout.WEST); + this.add(humiditypanelA, BorderLayout.WEST); + this.add(windspeedpanelA, BorderLayout.WEST); + this.add(visibilitypanelA, BorderLayout.WEST); + this.add(weatherincitypanelB, BorderLayout.EAST); + this.add(temperaturepanelB, BorderLayout.EAST); + this.add(skyconditionpanelB, BorderLayout.EAST); + this.add(humiditypanelB, BorderLayout.EAST); + this.add(windspeedpanelB, BorderLayout.EAST); + this.add(visibilitypanelB, BorderLayout.EAST); + + this.setVisible(true); + this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + } + + public void propertyChange(PropertyChangeEvent evt) { + final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); + setfield(compareCitiesState); + } + + public void setfield(CompareCitiesState compareCitiesState) { + cityA.setText(compareCitiesState.getFirstWeather().getCityName()); + tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); + skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); + humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); + windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); + visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); + } + public void actionPerformed(ActionEvent event) { + System.out.println("Enter" + event.getActionCommand()); + + } +} diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index c6e94041a..c7eea2f05 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -26,7 +26,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final WeatherViewModel weatherViewModel; private SearchResultViewModel searchResultViewModel; - private final LabelTextPanel weatherfincitypanel; + private final LabelTextPanel weatherincitypanel; private final LabelTextPanel temperaturepanel; private LabelTextPanel skyconditionpanel; private LabelTextPanel humiditypanel; @@ -54,7 +54,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); - weatherfincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); + weatherincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, // or the opposite.The button needs an action listener that pass the change to a ConverterController. @@ -68,24 +68,20 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel // cityname into Weather(call DAO). convertorController.execute((Weather) evt.getSource()); } - - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); - this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.add(weatherfincitypanel); - this.add(temperaturepanel); - this.add(skyconditionpanel); - this.add(humiditypanel); - this.add(windspeedpanel); - this.add(visibilitypanel); - this.add(unitconverter); }); - /* - * method listens for changes in the WeatherViewModel and updates each LabelTextPanel based on the new data. - */ + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + this.add(weatherincitypanel); + this.add(temperaturepanel); + this.add(skyconditionpanel); + this.add(humiditypanel); + this.add(windspeedpanel); + this.add(visibilitypanel); + this.add(unitconverter); } @Override From f4c98b488b30b4cd3d4a805edcf6a3c0b0e9bfb4 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 25 Nov 2024 10:19:39 -0500 Subject: [PATCH 161/267] SearchReturnInteractor --- src/main/java/use_case/note/SearchReturnInteractor.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java index 07fbd8d43..30434834c 100644 --- a/src/main/java/use_case/note/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -1,7 +1,6 @@ package use_case.note; import entity.Weather; -import use_case.note.WeatherDataAccessInterface; import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnInputData; import use_case.note.search_return.SearchReturnOutputBoundary; @@ -9,14 +8,8 @@ import java.io.IOException; import java.time.Instant; -import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; /** * The interactor for the search return use case. From b35a2ff9088fdccc75f98c2c6f86b4bfd7a35ca4 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Mon, 25 Nov 2024 10:20:54 -0500 Subject: [PATCH 162/267] Fixed changes in App Builder --- pom.xml | 13 +++++++++++- src/main/java/app/AppBuilder.java | 21 ++++++++++++++++--- .../data_access/NearbyCitiesAccessObject.java | 3 ++- .../data_access/WeatherDataAccessObject.java | 7 ++++--- src/main/java/entity/Weather.java | 1 - src/main/java/view/MainView.java | 14 +++++-------- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index c181fb0f6..4fb08385b 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,18 @@ jxmapviewer2 2.8 - + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + org.junit.jupiter + junit-jupiter + RELEASE + test + diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index f554df367..c82882076 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -20,6 +20,7 @@ import interface_adapter.nearby_list.NearbyListViewModel; import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherPresenter; +import interface_adapter.weather.WeatherState; import interface_adapter.weather.WeatherViewModel; import use_case.note.CompareCities.CompareCitiesDataAccessInterface; import use_case.note.CompareCities.CompareCitiesInteractor; @@ -40,6 +41,7 @@ import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; +import java.beans.PropertyChangeEvent; import java.io.IOException; import java.util.List; import java.util.Map; @@ -57,13 +59,14 @@ public class AppBuilder { private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); private MainView mainView; + private PropertyChangeEvent evt; /** * Sets the DAO to be used in this application. * @param weatherDataAccess the DAO to use * @return this builder */ - public AppBuilder addNoteDAO(WeatherDataAccessInterface weatherDataAccess) { + public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { weatherDAO = weatherDataAccess; return this; } @@ -99,6 +102,7 @@ public AppBuilder addAlertPopUseCase() { public Weather getWeather(String city) throws IOException { return WeatherDataAccessObject.getWeather(city); } + }; final AlertPopInteractor interactor = new AlertPopInteractor(accessInterface, outputBoundary); @@ -180,9 +184,18 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx } return this; } + public AppBuilder addSearchReturnUseCase() { - // can someone complete this its comfusing me. + final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); + final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); + + final WeatherController controller = new WeatherController(interactor); + if (mainView == null) { + throw new RuntimeException("Error"); + } + return this; } + public AppBuilder addSearchResultUseCase() { final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(searchResultViewModel); final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); @@ -197,7 +210,9 @@ public AppBuilder addSearchResultUseCase() { // add stuff for all the views public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); - mainView = new MainView(weatherViewModel); + searchResultViewModel = new SearchResultViewModel(); + evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); + mainView = new MainView(weatherViewModel, searchResultViewModel, evt); return this; } } diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index 0c8f0afba..b929673f8 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -24,7 +24,8 @@ public abstract class NearbyCitiesAccessObject implements NearbyCitiesAccessInte @Override public List getNearbyCities(Float latitude, Float longitude) throws IOException { - if (latitude == null || longitude == null || latitude < LOWER_LAT || latitude > UPPER_LAT || longitude < LOWER_LON || longitude > UPPER_LON) { + if (latitude == null || longitude == null || latitude < LOWER_LAT + || latitude > UPPER_LAT || longitude < LOWER_LON || longitude > UPPER_LON) { throw new IOException(); } try { diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index d0ef29247..4a08958e3 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -15,7 +15,6 @@ import java.util.HashMap; import java.util.Map; - /** * This class runs the API and creates a weather DAO. **/ @@ -69,10 +68,12 @@ public Weather getWeather(String citySearch) throws IOException { } return new Weather(citySearch, temp, looks, alertDescription, windspeed, humidity, visibility, lon, lat); - } else { + } + else { throw new IOException(responseBody.getString(MESSAGE)); } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { throw new IOException(ex); } } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 829b5dfd4..ac3b166f8 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -70,7 +70,6 @@ public void setTemperature(float temperature) { this.temperature = temperature; } - public String getDescription() { return description; } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 4438a0094..85ee3bdc1 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,9 +1,12 @@ package view; +import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; import javax.swing.JFrame; import java.awt.GridLayout; +import java.beans.PropertyChangeEvent; public class MainView extends JFrame { private MapPanelView mapPanelView; @@ -11,9 +14,9 @@ public class MainView extends JFrame { private final int frameWidth = 1200; private final int frameHeight = 1000; - public MainView(WeatherViewModel weatherViewModel) { + public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { mapPanelView = new MapPanelView(); - weatherPanelView = new WeatherPanelView(weatherViewModel); + weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); @@ -27,11 +30,4 @@ public MainView(WeatherViewModel weatherViewModel) { } - public void firePropertyChanged() { - - } -// public static void man(String[] args) { -// new MainView(); -// } - } From 6c63f0a8ae015ae30a8a94000a6b7da95fb68314 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Mon, 25 Nov 2024 10:22:58 -0500 Subject: [PATCH 163/267] Changed MapImagePanel to return a JXMapViewer object rather than a JPanel --- src/main/java/view/MapImagepanel.java | 62 +++++++++++++-------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index b61fa74c9..b0bd45393 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -1,46 +1,42 @@ package view; +import org.jxmapviewer.JXMapViewer; +import org.jxmapviewer.OSMTileFactoryInfo; +import org.jxmapviewer.viewer.DefaultTileFactory; +import org.jxmapviewer.viewer.GeoPosition; +import org.jxmapviewer.viewer.TileFactoryInfo; + import javax.swing.*; -import java.awt.*; /* * the MapImagePanel is responsible for displaying the map file. */ public class MapImagepanel extends JPanel { - private ImageIcon imagemap; - private String filename; - private JLabel displayfield; - - // if no arg given, use the example MapImage.png - public MapImagepanel() { - // this is a local image - this.filename = "/Users/sophie/IdeaProjects/WeatherWizard/src/main/java/view/MapImage.png"; - try { - imagemap = new ImageIcon(this.filename); - displayfield = new JLabel(imagemap); - this.add(displayfield); - this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); - - } catch (Exception e) { - System.out.println("image cannot be found"); - } - } + private static final int ZOOM_VALUE = 7; + private static final int NUM_THREADS = 8; + + private double[] coords; + private JXMapViewer mapViewer; + + // Generates a JXMapViewer object given latitude and longitude + public MapImagepanel(double latitude, double longitude) { + this.coords = new double[] {latitude, longitude}; + this.mapViewer = new JXMapViewer(); + + TileFactoryInfo info = new OSMTileFactoryInfo(); + DefaultTileFactory tileFactory = new DefaultTileFactory(info); + + this.mapViewer.setTileFactory(tileFactory); + + tileFactory.setThreadPoolSize(NUM_THREADS); + + GeoPosition position = new GeoPosition(this.coords); - // or pass a filename as an argument - public MapImagepanel(String filename) { - this.filename = filename; - try { - imagemap = new ImageIcon(this.filename); - displayfield = new JLabel(imagemap); - this.add(displayfield); - this.setPreferredSize(new Dimension(imagemap.getIconWidth(), imagemap.getIconHeight())); - - } catch (Exception e) { - System.out.println("image cannot be found"); - } + this.mapViewer.setZoom(ZOOM_VALUE); + mapViewer.setAddressLocation(position); } - public JLabel getDisplayfield() { - return displayfield; + public JXMapViewer getDisplayfield() { + return this.mapViewer; } } From 6e71550087e93e5665491cc2169bc6e0d3f8dbab Mon Sep 17 00:00:00 2001 From: Annie Bu Date: Mon, 25 Nov 2024 12:15:58 -0500 Subject: [PATCH 164/267] In Weather Class: Previously changed var "description" to var"alertDescription". This time, added var "description. //TODO: HistoricalWeatherObjectAccessData Changed weather declaration, uncertain if it there is key "description" and "alertDescription" for historical weather. If no we need to change Weather class. --- .../HistoricalWeatherDataAccessObject.java | 7 +++-- .../data_access/TestDataAccessObject.java | 26 +++++++++++++++++++ .../data_access/WeatherDataAccessObject.java | 7 ++--- src/main/java/entity/Weather.java | 13 +++++++--- .../alert_pop/AlertPopInteractorTest.java | 22 +++++++++++++--- 5 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 src/main/java/data_access/TestDataAccessObject.java diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 65de832a0..85f3620ac 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -71,16 +71,19 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Checking if the city and timestamp match the input if (cityNameCall.equals(city) && timeStamp.equals(timestamp)) { // Create weather object + //TODO: Changed weather declaration, uncertain if it there is key "description" and + // "alertDescription" for historical weather. If no we need to change Weather class. final Weather weather = new Weather( cityNameCall, weatherObject.getInt("temperature"), weatherObject.getString("looks"), - weatherObject.getString("alertDescription"), + weatherObject.getString("description"), weatherObject.getInt("windSpeed"), weatherObject.getInt("longitude"), weatherObject.getInt("humidity"), weatherObject.getInt("longitude"), - weatherObject.getInt("latitude") + weatherObject.getInt("latitude"), + weatherObject.getString("alertDescription") ); return weather; } diff --git a/src/main/java/data_access/TestDataAccessObject.java b/src/main/java/data_access/TestDataAccessObject.java new file mode 100644 index 000000000..e97b75c7f --- /dev/null +++ b/src/main/java/data_access/TestDataAccessObject.java @@ -0,0 +1,26 @@ +package data_access; + +import entity.Weather; +import use_case.note.WeatherDataAccessInterface; + +import java.util.HashMap; +import java.util.Map; + + +public class TestDataAccessObject implements WeatherDataAccessInterface { + + private final Map citytoweather = new HashMap<>(); + + /** + * Stores a Weather object into the citytoweather map in the class. + * @param weather a Weather object containing the city name and all other weather information. + */ + public void saveWeatherinfor(Weather weather) { + citytoweather.put(weather.getCityName(), weather); + } + + @Override + public Weather getWeather(String citySearch) { + return citytoweather.get(citySearch); + } +} diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 23e320359..0ba4bc7dd 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -20,7 +20,7 @@ * This class runs the API and creates a weather DAO. **/ -public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { +public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface{ private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; private static String city; @@ -60,6 +60,7 @@ public Weather getWeather(String citySearch) throws IOException { final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); + final String description = weatherJSON.getJSONObject("weather").getString("description"); String alertDescription = "no weather alert"; if (weatherJSON.has("alerts")) { final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); @@ -67,8 +68,8 @@ public Weather getWeather(String citySearch) throws IOException { alertDescription = alertsArray.getJSONObject(0).getString("description"); } } - return new Weather(citySearch, temp, looks, alertDescription, windspeed, humidity, - visibility, lon, lat); + return new Weather(citySearch, temp, looks, description, windspeed, humidity, + visibility, lon, lat, alertDescription); } else { throw new IOException(responseBody.getString(MESSAGE)); } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index eaa2b73cf..9246569ed 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -7,7 +7,7 @@ public class Weather { private float temperature; private String weather; - private final String alertDescription; + private final String description; private float windSpeed; private final int humidity; private final int visibility; @@ -15,12 +15,13 @@ public class Weather { private String cityName; private int lon; private int lat; + private final String alertDescription; - public Weather(String city, float temperature, String weather, String alertDescription, - float windSpeed, int humidity, int visibility, int lon, int lat) { + public Weather(String city, float temperature, String weather, String description, float windSpeed, + int humidity, int visibility, int lon, int lat, String alertDescription) { this.temperature = temperature; this.weather = weather; - this.alertDescription = alertDescription; + this.description = description; this.windSpeed = windSpeed; this.humidity = humidity; this.visibility = visibility; @@ -28,6 +29,7 @@ public Weather(String city, float temperature, String weather, String alertDescr this.metric = false; this.lon = lon; this.lat = lat; + this.alertDescription = alertDescription; } public void setWeather(String weather) { @@ -70,6 +72,9 @@ public void setTemperature(float temperature) { this.temperature = temperature; } + public String getDescription() { + return description; + } public String getAlertDescription() { return alertDescription; diff --git a/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java b/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java index f31174e7f..01b33a520 100644 --- a/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java +++ b/src/test/java/use_case/note/alert_pop/AlertPopInteractorTest.java @@ -1,20 +1,36 @@ package use_case.note.alert_pop; +import data_access.TestDataAccessObject; +import data_access.WeatherDataAccessObject; +import entity.Weather; +import interface_adapter.alert_pop.AlertPopPresenter; +import interface_adapter.weather.WeatherViewModel; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import use_case.note.WeatherDataAccessInterface; import static org.junit.jupiter.api.Assertions.*; class AlertPopInteractorTest { - private AlertPopInteractor interactor; + private TestDataAccessObject testDataAccess; + private WeatherViewModel weatherViewModel; + private AlertPopOutputBoundary alertPopOutputBoundary; + private AlertPopInputData alertPopInputData; @BeforeEach void init() { - interactor = new AlertPopInteractor(); + testDataAccess = new TestDataAccessObject(); + weatherViewModel = new WeatherViewModel(); + alertPopOutputBoundary = new AlertPopPresenter(weatherViewModel); } @Test - void execute() { + void successTest() { + alertPopInputData = new AlertPopInputData("Toronto"); + AlertPopInteractor interactor = new AlertPopInteractor(testDataAccess, alertPopOutputBoundary); + Weather weather = new Weather("Toronto", 12f, "Sunny", "broken clouds", + 21f, 69, 24, 79, 44, "no weather alert"); + testDataAccess.saveWeatherinfor(weather); } } \ No newline at end of file From 93200b7279463486d30e3a12594a4535dd9316c7 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Mon, 25 Nov 2024 19:35:23 -0500 Subject: [PATCH 165/267] refacotr SearchResultInteractor into the folder. Fixed the static method bug. --- src/main/java/app/AppBuilder.java | 5 ++--- .../converter/ConverterController.java | 5 ++++- .../{ => search_result}/SearchResultInteractor.java | 11 +++-------- .../{ => search_return}/SearchReturnInteractor.java | 8 +++----- src/main/java/view/MainView.java | 2 +- src/main/java/view/MapPanelView.java | 2 +- .../use_case/note/SearchResultInteractorTest.java | 4 ++++ 7 files changed, 18 insertions(+), 19 deletions(-) rename src/main/java/use_case/note/{ => search_result}/SearchResultInteractor.java (83%) rename src/main/java/use_case/note/{ => search_return}/SearchReturnInteractor.java (88%) create mode 100644 src/test/java/use_case/note/SearchResultInteractorTest.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index c0e5efd23..9924e340d 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -25,8 +25,8 @@ import use_case.note.CompareCities.CompareCitiesInteractor; import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; -import use_case.note.SearchResultInteractor; -import use_case.note.SearchReturnInteractor; +import use_case.note.search_result.SearchResultInteractor; +import use_case.note.search_return.SearchReturnInteractor; import use_case.note.WeatherDataAccessInterface; import use_case.note.alert_pop.AlertPopInteractor; import use_case.note.alert_pop.AlertPopOutputBoundary; @@ -36,7 +36,6 @@ import use_case.note.nearby_list.NearbyListInteractor; import use_case.note.nearby_list.NearbyListOutputBoundary; import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 526e0b180..2eabafb3f 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -4,6 +4,9 @@ import use_case.note.convert_farenheit.ConvertFarenheitInputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitInputData; +/** + * Controller for the convert case. + */ public class ConverterController { private final ConvertFarenheitInputBoundary convertInteractor; @@ -15,7 +18,7 @@ public ConverterController(ConvertFarenheitInputBoundary cInteractor) { * Executes the convert case. * @param weather the note to be recorded */ - public static void execute(Weather weather) { + public void execute(Weather weather) { final ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); convertInteractor.executeConvert(inputData); } diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java similarity index 83% rename from src/main/java/use_case/note/SearchResultInteractor.java rename to src/main/java/use_case/note/search_result/SearchResultInteractor.java index b33b9a07f..432a9b541 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -1,15 +1,10 @@ -package use_case.note; +package use_case.note.search_result; import java.io.IOException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import entity.Weather; -import use_case.note.search_result.SearchResultInputBoundary; -import use_case.note.search_result.SearchResultInputData; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; +import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; /** * The interactor for the search result use case. diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java similarity index 88% rename from src/main/java/use_case/note/SearchReturnInteractor.java rename to src/main/java/use_case/note/search_return/SearchReturnInteractor.java index 30434834c..3c0aaff22 100644 --- a/src/main/java/use_case/note/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java @@ -1,10 +1,8 @@ -package use_case.note; +package use_case.note.search_return; import entity.Weather; -import use_case.note.search_return.SearchReturnInputBoundary; -import use_case.note.search_return.SearchReturnInputData; -import use_case.note.search_return.SearchReturnOutputBoundary; -import use_case.note.search_return.SearchReturnOutputData; +import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; import java.io.IOException; import java.time.Instant; diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index e1c1afc82..65f506db3 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -11,7 +11,7 @@ public class MainView extends JFrame { private MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; - private SearchResultPanelView searchResultPanelView; + private HistoricalSearchedWeatherView searchResultPanelView; private final int frameWidth = 1500; private final int frameHeight = 1000; diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index a71ea8b8c..6782619be 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -53,7 +53,7 @@ public MapPanelView() { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); } } - ) + ); cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java new file mode 100644 index 000000000..182a5fe49 --- /dev/null +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -0,0 +1,4 @@ +package use_case.note; + +public class SearchResultInteractorTest { +} From fd1d89601174aa8a79e5c7426b7df3e89f116166 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:00:29 -0800 Subject: [PATCH 166/267] add SearchResultPanelView into MainView # Conflicts: # src/main/java/view/MainView.java --- src/main/java/view/MainView.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 65f506db3..fb7477cd4 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,6 +1,5 @@ package view; -import interface_adapter.SearchResult.SearchResultController; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; @@ -33,4 +32,8 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR } +// public static void man(String[] args) { +// new MainView(); +// } + } From c58fc066cfcada5ba1a73de910652dd3cf1973b1 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:36:39 -0800 Subject: [PATCH 167/267] add compareto panel for comparecities use case # Conflicts: # src/main/java/view/MapPanelView.java --- src/main/java/view/MapPanelView.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 6782619be..12e3c015e 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -23,11 +23,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private final JTextField cityinputfield1 = new JTextField(15); private final JTextField dateinputfield = new JTextField(15); private final JTextField cityinputfield2 = new JTextField(15); - private final int mappanelwidth = 370; private final int mappanelheight = 500; From 318d7d6e98f67c1a3aaa502b5867f0346e77f576 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 06:56:06 -0800 Subject: [PATCH 168/267] Test case --- .../note/CompareCitiesInteractorTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/use_case/note/CompareCitiesInteractorTest.java diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java new file mode 100644 index 000000000..0388fd5b2 --- /dev/null +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -0,0 +1,53 @@ +package use_case.note; + +import entity.User; +import entity.Weather; +import org.junit.Test; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; +import use_case.note.CompareCities.CompareCitiesInputData; +import use_case.note.CompareCities.CompareCitiesInteractor; +import use_case.note.CompareCities.CompareCitiesOutputBoundary; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class CompareCitiesInteractorTest { + + @Test + public void testExecuteRefreshSuccess() { + + CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new CompareCitiesDataAccessInterface() { + + + @Override + public String saveWeatherinfor(Weather weather) { + return ""; + } + + + @Override + public String loadWeather(Weather weather) { + return "test"; + } + }; + + CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(String message) { + assertEquals("test", message); + } + + @Override + public void prepareFailView(String errorMessage) { + fail(errorMessage); + } + }; + + CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); + CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); + + compareCitiesInteractor.execute(inputData); + + + } +} \ No newline at end of file From b5f459f2b345d543e3cdf43314c23a6332f0c05a Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 07:47:52 -0800 Subject: [PATCH 169/267] set controllers # Conflicts: # src/main/java/view/MainView.java --- src/main/java/app/AppBuilder.java | 39 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 9924e340d..c8133d7db 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -22,6 +22,7 @@ import interface_adapter.weather.WeatherState; import interface_adapter.weather.WeatherViewModel; import use_case.note.CompareCities.CompareCitiesDataAccessInterface; +import use_case.note.CompareCities.CompareCitiesInputBoundary; import use_case.note.CompareCities.CompareCitiesInteractor; import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; @@ -35,6 +36,7 @@ import use_case.note.nearby_list.NearbyCitiesAccessInterface; import use_case.note.nearby_list.NearbyListInteractor; import use_case.note.nearby_list.NearbyListOutputBoundary; +import use_case.note.search_result.SearchResultInputBoundary; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; @@ -61,6 +63,10 @@ public class AppBuilder { private MainView mainView; private PropertyChangeEvent evt; + private SearchResultInputBoundary searchResultInputBoundary; + private CompareCitiesInputBoundary compareCitiesInputBoundary; + private SearchReturnInputBoundary searchReturnInputBoundary; + /** * Sets the DAO to be used in this application. * @param weatherDataAccess the DAO to use @@ -71,21 +77,21 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { return this; } - /** - * Builds the application. - * @return the JFrame for the application - */ - public JFrame build() { - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Weather Wizard"); - frame.setSize(WIDTH, HEIGHT); - - frame.add(mainView); - - return frame; - - } +// /** +// * Builds the application. +// * @return the JFrame for the application +// */ +// public JFrame build() { +// final JFrame frame = new JFrame(); +// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); +// frame.setTitle("Weather Wizard"); +// frame.setSize(WIDTH, HEIGHT); +// +// frame.add(mainView); +// +// return frame; +// +// } /** * Creates the objects for the Note Use Case and connects the NoteView to its @@ -213,6 +219,9 @@ public AppBuilder addMainView() { searchResultViewModel = new SearchResultViewModel(); evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); + mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); + mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); + mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } } From a31fe60aa76e80fc46f287fe47c9d403a00e7b36 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 09:03:40 -0800 Subject: [PATCH 170/267] set default longitude and latitude for map. fix set controller in AppBuilder --- src/main/java/app/AppBuilder.java | 40 +++++++++++++++------------- src/main/java/view/MapPanelView.java | 4 ++- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index c8133d7db..2425dcbd5 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -77,21 +77,21 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { return this; } -// /** -// * Builds the application. -// * @return the JFrame for the application -// */ -// public JFrame build() { -// final JFrame frame = new JFrame(); -// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); -// frame.setTitle("Weather Wizard"); -// frame.setSize(WIDTH, HEIGHT); -// -// frame.add(mainView); -// -// return frame; -// -// } + /** + * Builds the application. + * @return the JFrame for the application + */ + public JFrame build() { + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setTitle("Weather Wizard"); + frame.setSize(WIDTH, HEIGHT); + + frame.add(mainView); + + return frame; + + } /** * Creates the objects for the Note Use Case and connects the NoteView to its @@ -122,6 +122,7 @@ public Weather getWeather(String city) throws IOException { public AppBuilder addCompareCitiesUseCase() { + // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { @Override @@ -157,6 +158,7 @@ public void clearcitytoweather() { final CompareCitiesInteractor interactor = new CompareCitiesInteractor(dai, outputBoundary); final CompareCitiesController controller = new CompareCitiesController(interactor); + mainView.mapPanelView.setCompareCitiesController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -196,6 +198,7 @@ public AppBuilder addSearchReturnUseCase() { final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); final WeatherController controller = new WeatherController(interactor); + mainView.mapPanelView.setWeatherController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -207,6 +210,7 @@ public AppBuilder addSearchResultUseCase() { final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); final SearchResultController controller = new SearchResultController(interactor); + mainView.mapPanelView.setSearchResultController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -219,9 +223,9 @@ public AppBuilder addMainView() { searchResultViewModel = new SearchResultViewModel(); evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); - mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); - mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); - mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); +// mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); +// mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); +// mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 12e3c015e..5128f1049 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -32,10 +32,12 @@ public class MapPanelView extends JPanel implements ActionListener { private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; + private final float torontoLatitude = 43.6532; + private final float torontoLongitude = -79.3832; public MapPanelView() { - mapimagepanel = new MapImagepanel(); + mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); cityinputfield1.addActionListener( event -> { From bd938a5417961c0a80690c0dc21fa2b94daa1987 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 10:28:20 -0800 Subject: [PATCH 171/267] fix bug --- .../InMemoryUserDataAccessObject.java | 52 +++++++++++++++++++ src/main/java/view/WeatherPanelView.java | 1 + .../note/CompareCitiesInteractorTest.java | 51 +++++++++++++++--- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 src/main/java/data_access/InMemoryUserDataAccessObject.java diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java new file mode 100644 index 000000000..180342727 --- /dev/null +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -0,0 +1,52 @@ +package data_access; + +import java.util.HashMap; +import java.util.Map; + +import entity.Weather; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; + +/** + * In-memory implementation of the DAO for storing weather data. This implementation does + * NOT persist data between runs of the program. + */ +public class InMemoryUserDataAccessObject implements CompareCitiesDataAccessInterface { + private final Map weathers = new HashMap<>(); + + @Override + public boolean isCityexist(String identifier) { + return weathers.containsKey(identifier); + } + + @Override + public Weather getWeather(String identifier) { + if (isCityexist(identifier)) { + if ("Toronto".equalsIgnoreCase(identifier)) { + final Weather torontoweather = new Weather("Toronto", 10.5, "rain", null, 0); + return torontoweather; + } + else { + final Weather tokyoweather = new Weather("Tokyo",1.0, "cloud", null, 1 ); + return tokyoweather; + } + } + else { + return null; + } + } + + @Override + public void saveWeatherinfor(Weather weather) { + weathers.put(weather.getCityName(), weather); + } + + @Override + public Map getcitytoweather() { + return weathers; + } + + @Override + public void clearcitytoweather() { + weathers.clear(); + } +} diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index c7eea2f05..35e8d4427 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -98,6 +98,7 @@ public void setfield(WeatherState weatherState) { windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); } + public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java index 0388fd5b2..4ce574900 100644 --- a/src/test/java/use_case/note/CompareCitiesInteractorTest.java +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -1,12 +1,12 @@ package use_case.note; -import entity.User; +import data_access.InMemoryUserDataAccessObject; +import data_access.WeatherDataAccessObject; import entity.Weather; +import interface_adapter.CompareCities.CompareCitiesPresenter; import org.junit.Test; -import use_case.note.CompareCities.CompareCitiesDataAccessInterface; -import use_case.note.CompareCities.CompareCitiesInputData; -import use_case.note.CompareCities.CompareCitiesInteractor; -import use_case.note.CompareCities.CompareCitiesOutputBoundary; +import org.junit.jupiter.api.Assertions; +import use_case.note.CompareCities.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -14,9 +14,46 @@ public class CompareCitiesInteractorTest { @Test - public void testExecuteRefreshSuccess() { + public void successTest() { + // this is the mock input data. + final CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Tokyo"); - CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new CompareCitiesDataAccessInterface() { + final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); + + CompareCitiesOutputBoundary SuccessPresenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + Assertions.assertEquals("Toronto", outputData.getFirstCityname()); + Assertions.assertEquals(10.5, outputData.getSecondWeather().getTemperature()); + Assertions.assertEquals("Tokyo", outputData.getSecondCityname()); + Assertions.assertEquals(0, outputData.getSecondWeather().getHumidity()); + } + + @Override + public void prepareFailView(String errorMessage) { + Assertions.fail("Use case failure is unexpected."); + } + } + + final CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, SuccessPresenter); + interactor.execute(inputData); + +// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); +// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); +// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); +// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); + } + + @Override + public boolean isCityexist("Toronto") { + return true; + } + + @Override + public boolean isCityExist(String cityname) { + return false; + } + } { @Override From 6c85f4c1a9e84ebdf97706cc1bd0be1999f0db25 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 16:10:49 -0800 Subject: [PATCH 172/267] Handle IO exception --- .../CompareCitiesInteractor.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index f9012b3ba..bea4582c2 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -2,6 +2,8 @@ import entity.Weather; +import java.io.IOException; + /* * The Comparecities Interactor. */ @@ -32,12 +34,27 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("city not found"); } else { - final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); - final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); - compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); - compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + // THE try-catch statement below is to check firstcityname, secondcityname have corresponding weathers. + try { + final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); + } + catch (IOException ioException) { + comparecitiesPresenter.prepareFailView(ioException.getMessage()); + } + + try { + final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + } + catch (IOException ioException) { + comparecitiesPresenter.prepareFailView(ioException.getMessage()); + } + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, - firstweather, secondcityname, secondweather, false); + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(firstcityname), + secondcityname, + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(secondcityname), false); comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); // After each round of execution, clear map in DAO. compareCitiesDataAccessInterface.clearcitytoweather(); From 8458aca06c525f528d652d331d32979739bb7716 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 16:36:09 -0800 Subject: [PATCH 173/267] FIX isCityExist method in DAO --- .../data_access/WeatherDataAccessObject.java | 48 ++++++++++++++----- .../CompareCitiesDataAccessInterface.java | 13 ++--- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index e598ed8f7..01ce52fab 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -19,10 +19,10 @@ * This class runs the API and creates a weather DAO. **/ -public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface{ +public class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; - private static String city; + // private static String city; private static final int SUCCESS_CODE = 200; private static final String CONTENT_TYPE_JSON = "application/json"; private static final String STATUS_CODE_LABEL = "cod"; @@ -31,6 +31,36 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private boolean cityexist; private final Map citytoweather = new HashMap<>(); + @Override + public boolean isCityExist(String citySearch) { + final OkHttpClient client = new OkHttpClient().newBuilder().build(); + + // Create a request to the OpenWeather API + final Request request = new Request.Builder() + .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=metric", citySearch, API_KEY)) + .addHeader("Content-Type", CONTENT_TYPE_JSON) + .build(); + + try { + final Response response = client.newCall(request).execute(); + + // Parse the response + final JSONObject responseBody = new JSONObject(response.body().string()); + + // Check if the status code is 200 (Success) + if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { + // City exists, as the API returned successful data + return true; + } else { + // City doesn't exist (API returned a different code or error message) + return false; + } + } catch (IOException | JSONException ex) { + // If there was an error with the API call (e.g., network error, parsing error), assume city doesn't exist + return false; + } + } + @Override public Weather getWeather(String citySearch) throws IOException { // Make an API call to get the user object. @@ -73,8 +103,7 @@ public Weather getWeather(String citySearch) throws IOException { } else { throw new IOException(responseBody.getString(MESSAGE)); } - } - catch (IOException | JSONException ex) { + } catch (IOException | JSONException ex) { throw new IOException(ex); } } @@ -90,15 +119,10 @@ public Map getcitytoweather() { } /* - * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. - */ + * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. + */ @Override public void clearcitytoweather() { this.citytoweather.clear(); } - - public boolean isCityexist() { - return cityexist; - } -} - +} \ No newline at end of file diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java index de387089c..097c2b4a8 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -11,10 +11,11 @@ public interface CompareCitiesDataAccessInterface { /** * Check if City exists. - * @param cityname the weather is displayed for - * @return if city exists + * @param cityName the weather is displayed for + * @return true if city exists + * @throws IOException if the city does not exist or oi. */ - boolean isCityexist(String cityname); + boolean isCityExist(String cityName); /** * Creates the Weather. @@ -37,12 +38,6 @@ public interface CompareCitiesDataAccessInterface { * */ Map getcitytoweather(); - /** - * Sets city. - * @param cityname check if the cityname is valid or not - */ - boolean isCityExist(String cityname); - /** * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. */ From a84a433aeafaf4defc757352c25583a1cecc719b Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 19:35:13 -0800 Subject: [PATCH 174/267] refactor --- src/main/java/view/MapImagepanel.java | 6 +++--- src/main/java/view/MapPanelView.java | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index b0bd45393..538625a4b 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -23,14 +23,14 @@ public MapImagepanel(double latitude, double longitude) { this.coords = new double[] {latitude, longitude}; this.mapViewer = new JXMapViewer(); - TileFactoryInfo info = new OSMTileFactoryInfo(); - DefaultTileFactory tileFactory = new DefaultTileFactory(info); + final TileFactoryInfo info = new OSMTileFactoryInfo(); + final DefaultTileFactory tileFactory = new DefaultTileFactory(info); this.mapViewer.setTileFactory(tileFactory); tileFactory.setThreadPoolSize(NUM_THREADS); - GeoPosition position = new GeoPosition(this.coords); + final GeoPosition position = new GeoPosition(this.coords); this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 5128f1049..2aca70081 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -23,35 +23,42 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private final JTextField cityinputfield1 = new JTextField(15); - private final JTextField dateinputfield = new JTextField(15); - private final JTextField cityinputfield2 = new JTextField(15); + private final JTextField cityinputfield1 = new JTextField(20); + private final JTextField dateinputfield = new JTextField(20); + private final JTextField cityinputfield2 = new JTextField(20); private final int mappanelwidth = 370; private final int mappanelheight = 500; private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; - private final float torontoLatitude = 43.6532; - private final float torontoLongitude = -79.3832; + private final double torontoLatitude = 43.6532; + private final double torontoLongitude = -79.3832; public MapPanelView() { - + // by default set the map center be Toronto. mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); - + // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { - // if the event is coming from cityinput field, execute weather controller - if (event.getSource() == cityinputfield1) { + // if the event is coming from cityinput field, execute weather controller, check if empty + if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { weatherController.execute(cityinputfield1.getText()); } + else { + cityinputfield1.setText("can not return empty"); + } } ); + // if Compare to another city -> CompareCityController cityinputfield2.addActionListener( event -> { - if (event.getSource() == cityinputfield2) { + if (event.getSource() == cityinputfield2 && cityinputfield2.getText().length() > 0) { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); } + else { + cityinputfield2.setText("can not return empty"); + } } ); cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); From 4498613210480945c7ad4be94d6fed8c26fb8d2d Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 19:36:02 -0800 Subject: [PATCH 175/267] still need fix (commit because i want to use git pull) --- .../note/CompareCitiesInteractorTest.java | 103 +++++++++--------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java index 4ce574900..f1cfe9cee 100644 --- a/src/test/java/use_case/note/CompareCitiesInteractorTest.java +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -21,6 +21,7 @@ public void successTest() { final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); CompareCitiesOutputBoundary SuccessPresenter = new CompareCitiesOutputBoundary() { + // make a presenter @Override public void prepareSuccessView(CompareCitiesOutPutData outputData) { Assertions.assertEquals("Toronto", outputData.getFirstCityname()); @@ -37,54 +38,56 @@ public void prepareFailView(String errorMessage) { final CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, SuccessPresenter); interactor.execute(inputData); - -// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); -// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); -// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); -// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); - } - - @Override - public boolean isCityexist("Toronto") { - return true; - } - - @Override - public boolean isCityExist(String cityname) { - return false; - } - } { - - - @Override - public String saveWeatherinfor(Weather weather) { - return ""; - } - - - @Override - public String loadWeather(Weather weather) { - return "test"; - } - }; - - CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { - @Override - public void prepareSuccessView(String message) { - assertEquals("test", message); - } - - @Override - public void prepareFailView(String errorMessage) { - fail(errorMessage); - } - }; - - CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); - CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); - - compareCitiesInteractor.execute(inputData); - - } -} \ No newline at end of file +} +// +//// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); +//// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); +//// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); +//// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); +// } +// +// @Override +// public boolean isCityexist(String cityname) { +// return true; +// } +// +// @Override +// public boolean isCityExist(String cityname) { +// return false; +// } +// } { +// +// +// @Override +// public String saveWeatherinfor(Weather weather) { +// return ""; +// } +// +// +// @Override +// public String loadWeather(Weather weather) { +// return "test"; +// } +// }; +// +// CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { +// @Override +// public void prepareSuccessView(String message) { +// assertEquals("test", message); +// } +// +// @Override +// public void prepareFailView(String errorMessage) { +// fail(errorMessage); +// } +// }; +// +// CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); +// CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); +// +// compareCitiesInteractor.execute(inputData); +// +// +// } +//} \ No newline at end of file From e00615b88be484398f3da9ec6e7d5ddf9de69d55 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 20:02:12 -0800 Subject: [PATCH 176/267] A bunch of bug fixed --- src/main/java/app/AppBuilder.java | 40 +++---------------- .../InMemoryUserDataAccessObject.java | 10 +++-- src/main/java/entity/Weather.java | 20 +++++----- .../CompareCitiesInteractor.java | 4 +- .../view/HistoricalSearchedWeatherView.java | 4 +- src/main/java/view/MainView.java | 2 +- src/main/java/view/mapimagepreview.java | 12 ------ src/main/java/view/mappanelpreview.java | 18 --------- 8 files changed, 27 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/view/mapimagepreview.java delete mode 100644 src/main/java/view/mappanelpreview.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 2425dcbd5..a78c42fa6 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -27,6 +27,7 @@ import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; import use_case.note.search_result.SearchResultInteractor; +import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnInteractor; import use_case.note.WeatherDataAccessInterface; import use_case.note.alert_pop.AlertPopInteractor; @@ -60,7 +61,7 @@ public class AppBuilder { private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MainView mainView; + private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState())); private PropertyChangeEvent evt; private SearchResultInputBoundary searchResultInputBoundary; @@ -106,7 +107,7 @@ public AppBuilder addAlertPopUseCase() { final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { @Override public Weather getWeather(String city) throws IOException { - return WeatherDataAccessObject.getWeather(city); + return weatherDAO.getWeather(city); } }; @@ -120,40 +121,10 @@ public Weather getWeather(String city) throws IOException { return this; } - public AppBuilder addCompareCitiesUseCase() { // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); - final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { - @Override - public boolean isCityexist(String cityname) { - return false; - } - @Override - public Weather getWeather(String cityname) throws IOException { - return null; - } - - @Override - public void saveWeatherinfor(Weather weather) { - - } - - @Override - public Map getcitytoweather() { - return Map.of(); - } - - @Override - public boolean isCityExist(String cityname) { - return false; - } - - @Override - public void clearcitytoweather() { - - } - }; + final CompareCitiesDataAccessInterface dai = new WeatherDataAccessObject(); final CompareCitiesInteractor interactor = new CompareCitiesInteractor(dai, outputBoundary); @@ -162,6 +133,7 @@ public void clearcitytoweather() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setCompareCitiesController(controller); return this; } @@ -195,7 +167,7 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx public AppBuilder addSearchReturnUseCase() { final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); - final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); + final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO, historyDAO); final WeatherController controller = new WeatherController(interactor); mainView.mapPanelView.setWeatherController(controller); diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java index 180342727..0ed6beebb 100644 --- a/src/main/java/data_access/InMemoryUserDataAccessObject.java +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -14,19 +14,21 @@ public class InMemoryUserDataAccessObject implements CompareCitiesDataAccessInte private final Map weathers = new HashMap<>(); @Override - public boolean isCityexist(String identifier) { + public boolean isCityExist(String identifier) { return weathers.containsKey(identifier); } @Override public Weather getWeather(String identifier) { - if (isCityexist(identifier)) { + if (isCityExist(identifier)) { if ("Toronto".equalsIgnoreCase(identifier)) { - final Weather torontoweather = new Weather("Toronto", 10.5, "rain", null, 0); + final Weather torontoweather = new Weather("Toronto", 10.5, "rain", + null, 0, 1, 1, 1, 1, null); return torontoweather; } else { - final Weather tokyoweather = new Weather("Tokyo",1.0, "cloud", null, 1 ); + final Weather tokyoweather = new Weather("Tokyo", 1.0, "cloud", null, + 2, 2, 2, 2, 2, null); return tokyoweather; } } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index c907d61c4..320d7d03d 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -5,20 +5,20 @@ */ public class Weather { - private float temperature; + private double temperature; private String weather; private final String description; - private float windSpeed; + private double windSpeed; private final int humidity; private final int visibility; private boolean metric; private String cityName; - private int lon; - private int lat; + private double lon; + private double lat; private final String alertDescription; - public Weather(String city, float temperature, String weather, String description, float windSpeed, - int humidity, int visibility, int lon, int lat, String alertDescription) { + public Weather(String city, double temperature, String weather, String description, double windSpeed, + int humidity, int visibility, double lon, double lat, String alertDescription) { this.temperature = temperature; this.weather = weather; this.description = description; @@ -44,7 +44,7 @@ public void setCityName(String cityName) { this.cityName = cityName; } - public int getLat() { + public double getLat() { return lat; } @@ -52,7 +52,7 @@ public void setLat(int lat) { this.lat = lat; } - public int getLon() { + public double getLon() { return lon; } @@ -89,11 +89,11 @@ public String getWeather() { return weather; } - public float getTemperature() { + public double getTemperature() { return temperature; } - public float getWindSpeed() { + public double getWindSpeed() { return windSpeed; } diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index bea4582c2..eb7ce39bc 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -29,8 +29,8 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("Cannot compare the same city"); } else { - if (!compareCitiesDataAccessInterface.isCityexist(firstcityname) - || !compareCitiesDataAccessInterface.isCityexist(secondcityname)) { + if (!compareCitiesDataAccessInterface.isCityExist(firstcityname) + || !compareCitiesDataAccessInterface.isCityExist(secondcityname)) { comparecitiesPresenter.prepareFailView("city not found"); } else { diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 3ce1e5d78..a68d670a8 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -78,7 +78,7 @@ private void changeProperty(String propertyName, Weather searchedWeather) { weatherfincitypanel.setoutput(searchedWeather.getCityName()); break; case "temperature": - final float temperature = searchedWeather.getTemperature(); + final double temperature = searchedWeather.getTemperature(); final String temperatureString = String.valueOf(temperature); temperaturepanel.setoutput(temperatureString); break; @@ -91,7 +91,7 @@ private void changeProperty(String propertyName, Weather searchedWeather) { humiditypanel.setoutput(humidityString); break; case "windSpeed": - final float windSpeed = searchedWeather.getWindSpeed(); + final double windSpeed = searchedWeather.getWindSpeed(); final String windSpeedString = String.valueOf(windSpeed); windspeedpanel.setoutput(windSpeedString); break; diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index fb7477cd4..05f5ef3cd 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -8,7 +8,7 @@ import java.beans.PropertyChangeEvent; public class MainView extends JFrame { - private MapPanelView mapPanelView; + public MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; private HistoricalSearchedWeatherView searchResultPanelView; diff --git a/src/main/java/view/mapimagepreview.java b/src/main/java/view/mapimagepreview.java deleted file mode 100644 index 44d9edb57..000000000 --- a/src/main/java/view/mapimagepreview.java +++ /dev/null @@ -1,12 +0,0 @@ -package view; - -import javax.swing.*; - -public class mapimagepreview { - public static void main(String[] args) { - // Create the JPanel and add components to it - JPanel panel = new MapImagepanel(); - // Display the JPanel in a JOptionPane dialog - JOptionPane.showMessageDialog(null, panel, "map image preview", JOptionPane.PLAIN_MESSAGE); - } -} diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java deleted file mode 100644 index 55fbe9866..000000000 --- a/src/main/java/view/mappanelpreview.java +++ /dev/null @@ -1,18 +0,0 @@ -package view; - -import interface_adapter.weather.WeatherViewModel; - -import javax.swing.*; - -/* -* this class give a preview on MapPanelview. - */ -public class mappanelpreview { - public static void main(String[] args) { - // Create the JPanel and add components to it - final MapPanelView panel = new MapPanelView(new WeatherViewModel()); - - // Display the JPanel in a JOptionPane dialog - JOptionPane.showMessageDialog(null, panel, "JPanel Preview", JOptionPane.PLAIN_MESSAGE); - } -} \ No newline at end of file From 8b42ced56fad58f4d4e541cc8ac375d7f4f85b21 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 26 Nov 2024 11:09:11 -0800 Subject: [PATCH 177/267] bug fixed- (historicalSearchedWeatherView was not initialized) --- src/main/java/view/MainView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 05f5ef3cd..47ffd1485 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -10,7 +10,7 @@ public class MainView extends JFrame { public MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; - private HistoricalSearchedWeatherView searchResultPanelView; + private HistoricalSearchedWeatherView historicalSearchedWeatherView; private final int frameWidth = 1500; private final int frameHeight = 1000; @@ -18,6 +18,7 @@ public class MainView extends JFrame { public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { mapPanelView = new MapPanelView(); weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); + historicalSearchedWeatherView = new HistoricalSearchedWeatherView(searchResultViewModel, evt); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); @@ -25,7 +26,7 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR this.setLayout(new GridLayout(1, 3)); this.add(mapPanelView); this.add(weatherPanelView); - this.add(searchResultPanelView); + this.add(historicalSearchedWeatherView); // pack() optimize window size this.pack(); this.setVisible(true); From c37c5be6c56ccc3509600435344970772f698876 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 19:07:37 -0500 Subject: [PATCH 178/267] Fixed Some bugs --- src/main/java/app/AppBuilder.java | 46 +++++++++++++------ src/main/java/app/MainApplication.java | 9 ++-- .../data_access/NearbyCitiesAccessObject.java | 1 + .../data_access/WeatherDataAccessObject.java | 13 ++++-- src/main/java/entity/Weather.java | 28 ++++------- .../CompareCitiesController.java | 10 ++++ .../CompareCities/CompareCitiesPresenter.java | 3 ++ .../CompareCities/CompareCitiesState.java | 3 ++ .../CompareCities/CompareCitiesViewModel.java | 3 ++ .../SearchResult/SearchResultPresenter.java | 5 +- .../SearchResult/SearchResultViewModel.java | 3 ++ .../alert_pop/AlertPopPresenter.java | 3 ++ .../converter/ConverterController.java | 8 +++- .../converter/ConverterPresenter.java | 3 ++ .../weather/WeatherState.java | 2 - .../CompareCitiesDataAccessInterface.java | 6 --- .../CompareCitiesInteractor.java | 26 +++++++---- .../HistoricalWeatherDataAccessInterface.java | 1 + .../use_case/note/SearchResultInteractor.java | 8 ++-- .../use_case/note/SearchReturnInteractor.java | 8 ++-- .../note/WeatherDataAccessInterface.java | 2 +- .../note/alert_pop/AlertPopInputBoundary.java | 4 +- .../note/alert_pop/AlertPopInteractor.java | 2 +- .../pin_weather/PinWeatherInputBoundary.java | 7 --- .../note/pin_weather/PinWeatherInputData.java | 5 -- .../pin_weather/PinWeatherOutputBoundary.java | 8 ---- .../pin_weather/PinWeatherOutputData.java | 20 -------- .../return_home/ReturnHomeInputBoundary.java | 7 --- .../note/return_home/ReturnHomeInputData.java | 5 -- .../return_home/ReturnHomeOutputBoundary.java | 8 ---- .../return_home/ReturnHomeOutputData.java | 14 ------ src/main/java/view/MainView.java | 12 ++--- src/main/java/view/MapPanelView.java | 36 +++++++++++++-- src/main/java/view/WeatherPanelView.java | 8 ++-- src/main/java/view/mappanelpreview.java | 2 +- .../use_case/note/ConvertInteractorTest.java | 3 +- 36 files changed, 168 insertions(+), 164 deletions(-) delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputData.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputData.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputData.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index c0e5efd23..dcb38faa5 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -36,16 +36,16 @@ import use_case.note.nearby_list.NearbyListInteractor; import use_case.note.nearby_list.NearbyListOutputBoundary; import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; +import view.MapPanelView; +import view.WeatherPanelView; import java.beans.PropertyChangeEvent; import java.io.IOException; import java.util.List; import java.util.Map; - /** * Builder for the Note Application. */ @@ -60,6 +60,8 @@ public class AppBuilder { private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); private MainView mainView; + private MapPanelView mapPanelView; + private WeatherPanelView weatherPanelView; private PropertyChangeEvent evt; /** @@ -79,7 +81,7 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { public JFrame build() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Weather Wizard"); + frame.setTitle("Weather L"); frame.setSize(WIDTH, HEIGHT); frame.add(mainView); @@ -94,14 +96,12 @@ public JFrame build() { *

This method must be called after addNoteView!

* @return this builder * @throws RuntimeException if this method is called before addNoteView - **/ public AppBuilder addAlertPopUseCase() { final AlertPopOutputBoundary outputBoundary = new AlertPopPresenter(weatherViewModel); final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { - @Override public Weather getWeather(String city) throws IOException { - return WeatherDataAccessObject.getWeather(city); + return new WeatherDataAccessObject().getWeather(city); } }; @@ -112,10 +112,10 @@ public Weather getWeather(String city) throws IOException { if (mainView == null) { throw new RuntimeException("Error"); } + mapPanelView.setAlertPopController(controller); return this; } - public AppBuilder addCompareCitiesUseCase() { final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { @@ -123,7 +123,7 @@ public AppBuilder addCompareCitiesUseCase() { public boolean isCityexist(String cityname) { return false; } - @Override + public Weather getWeather(String cityname) throws IOException { return null; } @@ -138,11 +138,6 @@ public Map getcitytoweather() { return Map.of(); } - @Override - public boolean isCityExist(String cityname) { - return false; - } - @Override public void clearcitytoweather() { @@ -155,6 +150,8 @@ public void clearcitytoweather() { if (mainView == null) { throw new RuntimeException("Error"); } + + mapPanelView.setCompareCitiesController(controller); return this; } @@ -166,8 +163,10 @@ public AppBuilder addConvertUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mapPanelView.setConverterController(controller); return this; } + public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { @@ -183,17 +182,19 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx if (mainView == null) { throw new RuntimeException("Error"); } + mapPanelView.setNearbyListController(controller); return this; } public AppBuilder addSearchReturnUseCase() { final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); - final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); + final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO, historyDAO); final WeatherController controller = new WeatherController(interactor); if (mainView == null) { throw new RuntimeException("Error"); } + mapPanelView.setWeatherController(controller); return this; } @@ -205,15 +206,30 @@ public AppBuilder addSearchResultUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mapPanelView.setSearchResultController(controller); return this; + } // add stuff for all the views public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); searchResultViewModel = new SearchResultViewModel(); - evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); + evt = new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); + System.out.println(mainView); + return this; + } + + public AppBuilder addMapPanelView() { + mapPanelView = new MapPanelView(); + System.out.println(mapPanelView); return this; } + + public AppBuilder addWeatherPanelView() { + weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); + return this; + } + } diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index b596ce135..fbab2b59f 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -32,13 +32,16 @@ public static void main(String[] args) { final AppBuilder builder = new AppBuilder(); builder.addDAO(noteDataAccess) + .addMainView() + .addMapPanelView() + .addWeatherPanelView() + .addSearchReturnUseCase() + .addSearchResultUseCase() .addCompareCitiesUseCase() .addConvertUseCase() .addNearbyListUseCase() - .addSearchReturnUseCase() - .addSearchResultUseCase() .addAlertPopUseCase() - .addMainView().build().setVisible(true); + .build().setVisible(true); } } diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index b929673f8..835afade8 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -3,6 +3,7 @@ import org.jetbrains.annotations.NotNull; import org.json.JSONArray; import org.json.JSONObject; + import use_case.note.nearby_list.NearbyCitiesAccessInterface; import java.io.IOException; diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index e6d7715be..f304415ef 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -19,7 +19,7 @@ * This class runs the API and creates a weather DAO. **/ -public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { +public class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; private static String city; @@ -31,7 +31,8 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private boolean cityexist; private final Map citytoweather = new HashMap<>(); - @Override + + public Weather getWeather(String citySearch) throws IOException { // Make an API call to get the user object. final OkHttpClient client = new OkHttpClient().newBuilder().build(); @@ -52,8 +53,8 @@ public Weather getWeather(String citySearch) throws IOException { this.cityexist = true; // get individual items from the json object - final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); - final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final double lat = (double) weatherJSON.getJSONObject(MAIN).getDouble("lat"); + final double lon = (double) weatherJSON.getJSONObject(MAIN).getDouble("lon"); final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); @@ -96,8 +97,10 @@ public void clearcitytoweather() { this.citytoweather.clear(); } - public boolean isCityexist() { + @Override + public boolean isCityexist(String cityname) { return cityexist; } + } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 84119b1e7..d37409991 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -1,7 +1,7 @@ package entity; /** - * The representation of a password-protected user for our program. + * The representation of a Weather object. */ public class Weather { @@ -13,11 +13,11 @@ public class Weather { private final int visibility; private boolean metric; private String cityName; - private int lon; - private int lat; + private final double lon; + private final double lat; public Weather(String city, float temperature, String weather, String alertDescription, - float windSpeed, int humidity, int visibility, int lon, int lat) { + float windSpeed, int humidity, int visibility, double lon, double lat) { this.temperature = temperature; this.weather = weather; this.alertDescription = alertDescription; @@ -38,26 +38,14 @@ public String getCityName() { return cityName; } - public void setCityName(String cityName) { - this.cityName = cityName; - } - - public int getLat() { + public double getLat() { return lat; } - public void setLat(int lat) { - this.lat = lat; - } - - public int getLon() { + public double getLon() { return lon; } - public void setLon(int lon) { - this.lon = lon; - } - public boolean isMetric() { return metric; } @@ -71,7 +59,7 @@ public void setTemperature(float temperature) { } public String getDescription() { - return description; + return alertDescription; } public void setWindSpeed(float windSpeed) { @@ -97,4 +85,4 @@ public int getHumidity() { public int getVisibility() { return visibility; } -} \ No newline at end of file +} diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java index 2f799237e..9fde6bc1d 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java @@ -2,12 +2,22 @@ import use_case.note.CompareCities.CompareCitiesInputBoundary; import use_case.note.CompareCities.CompareCitiesInputData; +/** + * The Controller for teh Compare Cities Use case. + */ public class CompareCitiesController { private final CompareCitiesInputBoundary interactor; + public CompareCitiesController(CompareCitiesInputBoundary interactor) { this.interactor = interactor; } + + /** + * The execute method. + * @param firstcityName is the first city to compare. + * @param secondcityName is the second city. + */ public void execute(String firstcityName, String secondcityName) { final CompareCitiesInputData compareCitiesInputData = new CompareCitiesInputData(firstcityName, secondcityName); interactor.execute(compareCitiesInputData); diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java index 34364a325..8550ef88a 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -3,6 +3,9 @@ import use_case.note.CompareCities.CompareCitiesOutPutData; import use_case.note.CompareCities.CompareCitiesOutputBoundary; +/** + * The Presenter for the Compare Cities Use case. + */ public class CompareCitiesPresenter implements CompareCitiesOutputBoundary { private final CompareCitiesViewModel viewModel; diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java index e78eec510..d6758be40 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java @@ -1,6 +1,9 @@ package interface_adapter.CompareCities; import entity.Weather; +/** + * The State for the Compare Cities Use case. + */ public class CompareCitiesState { private String error; diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java index baf04b02b..e3a22a6f5 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java @@ -1,6 +1,9 @@ package interface_adapter.CompareCities; import interface_adapter.ViewModel; +/** + * The View Model for the Compare Cities Use case. + */ public class CompareCitiesViewModel extends ViewModel { public CompareCitiesViewModel() { diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index 40253631a..f08a1aca3 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -1,9 +1,10 @@ package interface_adapter.SearchResult; -import interface_adapter.weather.WeatherViewModel; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; - +/** + * Presenter for the Search Result use case. + */ public class SearchResultPresenter implements SearchResultOutputBoundary { diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java index 5c3b5886f..d0094b8cb 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java @@ -1,6 +1,9 @@ package interface_adapter.SearchResult; import interface_adapter.ViewModel; +/** + * View Model for the Search Result use case. + */ public class SearchResultViewModel extends ViewModel { public SearchResultViewModel() { diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java index 434a47773..7efaadd3d 100644 --- a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java +++ b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java @@ -4,6 +4,9 @@ import use_case.note.alert_pop.AlertPopOutputBoundary; import use_case.note.alert_pop.AlertPopOutputData; +/** + * This is the Presenter for the ALERT POP use case. + */ public class AlertPopPresenter implements AlertPopOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 526e0b180..a8a6b5d96 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -4,11 +4,15 @@ import use_case.note.convert_farenheit.ConvertFarenheitInputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitInputData; +/** + * The Controller for the Convert Units Use case. + */ + public class ConverterController { - private final ConvertFarenheitInputBoundary convertInteractor; + private static ConvertFarenheitInputBoundary convertInteractor; public ConverterController(ConvertFarenheitInputBoundary cInteractor) { - this.convertInteractor = cInteractor; + convertInteractor = cInteractor; } /** diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java index c634c2d30..7ee80c653 100644 --- a/src/main/java/interface_adapter/converter/ConverterPresenter.java +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -3,6 +3,9 @@ import interface_adapter.weather.WeatherViewModel; import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitOutputData; +/** + * The Presenter for the Convert Units Use case. + */ public class ConverterPresenter implements ConvertFarenheitOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index 29b6b95a6..4d853b065 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -2,8 +2,6 @@ import entity.Weather; -import entity.Weather; - /** * The state information for the weather view model. */ diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java index de387089c..68e3c82c7 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -37,12 +37,6 @@ public interface CompareCitiesDataAccessInterface { * */ Map getcitytoweather(); - /** - * Sets city. - * @param cityname check if the cityname is valid or not - */ - boolean isCityExist(String cityname); - /** * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. */ diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index f9012b3ba..85ec100f4 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -2,6 +2,8 @@ import entity.Weather; +import java.io.IOException; + /* * The Comparecities Interactor. */ @@ -32,15 +34,21 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("city not found"); } else { - final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); - final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); - compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); - compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); - final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, - firstweather, secondcityname, secondweather, false); - comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); - // After each round of execution, clear map in DAO. - compareCitiesDataAccessInterface.clearcitytoweather(); + final Weather firstweather; + try { + firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); + final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); + compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, + firstweather, secondcityname, secondweather, false); + comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); + // After each round of execution, clear map in DAO. + compareCitiesDataAccessInterface.clearcitytoweather(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } } } diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index 904670ccf..6ce05f46f 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -21,6 +21,7 @@ public interface HistoricalWeatherDataAccessInterface { * Gets the weather data. * @param city the city to get the weather data for * @param timestamp the timestamp of the weather data + * @return Weather object if no error. * @throws IOException if there is an error getting the weather data */ Weather getWeather(String city, String timestamp) throws IOException; diff --git a/src/main/java/use_case/note/SearchResultInteractor.java b/src/main/java/use_case/note/SearchResultInteractor.java index b33b9a07f..aa984c6b7 100644 --- a/src/main/java/use_case/note/SearchResultInteractor.java +++ b/src/main/java/use_case/note/SearchResultInteractor.java @@ -1,9 +1,6 @@ package use_case.note; import java.io.IOException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import entity.Weather; import use_case.note.search_result.SearchResultInputBoundary; @@ -19,8 +16,9 @@ public class SearchResultInteractor implements SearchResultInputBoundary { private final WeatherDataAccessInterface weatherDataAccess; private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; - public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess, - HistoricalWeatherDataAccessInterface historicalDataInterface ) { + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, + WeatherDataAccessInterface weatherDataAccess, HistoricalWeatherDataAccessInterface + historicalDataInterface) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherDataAccessInterface = historicalDataInterface; diff --git a/src/main/java/use_case/note/SearchReturnInteractor.java b/src/main/java/use_case/note/SearchReturnInteractor.java index 30434834c..389555737 100644 --- a/src/main/java/use_case/note/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/SearchReturnInteractor.java @@ -1,12 +1,13 @@ package use_case.note; import entity.Weather; +import java.io.IOException; + import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnInputData; import use_case.note.search_return.SearchReturnOutputBoundary; import use_case.note.search_return.SearchReturnOutputData; -import java.io.IOException; import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -44,10 +45,11 @@ public void execute(SearchReturnInputData searchReturnInputData) { new SearchReturnOutputData(weatherData, false); outputBoundary.presentSuccessView(outputData); - } catch (IOException exception) { + } + catch (IOException exception) { // Handle exception if weather data retrieval fails and send failure view outputBoundary.prepareFailView("Failed to retrieve weather data: " + exception.getMessage()); } } -} \ No newline at end of file +} diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index 163d40981..44f758b4b 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -15,6 +15,6 @@ public interface WeatherDataAccessInterface { * @return the weather information * @throws IOException if the city does not exist or oi. */ - Weather getWeather(String city) throws IOException; + public Weather getWeather(String city) throws IOException; } diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java index 7d635bfb0..0c9d44bd9 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java @@ -1,6 +1,8 @@ package use_case.note.alert_pop; -// No input because alertpop is automatic. +/** + * No input because it is Automatic. + */ public interface AlertPopInputBoundary { void execute(AlertPopInputData alertPopInputData); diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java b/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java index 74eb14aac..b68661b04 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java @@ -17,7 +17,7 @@ public void execute(AlertPopInputData alertPopInputData) { try { String cityName = alertPopInputData.getCityName(); Weather weather = weatherAccess.getWeather(cityName); - String alert = weather.getAlertDescription(); + String alert = weather.getDescription(); String noAlert = "no weather alert"; if (noAlert.equals(alert)) { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java deleted file mode 100644 index 2e267e172..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.pin_weather; - -// Input is a click on "pin." -public interface PinWeatherInputBoundary { - - void execute(PinWeatherInputData pinWeatherInputData); -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java deleted file mode 100644 index 623290d9f..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.pin_weather; - -// Input is a click on "pin." -public class PinWeatherInputData { -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java deleted file mode 100644 index 6eac48913..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.pin_weather; - -public interface PinWeatherOutputBoundary { - - void presentSuccessView(PinWeatherOutputData pinWeatherOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java deleted file mode 100644 index cc0446619..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java +++ /dev/null @@ -1,20 +0,0 @@ -package use_case.note.pin_weather; - -public class PinWeatherOutputData { - - private final String weatherInfo; - private final boolean useCaseFailed; - - public PinWeatherOutputData(String weatherInfo, boolean useCaseFailed) { - this.weatherInfo = weatherInfo; - this.useCaseFailed = useCaseFailed; - } - - public String getWeatherInfo() { - return weatherInfo; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java deleted file mode 100644 index 93b43e15b..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.return_home; - -// Input is a click on the home button. -public interface ReturnHomeInputBoundary { - - void execute(ReturnHomeInputData returnHomeInputData); -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java deleted file mode 100644 index 27162a91e..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.return_home; - -// Input is a click on the home button. -public class ReturnHomeInputData { -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java deleted file mode 100644 index 258573eb3..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.return_home; - -public interface ReturnHomeOutputBoundary { - - void presentSuccessView(ReturnHomeOutputData returnHomeOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java deleted file mode 100644 index 49f1ba0c4..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.return_home; - -public class ReturnHomeOutputData { - - private final boolean useCaseFailed; - - public ReturnHomeOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 85ee3bdc1..484a9a47f 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -4,28 +4,28 @@ import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; -import javax.swing.JFrame; +import javax.swing.*; import java.awt.GridLayout; import java.beans.PropertyChangeEvent; -public class MainView extends JFrame { +public class MainView extends JPanel { private MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; + private HistoricalSearchedWeatherView historicalSearchedWeatherView; private final int frameWidth = 1200; private final int frameHeight = 1000; - public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { + public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, + PropertyChangeEvent evt) { mapPanelView = new MapPanelView(); weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); - this.setTitle("Weather Wizard"); - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); // I choose to use 1X2 gridlayout so we can have both panel side by side this.setLayout(new GridLayout(1, 2)); this.add(mapPanelView); this.add(weatherPanelView); + this.add(historicalSearchedWeatherView); // pack() optimize window size - this.pack(); this.setVisible(true); } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 7767cee1a..1ad0b4933 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,6 +1,10 @@ package view; +import interface_adapter.CompareCities.CompareCitiesController; import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.alert_pop.AlertPopController; +import interface_adapter.converter.ConverterController; +import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherState; @@ -23,14 +27,19 @@ public class MapPanelView extends JPanel implements ActionListener { private final MapImagepanel mapimagepanel; private final JTextField cityinputfield = new JTextField(15); - private final JButton alert; + private final JButton alert = new JButton("Alert"); private final JTextField dateinputfield = new JTextField(15); - private final JButton search; + private final JButton search = new JButton("Search"); private final int mappanelwidth = 370; private final int mappanelheight = 400; private SearchResultController searchResultController; private WeatherController weatherController; + private CompareCitiesController compareCitiesController; + + private NearbyListController nearbyListController; + private ConverterController converterController; + private AlertPopController alertPopController; public MapPanelView() { @@ -40,6 +49,7 @@ public MapPanelView() { event -> { // if the event is coming from cityinput field, execute weather controller if (event.getSource() == cityinputfield) { + System.out.println(weatherController); weatherController.execute(cityinputfield.getText()); } } @@ -85,10 +95,30 @@ public void actionPerformed(ActionEvent event) { // } public void setWeatherController(WeatherController weathercontroller) { + this.weatherController = weathercontroller; + System.out.println(this.weatherController); + } public void setSearchResultController(SearchResultController searchresultcontroller) { - this.searchResultController = searchresultcontroller; } + this.searchResultController = searchresultcontroller; + } + + public void setCompareCitiesController(CompareCitiesController compareCitiesController) { + this.compareCitiesController = compareCitiesController; + } + + public void setAlertPopController(AlertPopController alertPopController) { + this.alertPopController = alertPopController; + } + + public void setConverterController(ConverterController converterController) { + this.converterController = converterController; + } + + public void setNearbyListController(NearbyListController nearbyListController) { + this.nearbyListController = nearbyListController; + } } diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 8d64760a8..b68f8b76e 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -14,7 +14,6 @@ import entity.Weather; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.converter.ConverterController; -//import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherViewModel; /** @@ -23,6 +22,9 @@ * This part of view will have to change based on the output, so it depends on the view model **/ public class WeatherPanelView extends JPanel implements PropertyChangeListener, ActionListener { + private static final int WEATHER_PANEL_WIDTH = 370; + private static final int WEATHERPANELHEIGHT = 400; + private final WeatherViewModel weatherViewModel; private SearchResultViewModel searchResultViewModel; @@ -38,8 +40,6 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final JButton temperatureconverter; private ConverterController convertorController; - private static final int WEATHER_PANEL_WIDTH = 370; - public static final int WEATHERPANELHEIGHT = 400; public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { @@ -62,7 +62,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel // the method execute in class ConverterController takes Weather object as input, need fix this. // a potential solution is change evt.getSource() to city name, and in ConverterController, turn // cityname into Weather(call DAO). - convertorController.execute((Weather) evt.getSource()); + convertorController.execute((Weather) evt.getOldValue()); } skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java index 55fbe9866..6d2787971 100644 --- a/src/main/java/view/mappanelpreview.java +++ b/src/main/java/view/mappanelpreview.java @@ -10,7 +10,7 @@ public class mappanelpreview { public static void main(String[] args) { // Create the JPanel and add components to it - final MapPanelView panel = new MapPanelView(new WeatherViewModel()); + final MapPanelView panel = new MapPanelView(); // Display the JPanel in a JOptionPane dialog JOptionPane.showMessageDialog(null, panel, "JPanel Preview", JOptionPane.PLAIN_MESSAGE); diff --git a/src/test/java/use_case/note/ConvertInteractorTest.java b/src/test/java/use_case/note/ConvertInteractorTest.java index d56676e18..b6d7d4a0b 100644 --- a/src/test/java/use_case/note/ConvertInteractorTest.java +++ b/src/test/java/use_case/note/ConvertInteractorTest.java @@ -23,7 +23,8 @@ public void TestIfWeatherDNE() { WeatherDataAccessInterface Dao = new WeatherDataAccessInterface() { @Override public Weather getWeather(String city) throws IOException { - return WeatherDataAccessObject.getWeather(city); + + return new WeatherDataAccessObject().getWeather(city); } }; ConvertFarenheitOutputBoundary boundary = new ConvertFarenheitOutputBoundary() { From 6784e2fd12b747d61539ef882902ceae0cd17cc0 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:00:32 -0500 Subject: [PATCH 179/267] Corrected access to the lat lon variables in the dao and updated the change of type from int to double --- .../data_access/WeatherDataAccessObject.java | 10 ++++++---- src/main/java/entity/Weather.java | 18 +++--------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 01ce52fab..51661140e 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -82,8 +82,8 @@ public Weather getWeather(String citySearch) throws IOException { this.cityexist = true; // get individual items from the json object - final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); - final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final double lat = (int) responseBody.getJSONObject("city").getJSONObject("coord").getDouble("lat"); + final double lon = (int) responseBody.getJSONObject("city").getJSONObject("coord").getDouble("lon");; final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); @@ -100,10 +100,12 @@ public Weather getWeather(String citySearch) throws IOException { return new Weather(citySearch, temp, looks, description, windspeed, humidity, visibility, lon, lat, alertDescription); - } else { + } + else { throw new IOException(responseBody.getString(MESSAGE)); } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { throw new IOException(ex); } } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 320d7d03d..6ff75b168 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -13,8 +13,8 @@ public class Weather { private final int visibility; private boolean metric; private String cityName; - private double lon; - private double lat; + private final double lon; + private final double lat; private final String alertDescription; public Weather(String city, double temperature, String weather, String description, double windSpeed, @@ -40,26 +40,14 @@ public String getCityName() { return cityName; } - public void setCityName(String cityName) { - this.cityName = cityName; - } - public double getLat() { return lat; } - public void setLat(int lat) { - this.lat = lat; - } - public double getLon() { return lon; } - public void setLon(int lon) { - this.lon = lon; - } - public boolean isMetric() { return metric; } @@ -104,4 +92,4 @@ public int getHumidity() { public int getVisibility() { return visibility; } -} \ No newline at end of file +} From 92c3b789b886b0c4d05f2402206f7014bc9225de Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:07:56 -0500 Subject: [PATCH 180/267] Fixed view issues in appbuilder and main application --- src/main/java/app/AppBuilder.java | 14 +++++++++----- src/main/java/app/MainApplication.java | 2 -- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index a78c42fa6..32f62bafd 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -41,12 +41,11 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; +import view.MapPanelView; import java.beans.PropertyChangeEvent; import java.io.IOException; import java.util.List; -import java.util.Map; - /** * Builder for the Note Application. @@ -61,7 +60,9 @@ public class AppBuilder { private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState())); + private MapPanelView mapPanelView = new MapPanelView(); + private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, + new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState())); private PropertyChangeEvent evt; private SearchResultInputBoundary searchResultInputBoundary; @@ -100,8 +101,8 @@ public JFrame build() { *

This method must be called after addNoteView!

* @return this builder * @throws RuntimeException if this method is called before addNoteView - **/ + public AppBuilder addAlertPopUseCase() { final AlertPopOutputBoundary outputBoundary = new AlertPopPresenter(weatherViewModel); final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { @@ -147,6 +148,7 @@ public AppBuilder addConvertUseCase() { } return this; } + public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { @@ -163,6 +165,7 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx throw new RuntimeException("Error"); } return this; + } public AppBuilder addSearchReturnUseCase() { @@ -196,8 +199,9 @@ public AppBuilder addMainView() { evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); // mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); -// mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); +// mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); // mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } + } diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index fbab2b59f..1f29f57e9 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -33,8 +33,6 @@ public static void main(String[] args) { final AppBuilder builder = new AppBuilder(); builder.addDAO(noteDataAccess) .addMainView() - .addMapPanelView() - .addWeatherPanelView() .addSearchReturnUseCase() .addSearchResultUseCase() .addCompareCitiesUseCase() From db58532bed4115bd7b24d7b82aa5e508a0ac78f7 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:25:31 -0500 Subject: [PATCH 181/267] Set Controllers in AppBuilder and made a constant for ERROR. --- src/main/java/app/AppBuilder.java | 67 ++++++++++++++++++------ src/main/java/view/MainView.java | 2 +- src/main/java/view/MapPanelView.java | 13 +++++ src/main/java/view/WeatherPanelView.java | 4 ++ 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 32f62bafd..36fe030bd 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -41,7 +41,6 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; -import view.MapPanelView; import java.beans.PropertyChangeEvent; import java.io.IOException; @@ -54,13 +53,13 @@ public class AppBuilder { public static final int HEIGHT = 750; public static final int WIDTH = 1500; + private static final String ERROR = "Error"; private WeatherDataAccessInterface weatherDAO; private HistoricalWeatherDataAccessInterface historyDAO; private WeatherViewModel weatherViewModel = new WeatherViewModel(); private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MapPanelView mapPanelView = new MapPanelView(); private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState())); private PropertyChangeEvent evt; @@ -80,9 +79,10 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { } /** - * Builds the application. - * @return the JFrame for the application - */ + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public JFrame build() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); @@ -96,11 +96,9 @@ public JFrame build() { } /** - * Creates the objects for the Note Use Case and connects the NoteView to its - * controller. - *

This method must be called after addNoteView!

- * @return this builder - * @throws RuntimeException if this method is called before addNoteView + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. **/ public AppBuilder addAlertPopUseCase() { @@ -117,11 +115,18 @@ public Weather getWeather(String city) throws IOException { final AlertPopController controller = new AlertPopController(interactor); if (mainView == null) { - throw new RuntimeException("Error"); + throw new RuntimeException(ERROR); } + mainView.mapPanelView.setAlertPopController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ + public AppBuilder addCompareCitiesUseCase() { // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); @@ -137,6 +142,11 @@ public AppBuilder addCompareCitiesUseCase() { mainView.mapPanelView.setCompareCitiesController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addConvertUseCase() { final ConvertFarenheitOutputBoundary outputBoundary = new ConverterPresenter(weatherViewModel); @@ -146,8 +156,15 @@ public AppBuilder addConvertUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + + mainView.weatherPanelView.setConverterController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); @@ -164,9 +181,15 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx if (mainView == null) { throw new RuntimeException("Error"); } - return this; + mainView.mapPanelView.setNearbyListController(controller); + return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addSearchReturnUseCase() { final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); @@ -177,8 +200,14 @@ public AppBuilder addSearchReturnUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setWeatherController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addSearchResultUseCase() { final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(searchResultViewModel); @@ -189,18 +218,24 @@ public AppBuilder addSearchResultUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setSearchResultController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ // add stuff for all the views public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); searchResultViewModel = new SearchResultViewModel(); - evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); + evt = new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); -// mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); -// mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); -// mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); + // mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); + // mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); + // mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 47ffd1485..6a8fc3bbb 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -9,7 +9,7 @@ public class MainView extends JFrame { public MapPanelView mapPanelView; - private WeatherPanelView weatherPanelView; + public WeatherPanelView weatherPanelView; private HistoricalSearchedWeatherView historicalSearchedWeatherView; private final int frameWidth = 1500; diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 2aca70081..c1a175742 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -2,6 +2,9 @@ import interface_adapter.CompareCities.CompareCitiesController; import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.alert_pop.AlertPopController; +import interface_adapter.converter.ConverterController; +import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; import javax.swing.*; @@ -32,6 +35,8 @@ public class MapPanelView extends JPanel implements ActionListener { private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; + private NearbyListController nearbyListController; + private AlertPopController alertPopController; private final double torontoLatitude = 43.6532; private final double torontoLongitude = -79.3832; @@ -111,6 +116,14 @@ public void setSearchResultController(SearchResultController searchresultcontrol this.searchResultController = searchresultcontroller; } + public void setNearbyListController(NearbyListController nearbyListController) { + this.nearbyListController = nearbyListController; + } + + public void setAlertPopController(AlertPopController alertPopController) { + this.alertPopController = alertPopController; + } + public void setCompareCitiesController(CompareCitiesController compareCitiesController) { this.compareCitiesController = compareCitiesController; } diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 35e8d4427..a7085501e 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -103,4 +103,8 @@ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); } + + public void setConverterController(ConverterController converterController) { + this.convertorController = converterController; + } } From c689ca61b0f6e3ccc7881492b20bb6e3a2c8a0c4 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 13:01:45 -0800 Subject: [PATCH 182/267] bug fix --- src/main/java/app/MainApplication.java | 3 +-- src/main/java/data_access/WeatherDataAccessObject.java | 8 ++++++-- src/main/java/view/CompareCitiesView.java | 10 ++++++---- src/main/java/view/MapPanelView.java | 6 +++++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index b596ce135..1d3dcb874 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -37,8 +37,7 @@ public static void main(String[] args) { .addNearbyListUseCase() .addSearchReturnUseCase() .addSearchResultUseCase() - .addAlertPopUseCase() - .addMainView().build().setVisible(true); + .addAlertPopUseCase().build().setVisible(true); } } diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 01ce52fab..ccd060cbb 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -82,11 +82,15 @@ public Weather getWeather(String citySearch) throws IOException { this.cityexist = true; // get individual items from the json object - final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); - final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); +// final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); +// final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final int lat = 1; + final int lon = 1; final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); + + // todo: review looks final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); final String description = weatherJSON.getJSONObject("weather").getString("description"); diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 0c51531e3..585312431 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -88,9 +88,11 @@ public void setfield(CompareCitiesState compareCitiesState) { humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - } - public void actionPerformed(ActionEvent event) { - System.out.println("Enter" + event.getActionCommand()); - + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 2aca70081..2f986ea5b 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,6 +1,7 @@ package view; import interface_adapter.CompareCities.CompareCitiesController; +import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.weather.WeatherController; @@ -53,8 +54,10 @@ public MapPanelView() { // if Compare to another city -> CompareCityController cityinputfield2.addActionListener( event -> { - if (event.getSource() == cityinputfield2 && cityinputfield2.getText().length() > 0) { + if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); + new CompareCitiesView(compareCitiesViewModel); } else { cityinputfield2.setText("can not return empty"); @@ -77,6 +80,7 @@ public MapPanelView() { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(cityinputpanel); this.add(dateinputpanel); + this.add(comparetopanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); From 3e98e110650dd16d2275248f789cb148806fdab4 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Wed, 27 Nov 2024 17:22:37 -0500 Subject: [PATCH 183/267] Changed coordinates from float to double --- src/main/java/app/AppBuilder.java | 2 +- .../data_access/NearbyCitiesAccessObject.java | 17 ++++++++--------- .../nearby_list/NearbyListController.java | 2 +- .../NearbyCitiesAccessInterface.java | 2 +- .../note/nearby_list/NearbyListInputData.java | 10 +++++----- .../note/nearby_list/NearbyListInteractor.java | 4 ++-- .../use_case/note/NearbyListInteractorTest.java | 4 ++-- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index a78c42fa6..1172a4d90 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -151,7 +151,7 @@ public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { @Override - public List getNearbyCities(Float latitude, Float longitude) throws IOException { + public List getNearbyCities(double latitude, double longitude) throws IOException { return List.of(); } }; diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index b929673f8..a1b099d2c 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -16,16 +16,15 @@ * This class provides the service of getting nearby cities. */ public abstract class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { - private static final Float LOWER_LAT = -90.0f; - private static final Float UPPER_LAT = 90.0f; - private static final Float LOWER_LON = -180.0f; - private static final Float UPPER_LON = 180.0f; - private static final Float COMPARE_DIFF = 10.0f; + private static final double LOWER_LAT = -90.0; + private static final double UPPER_LAT = 90.0; + private static final double LOWER_LON = -180.0; + private static final double UPPER_LON = 180.0; + private static final double COMPARE_DIFF = 10.0; @Override - public List getNearbyCities(Float latitude, Float longitude) throws IOException { - if (latitude == null || longitude == null || latitude < LOWER_LAT - || latitude > UPPER_LAT || longitude < LOWER_LON || longitude > UPPER_LON) { + public List getNearbyCities(double latitude, double longitude) throws IOException { + if (latitude < LOWER_LAT || latitude > UPPER_LAT || longitude < LOWER_LON || longitude > UPPER_LON) { throw new IOException(); } try { @@ -39,7 +38,7 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx } @NotNull - private static ArrayList getCityNames(Float latitude, Float longitude, String jsonString) { + private static ArrayList getCityNames(double latitude, double longitude, String jsonString) { final JSONArray jsonArray = new JSONArray(jsonString); final ArrayList nearbyCities = new ArrayList<>(); diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListController.java b/src/main/java/interface_adapter/nearby_list/NearbyListController.java index 92d4a21f3..aca764c0a 100644 --- a/src/main/java/interface_adapter/nearby_list/NearbyListController.java +++ b/src/main/java/interface_adapter/nearby_list/NearbyListController.java @@ -19,7 +19,7 @@ public NearbyListController(NearbyListInputBoundary nearbyListInteractor) { * @param longitude the current longitude * @param latitude the current latitude */ - public void execute(float longitude, float latitude) { + public void execute(double longitude, double latitude) { // Create a NearbyListInputData object to encapsulate the input data final NearbyListInputData inputData = new NearbyListInputData(longitude, latitude); // Call the use case's execute method with the input data diff --git a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java index a588d62fc..5bb172f4c 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java +++ b/src/main/java/use_case/note/nearby_list/NearbyCitiesAccessInterface.java @@ -7,5 +7,5 @@ * Interface for generating list of nearby cities. */ public interface NearbyCitiesAccessInterface { - List getNearbyCities(Float latitude, Float longitude) throws IOException; + List getNearbyCities(double latitude, double longitude) throws IOException; } diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java index eef8830d5..60748d6ac 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInputData.java @@ -4,19 +4,19 @@ * An input is when the map moves. */ public class NearbyListInputData { - private final float longitude; - private final float latitude; + private final double longitude; + private final double latitude; - public NearbyListInputData(float longitude, float latitude) { + public NearbyListInputData(double longitude, double latitude) { this.longitude = longitude; this.latitude = latitude; } - public float getLongitude() { + public double getLongitude() { return longitude; } - public float getLatitude() { + public double getLatitude() { return latitude; } } diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java index 612679209..110236b74 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java @@ -18,8 +18,8 @@ public NearbyListInteractor(NearbyListOutputBoundary outputBoundary, NearbyCitie @Override public void execute(NearbyListInputData nearbyListInputData) { try { - final Float latitude = nearbyListInputData.getLatitude(); - final Float longitude = nearbyListInputData.getLongitude(); + final double latitude = nearbyListInputData.getLatitude(); + final double longitude = nearbyListInputData.getLongitude(); final ArrayList cities = (ArrayList) cityDataAccess.getNearbyCities(latitude, longitude); final NearbyListOutputData outputData = new NearbyListOutputData(cities, false); outputBoundary.presentSuccessView(outputData); diff --git a/src/test/java/use_case/note/NearbyListInteractorTest.java b/src/test/java/use_case/note/NearbyListInteractorTest.java index 2044d0891..48e4a663f 100644 --- a/src/test/java/use_case/note/NearbyListInteractorTest.java +++ b/src/test/java/use_case/note/NearbyListInteractorTest.java @@ -12,7 +12,7 @@ public class NearbyListInteractorTest { public void testOutput() { NearbyCitiesAccessInterface cityDAO = new NearbyCitiesAccessInterface() { @Override - public List getNearbyCities(Float latitude, Float longitude) throws IOException { + public List getNearbyCities(double latitude, double longitude) throws IOException { return List.of(); } }; @@ -30,7 +30,7 @@ public void prepareFailView(String errorMessage) { }; NearbyListInteractor cityInteractor = new NearbyListInteractor(cityOB, cityDAO); - NearbyListInputData input = new NearbyListInputData(0.0f, 0.0f); + NearbyListInputData input = new NearbyListInputData(0.0, 0.0); cityInteractor.execute(input); } } From 4dae480da7ca5a38288035b76855f86d8166f5ba Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 14:34:33 -0800 Subject: [PATCH 184/267] bug fix (looks, description), add sample json file --- .../data_access/WeatherDataAccessObject.java | 27 +- src/main/resources/weatherAPI.json | 1345 +++++++++++++++++ 2 files changed, 1360 insertions(+), 12 deletions(-) create mode 100644 src/main/resources/weatherAPI.json diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index ccd060cbb..1c9774c66 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -51,11 +51,13 @@ public boolean isCityExist(String citySearch) { if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { // City exists, as the API returned successful data return true; - } else { + } + else { // City doesn't exist (API returned a different code or error message) return false; } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { // If there was an error with the API call (e.g., network error, parsing error), assume city doesn't exist return false; } @@ -81,19 +83,18 @@ public Weather getWeather(String citySearch) throws IOException { final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); this.cityexist = true; // get individual items from the json object - -// final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); -// final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); - final int lat = 1; - final int lon = 1; + final JSONObject coordJSON = responseBody.getJSONObject("city").getJSONObject("coord"); + final double lon = coordJSON.getDouble("lon"); + final double lat = coordJSON.getDouble("lat"); final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); - // todo: review looks - final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + // final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + final String looks = weatherJSON.getJSONArray("weather").getJSONObject(0).getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); - final String description = weatherJSON.getJSONObject("weather").getString("description"); + // final String description = weatherJSON.getJSONObject("weather").getString("description"); + final String description = weatherJSON.getJSONArray("weather").getJSONObject(0).getString("description"); String alertDescription = "no weather alert"; if (weatherJSON.has("alerts")) { final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); @@ -104,10 +105,12 @@ public Weather getWeather(String citySearch) throws IOException { return new Weather(citySearch, temp, looks, description, windspeed, humidity, visibility, lon, lat, alertDescription); - } else { + } + else { throw new IOException(responseBody.getString(MESSAGE)); } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { throw new IOException(ex); } } diff --git a/src/main/resources/weatherAPI.json b/src/main/resources/weatherAPI.json new file mode 100644 index 000000000..649d9cfc4 --- /dev/null +++ b/src/main/resources/weatherAPI.json @@ -0,0 +1,1345 @@ +{ + "city" : { + "country" : "CA", + "coord" : { + "lon" : -79.4163, + "lat" : 43.7001 + }, + "sunrise" : 1732710456, + "timezone" : -18000, + "sunset" : 1732743824, + "name" : "Toronto", + "id" : 6167865, + "population" : 4612191 + }, + "cnt" : 40, + "cod" : "200", + "message" : 0, + "list" : [ { + "dt" : 1732752000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 4.05, + "temp_min" : 4.03, + "grnd_level" : 996, + "temp_kf" : 0.02, + "humidity" : 55, + "pressure" : 1013, + "sea_level" : 1013, + "feels_like" : 1.61, + "temp_max" : 4.05 + }, + "clouds" : { + "all" : 80 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 258, + "speed" : 2.69, + "gust" : 5.92 + } + }, { + "dt" : 1732762800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.53, + "temp_min" : 3.27, + "grnd_level" : 996, + "temp_kf" : 0.26, + "humidity" : 54, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : 1.96, + "temp_max" : 3.53 + }, + "clouds" : { + "all" : 92 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 278, + "speed" : 1.74, + "gust" : 3.73 + } + }, { + "dt" : 1732773600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.12, + "temp_min" : 3.12, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 52, + "pressure" : 1010, + "sea_level" : 1010, + "feels_like" : 3.12, + "temp_max" : 3.12 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 328, + "speed" : 1.14, + "gust" : 1.77 + } + }, { + "dt" : 1732784400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.16, + "temp_min" : 3.16, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 53, + "pressure" : 1008, + "sea_level" : 1008, + "feels_like" : 3.16, + "temp_max" : 3.16 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 68, + "speed" : 0.87, + "gust" : 1.2 + } + }, { + "dt" : 1732795200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.04, + "temp_min" : 3.04, + "grnd_level" : 991, + "temp_kf" : 0, + "humidity" : 57, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.43, + "temp_max" : 3.04 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 26, + "speed" : 1.71, + "gust" : 3.48 + } + }, { + "dt" : 1732806000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.55, + "temp_min" : 3.55, + "grnd_level" : 990, + "temp_kf" : 0, + "humidity" : 56, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.41, + "temp_max" : 3.55 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 345, + "speed" : 2.26, + "gust" : 3.77 + } + }, { + "dt" : 1732816800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 5.38, + "temp_min" : 5.38, + "grnd_level" : 989, + "temp_kf" : 0, + "humidity" : 49, + "pressure" : 1005, + "sea_level" : 1005, + "feels_like" : 2.39, + "temp_max" : 5.38 + }, + "clouds" : { + "all" : 85 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 317, + "speed" : 3.89, + "gust" : 5.52 + } + }, { + "dt" : 1732827600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 5.12, + "temp_min" : 5.12, + "grnd_level" : 991, + "temp_kf" : 0, + "humidity" : 46, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.99, + "temp_max" : 5.12 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 310, + "speed" : 4.03, + "gust" : 6.04 + } + }, { + "dt" : 1732838400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 2.6, + "temp_min" : 2.6, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 58, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -1.46, + "temp_max" : 2.6 + }, + "clouds" : { + "all" : 85 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 285, + "speed" : 4.62, + "gust" : 8.29 + } + }, { + "dt" : 1732849200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 03:00:00", + "weather" : [ { + "icon" : "03n", + "description" : "scattered clouds", + "main" : "Clouds", + "id" : 802 + } ], + "main" : { + "temp" : 1.53, + "temp_min" : 1.53, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 70, + "pressure" : 1010, + "sea_level" : 1010, + "feels_like" : -2.56, + "temp_max" : 1.53 + }, + "clouds" : { + "all" : 26 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 4.24, + "gust" : 9.02 + } + }, { + "dt" : 1732860000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 06:00:00", + "weather" : [ { + "icon" : "02n", + "description" : "few clouds", + "main" : "Clouds", + "id" : 801 + } ], + "main" : { + "temp" : 1.2, + "temp_min" : 1.2, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -3.13, + "temp_max" : 1.2 + }, + "clouds" : { + "all" : 22 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 253, + "speed" : 4.51, + "gust" : 8.84 + } + }, { + "dt" : 1732870800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 0.67, + "temp_min" : 0.67, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 62, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.16, + "temp_max" : 0.67 + }, + "clouds" : { + "all" : 73 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 250, + "speed" : 5.14, + "gust" : 9.86 + } + }, { + "dt" : 1732881600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.43, + "temp_min" : 0.43, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 63, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.69, + "temp_max" : 0.43 + }, + "clouds" : { + "all" : 86 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 248, + "speed" : 5.58, + "gust" : 10.77 + } + }, { + "dt" : 1732892400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.86, + "temp_min" : 0.86, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 63, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.25, + "temp_max" : 0.86 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 5.77, + "gust" : 10.56 + } + }, { + "dt" : 1732903200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 2.65, + "temp_min" : 2.65, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 46, + "pressure" : 1008, + "sea_level" : 1008, + "feels_like" : -2.09, + "temp_max" : 2.65 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 253, + "speed" : 6, + "gust" : 10 + } + }, { + "dt" : 1732914000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 1.98, + "temp_min" : 1.98, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 53, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -3.1, + "temp_max" : 1.98 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 255, + "speed" : 6.36, + "gust" : 11.97 + } + }, { + "dt" : 1732924800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.48, + "temp_min" : 0.48, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1011, + "sea_level" : 1011, + "feels_like" : -5.01, + "temp_max" : 0.48 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 6.35, + "gust" : 11.85 + } + }, { + "dt" : 1732935600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.03, + "temp_min" : -0.03, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1011, + "sea_level" : 1011, + "feels_like" : -5.62, + "temp_max" : -0.03 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 6.26, + "gust" : 11.62 + } + }, { + "dt" : 1732946400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.98, + "temp_min" : -0.98, + "grnd_level" : 995, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : -6.77, + "temp_max" : -0.98 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 252, + "speed" : 6.14, + "gust" : 12.41 + } + }, { + "dt" : 1732957200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 09:00:00", + "weather" : [ { + "icon" : "03n", + "description" : "scattered clouds", + "main" : "Clouds", + "id" : 802 + } ], + "main" : { + "temp" : -0.99, + "temp_min" : -0.99, + "grnd_level" : 995, + "temp_kf" : 0, + "humidity" : 66, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : -6.76, + "temp_max" : -0.99 + }, + "clouds" : { + "all" : 48 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 251, + "speed" : 6.11, + "gust" : 12.84 + } + }, { + "dt" : 1732968000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -1.15, + "temp_min" : -1.15, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1013, + "sea_level" : 1013, + "feels_like" : -7.06, + "temp_max" : -1.15 + }, + "clouds" : { + "all" : 55 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 251, + "speed" : 6.29, + "gust" : 12.65 + } + }, { + "dt" : 1732978800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.33, + "temp_min" : -0.33, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -5.89, + "temp_max" : -0.33 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 6.05, + "gust" : 10.71 + } + }, { + "dt" : 1732989600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 1.14, + "temp_min" : 1.14, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 47, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -3.93, + "temp_max" : 1.14 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 252, + "speed" : 5.84, + "gust" : 8.39 + } + }, { + "dt" : 1733000400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.08, + "temp_min" : 0.08, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 55, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -5.22, + "temp_max" : 0.08 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 248, + "speed" : 5.74, + "gust" : 8.98 + } + }, { + "dt" : 1733011200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.77, + "temp_min" : -0.77, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.35, + "temp_max" : -0.77 + }, + "clouds" : { + "all" : 98 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 248, + "speed" : 5.84, + "gust" : 10.17 + } + }, { + "dt" : 1733022000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.15, + "temp_min" : -1.15, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 65, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.62, + "temp_max" : -1.15 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.45, + "gust" : 10.23 + } + }, { + "dt" : 1733032800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.37, + "temp_min" : -1.37, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 65, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.05, + "temp_max" : -1.37 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.73, + "gust" : 10.81 + } + }, { + "dt" : 1733043600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.49, + "temp_min" : -1.49, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.13, + "temp_max" : -1.49 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 244, + "speed" : 5.61, + "gust" : 11.45 + } + }, { + "dt" : 1733054400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.36, + "temp_min" : -1.36, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.16, + "temp_max" : -1.36 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.97, + "gust" : 12.84 + } + }, { + "dt" : 1733065200, + "pop" : 0.99, + "visibility" : 2980, + "dt_txt" : "2024-12-01 15:00:00", + "snow" : { + "3h" : 0.68 + }, + "weather" : [ { + "icon" : "13d", + "description" : "light snow", + "main" : "Snow", + "id" : 600 + } ], + "main" : { + "temp" : -1.14, + "temp_min" : -1.14, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 85, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.49, + "temp_max" : -1.14 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 5.25, + "gust" : 11.59 + } + }, { + "dt" : 1733076000, + "pop" : 0.92, + "visibility" : 10000, + "dt_txt" : "2024-12-01 18:00:00", + "snow" : { + "3h" : 0.21 + }, + "weather" : [ { + "icon" : "13d", + "description" : "light snow", + "main" : "Snow", + "id" : 600 + } ], + "main" : { + "temp" : 1.58, + "temp_min" : 1.58, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -2.51, + "temp_max" : 1.58 + }, + "clouds" : { + "all" : 97 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 251, + "speed" : 4.26, + "gust" : 6.63 + } + }, { + "dt" : 1733086800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 1.32, + "temp_min" : 1.32, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 55, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -2.17, + "temp_max" : 1.32 + }, + "clouds" : { + "all" : 95 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 288, + "speed" : 3.31, + "gust" : 6.43 + } + }, { + "dt" : 1733097600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.14, + "temp_min" : -0.14, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1016, + "sea_level" : 1016, + "feels_like" : -4.26, + "temp_max" : -0.14 + }, + "clouds" : { + "all" : 86 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 285, + "speed" : 3.73, + "gust" : 9.09 + } + }, { + "dt" : 1733108400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.64, + "temp_min" : -0.64, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1017, + "sea_level" : 1017, + "feels_like" : -3.9, + "temp_max" : -0.64 + }, + "clouds" : { + "all" : 74 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 279, + "speed" : 2.62, + "gust" : 6.37 + } + }, { + "dt" : 1733119200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.89, + "temp_min" : -0.89, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 70, + "pressure" : 1017, + "sea_level" : 1017, + "feels_like" : -4.07, + "temp_max" : -0.89 + }, + "clouds" : { + "all" : 75 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 296, + "speed" : 2.49, + "gust" : 4.68 + } + }, { + "dt" : 1733130000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.77, + "temp_min" : -0.77, + "grnd_level" : 1001, + "temp_kf" : 0, + "humidity" : 68, + "pressure" : 1018, + "sea_level" : 1018, + "feels_like" : -3.96, + "temp_max" : -0.77 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 291, + "speed" : 2.52, + "gust" : 4.73 + } + }, { + "dt" : 1733140800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.97, + "temp_min" : -0.97, + "grnd_level" : 1001, + "temp_kf" : 0, + "humidity" : 71, + "pressure" : 1018, + "sea_level" : 1018, + "feels_like" : -4.14, + "temp_max" : -0.97 + }, + "clouds" : { + "all" : 82 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 321, + "speed" : 2.47, + "gust" : 6.01 + } + }, { + "dt" : 1733151600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.1, + "temp_min" : -0.1, + "grnd_level" : 1003, + "temp_kf" : 0, + "humidity" : 69, + "pressure" : 1020, + "sea_level" : 1020, + "feels_like" : -3, + "temp_max" : -0.1 + }, + "clouds" : { + "all" : 54 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 342, + "speed" : 2.37, + "gust" : 4.47 + } + }, { + "dt" : 1733162400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 1.01, + "temp_min" : 1.01, + "grnd_level" : 1003, + "temp_kf" : 0, + "humidity" : 59, + "pressure" : 1020, + "sea_level" : 1020, + "feels_like" : -1.04, + "temp_max" : 1.01 + }, + "clouds" : { + "all" : 60 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 306, + "speed" : 1.81, + "gust" : 2.47 + } + }, { + "dt" : 1733173200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.9, + "temp_min" : 0.9, + "grnd_level" : 1004, + "temp_kf" : 0, + "humidity" : 66, + "pressure" : 1021, + "sea_level" : 1021, + "feels_like" : -1.69, + "temp_max" : 0.9 + }, + "clouds" : { + "all" : 92 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 309, + "speed" : 2.25, + "gust" : 4.02 + } + } ] +} \ No newline at end of file From 4b78aa7b5ec504fd35931088892a3b6758951a75 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 15:11:01 -0800 Subject: [PATCH 185/267] . --- src/main/java/app/MainApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index 3140a3425..4e998cc81 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -27,7 +27,7 @@ public class MainApplication { */ public static void main(String[] args) { - // create the data access and inject it into our builder! + // create the data access and inject it into our builder final WeatherDataAccessInterface noteDataAccess = new WeatherDataAccessObject(); final AppBuilder builder = new AppBuilder(); From 5e276b923cedb21ef05c8b32dcd77d1089eaf85d Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 15:13:19 -0800 Subject: [PATCH 186/267] The correct main --- src/main/java/app/MainApplication.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index 4e998cc81..f264da5e0 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -32,16 +32,11 @@ public static void main(String[] args) { final AppBuilder builder = new AppBuilder(); builder.addDAO(noteDataAccess) - .addMainView() .addSearchReturnUseCase() .addSearchResultUseCase() .addCompareCitiesUseCase() .addConvertUseCase() .addNearbyListUseCase() - .addSearchReturnUseCase() - .addSearchResultUseCase() .addAlertPopUseCase().build().setVisible(true); - - } } From 7f1b18d44eab734e1f190ef0ea799c8e7a90f556 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:00:29 -0800 Subject: [PATCH 187/267] add SearchResultPanelView into MainView # Conflicts: # src/main/java/view/MainView.java --- src/main/java/view/MainView.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 65f506db3..fb7477cd4 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,6 +1,5 @@ package view; -import interface_adapter.SearchResult.SearchResultController; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.weather.WeatherViewModel; @@ -33,4 +32,8 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR } +// public static void man(String[] args) { +// new MainView(); +// } + } From c612bc8d792c24aec7e2993edb823d86ce632fb3 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 23 Nov 2024 16:36:39 -0800 Subject: [PATCH 188/267] add compareto panel for comparecities use case # Conflicts: # src/main/java/view/MapPanelView.java --- src/main/java/view/MapPanelView.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 6782619be..12e3c015e 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -23,11 +23,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private final JTextField cityinputfield1 = new JTextField(15); private final JTextField dateinputfield = new JTextField(15); private final JTextField cityinputfield2 = new JTextField(15); - private final int mappanelwidth = 370; private final int mappanelheight = 500; From 47adfaa185322ea5f3d7124fa7954e9452ccf9f8 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 06:56:06 -0800 Subject: [PATCH 189/267] Test case --- .../note/CompareCitiesInteractorTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/use_case/note/CompareCitiesInteractorTest.java diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java new file mode 100644 index 000000000..0388fd5b2 --- /dev/null +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -0,0 +1,53 @@ +package use_case.note; + +import entity.User; +import entity.Weather; +import org.junit.Test; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; +import use_case.note.CompareCities.CompareCitiesInputData; +import use_case.note.CompareCities.CompareCitiesInteractor; +import use_case.note.CompareCities.CompareCitiesOutputBoundary; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class CompareCitiesInteractorTest { + + @Test + public void testExecuteRefreshSuccess() { + + CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new CompareCitiesDataAccessInterface() { + + + @Override + public String saveWeatherinfor(Weather weather) { + return ""; + } + + + @Override + public String loadWeather(Weather weather) { + return "test"; + } + }; + + CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(String message) { + assertEquals("test", message); + } + + @Override + public void prepareFailView(String errorMessage) { + fail(errorMessage); + } + }; + + CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); + CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); + + compareCitiesInteractor.execute(inputData); + + + } +} \ No newline at end of file From 9dd1d903a736c36c4dc8678afa4159362884fdba Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 07:47:52 -0800 Subject: [PATCH 190/267] set controllers # Conflicts: # src/main/java/view/MainView.java --- src/main/java/app/AppBuilder.java | 39 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 9924e340d..c8133d7db 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -22,6 +22,7 @@ import interface_adapter.weather.WeatherState; import interface_adapter.weather.WeatherViewModel; import use_case.note.CompareCities.CompareCitiesDataAccessInterface; +import use_case.note.CompareCities.CompareCitiesInputBoundary; import use_case.note.CompareCities.CompareCitiesInteractor; import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; @@ -35,6 +36,7 @@ import use_case.note.nearby_list.NearbyCitiesAccessInterface; import use_case.note.nearby_list.NearbyListInteractor; import use_case.note.nearby_list.NearbyListOutputBoundary; +import use_case.note.search_result.SearchResultInputBoundary; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; @@ -61,6 +63,10 @@ public class AppBuilder { private MainView mainView; private PropertyChangeEvent evt; + private SearchResultInputBoundary searchResultInputBoundary; + private CompareCitiesInputBoundary compareCitiesInputBoundary; + private SearchReturnInputBoundary searchReturnInputBoundary; + /** * Sets the DAO to be used in this application. * @param weatherDataAccess the DAO to use @@ -71,21 +77,21 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { return this; } - /** - * Builds the application. - * @return the JFrame for the application - */ - public JFrame build() { - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.setTitle("Weather Wizard"); - frame.setSize(WIDTH, HEIGHT); - - frame.add(mainView); - - return frame; - - } +// /** +// * Builds the application. +// * @return the JFrame for the application +// */ +// public JFrame build() { +// final JFrame frame = new JFrame(); +// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); +// frame.setTitle("Weather Wizard"); +// frame.setSize(WIDTH, HEIGHT); +// +// frame.add(mainView); +// +// return frame; +// +// } /** * Creates the objects for the Note Use Case and connects the NoteView to its @@ -213,6 +219,9 @@ public AppBuilder addMainView() { searchResultViewModel = new SearchResultViewModel(); evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); + mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); + mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); + mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } } From 218ed9cf3d1bcffc54bbc93052e095b25dd2f5c3 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 09:03:40 -0800 Subject: [PATCH 191/267] set default longitude and latitude for map. fix set controller in AppBuilder --- src/main/java/app/AppBuilder.java | 40 +++++++++++++++------------- src/main/java/view/MapPanelView.java | 4 ++- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index c8133d7db..2425dcbd5 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -77,21 +77,21 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { return this; } -// /** -// * Builds the application. -// * @return the JFrame for the application -// */ -// public JFrame build() { -// final JFrame frame = new JFrame(); -// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); -// frame.setTitle("Weather Wizard"); -// frame.setSize(WIDTH, HEIGHT); -// -// frame.add(mainView); -// -// return frame; -// -// } + /** + * Builds the application. + * @return the JFrame for the application + */ + public JFrame build() { + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setTitle("Weather Wizard"); + frame.setSize(WIDTH, HEIGHT); + + frame.add(mainView); + + return frame; + + } /** * Creates the objects for the Note Use Case and connects the NoteView to its @@ -122,6 +122,7 @@ public Weather getWeather(String city) throws IOException { public AppBuilder addCompareCitiesUseCase() { + // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { @Override @@ -157,6 +158,7 @@ public void clearcitytoweather() { final CompareCitiesInteractor interactor = new CompareCitiesInteractor(dai, outputBoundary); final CompareCitiesController controller = new CompareCitiesController(interactor); + mainView.mapPanelView.setCompareCitiesController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -196,6 +198,7 @@ public AppBuilder addSearchReturnUseCase() { final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); final WeatherController controller = new WeatherController(interactor); + mainView.mapPanelView.setWeatherController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -207,6 +210,7 @@ public AppBuilder addSearchResultUseCase() { final SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDAO, historyDAO); final SearchResultController controller = new SearchResultController(interactor); + mainView.mapPanelView.setSearchResultController(controller); if (mainView == null) { throw new RuntimeException("Error"); } @@ -219,9 +223,9 @@ public AppBuilder addMainView() { searchResultViewModel = new SearchResultViewModel(); evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); - mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); - mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); - mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); +// mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); +// mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); +// mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 12e3c015e..5128f1049 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -32,10 +32,12 @@ public class MapPanelView extends JPanel implements ActionListener { private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; + private final float torontoLatitude = 43.6532; + private final float torontoLongitude = -79.3832; public MapPanelView() { - mapimagepanel = new MapImagepanel(); + mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); cityinputfield1.addActionListener( event -> { From 60a5aeeafd50e5f449f1b166a33fcaac07eacb54 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 10:28:20 -0800 Subject: [PATCH 192/267] fix bug --- .../InMemoryUserDataAccessObject.java | 52 +++++++++++++++++++ src/main/java/view/WeatherPanelView.java | 1 + .../note/CompareCitiesInteractorTest.java | 51 +++++++++++++++--- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 src/main/java/data_access/InMemoryUserDataAccessObject.java diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java new file mode 100644 index 000000000..180342727 --- /dev/null +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -0,0 +1,52 @@ +package data_access; + +import java.util.HashMap; +import java.util.Map; + +import entity.Weather; +import use_case.note.CompareCities.CompareCitiesDataAccessInterface; + +/** + * In-memory implementation of the DAO for storing weather data. This implementation does + * NOT persist data between runs of the program. + */ +public class InMemoryUserDataAccessObject implements CompareCitiesDataAccessInterface { + private final Map weathers = new HashMap<>(); + + @Override + public boolean isCityexist(String identifier) { + return weathers.containsKey(identifier); + } + + @Override + public Weather getWeather(String identifier) { + if (isCityexist(identifier)) { + if ("Toronto".equalsIgnoreCase(identifier)) { + final Weather torontoweather = new Weather("Toronto", 10.5, "rain", null, 0); + return torontoweather; + } + else { + final Weather tokyoweather = new Weather("Tokyo",1.0, "cloud", null, 1 ); + return tokyoweather; + } + } + else { + return null; + } + } + + @Override + public void saveWeatherinfor(Weather weather) { + weathers.put(weather.getCityName(), weather); + } + + @Override + public Map getcitytoweather() { + return weathers; + } + + @Override + public void clearcitytoweather() { + weathers.clear(); + } +} diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index c7eea2f05..35e8d4427 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -98,6 +98,7 @@ public void setfield(WeatherState weatherState) { windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); } + public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java index 0388fd5b2..4ce574900 100644 --- a/src/test/java/use_case/note/CompareCitiesInteractorTest.java +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -1,12 +1,12 @@ package use_case.note; -import entity.User; +import data_access.InMemoryUserDataAccessObject; +import data_access.WeatherDataAccessObject; import entity.Weather; +import interface_adapter.CompareCities.CompareCitiesPresenter; import org.junit.Test; -import use_case.note.CompareCities.CompareCitiesDataAccessInterface; -import use_case.note.CompareCities.CompareCitiesInputData; -import use_case.note.CompareCities.CompareCitiesInteractor; -import use_case.note.CompareCities.CompareCitiesOutputBoundary; +import org.junit.jupiter.api.Assertions; +import use_case.note.CompareCities.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -14,9 +14,46 @@ public class CompareCitiesInteractorTest { @Test - public void testExecuteRefreshSuccess() { + public void successTest() { + // this is the mock input data. + final CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Tokyo"); - CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new CompareCitiesDataAccessInterface() { + final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); + + CompareCitiesOutputBoundary SuccessPresenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + Assertions.assertEquals("Toronto", outputData.getFirstCityname()); + Assertions.assertEquals(10.5, outputData.getSecondWeather().getTemperature()); + Assertions.assertEquals("Tokyo", outputData.getSecondCityname()); + Assertions.assertEquals(0, outputData.getSecondWeather().getHumidity()); + } + + @Override + public void prepareFailView(String errorMessage) { + Assertions.fail("Use case failure is unexpected."); + } + } + + final CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, SuccessPresenter); + interactor.execute(inputData); + +// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); +// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); +// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); +// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); + } + + @Override + public boolean isCityexist("Toronto") { + return true; + } + + @Override + public boolean isCityExist(String cityname) { + return false; + } + } { @Override From c46d947e3fae763fba0629c4f5e98fa04e439aa7 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 16:10:49 -0800 Subject: [PATCH 193/267] Handle IO exception --- .../CompareCitiesInteractor.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index f9012b3ba..bea4582c2 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -2,6 +2,8 @@ import entity.Weather; +import java.io.IOException; + /* * The Comparecities Interactor. */ @@ -32,12 +34,27 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("city not found"); } else { - final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); - final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); - compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); - compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + // THE try-catch statement below is to check firstcityname, secondcityname have corresponding weathers. + try { + final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); + } + catch (IOException ioException) { + comparecitiesPresenter.prepareFailView(ioException.getMessage()); + } + + try { + final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); + compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + } + catch (IOException ioException) { + comparecitiesPresenter.prepareFailView(ioException.getMessage()); + } + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, - firstweather, secondcityname, secondweather, false); + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(firstcityname), + secondcityname, + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(secondcityname), false); comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); // After each round of execution, clear map in DAO. compareCitiesDataAccessInterface.clearcitytoweather(); From 0a7c8694eb80a5a051a3e3785db4b7bbd9d14cef Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 16:36:09 -0800 Subject: [PATCH 194/267] FIX isCityExist method in DAO --- .../data_access/WeatherDataAccessObject.java | 48 ++++++++++++++----- .../CompareCitiesDataAccessInterface.java | 13 ++--- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index e598ed8f7..01ce52fab 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -19,10 +19,10 @@ * This class runs the API and creates a weather DAO. **/ -public abstract class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface{ +public class WeatherDataAccessObject implements WeatherDataAccessInterface, CompareCitiesDataAccessInterface { private static final String API_KEY = "7cce48d7f1f6785f54c0d08aa117ad83"; private static final String MAIN = "main"; - private static String city; + // private static String city; private static final int SUCCESS_CODE = 200; private static final String CONTENT_TYPE_JSON = "application/json"; private static final String STATUS_CODE_LABEL = "cod"; @@ -31,6 +31,36 @@ public abstract class WeatherDataAccessObject implements WeatherDataAccessInterf private boolean cityexist; private final Map citytoweather = new HashMap<>(); + @Override + public boolean isCityExist(String citySearch) { + final OkHttpClient client = new OkHttpClient().newBuilder().build(); + + // Create a request to the OpenWeather API + final Request request = new Request.Builder() + .url(String.format("http://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=metric", citySearch, API_KEY)) + .addHeader("Content-Type", CONTENT_TYPE_JSON) + .build(); + + try { + final Response response = client.newCall(request).execute(); + + // Parse the response + final JSONObject responseBody = new JSONObject(response.body().string()); + + // Check if the status code is 200 (Success) + if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { + // City exists, as the API returned successful data + return true; + } else { + // City doesn't exist (API returned a different code or error message) + return false; + } + } catch (IOException | JSONException ex) { + // If there was an error with the API call (e.g., network error, parsing error), assume city doesn't exist + return false; + } + } + @Override public Weather getWeather(String citySearch) throws IOException { // Make an API call to get the user object. @@ -73,8 +103,7 @@ public Weather getWeather(String citySearch) throws IOException { } else { throw new IOException(responseBody.getString(MESSAGE)); } - } - catch (IOException | JSONException ex) { + } catch (IOException | JSONException ex) { throw new IOException(ex); } } @@ -90,15 +119,10 @@ public Map getcitytoweather() { } /* - * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. - */ + * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. + */ @Override public void clearcitytoweather() { this.citytoweather.clear(); } - - public boolean isCityexist() { - return cityexist; - } -} - +} \ No newline at end of file diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java index de387089c..097c2b4a8 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesDataAccessInterface.java @@ -11,10 +11,11 @@ public interface CompareCitiesDataAccessInterface { /** * Check if City exists. - * @param cityname the weather is displayed for - * @return if city exists + * @param cityName the weather is displayed for + * @return true if city exists + * @throws IOException if the city does not exist or oi. */ - boolean isCityexist(String cityname); + boolean isCityExist(String cityName); /** * Creates the Weather. @@ -37,12 +38,6 @@ public interface CompareCitiesDataAccessInterface { * */ Map getcitytoweather(); - /** - * Sets city. - * @param cityname check if the cityname is valid or not - */ - boolean isCityExist(String cityname); - /** * This method "clean" the elements inside this.citytoweather we don't want to accumulate pairs. */ From 522c891cf8f761dc9cb2a335bfb3880cb628d12e Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 19:35:13 -0800 Subject: [PATCH 195/267] refactor --- src/main/java/view/MapImagepanel.java | 6 +++--- src/main/java/view/MapPanelView.java | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index b0bd45393..538625a4b 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -23,14 +23,14 @@ public MapImagepanel(double latitude, double longitude) { this.coords = new double[] {latitude, longitude}; this.mapViewer = new JXMapViewer(); - TileFactoryInfo info = new OSMTileFactoryInfo(); - DefaultTileFactory tileFactory = new DefaultTileFactory(info); + final TileFactoryInfo info = new OSMTileFactoryInfo(); + final DefaultTileFactory tileFactory = new DefaultTileFactory(info); this.mapViewer.setTileFactory(tileFactory); tileFactory.setThreadPoolSize(NUM_THREADS); - GeoPosition position = new GeoPosition(this.coords); + final GeoPosition position = new GeoPosition(this.coords); this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 5128f1049..2aca70081 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -23,35 +23,42 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private final JTextField cityinputfield1 = new JTextField(15); - private final JTextField dateinputfield = new JTextField(15); - private final JTextField cityinputfield2 = new JTextField(15); + private final JTextField cityinputfield1 = new JTextField(20); + private final JTextField dateinputfield = new JTextField(20); + private final JTextField cityinputfield2 = new JTextField(20); private final int mappanelwidth = 370; private final int mappanelheight = 500; private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; - private final float torontoLatitude = 43.6532; - private final float torontoLongitude = -79.3832; + private final double torontoLatitude = 43.6532; + private final double torontoLongitude = -79.3832; public MapPanelView() { - + // by default set the map center be Toronto. mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); - + // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { - // if the event is coming from cityinput field, execute weather controller - if (event.getSource() == cityinputfield1) { + // if the event is coming from cityinput field, execute weather controller, check if empty + if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { weatherController.execute(cityinputfield1.getText()); } + else { + cityinputfield1.setText("can not return empty"); + } } ); + // if Compare to another city -> CompareCityController cityinputfield2.addActionListener( event -> { - if (event.getSource() == cityinputfield2) { + if (event.getSource() == cityinputfield2 && cityinputfield2.getText().length() > 0) { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); } + else { + cityinputfield2.setText("can not return empty"); + } } ); cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); From 444f2a13ba757333c6c4086a597fd7f732906165 Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 19:36:02 -0800 Subject: [PATCH 196/267] still need fix (commit because i want to use git pull) --- .../note/CompareCitiesInteractorTest.java | 103 +++++++++--------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java index 4ce574900..f1cfe9cee 100644 --- a/src/test/java/use_case/note/CompareCitiesInteractorTest.java +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -21,6 +21,7 @@ public void successTest() { final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); CompareCitiesOutputBoundary SuccessPresenter = new CompareCitiesOutputBoundary() { + // make a presenter @Override public void prepareSuccessView(CompareCitiesOutPutData outputData) { Assertions.assertEquals("Toronto", outputData.getFirstCityname()); @@ -37,54 +38,56 @@ public void prepareFailView(String errorMessage) { final CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, SuccessPresenter); interactor.execute(inputData); - -// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); -// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); -// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); -// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); - } - - @Override - public boolean isCityexist("Toronto") { - return true; - } - - @Override - public boolean isCityExist(String cityname) { - return false; - } - } { - - - @Override - public String saveWeatherinfor(Weather weather) { - return ""; - } - - - @Override - public String loadWeather(Weather weather) { - return "test"; - } - }; - - CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { - @Override - public void prepareSuccessView(String message) { - assertEquals("test", message); - } - - @Override - public void prepareFailView(String errorMessage) { - fail(errorMessage); - } - }; - - CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); - CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); - - compareCitiesInteractor.execute(inputData); - - } -} \ No newline at end of file +} +// +//// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); +//// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); +//// Weather weather2 = compareCitiesDataAccessInterface.getWeather(inputData.getSecondcityname()); +//// compareCitiesDataAccessInterface.saveWeatherinfor(weather2); +// } +// +// @Override +// public boolean isCityexist(String cityname) { +// return true; +// } +// +// @Override +// public boolean isCityExist(String cityname) { +// return false; +// } +// } { +// +// +// @Override +// public String saveWeatherinfor(Weather weather) { +// return ""; +// } +// +// +// @Override +// public String loadWeather(Weather weather) { +// return "test"; +// } +// }; +// +// CompareCitiesOutputBoundary compareCitiesOB = new CompareCitiesOutputBoundary() { +// @Override +// public void prepareSuccessView(String message) { +// assertEquals("test", message); +// } +// +// @Override +// public void prepareFailView(String errorMessage) { +// fail(errorMessage); +// } +// }; +// +// CompareCitiesInteractor compareCitiesInteractor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, compareCitiesOB); +// CompareCitiesInputData inputData = new CompareCitiesInputData("City1", "City2"); +// +// compareCitiesInteractor.execute(inputData); +// +// +// } +//} \ No newline at end of file From 65cab859b8fc1882e5e79dce6b27e26a5938bc7d Mon Sep 17 00:00:00 2001 From: sophie Date: Mon, 25 Nov 2024 20:02:12 -0800 Subject: [PATCH 197/267] A bunch of bug fixed --- src/main/java/app/AppBuilder.java | 40 +++---------------- .../InMemoryUserDataAccessObject.java | 10 +++-- src/main/java/entity/Weather.java | 20 +++++----- .../CompareCitiesInteractor.java | 4 +- .../view/HistoricalSearchedWeatherView.java | 4 +- src/main/java/view/MainView.java | 2 +- src/main/java/view/mapimagepreview.java | 12 ------ src/main/java/view/mappanelpreview.java | 18 --------- 8 files changed, 27 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/view/mapimagepreview.java delete mode 100644 src/main/java/view/mappanelpreview.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 2425dcbd5..a78c42fa6 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -27,6 +27,7 @@ import use_case.note.CompareCities.CompareCitiesOutputBoundary; import use_case.note.HistoricalWeatherDataAccessInterface; import use_case.note.search_result.SearchResultInteractor; +import use_case.note.search_return.SearchReturnInputBoundary; import use_case.note.search_return.SearchReturnInteractor; import use_case.note.WeatherDataAccessInterface; import use_case.note.alert_pop.AlertPopInteractor; @@ -60,7 +61,7 @@ public class AppBuilder { private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MainView mainView; + private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState())); private PropertyChangeEvent evt; private SearchResultInputBoundary searchResultInputBoundary; @@ -106,7 +107,7 @@ public AppBuilder addAlertPopUseCase() { final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { @Override public Weather getWeather(String city) throws IOException { - return WeatherDataAccessObject.getWeather(city); + return weatherDAO.getWeather(city); } }; @@ -120,40 +121,10 @@ public Weather getWeather(String city) throws IOException { return this; } - public AppBuilder addCompareCitiesUseCase() { // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); - final CompareCitiesDataAccessInterface dai = new CompareCitiesDataAccessInterface() { - @Override - public boolean isCityexist(String cityname) { - return false; - } - @Override - public Weather getWeather(String cityname) throws IOException { - return null; - } - - @Override - public void saveWeatherinfor(Weather weather) { - - } - - @Override - public Map getcitytoweather() { - return Map.of(); - } - - @Override - public boolean isCityExist(String cityname) { - return false; - } - - @Override - public void clearcitytoweather() { - - } - }; + final CompareCitiesDataAccessInterface dai = new WeatherDataAccessObject(); final CompareCitiesInteractor interactor = new CompareCitiesInteractor(dai, outputBoundary); @@ -162,6 +133,7 @@ public void clearcitytoweather() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setCompareCitiesController(controller); return this; } @@ -195,7 +167,7 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx public AppBuilder addSearchReturnUseCase() { final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); - final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO); + final SearchReturnInteractor interactor = new SearchReturnInteractor(outputBoundary, weatherDAO, historyDAO); final WeatherController controller = new WeatherController(interactor); mainView.mapPanelView.setWeatherController(controller); diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java index 180342727..0ed6beebb 100644 --- a/src/main/java/data_access/InMemoryUserDataAccessObject.java +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -14,19 +14,21 @@ public class InMemoryUserDataAccessObject implements CompareCitiesDataAccessInte private final Map weathers = new HashMap<>(); @Override - public boolean isCityexist(String identifier) { + public boolean isCityExist(String identifier) { return weathers.containsKey(identifier); } @Override public Weather getWeather(String identifier) { - if (isCityexist(identifier)) { + if (isCityExist(identifier)) { if ("Toronto".equalsIgnoreCase(identifier)) { - final Weather torontoweather = new Weather("Toronto", 10.5, "rain", null, 0); + final Weather torontoweather = new Weather("Toronto", 10.5, "rain", + null, 0, 1, 1, 1, 1, null); return torontoweather; } else { - final Weather tokyoweather = new Weather("Tokyo",1.0, "cloud", null, 1 ); + final Weather tokyoweather = new Weather("Tokyo", 1.0, "cloud", null, + 2, 2, 2, 2, 2, null); return tokyoweather; } } diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index c907d61c4..320d7d03d 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -5,20 +5,20 @@ */ public class Weather { - private float temperature; + private double temperature; private String weather; private final String description; - private float windSpeed; + private double windSpeed; private final int humidity; private final int visibility; private boolean metric; private String cityName; - private int lon; - private int lat; + private double lon; + private double lat; private final String alertDescription; - public Weather(String city, float temperature, String weather, String description, float windSpeed, - int humidity, int visibility, int lon, int lat, String alertDescription) { + public Weather(String city, double temperature, String weather, String description, double windSpeed, + int humidity, int visibility, double lon, double lat, String alertDescription) { this.temperature = temperature; this.weather = weather; this.description = description; @@ -44,7 +44,7 @@ public void setCityName(String cityName) { this.cityName = cityName; } - public int getLat() { + public double getLat() { return lat; } @@ -52,7 +52,7 @@ public void setLat(int lat) { this.lat = lat; } - public int getLon() { + public double getLon() { return lon; } @@ -89,11 +89,11 @@ public String getWeather() { return weather; } - public float getTemperature() { + public double getTemperature() { return temperature; } - public float getWindSpeed() { + public double getWindSpeed() { return windSpeed; } diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index bea4582c2..eb7ce39bc 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -29,8 +29,8 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { comparecitiesPresenter.prepareFailView("Cannot compare the same city"); } else { - if (!compareCitiesDataAccessInterface.isCityexist(firstcityname) - || !compareCitiesDataAccessInterface.isCityexist(secondcityname)) { + if (!compareCitiesDataAccessInterface.isCityExist(firstcityname) + || !compareCitiesDataAccessInterface.isCityExist(secondcityname)) { comparecitiesPresenter.prepareFailView("city not found"); } else { diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 3ce1e5d78..a68d670a8 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -78,7 +78,7 @@ private void changeProperty(String propertyName, Weather searchedWeather) { weatherfincitypanel.setoutput(searchedWeather.getCityName()); break; case "temperature": - final float temperature = searchedWeather.getTemperature(); + final double temperature = searchedWeather.getTemperature(); final String temperatureString = String.valueOf(temperature); temperaturepanel.setoutput(temperatureString); break; @@ -91,7 +91,7 @@ private void changeProperty(String propertyName, Weather searchedWeather) { humiditypanel.setoutput(humidityString); break; case "windSpeed": - final float windSpeed = searchedWeather.getWindSpeed(); + final double windSpeed = searchedWeather.getWindSpeed(); final String windSpeedString = String.valueOf(windSpeed); windspeedpanel.setoutput(windSpeedString); break; diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index fb7477cd4..05f5ef3cd 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -8,7 +8,7 @@ import java.beans.PropertyChangeEvent; public class MainView extends JFrame { - private MapPanelView mapPanelView; + public MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; private HistoricalSearchedWeatherView searchResultPanelView; diff --git a/src/main/java/view/mapimagepreview.java b/src/main/java/view/mapimagepreview.java deleted file mode 100644 index 44d9edb57..000000000 --- a/src/main/java/view/mapimagepreview.java +++ /dev/null @@ -1,12 +0,0 @@ -package view; - -import javax.swing.*; - -public class mapimagepreview { - public static void main(String[] args) { - // Create the JPanel and add components to it - JPanel panel = new MapImagepanel(); - // Display the JPanel in a JOptionPane dialog - JOptionPane.showMessageDialog(null, panel, "map image preview", JOptionPane.PLAIN_MESSAGE); - } -} diff --git a/src/main/java/view/mappanelpreview.java b/src/main/java/view/mappanelpreview.java deleted file mode 100644 index 55fbe9866..000000000 --- a/src/main/java/view/mappanelpreview.java +++ /dev/null @@ -1,18 +0,0 @@ -package view; - -import interface_adapter.weather.WeatherViewModel; - -import javax.swing.*; - -/* -* this class give a preview on MapPanelview. - */ -public class mappanelpreview { - public static void main(String[] args) { - // Create the JPanel and add components to it - final MapPanelView panel = new MapPanelView(new WeatherViewModel()); - - // Display the JPanel in a JOptionPane dialog - JOptionPane.showMessageDialog(null, panel, "JPanel Preview", JOptionPane.PLAIN_MESSAGE); - } -} \ No newline at end of file From 0324e6bfeca732dc5b7a9ae62051dfce344bb967 Mon Sep 17 00:00:00 2001 From: sophie Date: Tue, 26 Nov 2024 11:09:11 -0800 Subject: [PATCH 198/267] bug fixed- (historicalSearchedWeatherView was not initialized) --- src/main/java/view/MainView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 05f5ef3cd..47ffd1485 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -10,7 +10,7 @@ public class MainView extends JFrame { public MapPanelView mapPanelView; private WeatherPanelView weatherPanelView; - private HistoricalSearchedWeatherView searchResultPanelView; + private HistoricalSearchedWeatherView historicalSearchedWeatherView; private final int frameWidth = 1500; private final int frameHeight = 1000; @@ -18,6 +18,7 @@ public class MainView extends JFrame { public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { mapPanelView = new MapPanelView(); weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); + historicalSearchedWeatherView = new HistoricalSearchedWeatherView(searchResultViewModel, evt); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); @@ -25,7 +26,7 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR this.setLayout(new GridLayout(1, 3)); this.add(mapPanelView); this.add(weatherPanelView); - this.add(searchResultPanelView); + this.add(historicalSearchedWeatherView); // pack() optimize window size this.pack(); this.setVisible(true); From bdf60a7587e7cdef0517ac25a419c5f901f4aae6 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 13:01:45 -0800 Subject: [PATCH 199/267] bug fix --- src/main/java/app/MainApplication.java | 3 +-- src/main/java/data_access/WeatherDataAccessObject.java | 8 ++++++-- src/main/java/view/CompareCitiesView.java | 10 ++++++---- src/main/java/view/MapPanelView.java | 6 +++++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/java/app/MainApplication.java b/src/main/java/app/MainApplication.java index b596ce135..1d3dcb874 100644 --- a/src/main/java/app/MainApplication.java +++ b/src/main/java/app/MainApplication.java @@ -37,8 +37,7 @@ public static void main(String[] args) { .addNearbyListUseCase() .addSearchReturnUseCase() .addSearchResultUseCase() - .addAlertPopUseCase() - .addMainView().build().setVisible(true); + .addAlertPopUseCase().build().setVisible(true); } } diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index 01ce52fab..ccd060cbb 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -82,11 +82,15 @@ public Weather getWeather(String citySearch) throws IOException { this.cityexist = true; // get individual items from the json object - final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); - final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); +// final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); +// final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); + final int lat = 1; + final int lon = 1; final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); + + // todo: review looks final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); final String description = weatherJSON.getJSONObject("weather").getString("description"); diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 0c51531e3..585312431 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -88,9 +88,11 @@ public void setfield(CompareCitiesState compareCitiesState) { humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - } - public void actionPerformed(ActionEvent event) { - System.out.println("Enter" + event.getActionCommand()); - + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 2aca70081..2f986ea5b 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,6 +1,7 @@ package view; import interface_adapter.CompareCities.CompareCitiesController; +import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.weather.WeatherController; @@ -53,8 +54,10 @@ public MapPanelView() { // if Compare to another city -> CompareCityController cityinputfield2.addActionListener( event -> { - if (event.getSource() == cityinputfield2 && cityinputfield2.getText().length() > 0) { + if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); + new CompareCitiesView(compareCitiesViewModel); } else { cityinputfield2.setText("can not return empty"); @@ -77,6 +80,7 @@ public MapPanelView() { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(cityinputpanel); this.add(dateinputpanel); + this.add(comparetopanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); From 70a3f82bcaab782f2d6a405ae4ef923b8ab51b8a Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 14:34:33 -0800 Subject: [PATCH 200/267] bug fix (looks, description), add sample json file --- .../data_access/WeatherDataAccessObject.java | 27 +- src/main/resources/weatherAPI.json | 1345 +++++++++++++++++ 2 files changed, 1360 insertions(+), 12 deletions(-) create mode 100644 src/main/resources/weatherAPI.json diff --git a/src/main/java/data_access/WeatherDataAccessObject.java b/src/main/java/data_access/WeatherDataAccessObject.java index ccd060cbb..1c9774c66 100644 --- a/src/main/java/data_access/WeatherDataAccessObject.java +++ b/src/main/java/data_access/WeatherDataAccessObject.java @@ -51,11 +51,13 @@ public boolean isCityExist(String citySearch) { if (responseBody.getInt(STATUS_CODE_LABEL) == SUCCESS_CODE) { // City exists, as the API returned successful data return true; - } else { + } + else { // City doesn't exist (API returned a different code or error message) return false; } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { // If there was an error with the API call (e.g., network error, parsing error), assume city doesn't exist return false; } @@ -81,19 +83,18 @@ public Weather getWeather(String citySearch) throws IOException { final JSONObject weatherJSON = responseBody.getJSONArray(WEATHER_LIST).getJSONObject(0); this.cityexist = true; // get individual items from the json object - -// final int lat = (int) weatherJSON.getJSONObject(MAIN).getDouble("lat"); -// final int lon = (int) weatherJSON.getJSONObject(MAIN).getDouble("lon"); - final int lat = 1; - final int lon = 1; + final JSONObject coordJSON = responseBody.getJSONObject("city").getJSONObject("coord"); + final double lon = coordJSON.getDouble("lon"); + final double lat = coordJSON.getDouble("lat"); final int temp = (int) weatherJSON.getJSONObject(MAIN).getDouble("temp"); final int humidity = (int) weatherJSON.getJSONObject(MAIN).getDouble("humidity"); final int windspeed = (int) weatherJSON.getJSONObject("wind").getDouble("speed"); - // todo: review looks - final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + // final String looks = weatherJSON.getJSONObject("weather").getString(MAIN); + final String looks = weatherJSON.getJSONArray("weather").getJSONObject(0).getString(MAIN); final int visibility = weatherJSON.getInt("visibility"); - final String description = weatherJSON.getJSONObject("weather").getString("description"); + // final String description = weatherJSON.getJSONObject("weather").getString("description"); + final String description = weatherJSON.getJSONArray("weather").getJSONObject(0).getString("description"); String alertDescription = "no weather alert"; if (weatherJSON.has("alerts")) { final JSONArray alertsArray = weatherJSON.getJSONArray("alerts"); @@ -104,10 +105,12 @@ public Weather getWeather(String citySearch) throws IOException { return new Weather(citySearch, temp, looks, description, windspeed, humidity, visibility, lon, lat, alertDescription); - } else { + } + else { throw new IOException(responseBody.getString(MESSAGE)); } - } catch (IOException | JSONException ex) { + } + catch (IOException | JSONException ex) { throw new IOException(ex); } } diff --git a/src/main/resources/weatherAPI.json b/src/main/resources/weatherAPI.json new file mode 100644 index 000000000..649d9cfc4 --- /dev/null +++ b/src/main/resources/weatherAPI.json @@ -0,0 +1,1345 @@ +{ + "city" : { + "country" : "CA", + "coord" : { + "lon" : -79.4163, + "lat" : 43.7001 + }, + "sunrise" : 1732710456, + "timezone" : -18000, + "sunset" : 1732743824, + "name" : "Toronto", + "id" : 6167865, + "population" : 4612191 + }, + "cnt" : 40, + "cod" : "200", + "message" : 0, + "list" : [ { + "dt" : 1732752000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 4.05, + "temp_min" : 4.03, + "grnd_level" : 996, + "temp_kf" : 0.02, + "humidity" : 55, + "pressure" : 1013, + "sea_level" : 1013, + "feels_like" : 1.61, + "temp_max" : 4.05 + }, + "clouds" : { + "all" : 80 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 258, + "speed" : 2.69, + "gust" : 5.92 + } + }, { + "dt" : 1732762800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.53, + "temp_min" : 3.27, + "grnd_level" : 996, + "temp_kf" : 0.26, + "humidity" : 54, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : 1.96, + "temp_max" : 3.53 + }, + "clouds" : { + "all" : 92 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 278, + "speed" : 1.74, + "gust" : 3.73 + } + }, { + "dt" : 1732773600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.12, + "temp_min" : 3.12, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 52, + "pressure" : 1010, + "sea_level" : 1010, + "feels_like" : 3.12, + "temp_max" : 3.12 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 328, + "speed" : 1.14, + "gust" : 1.77 + } + }, { + "dt" : 1732784400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.16, + "temp_min" : 3.16, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 53, + "pressure" : 1008, + "sea_level" : 1008, + "feels_like" : 3.16, + "temp_max" : 3.16 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 68, + "speed" : 0.87, + "gust" : 1.2 + } + }, { + "dt" : 1732795200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.04, + "temp_min" : 3.04, + "grnd_level" : 991, + "temp_kf" : 0, + "humidity" : 57, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.43, + "temp_max" : 3.04 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 26, + "speed" : 1.71, + "gust" : 3.48 + } + }, { + "dt" : 1732806000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 3.55, + "temp_min" : 3.55, + "grnd_level" : 990, + "temp_kf" : 0, + "humidity" : 56, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.41, + "temp_max" : 3.55 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 345, + "speed" : 2.26, + "gust" : 3.77 + } + }, { + "dt" : 1732816800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 5.38, + "temp_min" : 5.38, + "grnd_level" : 989, + "temp_kf" : 0, + "humidity" : 49, + "pressure" : 1005, + "sea_level" : 1005, + "feels_like" : 2.39, + "temp_max" : 5.38 + }, + "clouds" : { + "all" : 85 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 317, + "speed" : 3.89, + "gust" : 5.52 + } + }, { + "dt" : 1732827600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-28 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 5.12, + "temp_min" : 5.12, + "grnd_level" : 991, + "temp_kf" : 0, + "humidity" : 46, + "pressure" : 1007, + "sea_level" : 1007, + "feels_like" : 1.99, + "temp_max" : 5.12 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 310, + "speed" : 4.03, + "gust" : 6.04 + } + }, { + "dt" : 1732838400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 2.6, + "temp_min" : 2.6, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 58, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -1.46, + "temp_max" : 2.6 + }, + "clouds" : { + "all" : 85 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 285, + "speed" : 4.62, + "gust" : 8.29 + } + }, { + "dt" : 1732849200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 03:00:00", + "weather" : [ { + "icon" : "03n", + "description" : "scattered clouds", + "main" : "Clouds", + "id" : 802 + } ], + "main" : { + "temp" : 1.53, + "temp_min" : 1.53, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 70, + "pressure" : 1010, + "sea_level" : 1010, + "feels_like" : -2.56, + "temp_max" : 1.53 + }, + "clouds" : { + "all" : 26 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 4.24, + "gust" : 9.02 + } + }, { + "dt" : 1732860000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 06:00:00", + "weather" : [ { + "icon" : "02n", + "description" : "few clouds", + "main" : "Clouds", + "id" : 801 + } ], + "main" : { + "temp" : 1.2, + "temp_min" : 1.2, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -3.13, + "temp_max" : 1.2 + }, + "clouds" : { + "all" : 22 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 253, + "speed" : 4.51, + "gust" : 8.84 + } + }, { + "dt" : 1732870800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 0.67, + "temp_min" : 0.67, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 62, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.16, + "temp_max" : 0.67 + }, + "clouds" : { + "all" : 73 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 250, + "speed" : 5.14, + "gust" : 9.86 + } + }, { + "dt" : 1732881600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.43, + "temp_min" : 0.43, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 63, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.69, + "temp_max" : 0.43 + }, + "clouds" : { + "all" : 86 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 248, + "speed" : 5.58, + "gust" : 10.77 + } + }, { + "dt" : 1732892400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.86, + "temp_min" : 0.86, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 63, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -4.25, + "temp_max" : 0.86 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 5.77, + "gust" : 10.56 + } + }, { + "dt" : 1732903200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 2.65, + "temp_min" : 2.65, + "grnd_level" : 992, + "temp_kf" : 0, + "humidity" : 46, + "pressure" : 1008, + "sea_level" : 1008, + "feels_like" : -2.09, + "temp_max" : 2.65 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 253, + "speed" : 6, + "gust" : 10 + } + }, { + "dt" : 1732914000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-29 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 1.98, + "temp_min" : 1.98, + "grnd_level" : 993, + "temp_kf" : 0, + "humidity" : 53, + "pressure" : 1009, + "sea_level" : 1009, + "feels_like" : -3.1, + "temp_max" : 1.98 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 255, + "speed" : 6.36, + "gust" : 11.97 + } + }, { + "dt" : 1732924800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.48, + "temp_min" : 0.48, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1011, + "sea_level" : 1011, + "feels_like" : -5.01, + "temp_max" : 0.48 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 6.35, + "gust" : 11.85 + } + }, { + "dt" : 1732935600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.03, + "temp_min" : -0.03, + "grnd_level" : 994, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1011, + "sea_level" : 1011, + "feels_like" : -5.62, + "temp_max" : -0.03 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 257, + "speed" : 6.26, + "gust" : 11.62 + } + }, { + "dt" : 1732946400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.98, + "temp_min" : -0.98, + "grnd_level" : 995, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : -6.77, + "temp_max" : -0.98 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 252, + "speed" : 6.14, + "gust" : 12.41 + } + }, { + "dt" : 1732957200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 09:00:00", + "weather" : [ { + "icon" : "03n", + "description" : "scattered clouds", + "main" : "Clouds", + "id" : 802 + } ], + "main" : { + "temp" : -0.99, + "temp_min" : -0.99, + "grnd_level" : 995, + "temp_kf" : 0, + "humidity" : 66, + "pressure" : 1012, + "sea_level" : 1012, + "feels_like" : -6.76, + "temp_max" : -0.99 + }, + "clouds" : { + "all" : 48 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 251, + "speed" : 6.11, + "gust" : 12.84 + } + }, { + "dt" : 1732968000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -1.15, + "temp_min" : -1.15, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1013, + "sea_level" : 1013, + "feels_like" : -7.06, + "temp_max" : -1.15 + }, + "clouds" : { + "all" : 55 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 251, + "speed" : 6.29, + "gust" : 12.65 + } + }, { + "dt" : 1732978800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.33, + "temp_min" : -0.33, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -5.89, + "temp_max" : -0.33 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 6.05, + "gust" : 10.71 + } + }, { + "dt" : 1732989600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 1.14, + "temp_min" : 1.14, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 47, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -3.93, + "temp_max" : 1.14 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 252, + "speed" : 5.84, + "gust" : 8.39 + } + }, { + "dt" : 1733000400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-11-30 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.08, + "temp_min" : 0.08, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 55, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -5.22, + "temp_max" : 0.08 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 248, + "speed" : 5.74, + "gust" : 8.98 + } + }, { + "dt" : 1733011200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.77, + "temp_min" : -0.77, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.35, + "temp_max" : -0.77 + }, + "clouds" : { + "all" : 98 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 248, + "speed" : 5.84, + "gust" : 10.17 + } + }, { + "dt" : 1733022000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.15, + "temp_min" : -1.15, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 65, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.62, + "temp_max" : -1.15 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.45, + "gust" : 10.23 + } + }, { + "dt" : 1733032800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.37, + "temp_min" : -1.37, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 65, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.05, + "temp_max" : -1.37 + }, + "clouds" : { + "all" : 99 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.73, + "gust" : 10.81 + } + }, { + "dt" : 1733043600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.49, + "temp_min" : -1.49, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.13, + "temp_max" : -1.49 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 244, + "speed" : 5.61, + "gust" : 11.45 + } + }, { + "dt" : 1733054400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -1.36, + "temp_min" : -1.36, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -7.16, + "temp_max" : -1.36 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 243, + "speed" : 5.97, + "gust" : 12.84 + } + }, { + "dt" : 1733065200, + "pop" : 0.99, + "visibility" : 2980, + "dt_txt" : "2024-12-01 15:00:00", + "snow" : { + "3h" : 0.68 + }, + "weather" : [ { + "icon" : "13d", + "description" : "light snow", + "main" : "Snow", + "id" : 600 + } ], + "main" : { + "temp" : -1.14, + "temp_min" : -1.14, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 85, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -6.49, + "temp_max" : -1.14 + }, + "clouds" : { + "all" : 100 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 250, + "speed" : 5.25, + "gust" : 11.59 + } + }, { + "dt" : 1733076000, + "pop" : 0.92, + "visibility" : 10000, + "dt_txt" : "2024-12-01 18:00:00", + "snow" : { + "3h" : 0.21 + }, + "weather" : [ { + "icon" : "13d", + "description" : "light snow", + "main" : "Snow", + "id" : 600 + } ], + "main" : { + "temp" : 1.58, + "temp_min" : 1.58, + "grnd_level" : 997, + "temp_kf" : 0, + "humidity" : 60, + "pressure" : 1014, + "sea_level" : 1014, + "feels_like" : -2.51, + "temp_max" : 1.58 + }, + "clouds" : { + "all" : 97 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 251, + "speed" : 4.26, + "gust" : 6.63 + } + }, { + "dt" : 1733086800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-01 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 1.32, + "temp_min" : 1.32, + "grnd_level" : 998, + "temp_kf" : 0, + "humidity" : 55, + "pressure" : 1015, + "sea_level" : 1015, + "feels_like" : -2.17, + "temp_max" : 1.32 + }, + "clouds" : { + "all" : 95 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 288, + "speed" : 3.31, + "gust" : 6.43 + } + }, { + "dt" : 1733097600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 00:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : -0.14, + "temp_min" : -0.14, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 67, + "pressure" : 1016, + "sea_level" : 1016, + "feels_like" : -4.26, + "temp_max" : -0.14 + }, + "clouds" : { + "all" : 86 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 285, + "speed" : 3.73, + "gust" : 9.09 + } + }, { + "dt" : 1733108400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 03:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.64, + "temp_min" : -0.64, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 64, + "pressure" : 1017, + "sea_level" : 1017, + "feels_like" : -3.9, + "temp_max" : -0.64 + }, + "clouds" : { + "all" : 74 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 279, + "speed" : 2.62, + "gust" : 6.37 + } + }, { + "dt" : 1733119200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 06:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.89, + "temp_min" : -0.89, + "grnd_level" : 1000, + "temp_kf" : 0, + "humidity" : 70, + "pressure" : 1017, + "sea_level" : 1017, + "feels_like" : -4.07, + "temp_max" : -0.89 + }, + "clouds" : { + "all" : 75 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 296, + "speed" : 2.49, + "gust" : 4.68 + } + }, { + "dt" : 1733130000, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 09:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.77, + "temp_min" : -0.77, + "grnd_level" : 1001, + "temp_kf" : 0, + "humidity" : 68, + "pressure" : 1018, + "sea_level" : 1018, + "feels_like" : -3.96, + "temp_max" : -0.77 + }, + "clouds" : { + "all" : 78 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 291, + "speed" : 2.52, + "gust" : 4.73 + } + }, { + "dt" : 1733140800, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 12:00:00", + "weather" : [ { + "icon" : "04n", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.97, + "temp_min" : -0.97, + "grnd_level" : 1001, + "temp_kf" : 0, + "humidity" : 71, + "pressure" : 1018, + "sea_level" : 1018, + "feels_like" : -4.14, + "temp_max" : -0.97 + }, + "clouds" : { + "all" : 82 + }, + "sys" : { + "pod" : "n" + }, + "wind" : { + "deg" : 321, + "speed" : 2.47, + "gust" : 6.01 + } + }, { + "dt" : 1733151600, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 15:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : -0.1, + "temp_min" : -0.1, + "grnd_level" : 1003, + "temp_kf" : 0, + "humidity" : 69, + "pressure" : 1020, + "sea_level" : 1020, + "feels_like" : -3, + "temp_max" : -0.1 + }, + "clouds" : { + "all" : 54 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 342, + "speed" : 2.37, + "gust" : 4.47 + } + }, { + "dt" : 1733162400, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 18:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "broken clouds", + "main" : "Clouds", + "id" : 803 + } ], + "main" : { + "temp" : 1.01, + "temp_min" : 1.01, + "grnd_level" : 1003, + "temp_kf" : 0, + "humidity" : 59, + "pressure" : 1020, + "sea_level" : 1020, + "feels_like" : -1.04, + "temp_max" : 1.01 + }, + "clouds" : { + "all" : 60 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 306, + "speed" : 1.81, + "gust" : 2.47 + } + }, { + "dt" : 1733173200, + "pop" : 0, + "visibility" : 10000, + "dt_txt" : "2024-12-02 21:00:00", + "weather" : [ { + "icon" : "04d", + "description" : "overcast clouds", + "main" : "Clouds", + "id" : 804 + } ], + "main" : { + "temp" : 0.9, + "temp_min" : 0.9, + "grnd_level" : 1004, + "temp_kf" : 0, + "humidity" : 66, + "pressure" : 1021, + "sea_level" : 1021, + "feels_like" : -1.69, + "temp_max" : 0.9 + }, + "clouds" : { + "all" : 92 + }, + "sys" : { + "pod" : "d" + }, + "wind" : { + "deg" : 309, + "speed" : 2.25, + "gust" : 4.02 + } + } ] +} \ No newline at end of file From 04328c9e6ddeb901f9be1dfc53d8a9ad117ad043 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 19:07:37 -0500 Subject: [PATCH 201/267] Fixed Some bugs --- .../data_access/NearbyCitiesAccessObject.java | 1 + .../CompareCitiesController.java | 10 ++++++++++ .../CompareCities/CompareCitiesPresenter.java | 3 +++ .../CompareCities/CompareCitiesState.java | 3 +++ .../CompareCities/CompareCitiesViewModel.java | 3 +++ .../SearchResult/SearchResultPresenter.java | 5 +++-- .../SearchResult/SearchResultViewModel.java | 3 +++ .../alert_pop/AlertPopPresenter.java | 3 +++ .../converter/ConverterPresenter.java | 3 +++ .../weather/WeatherState.java | 2 -- .../HistoricalWeatherDataAccessInterface.java | 1 + .../note/WeatherDataAccessInterface.java | 2 +- .../note/alert_pop/AlertPopInputBoundary.java | 4 +++- .../note/alert_pop/AlertPopInteractor.java | 2 +- .../pin_weather/PinWeatherInputBoundary.java | 7 ------- .../note/pin_weather/PinWeatherInputData.java | 5 ----- .../pin_weather/PinWeatherOutputBoundary.java | 8 -------- .../pin_weather/PinWeatherOutputData.java | 20 ------------------- .../return_home/ReturnHomeInputBoundary.java | 7 ------- .../note/return_home/ReturnHomeInputData.java | 5 ----- .../return_home/ReturnHomeOutputBoundary.java | 8 -------- .../return_home/ReturnHomeOutputData.java | 14 ------------- .../search_result/SearchResultInteractor.java | 5 +++-- .../use_case/note/ConvertInteractorTest.java | 3 ++- 24 files changed, 43 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherInputData.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java delete mode 100644 src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeInputData.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java delete mode 100644 src/main/java/use_case/note/return_home/ReturnHomeOutputData.java diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index b929673f8..835afade8 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -3,6 +3,7 @@ import org.jetbrains.annotations.NotNull; import org.json.JSONArray; import org.json.JSONObject; + import use_case.note.nearby_list.NearbyCitiesAccessInterface; import java.io.IOException; diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java index 2f799237e..9fde6bc1d 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesController.java @@ -2,12 +2,22 @@ import use_case.note.CompareCities.CompareCitiesInputBoundary; import use_case.note.CompareCities.CompareCitiesInputData; +/** + * The Controller for teh Compare Cities Use case. + */ public class CompareCitiesController { private final CompareCitiesInputBoundary interactor; + public CompareCitiesController(CompareCitiesInputBoundary interactor) { this.interactor = interactor; } + + /** + * The execute method. + * @param firstcityName is the first city to compare. + * @param secondcityName is the second city. + */ public void execute(String firstcityName, String secondcityName) { final CompareCitiesInputData compareCitiesInputData = new CompareCitiesInputData(firstcityName, secondcityName); interactor.execute(compareCitiesInputData); diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java index 7586935dd..7db014fb9 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesPresenter.java @@ -3,6 +3,9 @@ import use_case.note.CompareCities.CompareCitiesOutPutData; import use_case.note.CompareCities.CompareCitiesOutputBoundary; +/** + * The Presenter for the Compare Cities Use case. + */ public class CompareCitiesPresenter implements CompareCitiesOutputBoundary { private final CompareCitiesViewModel viewModel; diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java index e78eec510..d6758be40 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesState.java @@ -1,6 +1,9 @@ package interface_adapter.CompareCities; import entity.Weather; +/** + * The State for the Compare Cities Use case. + */ public class CompareCitiesState { private String error; diff --git a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java index baf04b02b..e3a22a6f5 100644 --- a/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java +++ b/src/main/java/interface_adapter/CompareCities/CompareCitiesViewModel.java @@ -1,6 +1,9 @@ package interface_adapter.CompareCities; import interface_adapter.ViewModel; +/** + * The View Model for the Compare Cities Use case. + */ public class CompareCitiesViewModel extends ViewModel { public CompareCitiesViewModel() { diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index 40253631a..f08a1aca3 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -1,9 +1,10 @@ package interface_adapter.SearchResult; -import interface_adapter.weather.WeatherViewModel; import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_result.SearchResultOutputData; - +/** + * Presenter for the Search Result use case. + */ public class SearchResultPresenter implements SearchResultOutputBoundary { diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java index 5c3b5886f..d0094b8cb 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultViewModel.java @@ -1,6 +1,9 @@ package interface_adapter.SearchResult; import interface_adapter.ViewModel; +/** + * View Model for the Search Result use case. + */ public class SearchResultViewModel extends ViewModel { public SearchResultViewModel() { diff --git a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java index 434a47773..7efaadd3d 100644 --- a/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java +++ b/src/main/java/interface_adapter/alert_pop/AlertPopPresenter.java @@ -4,6 +4,9 @@ import use_case.note.alert_pop.AlertPopOutputBoundary; import use_case.note.alert_pop.AlertPopOutputData; +/** + * This is the Presenter for the ALERT POP use case. + */ public class AlertPopPresenter implements AlertPopOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/converter/ConverterPresenter.java b/src/main/java/interface_adapter/converter/ConverterPresenter.java index c634c2d30..7ee80c653 100644 --- a/src/main/java/interface_adapter/converter/ConverterPresenter.java +++ b/src/main/java/interface_adapter/converter/ConverterPresenter.java @@ -3,6 +3,9 @@ import interface_adapter.weather.WeatherViewModel; import use_case.note.convert_farenheit.ConvertFarenheitOutputBoundary; import use_case.note.convert_farenheit.ConvertFarenheitOutputData; +/** + * The Presenter for the Convert Units Use case. + */ public class ConverterPresenter implements ConvertFarenheitOutputBoundary { private final WeatherViewModel viewModel; diff --git a/src/main/java/interface_adapter/weather/WeatherState.java b/src/main/java/interface_adapter/weather/WeatherState.java index 29b6b95a6..4d853b065 100644 --- a/src/main/java/interface_adapter/weather/WeatherState.java +++ b/src/main/java/interface_adapter/weather/WeatherState.java @@ -2,8 +2,6 @@ import entity.Weather; -import entity.Weather; - /** * The state information for the weather view model. */ diff --git a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java index 904670ccf..6ce05f46f 100644 --- a/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/HistoricalWeatherDataAccessInterface.java @@ -21,6 +21,7 @@ public interface HistoricalWeatherDataAccessInterface { * Gets the weather data. * @param city the city to get the weather data for * @param timestamp the timestamp of the weather data + * @return Weather object if no error. * @throws IOException if there is an error getting the weather data */ Weather getWeather(String city, String timestamp) throws IOException; diff --git a/src/main/java/use_case/note/WeatherDataAccessInterface.java b/src/main/java/use_case/note/WeatherDataAccessInterface.java index 163d40981..44f758b4b 100644 --- a/src/main/java/use_case/note/WeatherDataAccessInterface.java +++ b/src/main/java/use_case/note/WeatherDataAccessInterface.java @@ -15,6 +15,6 @@ public interface WeatherDataAccessInterface { * @return the weather information * @throws IOException if the city does not exist or oi. */ - Weather getWeather(String city) throws IOException; + public Weather getWeather(String city) throws IOException; } diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java index 7d635bfb0..0c9d44bd9 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInputBoundary.java @@ -1,6 +1,8 @@ package use_case.note.alert_pop; -// No input because alertpop is automatic. +/** + * No input because it is Automatic. + */ public interface AlertPopInputBoundary { void execute(AlertPopInputData alertPopInputData); diff --git a/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java b/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java index 74eb14aac..b68661b04 100644 --- a/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java +++ b/src/main/java/use_case/note/alert_pop/AlertPopInteractor.java @@ -17,7 +17,7 @@ public void execute(AlertPopInputData alertPopInputData) { try { String cityName = alertPopInputData.getCityName(); Weather weather = weatherAccess.getWeather(cityName); - String alert = weather.getAlertDescription(); + String alert = weather.getDescription(); String noAlert = "no weather alert"; if (noAlert.equals(alert)) { diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java deleted file mode 100644 index 2e267e172..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.pin_weather; - -// Input is a click on "pin." -public interface PinWeatherInputBoundary { - - void execute(PinWeatherInputData pinWeatherInputData); -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java deleted file mode 100644 index 623290d9f..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.pin_weather; - -// Input is a click on "pin." -public class PinWeatherInputData { -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java deleted file mode 100644 index 6eac48913..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.pin_weather; - -public interface PinWeatherOutputBoundary { - - void presentSuccessView(PinWeatherOutputData pinWeatherOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java b/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java deleted file mode 100644 index cc0446619..000000000 --- a/src/main/java/use_case/note/pin_weather/PinWeatherOutputData.java +++ /dev/null @@ -1,20 +0,0 @@ -package use_case.note.pin_weather; - -public class PinWeatherOutputData { - - private final String weatherInfo; - private final boolean useCaseFailed; - - public PinWeatherOutputData(String weatherInfo, boolean useCaseFailed) { - this.weatherInfo = weatherInfo; - this.useCaseFailed = useCaseFailed; - } - - public String getWeatherInfo() { - return weatherInfo; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java deleted file mode 100644 index 93b43e15b..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputBoundary.java +++ /dev/null @@ -1,7 +0,0 @@ -package use_case.note.return_home; - -// Input is a click on the home button. -public interface ReturnHomeInputBoundary { - - void execute(ReturnHomeInputData returnHomeInputData); -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java b/src/main/java/use_case/note/return_home/ReturnHomeInputData.java deleted file mode 100644 index 27162a91e..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeInputData.java +++ /dev/null @@ -1,5 +0,0 @@ -package use_case.note.return_home; - -// Input is a click on the home button. -public class ReturnHomeInputData { -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java deleted file mode 100644 index 258573eb3..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputBoundary.java +++ /dev/null @@ -1,8 +0,0 @@ -package use_case.note.return_home; - -public interface ReturnHomeOutputBoundary { - - void presentSuccessView(ReturnHomeOutputData returnHomeOutputData); - - void prepareFailView(String errorMessage); -} diff --git a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java b/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java deleted file mode 100644 index 49f1ba0c4..000000000 --- a/src/main/java/use_case/note/return_home/ReturnHomeOutputData.java +++ /dev/null @@ -1,14 +0,0 @@ -package use_case.note.return_home; - -public class ReturnHomeOutputData { - - private final boolean useCaseFailed; - - public ReturnHomeOutputData(boolean useCaseFailed) { - this.useCaseFailed = useCaseFailed; - } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } -} diff --git a/src/main/java/use_case/note/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java index 432a9b541..99d3c96bb 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -14,8 +14,9 @@ public class SearchResultInteractor implements SearchResultInputBoundary { private final WeatherDataAccessInterface weatherDataAccess; private final HistoricalWeatherDataAccessInterface historicalWeatherDataAccessInterface; - public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, WeatherDataAccessInterface weatherDataAccess, - HistoricalWeatherDataAccessInterface historicalDataInterface ) { + public SearchResultInteractor(SearchResultOutputBoundary outputBoundary, + WeatherDataAccessInterface weatherDataAccess, HistoricalWeatherDataAccessInterface + historicalDataInterface) { this.outputBoundary = outputBoundary; this.weatherDataAccess = weatherDataAccess; this.historicalWeatherDataAccessInterface = historicalDataInterface; diff --git a/src/test/java/use_case/note/ConvertInteractorTest.java b/src/test/java/use_case/note/ConvertInteractorTest.java index d56676e18..b6d7d4a0b 100644 --- a/src/test/java/use_case/note/ConvertInteractorTest.java +++ b/src/test/java/use_case/note/ConvertInteractorTest.java @@ -23,7 +23,8 @@ public void TestIfWeatherDNE() { WeatherDataAccessInterface Dao = new WeatherDataAccessInterface() { @Override public Weather getWeather(String city) throws IOException { - return WeatherDataAccessObject.getWeather(city); + + return new WeatherDataAccessObject().getWeather(city); } }; ConvertFarenheitOutputBoundary boundary = new ConvertFarenheitOutputBoundary() { From 274bd91cad78a57ca961b1c6a7dd441a0b61e5e7 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:00:32 -0500 Subject: [PATCH 202/267] Corrected access to the lat lon variables in the dao and updated the change of type from int to double --- src/main/java/entity/Weather.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 320d7d03d..6ff75b168 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -13,8 +13,8 @@ public class Weather { private final int visibility; private boolean metric; private String cityName; - private double lon; - private double lat; + private final double lon; + private final double lat; private final String alertDescription; public Weather(String city, double temperature, String weather, String description, double windSpeed, @@ -40,26 +40,14 @@ public String getCityName() { return cityName; } - public void setCityName(String cityName) { - this.cityName = cityName; - } - public double getLat() { return lat; } - public void setLat(int lat) { - this.lat = lat; - } - public double getLon() { return lon; } - public void setLon(int lon) { - this.lon = lon; - } - public boolean isMetric() { return metric; } @@ -104,4 +92,4 @@ public int getHumidity() { public int getVisibility() { return visibility; } -} \ No newline at end of file +} From 06aa560cbe99fe2a27613bbd2f7cb9cbbdf1b388 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:07:56 -0500 Subject: [PATCH 203/267] Fixed view issues in appbuilder and main application --- src/main/java/app/AppBuilder.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index a78c42fa6..32f62bafd 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -41,12 +41,11 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; +import view.MapPanelView; import java.beans.PropertyChangeEvent; import java.io.IOException; import java.util.List; -import java.util.Map; - /** * Builder for the Note Application. @@ -61,7 +60,9 @@ public class AppBuilder { private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState())); + private MapPanelView mapPanelView = new MapPanelView(); + private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, + new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState())); private PropertyChangeEvent evt; private SearchResultInputBoundary searchResultInputBoundary; @@ -100,8 +101,8 @@ public JFrame build() { *

This method must be called after addNoteView!

* @return this builder * @throws RuntimeException if this method is called before addNoteView - **/ + public AppBuilder addAlertPopUseCase() { final AlertPopOutputBoundary outputBoundary = new AlertPopPresenter(weatherViewModel); final WeatherDataAccessInterface accessInterface = new WeatherDataAccessInterface() { @@ -147,6 +148,7 @@ public AppBuilder addConvertUseCase() { } return this; } + public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { @@ -163,6 +165,7 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx throw new RuntimeException("Error"); } return this; + } public AppBuilder addSearchReturnUseCase() { @@ -196,8 +199,9 @@ public AppBuilder addMainView() { evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); // mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); -// mainView.mapPanelView.setWeatherController(new WeatherController(searchReturnInputBoundary)); +// mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); // mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } + } From f6dc82d2f5b586ff85370ade9937d28c902e0339 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Tue, 26 Nov 2024 21:25:31 -0500 Subject: [PATCH 204/267] Set Controllers in AppBuilder and made a constant for ERROR. --- src/main/java/app/AppBuilder.java | 67 ++++++++++++++++++------ src/main/java/view/MainView.java | 2 +- src/main/java/view/MapPanelView.java | 13 +++++ src/main/java/view/WeatherPanelView.java | 4 ++ 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 32f62bafd..36fe030bd 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -41,7 +41,6 @@ import use_case.note.search_result.SearchResultOutputBoundary; import use_case.note.search_return.SearchReturnOutputBoundary; import view.MainView; -import view.MapPanelView; import java.beans.PropertyChangeEvent; import java.io.IOException; @@ -54,13 +53,13 @@ public class AppBuilder { public static final int HEIGHT = 750; public static final int WIDTH = 1500; + private static final String ERROR = "Error"; private WeatherDataAccessInterface weatherDAO; private HistoricalWeatherDataAccessInterface historyDAO; private WeatherViewModel weatherViewModel = new WeatherViewModel(); private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MapPanelView mapPanelView = new MapPanelView(); private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState())); private PropertyChangeEvent evt; @@ -80,9 +79,10 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { } /** - * Builds the application. - * @return the JFrame for the application - */ + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public JFrame build() { final JFrame frame = new JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); @@ -96,11 +96,9 @@ public JFrame build() { } /** - * Creates the objects for the Note Use Case and connects the NoteView to its - * controller. - *

This method must be called after addNoteView!

- * @return this builder - * @throws RuntimeException if this method is called before addNoteView + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. **/ public AppBuilder addAlertPopUseCase() { @@ -117,11 +115,18 @@ public Weather getWeather(String city) throws IOException { final AlertPopController controller = new AlertPopController(interactor); if (mainView == null) { - throw new RuntimeException("Error"); + throw new RuntimeException(ERROR); } + mainView.mapPanelView.setAlertPopController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ + public AppBuilder addCompareCitiesUseCase() { // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); @@ -137,6 +142,11 @@ public AppBuilder addCompareCitiesUseCase() { mainView.mapPanelView.setCompareCitiesController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addConvertUseCase() { final ConvertFarenheitOutputBoundary outputBoundary = new ConverterPresenter(weatherViewModel); @@ -146,8 +156,15 @@ public AppBuilder addConvertUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + + mainView.weatherPanelView.setConverterController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); @@ -164,9 +181,15 @@ public List getNearbyCities(Float latitude, Float longitude) throws IOEx if (mainView == null) { throw new RuntimeException("Error"); } - return this; + mainView.mapPanelView.setNearbyListController(controller); + return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addSearchReturnUseCase() { final SearchReturnOutputBoundary outputBoundary = new WeatherPresenter(weatherViewModel); @@ -177,8 +200,14 @@ public AppBuilder addSearchReturnUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setWeatherController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ public AppBuilder addSearchResultUseCase() { final SearchResultOutputBoundary outputBoundary = new SearchResultPresenter(searchResultViewModel); @@ -189,18 +218,24 @@ public AppBuilder addSearchResultUseCase() { if (mainView == null) { throw new RuntimeException("Error"); } + mainView.mapPanelView.setSearchResultController(controller); return this; } + /** + * USE case. + * @return sjsjnk. + * @throws RuntimeException becais. + **/ // add stuff for all the views public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); searchResultViewModel = new SearchResultViewModel(); - evt = new PropertyChangeEvent(weatherViewModel,"Weather", null, new WeatherState()); + evt = new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState()); mainView = new MainView(weatherViewModel, searchResultViewModel, evt); -// mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); -// mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); -// mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); + // mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); + // mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); + // mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); return this; } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 47ffd1485..6a8fc3bbb 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -9,7 +9,7 @@ public class MainView extends JFrame { public MapPanelView mapPanelView; - private WeatherPanelView weatherPanelView; + public WeatherPanelView weatherPanelView; private HistoricalSearchedWeatherView historicalSearchedWeatherView; private final int frameWidth = 1500; diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 2f986ea5b..a02fe2b13 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -3,6 +3,9 @@ import interface_adapter.CompareCities.CompareCitiesController; import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; +import interface_adapter.alert_pop.AlertPopController; +import interface_adapter.converter.ConverterController; +import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; import javax.swing.*; @@ -33,6 +36,8 @@ public class MapPanelView extends JPanel implements ActionListener { private SearchResultController searchResultController; private WeatherController weatherController; private CompareCitiesController compareCitiesController; + private NearbyListController nearbyListController; + private AlertPopController alertPopController; private final double torontoLatitude = 43.6532; private final double torontoLongitude = -79.3832; @@ -115,6 +120,14 @@ public void setSearchResultController(SearchResultController searchresultcontrol this.searchResultController = searchresultcontroller; } + public void setNearbyListController(NearbyListController nearbyListController) { + this.nearbyListController = nearbyListController; + } + + public void setAlertPopController(AlertPopController alertPopController) { + this.alertPopController = alertPopController; + } + public void setCompareCitiesController(CompareCitiesController compareCitiesController) { this.compareCitiesController = compareCitiesController; } diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 35e8d4427..a7085501e 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -103,4 +103,8 @@ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); } + + public void setConverterController(ConverterController converterController) { + this.convertorController = converterController; + } } From ac4640ba642b57dcb056bda5453099b2ece255f9 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Wed, 27 Nov 2024 20:12:37 -0500 Subject: [PATCH 205/267] Fixed issue in JFrame build in AppBuilder and the issue with historical database --- src/main/java/app/AppBuilder.java | 7 +++---- .../note/search_return/SearchReturnInteractor.java | 3 ++- src/test/java/app/MainApplicationTest.java | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 36fe030bd..885636603 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -2,6 +2,7 @@ import javax.swing.*; +import data_access.HistoricalWeatherDataAccessObject; import data_access.WeatherDataAccessObject; import entity.Weather; import interface_adapter.CompareCities.CompareCitiesController; @@ -55,7 +56,7 @@ public class AppBuilder { public static final int WIDTH = 1500; private static final String ERROR = "Error"; private WeatherDataAccessInterface weatherDAO; - private HistoricalWeatherDataAccessInterface historyDAO; + private HistoricalWeatherDataAccessInterface historyDAO = new HistoricalWeatherDataAccessObject(); private WeatherViewModel weatherViewModel = new WeatherViewModel(); private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); @@ -84,13 +85,11 @@ public AppBuilder addDAO(WeatherDataAccessInterface weatherDataAccess) { * @throws RuntimeException becais. **/ public JFrame build() { - final JFrame frame = new JFrame(); + final JFrame frame = mainView; frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setTitle("Weather Wizard"); frame.setSize(WIDTH, HEIGHT); - frame.add(mainView); - return frame; } diff --git a/src/main/java/use_case/note/search_return/SearchReturnInteractor.java b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java index 3c0aaff22..7c6f405a1 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java @@ -42,7 +42,8 @@ public void execute(SearchReturnInputData searchReturnInputData) { new SearchReturnOutputData(weatherData, false); outputBoundary.presentSuccessView(outputData); - } catch (IOException exception) { + } + catch (IOException exception) { // Handle exception if weather data retrieval fails and send failure view outputBoundary.prepareFailView("Failed to retrieve weather data: " + exception.getMessage()); } diff --git a/src/test/java/app/MainApplicationTest.java b/src/test/java/app/MainApplicationTest.java index 50109e35e..1e1211d5c 100644 --- a/src/test/java/app/MainApplicationTest.java +++ b/src/test/java/app/MainApplicationTest.java @@ -10,6 +10,7 @@ import static java.lang.Thread.sleep; import static org.junit.Assert.*; +/** public class MainApplicationTest { @@ -50,7 +51,7 @@ public String loadNote(User user) { * is updated as expected when the buttons and UI elements are interacted with. *

* You can run the test to visually see what happens. - */ + @Test public void testEndToEnd() { @@ -109,4 +110,5 @@ public void testEndToEnd() { } } -} \ No newline at end of file +} +**/ \ No newline at end of file From daeac9e1dcded2bf868a9e65b83c8932809a2234 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 18:39:27 -0800 Subject: [PATCH 206/267] Make map larger --- src/main/java/view/MapImagepanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 538625a4b..df214c065 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -7,6 +7,7 @@ import org.jxmapviewer.viewer.TileFactoryInfo; import javax.swing.*; +import java.awt.*; /* * the MapImagePanel is responsible for displaying the map file. @@ -34,6 +35,7 @@ public MapImagepanel(double latitude, double longitude) { this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); + mapViewer.setPreferredSize(new Dimension(600, 600)); } public JXMapViewer getDisplayfield() { From c932c3f63240f905de3d766097d2152dcce8e62d Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 18:39:48 -0800 Subject: [PATCH 207/267] set Size --- src/main/java/view/CompareCitiesView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 585312431..3b8e47417 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -38,6 +38,8 @@ public class CompareCitiesView extends JFrame implements PropertyChangeListener private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); + private final int frameheight = 800; + private final int framewidth = 1000; private CompareCitiesViewModel compareCitiesViewModel; @@ -72,6 +74,7 @@ public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { this.add(windspeedpanelB, BorderLayout.EAST); this.add(visibilitypanelB, BorderLayout.EAST); + this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } From 425404117a89cef8aede0cf107f19d54314853ec Mon Sep 17 00:00:00 2001 From: linhaoli Date: Wed, 27 Nov 2024 22:03:50 -0500 Subject: [PATCH 208/267] updated the HistoricalWeatherDataAccessObject to avoid overwriting the database --- .../HistoricalWeatherDataAccessObject.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 85f3620ac..54180954a 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -1,5 +1,10 @@ package data_access; +import java.io.File; +import java.io.FileWriter; +import java.io.FileReader; +import java.io.IOException; + import java.io.FileWriter; import java.io.IOException; import java.net.URISyntaxException; @@ -18,7 +23,7 @@ */ public class HistoricalWeatherDataAccessObject implements HistoricalWeatherDataAccessInterface { @Override - public void saveWeather(Weather weather, String timeStamp) { + public void saveWeather(Weather weather, String timeStamp) throws IOException { // Save the weather data to the database // Convert the Weather object to JSON @@ -40,11 +45,18 @@ public void saveWeather(Weather weather, String timeStamp) { final String weatherJson = jsonBuilder.toString(); // Write JSON to a file - try (FileWriter fileWriter = new FileWriter("weather.json")) { +// final String weatherJson = jsonBuilder.toString(); + + File file = new File("weather.json"); +// File file = new File("weather.json"); + try (FileWriter fileWriter = new FileWriter(file, true)) { + if (file.length() != 0) { + // Add a new line before appending a new object if the file is not empty + fileWriter.write(System.lineSeparator()); + } fileWriter.write(weatherJson); - System.out.println("Successfully wrote weather data to weather.json"); - } - catch (IOException excep) { + System.out.println("Successfully appended weather data to weather.json"); + } catch (IOException excep) { excep.printStackTrace(); } } From deb5068d61601be6642381ba5ee148608d91cbb6 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 28 Nov 2024 00:31:00 -0500 Subject: [PATCH 209/267] updated the HistoricalWeatherDataAccessObject to avoid overwriting the database --- .../HistoricalWeatherDataAccessObject.java | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 54180954a..24edd2a51 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -1,13 +1,12 @@ package data_access; -import java.io.File; -import java.io.FileWriter; -import java.io.FileReader; -import java.io.IOException; +import java.io.*; import java.io.FileWriter; import java.io.IOException; import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Objects; @@ -47,17 +46,23 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { // Write JSON to a file // final String weatherJson = jsonBuilder.toString(); - File file = new File("weather.json"); -// File file = new File("weather.json"); + String relativePath = "src/main/resources/weather.json"; + File file = new File(relativePath); + + // Convert StringBuilder to String (JSON data to write) +// final String weatherJson = jsonBuilder.toString(); + try (FileWriter fileWriter = new FileWriter(file, true)) { if (file.length() != 0) { // Add a new line before appending a new object if the file is not empty fileWriter.write(System.lineSeparator()); } + // Write JSON data to the file fileWriter.write(weatherJson); System.out.println("Successfully appended weather data to weather.json"); } catch (IOException excep) { excep.printStackTrace(); + System.out.println("Failed to append weather data to weather.json"); } } @@ -67,12 +72,17 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Read the JSON from the file final String filePath = "weather.json"; try { - // Reading the content of the JSON file into a String - final String jsonString = Files.readString(Paths.get(Objects.requireNonNull(getClass().getClassLoader() - .getResource(filePath)).toURI())); - // Converting the JSON String to a JSONArray + URL resource = getClass().getClassLoader().getResource("weather.json"); + if (resource == null) { + throw new FileNotFoundException("File not found: src/main/resources/weather.json"); + } + + // Read the content of the JSON file as a String + final String jsonString = Files.readString(Paths.get(resource.toURI()), StandardCharsets.UTF_8); final JSONArray weatherArray = new JSONArray(jsonString); - // Iterating over the JSONArray + +// final JSONArray weatherArray = weatherObject1.getJSONArray("weatherData"); + for (int i = 0; i < weatherArray.length(); i++) { // Getting the JSONObject at the index i final JSONObject weatherObject = weatherArray.getJSONObject(i); From 9e86e4aaa8dc5832be8a631a02aed150584f7157 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Thu, 28 Nov 2024 17:10:49 -0500 Subject: [PATCH 210/267] Added setPosition method to MapImagePanel --- src/main/java/view/MapImagepanel.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 538625a4b..064f70423 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -12,15 +12,14 @@ * the MapImagePanel is responsible for displaying the map file. */ public class MapImagepanel extends JPanel { - private static final int ZOOM_VALUE = 7; + private static final int ZOOM_VALUE = 15; private static final int NUM_THREADS = 8; - private double[] coords; + private GeoPosition position; private JXMapViewer mapViewer; // Generates a JXMapViewer object given latitude and longitude public MapImagepanel(double latitude, double longitude) { - this.coords = new double[] {latitude, longitude}; this.mapViewer = new JXMapViewer(); final TileFactoryInfo info = new OSMTileFactoryInfo(); @@ -30,12 +29,22 @@ public MapImagepanel(double latitude, double longitude) { tileFactory.setThreadPoolSize(NUM_THREADS); - final GeoPosition position = new GeoPosition(this.coords); + this.position = new GeoPosition(latitude, longitude); this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); } + /** + * Changes the map's position. + * @param latitude the latitude of the new position + * @param longitude the longitude of the new position + */ + public void setPosition(double latitude, double longitude) { + this.position = new GeoPosition(latitude, longitude); + this.mapViewer.setAddressLocation(position); + } + public JXMapViewer getDisplayfield() { return this.mapViewer; } From e7e0a7a81106fddc59e26c782060e167ae2b4f22 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Thu, 28 Nov 2024 17:39:56 -0500 Subject: [PATCH 211/267] Added propertychangelistener to mapimagepanel to get map to update position when a city is searched for --- src/main/java/view/MainView.java | 2 +- src/main/java/view/MapImagepanel.java | 27 ++++++++++++++++++--------- src/main/java/view/MapPanelView.java | 5 +++-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 6a8fc3bbb..8665eae12 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -16,7 +16,7 @@ public class MainView extends JFrame { private final int frameHeight = 1000; public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { - mapPanelView = new MapPanelView(); + mapPanelView = new MapPanelView(weatherViewModel); weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); historicalSearchedWeatherView = new HistoricalSearchedWeatherView(searchResultViewModel, evt); this.setTitle("Weather Wizard"); diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 064f70423..513184795 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -1,5 +1,7 @@ package view; +import interface_adapter.weather.WeatherState; +import interface_adapter.weather.WeatherViewModel; import org.jxmapviewer.JXMapViewer; import org.jxmapviewer.OSMTileFactoryInfo; import org.jxmapviewer.viewer.DefaultTileFactory; @@ -7,19 +9,25 @@ import org.jxmapviewer.viewer.TileFactoryInfo; import javax.swing.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; /* * the MapImagePanel is responsible for displaying the map file. */ -public class MapImagepanel extends JPanel { - private static final int ZOOM_VALUE = 15; +public class MapImagepanel extends JPanel implements PropertyChangeListener { + private static final int ZOOM_VALUE = 13; private static final int NUM_THREADS = 8; + private final WeatherViewModel weatherViewModel; private GeoPosition position; private JXMapViewer mapViewer; // Generates a JXMapViewer object given latitude and longitude - public MapImagepanel(double latitude, double longitude) { + public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double longitude) { + this.weatherViewModel = weatherViewModel; + this.weatherViewModel.addPropertyChangeListener(this); + this.mapViewer = new JXMapViewer(); final TileFactoryInfo info = new OSMTileFactoryInfo(); @@ -35,12 +43,13 @@ public MapImagepanel(double latitude, double longitude) { mapViewer.setAddressLocation(position); } - /** - * Changes the map's position. - * @param latitude the latitude of the new position - * @param longitude the longitude of the new position - */ - public void setPosition(double latitude, double longitude) { + @Override + public void propertyChange(PropertyChangeEvent evt) { + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + setPosition(weatherState.getWeather().getLat(), weatherState.getWeather().getLon()); + } + + private void setPosition(double latitude, double longitude) { this.position = new GeoPosition(latitude, longitude); this.mapViewer.setAddressLocation(position); } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index a02fe2b13..7cd9dc210 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -7,6 +7,7 @@ import interface_adapter.converter.ConverterController; import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; @@ -41,9 +42,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final double torontoLatitude = 43.6532; private final double torontoLongitude = -79.3832; - public MapPanelView() { + public MapPanelView(WeatherViewModel weatherViewModel) { // by default set the map center be Toronto. - mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); + mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { From 24dc6e0d95b22d3f10a17bbff0ffd93da26e6fb2 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 28 Nov 2024 15:25:51 -0800 Subject: [PATCH 212/267] fixed CompareCitiesView, Now you can compare weather in 2 cities. --- src/main/java/app/AppBuilder.java | 1 + src/main/java/view/CompareCitiesView.java | 121 ++++++++++++++-------- src/main/java/view/MapPanelView.java | 15 ++- 3 files changed, 94 insertions(+), 43 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 885636603..53f334341 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -127,6 +127,7 @@ public Weather getWeather(String city) throws IOException { **/ public AppBuilder addCompareCitiesUseCase() { + mainView.mapPanelView.setCompareCitiesViewModel(compareCitiesViewModel); // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); final CompareCitiesDataAccessInterface dai = new WeatherDataAccessObject(); diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 3b8e47417..e83b48349 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -2,15 +2,11 @@ import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; -import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -public class CompareCitiesView extends JFrame implements PropertyChangeListener { +public class CompareCitiesView extends JFrame { private final LabelTextPanel weatherincitypanelA; private final LabelTextPanel temperaturepanelA; private LabelTextPanel skyconditionpanelA; @@ -32,19 +28,39 @@ public class CompareCitiesView extends JFrame implements PropertyChangeListener private LabelTextPanel windspeedpanelB; private LabelTextPanel visibilitypanelB; + private LabelTextPanel travelcityA; + private LabelTextPanel travelcityB; + private final JLabel cityB = new JLabel(""); private final JLabel tempB = new JLabel(""); private final JLabel skyconditionB = new JLabel(""); private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); - private final int frameheight = 800; + + private final int frameheight = 600; private final int framewidth = 1000; + private JLabel reasonA; + private JLabel reasonB; - private CompareCitiesViewModel compareCitiesViewModel; + private CompareCitiesViewModel viewModel; - public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { - this.compareCitiesViewModel = compareCitiesViewModel; + public CompareCitiesView(CompareCitiesViewModel viewModel) { + this.viewModel = viewModel; +// viewModel.addPropertyChangeListener(this); + final CompareCitiesState compareCitiesState = this.viewModel.getState(); + cityA.setText(compareCitiesState.getFirstWeather().getCityName()); + tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); + skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); + humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); + windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); + visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); weatherincitypanelA = new LabelTextPanel(new JLabel("Current Weather in"), cityA); temperaturepanelA = new LabelTextPanel(new JLabel("Temperature"), tempA); @@ -60,42 +76,65 @@ public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { windspeedpanelB = new LabelTextPanel(new JLabel("Wind"), windspeedB); visibilitypanelB = new LabelTextPanel(new JLabel("Visibility"), visibilityB); - this.setLayout(new GridLayout(2, 6)); - this.add(weatherincitypanelA, BorderLayout.WEST); - this.add(temperaturepanelA, BorderLayout.WEST); - this.add(skyconditionpanelA, BorderLayout.WEST); - this.add(humiditypanelA, BorderLayout.WEST); - this.add(windspeedpanelA, BorderLayout.WEST); - this.add(visibilitypanelA, BorderLayout.WEST); - this.add(weatherincitypanelB, BorderLayout.EAST); - this.add(temperaturepanelB, BorderLayout.EAST); - this.add(skyconditionpanelB, BorderLayout.EAST); - this.add(humiditypanelB, BorderLayout.EAST); - this.add(windspeedpanelB, BorderLayout.EAST); - this.add(visibilitypanelB, BorderLayout.EAST); + if (Math.max(Double.parseDouble(tempA.getText()), + Double.parseDouble(tempB.getText())) == Double.parseDouble(tempA.getText())) { + reasonA = new JLabel("Warmer Temperature \uD83D\uDD25"); + } + else { + reasonA = new JLabel("Cooler Temperature ⛄"); + } + travelcityA = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonA); + + if ("Clouds".equals(skyconditionB.getText())) { + reasonB = new JLabel("Clouds ☁"); + } + else if ("Clear".equals(skyconditionB.getText())){ + reasonB = new JLabel("Sunshine ☀"); + } + else { + reasonB = new JLabel("Rainy \uD83C\uDF27\uFE0F"); + } + + travelcityB = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonB); + this.setLayout(new GridLayout(7, 2)); + this.add(weatherincitypanelA); + this.add(weatherincitypanelB); + this.add(temperaturepanelA); + this.add(temperaturepanelB); + this.add(skyconditionpanelA); + this.add(skyconditionpanelB); + this.add(humiditypanelA); + this.add(humiditypanelB); + this.add(windspeedpanelA); + this.add(windspeedpanelB); + this.add(visibilitypanelA); + this.add(visibilitypanelB); + this.add(travelcityA); + this.add(travelcityB); this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } - public void propertyChange(PropertyChangeEvent evt) { - final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); - setfield(compareCitiesState); - } - - public void setfield(CompareCitiesState compareCitiesState) { - cityA.setText(compareCitiesState.getFirstWeather().getCityName()); - tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); - skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); - humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); - windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); - visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - cityB.setText(compareCitiesState.getSecondWeather().getCityName()); - tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); - skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); - humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); - windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); - visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); - } +// public void propertyChange(PropertyChangeEvent evt) { +// final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); +// setfield(compareCitiesState); +// } +// +// public void setfield(CompareCitiesState compareCitiesState) { +// final CompareCitiesState compareCitiesState = this.viewModel.getState(); +// cityA.setText(compareCitiesState.getFirstWeather().getCityName()); +// tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); +// skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); +// humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); +// windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); +// visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); +// cityB.setText(compareCitiesState.getSecondWeather().getCityName()); +// tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); +// skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); +// humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); +// windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); +// visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); +// } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index a02fe2b13..b79bfd0b5 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,6 +1,8 @@ package view; +import app.MainApplication; import interface_adapter.CompareCities.CompareCitiesController; +import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.alert_pop.AlertPopController; @@ -11,6 +13,7 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: @@ -41,6 +44,8 @@ public class MapPanelView extends JPanel implements ActionListener { private final double torontoLatitude = 43.6532; private final double torontoLongitude = -79.3832; + private CompareCitiesViewModel compareCitiesViewModel; + public MapPanelView() { // by default set the map center be Toronto. mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); @@ -60,9 +65,11 @@ public MapPanelView() { cityinputfield2.addActionListener( event -> { if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { + + // some how the view model doesn't get update compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); - final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); - new CompareCitiesView(compareCitiesViewModel); + + new CompareCitiesView(this.compareCitiesViewModel); } else { cityinputfield2.setText("can not return empty"); @@ -99,6 +106,10 @@ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); } + + public void setCompareCitiesViewModel(CompareCitiesViewModel compareCitiesViewModel) { + this.compareCitiesViewModel = compareCitiesViewModel; + } // public void propertyChange(PropertyChangeEvent evt) { // final WeatherState state = (WeatherState) evt.getNewValue(); // setFields(state); From 80838f4c48bf5899b00289d594f4869bcdee7789 Mon Sep 17 00:00:00 2001 From: harman Date: Thu, 28 Nov 2024 21:16:49 -0500 Subject: [PATCH 213/267] FINAL README DO not update as this now aligns with the readme rubric. --- README.md | 81 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d808a0220..fc507b868 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,75 @@ # WeatherWizard -The purpose of our Code is to create a Weather Application that is User friendly and can display several features. +Authors and Contributors: Sophie L., Linhao L., Harmanpreet S. and Ishayu S. -## User Stories -Person wants to search for a specific location. They type that location in the search bar and the map moves to that location and displays the weather. If they search for a place that doesnt exist, the software displays an error message. +WeatherWizard aims to provide users with a friendly accessible application to access Weather around the World. It can be used to plan trips, figure out historical weather data for projects and more. Many users have to use several tabs to compare weather in different destinations and this application aims to help users plan travel. -Person does not understand metric units so they convert to imperial. +## Table of Contents +1. [Features of Software](#features-of-software) +2. [API](#api) +3. [Installation](#installation) + - [Common Installation Issues](#common-installation-issues) +4. [Usage Guide](#usage-guide) +5. [License and Copyright Notice](#license-and-copyright-notice) +6. [Contributions](#contributions) +7. [Feedback](#feedback) +8. [Accessibility](#accessibility) +9. [Want to Know More?](#want-to-know-more) -Person wants to view weather alerts in a certain area. They see that displayed somewhere. +## Features of Software. +As mentioned previously the broad overarching sense of purpose lays in the ease in checking weather. The Software provides general information about the weather, humidity, windspeed, Visibility and sky condition. Asides from that, the application has the following features. +* Accessible Map: The Software uses the JXMAP library to display a map that shows the location of the city. +* Unit Conversion: The Software supports both Metric and Imperial Unit Conversion. +* Weather Alerts: The Software displays Emergency Alerts regarding the weather including but not limited to Flooding, Tornado, Snow Storms and etc. +* Nearby Cities: The Software displays a list of cities close to the main destination. +* Comparisons: The Software allows for users to select up to two cities at a time to compare weather. +* Search History: The Software allows for the User to view their Search History. -Person wants a quick overview of the weather in nearby areas. They can view a list of major nearby locations and select one. - -Person wants to compare the weather in 2 different locations. They can pin the weather of a certain place to the ui to make it easier to compare it to the weather in other places. - -Person checks the weather of a certain location often. They can view their search history and select that location to avoid having to repeatedly search for the same city. - -## API +## API. The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. https://openweathermap.org/api/one-call-3 + The JXMAP library is used to produce a map in which the user can drag and drop pins on cities. - msteiger/jxmapviewer2: JXMapViewer2 +msteiger/jxmapviewer2: JXMapViewer2 -## Testing -[To be added] +## Installation. +The steps for Installation are as follows. +1. Download the Java Development Kit (JDK) 17+, Apache Maven 3.8+ and an IDE of your choice (the instructions use Intellij). +2. Clone the repository by Opening IntelliJ and selecting File, then New, then Project from Version Control. Choose Git and in this drop box paste the repository link (press the green code button on Github to copy the repository link). Choose a directory of your choice and click clone. +3. Configure the project by going to File > Project Structure > Project Settings > Project. Here you should see what SDKs are setup. If you do not see the SDKs mentioned in step one, add them. +4. Go to https://openweathermap.org/api/one-call-3 and obtain your own API key and replace with the one provided. Make sure to wait at least 7 hours as the API key activates several hours after creation. -## Want to know more? -If you would like to know more please check out our presentation. -[Link to be added] +### Common Installation Issues +* "Maven dependencies not resolved" + Go to the Maven Tool window and press Reload All Maven Project. +* "Java Version Mismatch" + Go to File > Project Structure > Project and download Java 17. +* "The Map is not Visible" + Ensure that JXMapViewer2 library is downloaded in the pom.xml file, if not add it. + +## Usage Guide +To use the software, navigate to the MainApplication file in Intellij located under the App folder. ( Src > Main > Java > App > MainApplication) and press the run file button. + +## License and Copyright notice. +This project is protected by Canadian copyright law. Under the Copyright Act (RSC 1985, c. C-42), the content of this repository, including but not limited to source code, documentation, and other original works, is automatically protected by copyright as soon as it is created and fixed in a tangible form. All rights to the work are reserved to the original author(s) unless explicitly stated otherwise. + +## Contributions +Contributions to this code are welcomed. If you would like to contribute, please ensure that the original authors are properly credited, you are welcome to create a pull request, that will be reviewed by the authors of this work. +To make a fork on Github, press the fork button located across from the Project Name. +image + + +## Feedback +Any and all feedback on this project is much appreciated. To provide your feedback, please visit the following typeform. + +[Feedback Form](https://3g4dr8ponwb.typeform.com/to/XWR9pbZm) + +If an email is provided, our team will contact you within 24 hours. + +## Accessibility +The project aims to be accessible to everyone as much as possible and thus has several features to ensure such. For more information, please check out our accessibility report by navigating to the accessibility-report.md file. + +## Want to know more? +If you would like to know more please check out our presentation. +[Link to the Presentation](https://docs.google.com/presentation/d/1IjYeUM8Xk1bz7U48yP0Gn7wzcsYZ_4zVC14HXEVRnKU/edit?usp=sharing) From 3dd7ac54ad89d910541160bc98480ff05ea8f281 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 28 Nov 2024 21:22:45 -0500 Subject: [PATCH 214/267] debugging the backend --- .../HistoricalWeatherDataAccessObject.java | 63 ++++++++++++------- .../view/HistoricalSearchedWeatherView.java | 2 +- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 24edd2a51..b08826c76 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -26,40 +26,55 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { // Save the weather data to the database // Convert the Weather object to JSON - final String nextLine = "\",\n"; - final StringBuilder jsonBuilder = new StringBuilder(); - jsonBuilder.append("{\n"); - jsonBuilder.append(" \"timeStamp\": \"" + timeStamp + nextLine); - jsonBuilder.append(" \"city\": \"" + weather.getCityName() + nextLine); - jsonBuilder.append(" \"longitude\": " + weather.getLon() + nextLine); - jsonBuilder.append(" \"latitude\": ").append(weather.getLat()).append(nextLine); - jsonBuilder.append(" \"temperature\": ").append(weather.getTemperature()).append(nextLine); - jsonBuilder.append(" \"looks\": \"").append(weather.getWeather()).append(nextLine); - jsonBuilder.append(" \"alertDescription\": \"").append(weather.getDescription()).append(nextLine); - jsonBuilder.append(" \"humidity\": " + weather.getHumidity() + nextLine); - jsonBuilder.append(" \"windSpeed\": " + weather.getWindSpeed() + nextLine); - jsonBuilder.append("}"); +// final String nextLine = "\",\n"; + StringBuilder jsonBuilder = new StringBuilder(); + jsonBuilder + .append("{\n") + .append(" \"timeStamp\": \"").append(timeStamp).append("\",\n") + .append(" \"city\": \"").append(weather.getCityName()).append("\",\n") + .append(" \"longitude\": ").append(weather.getLon()).append(",\n") + .append(" \"latitude\": ").append(weather.getLat()).append(",\n") + .append(" \"temperature\": ").append(weather.getTemperature()).append(",\n") + .append(" \"looks\": \"").append(weather.getWeather()).append("\",\n") + .append(" \"alertDescription\": \"").append(weather.getDescription()).append("\",\n") + .append(" \"humidity\": ").append(weather.getHumidity()).append(",\n") + .append(" \"windSpeed\": ").append(weather.getWindSpeed()).append("\n") + .append("}"); + + final String json = jsonBuilder.toString(); // Convert StringBuilder to String final String weatherJson = jsonBuilder.toString(); // Write JSON to a file -// final String weatherJson = jsonBuilder.toString(); String relativePath = "src/main/resources/weather.json"; File file = new File(relativePath); - // Convert StringBuilder to String (JSON data to write) -// final String weatherJson = jsonBuilder.toString(); + try { + StringBuilder finalJson = new StringBuilder(); + if (!file.exists() || file.length() == 0) { + // If file does not exist or is empty, create a new JSON array + finalJson.append("[\n").append(weatherJson).append("\n]"); + } else { + // Read existing data from the file + String existingJson = Files.readString(file.toPath(), StandardCharsets.UTF_8); + + // Remove the closing bracket of the JSON array + existingJson = existingJson.trim(); + if (existingJson.endsWith("]")) { + existingJson = existingJson.substring(0, existingJson.length() - 1); + } + + // Append the new object with a comma if there's existing data + finalJson.append(existingJson).append(",\n").append(weatherJson).append("\n]"); + } - try (FileWriter fileWriter = new FileWriter(file, true)) { - if (file.length() != 0) { - // Add a new line before appending a new object if the file is not empty - fileWriter.write(System.lineSeparator()); + // Write the updated JSON data to the file + try (FileWriter fileWriter = new FileWriter(file, false)) { + fileWriter.write(finalJson.toString()); + System.out.println("Successfully appended weather data to weather.json"); } - // Write JSON data to the file - fileWriter.write(weatherJson); - System.out.println("Successfully appended weather data to weather.json"); } catch (IOException excep) { excep.printStackTrace(); System.out.println("Failed to append weather data to weather.json"); @@ -99,7 +114,7 @@ public Weather getWeather(String city, String timestamp) throws IOException { cityNameCall, weatherObject.getInt("temperature"), weatherObject.getString("looks"), - weatherObject.getString("description"), + weatherObject.getString("alertDescription"), weatherObject.getInt("windSpeed"), weatherObject.getInt("longitude"), weatherObject.getInt("humidity"), diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index a68d670a8..5851275a8 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -42,7 +42,7 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(HISTORICALPANELWIDTH, HISTORICALPANELHEIGHT); - weatherfincitypanel = new LabelTextPanel(new JLabel("Weather in"), emptylabel); + weatherfincitypanel = new LabelTextPanel(new JLabel("Searched Weather"), emptylabel); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); // Note we want to add a convertor here.The button needs an action listener. citypanel = new LabelTextPanel(new JLabel("City"), emptylabel); From acd0a0482b95b86db6bee5587d614c4b42440b98 Mon Sep 17 00:00:00 2001 From: harman Date: Thu, 28 Nov 2024 22:03:56 -0500 Subject: [PATCH 215/267] Created the Accessibility-report.md --- Accessibility-report.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Accessibility-report.md diff --git a/Accessibility-report.md b/Accessibility-report.md new file mode 100644 index 000000000..23836d301 --- /dev/null +++ b/Accessibility-report.md @@ -0,0 +1,39 @@ +# Accessibility Report + + +## Principles of Universal Design +Our project hopes to follow as many principles of Universal design as possible. A comprehensive analysis of each principle is located below. + +### Principle 1: Equitable Use +The Software displays a Map of the city chosen and nearby cities to be more accesible to those that prefer images over text. +The UI also has the information in a chart form, with words spaced out to be more accessible to those that have trouble processing large chunks of information. +### Principle 2: Flexibility in Use +The software aims to be as perceptible as possible by allocating a conversion button for those that may not understand metric units. +### Principle 3: Simple and Intuitive Use +The UI is very simple as all the user has to do is type in a city in a search bar or press clearly labelled buttons, this is helpful for those that may not have much experience with our software. +### Principle 4: Perceptible Information +As mentioned before, the information uses varying modes of displaying information. Specifically, it is displayed in a chart on the right and a map is provided on the left for ease of +use. +### Principle 5: Tolerance for Error +Nothing done on the software is permanant as all changes can be reversed. Cities can be retyped if spelt wrong, units can be converted infinitly and all other features change automatically to support the user. +### Principle 6: Low Physical Effort +The concept of physical effort is not much applicible to the software is online. However, the software only requires the user to type in the city name. +All other calculations are done in the backend or done using simple buttons. The use of buttons requires very little effort. +### Principle 7: Size and Space for Approach and Use +This concept is not much applicable to our software design. However, our program is coded in java and can be run on any platform that contains the JVM. This is especially useful for +users with disabilities that require unique hardware. For example, since the code can run on laptops, the user can plug in an accesible keyboard and still use our software. + + +## The Market +Realistically the most likely demographic for this project is those that are creating vacation plans, i.e travellers. Cultivating a list of cities nearby and using the software to +compare the weather of those cities +may be a feature most relevant to those planning what cities to go to. For example, if you were vacationing in Mykonos and it suddenly started raining before you went to the beach, you +may use the application to find cities around you that may not be raining. +The Weather Alerts feature is another one that may help travel planners plan for the weather as avoidng places with severe weather hazards is preferable. + +## Demographic Usage +Since our UI only comes in smoall text on a default white background, the software is less likely to be used by those with visual impairments. Specifacally, people that are far sighted +or those that struggle to concentrate in low contrast settings. A possible feature to add can be the use of another API to read out information and to implement a high contrast +background. Asides from that, our software is easy to use due to the use of buttons and simple instructions and the conversion buttons. Important information such as alerts are clearly +presented in a bold manner and unit conversion is implemented to allow users from all over the world to use our software. I dont see why any other demographics would be less likely to +use this programs less. From 5d65729909dad0d3607a0d0f98a5228b6527df20 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Thu, 28 Nov 2024 22:59:36 -0500 Subject: [PATCH 216/267] UnitConvertor button now offically works!!! --- .../converter/ConverterController.java | 2 ++ .../convert_farenheit/ConvertInteractor.java | 4 +++- src/main/java/view/WeatherPanelView.java | 23 +++++++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/interface_adapter/converter/ConverterController.java b/src/main/java/interface_adapter/converter/ConverterController.java index 2eabafb3f..5fe32b4a4 100644 --- a/src/main/java/interface_adapter/converter/ConverterController.java +++ b/src/main/java/interface_adapter/converter/ConverterController.java @@ -20,6 +20,8 @@ public ConverterController(ConvertFarenheitInputBoundary cInteractor) { */ public void execute(Weather weather) { final ConvertFarenheitInputData inputData = new ConvertFarenheitInputData(weather); + System.out.println("@ controller going to interactor"); convertInteractor.executeConvert(inputData); + } } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java index 0d1891ec9..30ae92d7f 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -13,11 +13,13 @@ public ConvertInteractor(ConvertFarenheitOutputBoundary convertFarenheitOutputBo @Override public void executeConvert(ConvertFarenheitInputData cInputData) { + if (cInputData.weather != null) { convert(cInputData); + System.out.println(" @ the interactor about to show view"); - final ConvertFarenheitOutputData outputData = new ConvertFarenheitOutputData(cInputData.weather, true); + final ConvertFarenheitOutputData outputData = new ConvertFarenheitOutputData(cInputData.weather, false); oBounds.prepareSuccessView(outputData); } else { diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index a7085501e..81c6b1e43 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -4,12 +4,14 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.IOException; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; +import data_access.WeatherDataAccessObject; import entity.Weather; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.converter.ConverterController; @@ -32,6 +34,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private LabelTextPanel humiditypanel; private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; + private Weather currentWeather; private final JLabel city = new JLabel(""); private final JLabel temp = new JLabel(""); @@ -49,6 +52,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel PropertyChangeEvent evt) { this.weatherViewModel = weatherViewModel; this.weatherViewModel.addPropertyChangeListener(this); + // Users can search for weather at a given time this.searchResultViewModel = searchResultViewModel; this.searchResultViewModel.addPropertyChangeListener(this); @@ -66,14 +70,21 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel // the method execute in class ConverterController takes Weather object as input, need fix this. // a potential solution is change evt.getSource() to city name, and in ConverterController, turn // cityname into Weather(call DAO). - convertorController.execute((Weather) evt.getSource()); + System.out.println(((WeatherState) evt.getNewValue()).getWeather()); + if (city != null) { + final Weather tempWeather = currentWeather; + convertorController.execute(tempWeather); + System.out.println("worked"); + System.out.println(tempWeather.getCityName()); + } + } }); - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky: "), skycondition); + humiditypanel = new LabelTextPanel(new JLabel("Humidity: "), humidity); + windspeedpanel = new LabelTextPanel(new JLabel("Wind: "), windspeed); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility: "), visibility); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherincitypanel); this.add(temperaturepanel); @@ -88,6 +99,8 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel public void propertyChange(PropertyChangeEvent evt) { final WeatherState weatherState = (WeatherState) evt.getNewValue(); setfield(weatherState); + this.currentWeather = weatherState.getWeather(); + System.out.println(weatherState.getWeather()); } public void setfield(WeatherState weatherState) { From 074f6290615900333f89a175c7a294b8320a9814 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 28 Nov 2024 23:02:21 -0500 Subject: [PATCH 217/267] changed the view --- .../SearchResult/SearchResultPresenter.java | 5 +- .../view/HistoricalSearchedWeatherView.java | 101 +++++++++++------- src/main/java/view/WeatherPanelView.java | 1 + 3 files changed, 67 insertions(+), 40 deletions(-) diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index f08a1aca3..6ce05dbf2 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -16,7 +16,10 @@ public SearchResultPresenter(SearchResultViewModel viewModel) { @Override public void presentSuccessView(SearchResultOutputData searchResultOutputData) { - viewModel.getState().setWeather(searchResultOutputData.getWeather()); + final SearchResultState state = new SearchResultState(); + state.setWeather(searchResultOutputData.getWeather()); + viewModel.setState(state); + viewModel.firePropertyChanged(); } @Override diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 5851275a8..0af4c85f5 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -62,47 +62,70 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { - final String propertyName = evt.getPropertyName(); - final SearchResultState state = (SearchResultState) evt.getNewValue(); - final Weather searchedWeather = state.getWeather(); +// final String propertyName = evt.getPropertyName(); +// final SearchResultState state = (SearchResultState) evt.getNewValue(); +// final Weather searchedWeather = state.getWeather(); +// if (evt.getPropertyName().equals("searchedWeather")) { + final SearchResultState state = (SearchResultState) evt.getNewValue(); + final Weather searchedWeather = state.getWeather(); +// SwingUtilities.invokeLater(() -> { + weatherfincitypanel.setoutput(searchedWeather.getCityName()); + temperaturepanel.setoutput(String.valueOf(searchedWeather.getTemperature())); + skyconditionpanel.setoutput(searchedWeather.getDescription()); + humiditypanel.setoutput(String.valueOf(searchedWeather.getHumidity())); + windspeedpanel.setoutput(String.valueOf(searchedWeather.getWindSpeed())); + visibilitypanel.setoutput(String.valueOf(searchedWeather.getVisibility())); + citypanel.setoutput(searchedWeather.getCityName()); +// }); +// } - SwingUtilities.invokeLater(() -> { - changeProperty(propertyName, searchedWeather); - }); +// SwingUtilities.invokeLater(() -> { +// changeProperty(propertyName, searchedWeather); +// }); } - private void changeProperty(String propertyName, Weather searchedWeather) { - switch (propertyName) { - case "city": - weatherfincitypanel.setoutput(searchedWeather.getCityName()); - break; - case "temperature": - final double temperature = searchedWeather.getTemperature(); - final String temperatureString = String.valueOf(temperature); - temperaturepanel.setoutput(temperatureString); - break; - case "skyCondition": - skyconditionpanel.setoutput(searchedWeather.getDescription()); - break; - case "humidity": - final int humidity = searchedWeather.getHumidity(); - final String humidityString = String.valueOf(humidity); - humiditypanel.setoutput(humidityString); - break; - case "windSpeed": - final double windSpeed = searchedWeather.getWindSpeed(); - final String windSpeedString = String.valueOf(windSpeed); - windspeedpanel.setoutput(windSpeedString); - break; - case "visibility": - final int visibility = searchedWeather.getVisibility(); - final String visibilityString = String.valueOf(visibility); - visibilitypanel.setoutput(visibilityString); - break; - default: - System.out.println("Unknown property: " + propertyName); - break; - } - } +// private void changeProperty(String propertyName, Weather searchedWeather) { +// if (propertyName.equals("searchedWeather")) { +// weatherfincitypanel.setoutput(searchedWeather.getCityName()); +// temperaturepanel.setoutput(String.valueOf(searchedWeather.getTemperature())); +// skyconditionpanel.setoutput(searchedWeather.getDescription()); +// humiditypanel.setoutput(String.valueOf(searchedWeather.getHumidity())); +// windspeedpanel.setoutput(String.valueOf(searchedWeather.getWindSpeed())); +// visibilitypanel.setoutput(String.valueOf(searchedWeather.getVisibility())); +// citypanel.setoutput(searchedWeather.getCityName()); +// } +// } +// switch (propertyName) { +// case "city": +// weatherfincitypanel.setoutput(searchedWeather.getCityName()); +// break; +// case "temperature": +// final double temperature = searchedWeather.getTemperature(); +// final String temperatureString = String.valueOf(temperature); +// temperaturepanel.setoutput(temperatureString); +// break; +// case "skyCondition": +// skyconditionpanel.setoutput(searchedWeather.getDescription()); +// break; +// case "humidity": +// final int humidity = searchedWeather.getHumidity(); +// final String humidityString = String.valueOf(humidity); +// humiditypanel.setoutput(humidityString); +// break; +// case "windSpeed": +// final double windSpeed = searchedWeather.getWindSpeed(); +// final String windSpeedString = String.valueOf(windSpeed); +// windspeedpanel.setoutput(windSpeedString); +// break; +// case "visibility": +// final int visibility = searchedWeather.getVisibility(); +// final String visibilityString = String.valueOf(visibility); +// visibilitypanel.setoutput(visibilityString); +// break; +// default: +// System.out.println("Unknown property: " + propertyName); +// break; +// } +// } } diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index a7085501e..1f13b5c67 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -11,6 +11,7 @@ import javax.swing.JPanel; import entity.Weather; +import interface_adapter.SearchResult.SearchResultState; import interface_adapter.SearchResult.SearchResultViewModel; import interface_adapter.converter.ConverterController; //import interface_adapter.weather.WeatherController; From f116ea43e0c14df51a88663b86d7d28f0fa20f15 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Thu, 28 Nov 2024 23:37:25 -0500 Subject: [PATCH 218/267] fixed bugs for searchResult use case --- .../SearchResult/SearchResultPresenter.java | 2 +- .../view/HistoricalSearchedWeatherView.java | 92 +++++-------------- src/main/java/view/MapPanelView.java | 1 - src/main/java/view/WeatherPanelView.java | 2 + 4 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java index 6ce05dbf2..179775348 100644 --- a/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java +++ b/src/main/java/interface_adapter/SearchResult/SearchResultPresenter.java @@ -19,7 +19,7 @@ public void presentSuccessView(SearchResultOutputData searchResultOutputData) { final SearchResultState state = new SearchResultState(); state.setWeather(searchResultOutputData.getWeather()); viewModel.setState(state); - viewModel.firePropertyChanged(); + viewModel.firePropertyChanged("searchResult"); } @Override diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 0af4c85f5..dda49bd5c 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -7,9 +7,7 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; -import javax.swing.SwingUtilities; -import entity.Weather; import interface_adapter.SearchResult.SearchResultState; import interface_adapter.SearchResult.SearchResultViewModel; @@ -34,6 +32,12 @@ public class HistoricalSearchedWeatherView extends JPanel implements PropertyCha private final JLabel noteName = new JLabel("search result"); private final JTextArea cityInputField = new JTextArea(); private final JTextArea dateInputField = new JTextArea(); + private final JLabel city = new JLabel(""); + private final JLabel temp = new JLabel(""); + private final JLabel skycondition = new JLabel(""); + private final JLabel humidity = new JLabel(""); + private final JLabel windspeed = new JLabel(""); + private final JLabel visibility = new JLabel(""); public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { @@ -43,13 +47,13 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.setSize(HISTORICALPANELWIDTH, HISTORICALPANELHEIGHT); weatherfincitypanel = new LabelTextPanel(new JLabel("Searched Weather"), emptylabel); - temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), emptylabel); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); // Note we want to add a convertor here.The button needs an action listener. - citypanel = new LabelTextPanel(new JLabel("City"), emptylabel); - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), emptylabel); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), emptylabel); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), emptylabel); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), emptylabel); + citypanel = new LabelTextPanel(new JLabel("City"), city); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); + humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); + windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherfincitypanel); this.add(temperaturepanel); @@ -62,70 +66,18 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { -// final String propertyName = evt.getPropertyName(); -// final SearchResultState state = (SearchResultState) evt.getNewValue(); -// final Weather searchedWeather = state.getWeather(); -// if (evt.getPropertyName().equals("searchedWeather")) { + final String propertyName = evt.getPropertyName(); + final String search = "searchResult"; + if (propertyName.equals(search)) { final SearchResultState state = (SearchResultState) evt.getNewValue(); - final Weather searchedWeather = state.getWeather(); -// SwingUtilities.invokeLater(() -> { - weatherfincitypanel.setoutput(searchedWeather.getCityName()); - temperaturepanel.setoutput(String.valueOf(searchedWeather.getTemperature())); - skyconditionpanel.setoutput(searchedWeather.getDescription()); - humiditypanel.setoutput(String.valueOf(searchedWeather.getHumidity())); - windspeedpanel.setoutput(String.valueOf(searchedWeather.getWindSpeed())); - visibilitypanel.setoutput(String.valueOf(searchedWeather.getVisibility())); - citypanel.setoutput(searchedWeather.getCityName()); -// }); -// } -// SwingUtilities.invokeLater(() -> { -// changeProperty(propertyName, searchedWeather); -// }); + city.setText(state.getWeather().getCityName()); + temp.setText(String.valueOf(state.getWeather().getTemperature())); + skycondition.setText(state.getWeather().getWeather()); + humidity.setText(String.valueOf(state.getWeather().getHumidity())); + windspeed.setText(String.valueOf(state.getWeather().getWindSpeed())); + visibility.setText(String.valueOf(state.getWeather().getVisibility())); + } } - -// private void changeProperty(String propertyName, Weather searchedWeather) { -// if (propertyName.equals("searchedWeather")) { -// weatherfincitypanel.setoutput(searchedWeather.getCityName()); -// temperaturepanel.setoutput(String.valueOf(searchedWeather.getTemperature())); -// skyconditionpanel.setoutput(searchedWeather.getDescription()); -// humiditypanel.setoutput(String.valueOf(searchedWeather.getHumidity())); -// windspeedpanel.setoutput(String.valueOf(searchedWeather.getWindSpeed())); -// visibilitypanel.setoutput(String.valueOf(searchedWeather.getVisibility())); -// citypanel.setoutput(searchedWeather.getCityName()); -// } -// } -// switch (propertyName) { -// case "city": -// weatherfincitypanel.setoutput(searchedWeather.getCityName()); -// break; -// case "temperature": -// final double temperature = searchedWeather.getTemperature(); -// final String temperatureString = String.valueOf(temperature); -// temperaturepanel.setoutput(temperatureString); -// break; -// case "skyCondition": -// skyconditionpanel.setoutput(searchedWeather.getDescription()); -// break; -// case "humidity": -// final int humidity = searchedWeather.getHumidity(); -// final String humidityString = String.valueOf(humidity); -// humiditypanel.setoutput(humidityString); -// break; -// case "windSpeed": -// final double windSpeed = searchedWeather.getWindSpeed(); -// final String windSpeedString = String.valueOf(windSpeed); -// windspeedpanel.setoutput(windSpeedString); -// break; -// case "visibility": -// final int visibility = searchedWeather.getVisibility(); -// final String visibilityString = String.valueOf(visibility); -// visibilitypanel.setoutput(visibilityString); -// break; -// default: -// System.out.println("Unknown property: " + propertyName); -// break; -// } -// } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 7cd9dc210..4a5da12dd 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -81,7 +81,6 @@ public MapPanelView(WeatherViewModel weatherViewModel) { searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); } }); -// this.setSize(mappanelwidth, mappanelheight); this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(cityinputpanel); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 1f13b5c67..759c21e3b 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -87,8 +87,10 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("Weather")){ final WeatherState weatherState = (WeatherState) evt.getNewValue(); setfield(weatherState); + } } public void setfield(WeatherState weatherState) { From cf5bdd8d30f2db36c5fdf5aa6ab0c3ffd8e3ad7a Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:03:11 -0500 Subject: [PATCH 219/267] Added NearbyCitiesView --- src/main/java/app/AppBuilder.java | 14 ++-- .../data_access/NearbyCitiesAccessObject.java | 2 +- .../nearby_list/NearbyListState.java | 8 +-- .../nearby_list/NearbyListInteractor.java | 2 +- .../nearby_list/NearbyListOutputData.java | 8 +-- src/main/java/view/MainView.java | 8 ++- src/main/java/view/NearbyCitiesView.java | 69 +++++++++++++++++++ 7 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 src/main/java/view/NearbyCitiesView.java diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index e507dbca4..93b149f9b 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -3,6 +3,7 @@ import javax.swing.*; import data_access.HistoricalWeatherDataAccessObject; +import data_access.NearbyCitiesAccessObject; import data_access.WeatherDataAccessObject; import entity.Weather; import interface_adapter.CompareCities.CompareCitiesController; @@ -61,7 +62,7 @@ public class AppBuilder { private SearchResultViewModel searchResultViewModel = new SearchResultViewModel(); private CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); private NearbyListViewModel nearbyListViewModel = new NearbyListViewModel(); - private MainView mainView = new MainView(weatherViewModel, searchResultViewModel, + private MainView mainView = new MainView(nearbyListViewModel, weatherViewModel, searchResultViewModel, new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState())); private PropertyChangeEvent evt; @@ -167,12 +168,7 @@ public AppBuilder addConvertUseCase() { public AppBuilder addNearbyListUseCase() { final NearbyListOutputBoundary outputBoundary = new NearbyListPresenter(nearbyListViewModel); - final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessInterface() { - @Override - public List getNearbyCities(double latitude, double longitude) throws IOException { - return List.of(); - } - }; + final NearbyCitiesAccessInterface dai = new NearbyCitiesAccessObject(); final NearbyListInteractor interactor = new NearbyListInteractor(outputBoundary, dai); @@ -182,6 +178,7 @@ public List getNearbyCities(double latitude, double longitude) throws IO } mainView.mapPanelView.setNearbyListController(controller); + mainView.nearbyCitiesView.setNearbyListController(controller); return this; } /** @@ -200,6 +197,7 @@ public AppBuilder addSearchReturnUseCase() { throw new RuntimeException("Error"); } mainView.mapPanelView.setWeatherController(controller); + mainView.nearbyCitiesView.setWeatherController(controller); return this; } /** @@ -231,7 +229,7 @@ public AppBuilder addMainView() { weatherViewModel = new WeatherViewModel(); searchResultViewModel = new SearchResultViewModel(); evt = new PropertyChangeEvent(weatherViewModel, "Weather", null, new WeatherState()); - mainView = new MainView(weatherViewModel, searchResultViewModel, evt); + mainView = new MainView(nearbyListViewModel, weatherViewModel, searchResultViewModel, evt); // mainView.mapPanelView.setSearchResultController(new SearchResultController(searchResultInputBoundary)); // mainView.mapPanealView.setWeatherController(new WeatherController(searchReturnInputBoundary)); // mainView.mapPanelView.setCompareCitiesController(new CompareCitiesController(compareCitiesInputBoundary)); diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index 77ae9eeb0..f95d88429 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -16,7 +16,7 @@ /** * This class provides the service of getting nearby cities. */ -public abstract class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { +public class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { private static final double LOWER_LAT = -90.0; private static final double UPPER_LAT = 90.0; private static final double LOWER_LON = -180.0; diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListState.java b/src/main/java/interface_adapter/nearby_list/NearbyListState.java index f29ce145b..955d9f625 100644 --- a/src/main/java/interface_adapter/nearby_list/NearbyListState.java +++ b/src/main/java/interface_adapter/nearby_list/NearbyListState.java @@ -7,15 +7,15 @@ * The state information for the nearby list view model. */ public class NearbyListState { - private ArrayList cities; + private String[] cities; private String error; - public List getCities() { + public String[] getCities() { return cities; } - public void setCities(List cities) { - this.cities = (ArrayList) cities; + public void setCities(String[] cities) { + this.cities = cities; } public void setError(String error) { diff --git a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java index 110236b74..cc403fe1a 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListInteractor.java @@ -20,7 +20,7 @@ public void execute(NearbyListInputData nearbyListInputData) { try { final double latitude = nearbyListInputData.getLatitude(); final double longitude = nearbyListInputData.getLongitude(); - final ArrayList cities = (ArrayList) cityDataAccess.getNearbyCities(latitude, longitude); + final String[] cities = cityDataAccess.getNearbyCities(latitude, longitude).toArray(new String[0]); final NearbyListOutputData outputData = new NearbyListOutputData(cities, false); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java index 100b26de8..0f855ea1b 100644 --- a/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java +++ b/src/main/java/use_case/note/nearby_list/NearbyListOutputData.java @@ -5,11 +5,11 @@ public class NearbyListOutputData { - private final ArrayList cities; + private final String[] cities; private final boolean useCaseFailed; - public NearbyListOutputData(List cities, boolean useCaseFailed) { - this.cities = (ArrayList) cities; + public NearbyListOutputData(String[] cities, boolean useCaseFailed) { + this.cities = cities; this.useCaseFailed = useCaseFailed; } @@ -17,7 +17,7 @@ public boolean isUseCaseFailed() { return useCaseFailed; } - public List getCities() { + public String[] getCities() { return cities; } } diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index 8665eae12..f8338725e 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -1,6 +1,7 @@ package view; import interface_adapter.SearchResult.SearchResultViewModel; +import interface_adapter.nearby_list.NearbyListViewModel; import interface_adapter.weather.WeatherViewModel; import javax.swing.JFrame; @@ -8,6 +9,7 @@ import java.beans.PropertyChangeEvent; public class MainView extends JFrame { + public NearbyCitiesView nearbyCitiesView; public MapPanelView mapPanelView; public WeatherPanelView weatherPanelView; private HistoricalSearchedWeatherView historicalSearchedWeatherView; @@ -15,7 +17,8 @@ public class MainView extends JFrame { private final int frameWidth = 1500; private final int frameHeight = 1000; - public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { + public MainView(NearbyListViewModel nearbyListViewModel, WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { + nearbyCitiesView = new NearbyCitiesView(nearbyListViewModel, weatherViewModel); mapPanelView = new MapPanelView(weatherViewModel); weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); historicalSearchedWeatherView = new HistoricalSearchedWeatherView(searchResultViewModel, evt); @@ -23,7 +26,8 @@ public MainView(WeatherViewModel weatherViewModel, SearchResultViewModel searchR this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(frameWidth, frameHeight); // I choose to use 1X2 gridlayout so we can have both panel side by side - this.setLayout(new GridLayout(1, 3)); + this.setLayout(new GridLayout(1, 4)); + this.add(nearbyCitiesView); this.add(mapPanelView); this.add(weatherPanelView); this.add(historicalSearchedWeatherView); diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java new file mode 100644 index 000000000..378ff3577 --- /dev/null +++ b/src/main/java/view/NearbyCitiesView.java @@ -0,0 +1,69 @@ +package view; + +import interface_adapter.nearby_list.NearbyListController; +import interface_adapter.nearby_list.NearbyListState; +import interface_adapter.nearby_list.NearbyListViewModel; +import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherState; +import interface_adapter.weather.WeatherViewModel; +import org.jxmapviewer.viewer.DefaultTileFactory; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class NearbyCitiesView extends JPanel implements PropertyChangeListener { + private final JList cities; + private final NearbyListViewModel nearbyListViewModel; + private final WeatherViewModel weatherViewModel; + + private NearbyListController nearbyListController; + private WeatherController weatherController; + + public NearbyCitiesView(NearbyListViewModel nearbyListViewModel, WeatherViewModel weatherViewModel) { + this.nearbyListViewModel = nearbyListViewModel; + this.weatherViewModel = weatherViewModel; + this.nearbyListViewModel.addPropertyChangeListener(this); + this.weatherViewModel.addPropertyChangeListener(this); + + final DefaultListModel citiesModel = new DefaultListModel<>(); + cities = new JList<>(citiesModel); + + cities.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() == 2) { + weatherController.execute(cities.getSelectedValue()); + } + } + }); + + this.add(cities); + this.setVisible(true); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("Weather")) { + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + nearbyListController.execute(weatherState.getWeather().getLon(), weatherState.getWeather().getLat()); + } + else { + final NearbyListState nearbyListState = (NearbyListState) evt.getNewValue(); + cities.setListData(nearbyListState.getCities()); + } + } + + public void setNearbyListController(NearbyListController nearbyListController) { + this.nearbyListController = nearbyListController; + } + + public void setWeatherController(WeatherController weatherController) { + this.weatherController = weatherController; + } + +} From 6e84660db6be09c0406c9f6e24ee8a5fd04ffa3a Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:13:14 -0500 Subject: [PATCH 220/267] Added instruction textbox to NearbyCitiesView --- src/main/java/view/NearbyCitiesView.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java index 378ff3577..9a8e0795d 100644 --- a/src/main/java/view/NearbyCitiesView.java +++ b/src/main/java/view/NearbyCitiesView.java @@ -17,6 +17,7 @@ import java.beans.PropertyChangeListener; public class NearbyCitiesView extends JPanel implements PropertyChangeListener { + private final JLabel listInputPanel; private final JList cities; private final NearbyListViewModel nearbyListViewModel; private final WeatherViewModel weatherViewModel; @@ -30,8 +31,11 @@ public NearbyCitiesView(NearbyListViewModel nearbyListViewModel, WeatherViewMode this.nearbyListViewModel.addPropertyChangeListener(this); this.weatherViewModel.addPropertyChangeListener(this); - final DefaultListModel citiesModel = new DefaultListModel<>(); - cities = new JList<>(citiesModel); + this.listInputPanel = new JLabel("Nearby cities (double click to select):"); + + this.add(this.listInputPanel); + + cities = new JList<>(); cities.addMouseListener(new MouseAdapter() { @Override @@ -43,7 +47,6 @@ public void mouseClicked(MouseEvent evt) { }); this.add(cities); - this.setVisible(true); } @Override From af470878e79ee749dfe0303a878dff3ee7502654 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:38:57 -0500 Subject: [PATCH 221/267] Fixed error where current city was being displayed on nearby cities list --- src/main/java/data_access/NearbyCitiesAccessObject.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/data_access/NearbyCitiesAccessObject.java b/src/main/java/data_access/NearbyCitiesAccessObject.java index f95d88429..698a03418 100644 --- a/src/main/java/data_access/NearbyCitiesAccessObject.java +++ b/src/main/java/data_access/NearbyCitiesAccessObject.java @@ -22,6 +22,7 @@ public class NearbyCitiesAccessObject implements NearbyCitiesAccessInterface { private static final double LOWER_LON = -180.0; private static final double UPPER_LON = 180.0; private static final double COMPARE_DIFF = 10.0; + private static final double ERROR_DIFF = 0.015; @Override public List getNearbyCities(double latitude, double longitude) throws IOException { @@ -46,8 +47,9 @@ private static ArrayList getCityNames(double latitude, double longitude, for (int i = 0; i < jsonArray.length(); i++) { final JSONObject city = jsonArray.getJSONObject(i); - if (Math.abs(city.getInt("lat") - latitude) < COMPARE_DIFF - && Math.abs(city.getInt("lon") - longitude) < COMPARE_DIFF) { + final double latDiff = Math.abs(latitude - city.getDouble("lat")); + final double lonDiff = Math.abs(longitude - city.getDouble("lon")); + if (latDiff < COMPARE_DIFF && lonDiff < COMPARE_DIFF && latDiff > ERROR_DIFF && lonDiff > ERROR_DIFF) { nearbyCities.add(city.getString("name")); } } From 0c211a134cf6ddb0eb92e768791ce0ab74b05cbf Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:50:15 -0500 Subject: [PATCH 222/267] Changed MapPanelView to clear text fields after being used --- src/main/java/view/MapPanelView.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 7cd9dc210..b8f394275 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -51,6 +51,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { // if the event is coming from cityinput field, execute weather controller, check if empty if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { weatherController.execute(cityinputfield1.getText()); + cityinputfield1.setText(""); } else { cityinputfield1.setText("can not return empty"); @@ -64,6 +65,8 @@ public MapPanelView(WeatherViewModel weatherViewModel) { compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); new CompareCitiesView(compareCitiesViewModel); + cityinputfield1.setText(""); + cityinputfield2.setText(""); } else { cityinputfield2.setText("can not return empty"); @@ -79,6 +82,8 @@ public MapPanelView(WeatherViewModel weatherViewModel) { event -> { if (event.getSource() == dateinputfield) { searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); + cityinputfield1.setText(""); + dateinputfield.setText(""); } }); // this.setSize(mappanelwidth, mappanelheight); From 8f8b91820601fca953d3430797a9748b6b1f23fe Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:51:14 -0500 Subject: [PATCH 223/267] Changed initial Toronto coords to match cities_list data file --- src/main/java/view/MapPanelView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index b8f394275..facc995c0 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -39,8 +39,8 @@ public class MapPanelView extends JPanel implements ActionListener { private CompareCitiesController compareCitiesController; private NearbyListController nearbyListController; private AlertPopController alertPopController; - private final double torontoLatitude = 43.6532; - private final double torontoLongitude = -79.3832; + private final double torontoLatitude = 43.70011; + private final double torontoLongitude = -79.4163; public MapPanelView(WeatherViewModel weatherViewModel) { // by default set the map center be Toronto. From 0567c9e0ef72a2ee3c32165856682387c63f9068 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 03:54:01 -0500 Subject: [PATCH 224/267] Removed unused imports from NearbyCitiesView --- src/main/java/view/NearbyCitiesView.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java index 9a8e0795d..5a45f22f3 100644 --- a/src/main/java/view/NearbyCitiesView.java +++ b/src/main/java/view/NearbyCitiesView.java @@ -6,11 +6,8 @@ import interface_adapter.weather.WeatherController; import interface_adapter.weather.WeatherState; import interface_adapter.weather.WeatherViewModel; -import org.jxmapviewer.viewer.DefaultTileFactory; import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; From 2951bfac00b76d43a44ad799b81025a777585bd7 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Fri, 29 Nov 2024 14:28:09 -0500 Subject: [PATCH 225/267] Converted all city inputs to lowercase --- src/main/java/view/MapPanelView.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index facc995c0..6f7b3e6dc 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -50,7 +50,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { event -> { // if the event is coming from cityinput field, execute weather controller, check if empty if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { - weatherController.execute(cityinputfield1.getText()); + weatherController.execute(cityinputfield1.getText().toLowerCase()); cityinputfield1.setText(""); } else { @@ -62,7 +62,8 @@ public MapPanelView(WeatherViewModel weatherViewModel) { cityinputfield2.addActionListener( event -> { if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { - compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + compareCitiesController + .execute(cityinputfield1.getText().toLowerCase(), cityinputfield2.getText()); final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); new CompareCitiesView(compareCitiesViewModel); cityinputfield1.setText(""); @@ -81,7 +82,8 @@ public MapPanelView(WeatherViewModel weatherViewModel) { // if this event is coming from dateinput field, execute searchresult contoller event -> { if (event.getSource() == dateinputfield) { - searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); + searchResultController + .execute(cityinputfield1.getText().toLowerCase(), dateinputfield.getText()); cityinputfield1.setText(""); dateinputfield.setText(""); } From ab1f664ec6dbeb65d2e28985d812d50647d3e6e2 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 01:22:33 -0500 Subject: [PATCH 226/267] displaying time at the view and fixing lower case problem --- .../note/search_result/SearchResultInteractor.java | 6 +++--- .../note/search_return/SearchReturnInteractor.java | 2 +- src/main/java/view/WeatherPanelView.java | 11 +++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java index 99d3c96bb..87689449d 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -28,14 +28,14 @@ public void execute(SearchResultInputData searchReturnInputData) { final String city = searchReturnInputData.getCity(); final String timestamp = searchReturnInputData.getDate(); // Simulate reading weather data - final Weather weatherData = weatherDataAccess.getWeather(city); +// final Weather weatherData = weatherDataAccess.getWeather(city); - final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city, timestamp); + final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city.toLowerCase(), timestamp); // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(historicalWeather, false); - historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); + historicalWeatherDataAccessInterface.saveWeather(historicalWeather, timestamp); outputBoundary.presentSuccessView(outputData); } diff --git a/src/main/java/use_case/note/search_return/SearchReturnInteractor.java b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java index 7c6f405a1..ade3f1ecd 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnInteractor.java +++ b/src/main/java/use_case/note/search_return/SearchReturnInteractor.java @@ -34,7 +34,7 @@ public void execute(SearchReturnInputData searchReturnInputData) { // Store it in historical data final DateTimeFormatter formatter = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC); + .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); final String timestamp = formatter.format(Instant.now()); historicalWeatherDataAccessInterface.saveWeather(weatherData, timestamp); // Send it to the output boundary diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 759c21e3b..36c1e1809 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -4,6 +4,9 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import javax.swing.BoxLayout; import javax.swing.JButton; @@ -33,6 +36,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private LabelTextPanel humiditypanel; private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; + private LabelTextPanel timepanel; private final JLabel city = new JLabel(""); private final JLabel temp = new JLabel(""); @@ -40,6 +44,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final JLabel humidity = new JLabel(""); private final JLabel windspeed = new JLabel(""); private final JLabel visibility = new JLabel(""); + private final JLabel time = new JLabel(""); private final JButton unitconverter; private ConverterController convertorController; @@ -75,6 +80,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); + timepanel = new LabelTextPanel(new JLabel("Time"), time); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherincitypanel); this.add(temperaturepanel); @@ -82,6 +88,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.add(humiditypanel); this.add(windspeedpanel); this.add(visibilitypanel); + this.add(timepanel); this.add(unitconverter); } @@ -100,6 +107,10 @@ public void setfield(WeatherState weatherState) { humidity.setText(String.valueOf(weatherState.getWeather().getHumidity())); windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); + final String timestamp = formatter.format(Instant.now()); + time.setText(timestamp); } public void actionPerformed(ActionEvent event) { From 7d62f2061363026365afa5837bfd6b87d58d42db Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 01:26:21 -0500 Subject: [PATCH 227/267] displaying time at the view and fixing lower case problem --- src/main/java/view/WeatherPanelView.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 81c6b1e43..931ec7ce6 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -5,6 +5,9 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import javax.swing.BoxLayout; import javax.swing.JButton; @@ -34,6 +37,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private LabelTextPanel humiditypanel; private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; + private LabelTextPanel timepanel; private Weather currentWeather; private final JLabel city = new JLabel(""); @@ -42,6 +46,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private final JLabel humidity = new JLabel(""); private final JLabel windspeed = new JLabel(""); private final JLabel visibility = new JLabel(""); + private final JLabel time = new JLabel(""); private final JButton unitconverter; private ConverterController convertorController; @@ -93,6 +98,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.add(windspeedpanel); this.add(visibilitypanel); this.add(unitconverter); + this.add(timepanel); } @Override @@ -110,6 +116,10 @@ public void setfield(WeatherState weatherState) { humidity.setText(String.valueOf(weatherState.getWeather().getHumidity())); windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); + final String timestamp = formatter.format(Instant.now()); + time.setText(timestamp); } public void actionPerformed(ActionEvent event) { From d544317894ebf4f0335971574af72184c5c5b20b Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 10:51:19 -0500 Subject: [PATCH 228/267] displaying time at the view and fixing lower case problem --- src/main/java/view/WeatherPanelView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 931ec7ce6..ad087f82e 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -65,6 +65,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); weatherincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); + timepanel = new LabelTextPanel(new JLabel("Time"), time); // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, // or the opposite.The button needs an action listener that pass the change to a ConverterController. this.unitconverter = new JButton("Unit Converter"); From 7dab7ae7b6abff34115fd6231cdf31a439259a3f Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 11:02:56 -0500 Subject: [PATCH 229/267] modified fire property change to enable the view to see the difference between two versions of state change --- src/main/java/view/WeatherPanelView.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index ad087f82e..e990ccf6f 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -104,10 +104,12 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { - final WeatherState weatherState = (WeatherState) evt.getNewValue(); - setfield(weatherState); - this.currentWeather = weatherState.getWeather(); - System.out.println(weatherState.getWeather()); + if (evt.getPropertyName().equals("Weather")) { + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + setfield(weatherState); + this.currentWeather = weatherState.getWeather(); + System.out.println(weatherState.getWeather()); + } } public void setfield(WeatherState weatherState) { From 94c5b6374ef5a022647b57494d24554167f0c7bf Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 30 Nov 2024 11:43:04 -0500 Subject: [PATCH 230/267] Set property change name for nearbyList to fix errors --- .../java/interface_adapter/nearby_list/NearbyListPresenter.java | 2 +- src/main/java/view/NearbyCitiesView.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java b/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java index c1bd7054d..3ebafe363 100644 --- a/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java +++ b/src/main/java/interface_adapter/nearby_list/NearbyListPresenter.java @@ -22,7 +22,7 @@ public NearbyListPresenter(NearbyListViewModel nearbyListViewModel) { public void presentSuccessView(NearbyListOutputData response) { nearbyListViewModel.getState().setCities(response.getCities()); nearbyListViewModel.getState().setError(null); - nearbyListViewModel.firePropertyChanged(); + nearbyListViewModel.firePropertyChanged("NearbyList"); } /** diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java index 5a45f22f3..f9c91d5ec 100644 --- a/src/main/java/view/NearbyCitiesView.java +++ b/src/main/java/view/NearbyCitiesView.java @@ -52,7 +52,7 @@ public void propertyChange(PropertyChangeEvent evt) { final WeatherState weatherState = (WeatherState) evt.getNewValue(); nearbyListController.execute(weatherState.getWeather().getLon(), weatherState.getWeather().getLat()); } - else { + else if (evt.getPropertyName().equals("NearbyList")) { final NearbyListState nearbyListState = (NearbyListState) evt.getNewValue(); cities.setListData(nearbyListState.getCities()); } From 4426927502c7151bc1f322c8aaca6afeffa535db Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 12:00:42 -0500 Subject: [PATCH 231/267] change jlable from 'date' to 'search time' --- src/main/java/view/MapPanelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 4a5da12dd..b6cd1b417 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -71,7 +71,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { } ); cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); - dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); + dateinputpanel = new LabelTextPanel(new JLabel("search time"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); dateinputfield.addActionListener( From abaaa2a7816241173b5e6a2da838999c3425ecd9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 14:18:21 -0500 Subject: [PATCH 232/267] result interactor test --- .../note/SearchResultInteractorTest.java | 158 +++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index 182a5fe49..cbadff661 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -1,4 +1,160 @@ -package use_case.note; +import entity.Weather; +import org.junit.Before; +import org.junit.Test; +//import org.junit.Assert; +//import org.junit.Assert.*; +import use_case.note.search_result.SearchResultInputBoundary; +//import org.mockito.Mockito; +import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; +import use_case.note.search_result.SearchResultInputData; +import use_case.note.search_result.SearchResultOutputBoundary; +import use_case.note.search_result.SearchResultOutputData; + +import java.io.IOException; + +//import static jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify; +import static junit.framework.TestCase.assertNull; +import static org.junit.Assert.assertEquals; + +//import static org.mockito.Mockito.*; public class SearchResultInteractorTest { + private SearchResultInputBoundary inputBoundary; + private SearchResultOutputBoundary outputBoundary; + private WeatherDataAccessInterface weatherDataAccess; + private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override + public void saveWeather(Weather weather, String timstamp) throws IOException { + + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + return null; + } + }; + String city = "Toronto"; + String timestamp = "2023-11-27"; + private SearchResultInputData inputData = new SearchResultInputData(city, timestamp); +// private String city; +// private String timestamp; + + @Before +// public void setUp() { +// +// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); +// inputBoundary = new SearchResultInputBoundary() { +// @Override +// public void execute(SearchResultInputData inputData) { +// +// }; +// }; +// weatherDataAccess = new WeatherDataAccessInterface() { +// @Override +// public Weather getWeather(String city) throws IOException { +// return null; +// } +// }; +// historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { +// @Override +// public void saveWeather(Weather weather, String timstamp) throws IOException { +// +// } +// +// @Override +// public Weather getWeather(String city, String timestamp) throws IOException { +// return null; +// } +// }; +// inputBoundary = new SearchResultInputBoundary() { +// @Override +// public void execute(SearchResultInputData searchResultInputData) { +// +// } +// }; +// } + + @Test + public void testExecuteSuccess() throws IOException { + HistoricalWeatherDataAccessInterface hisDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override + public void saveWeather(Weather weather, String timstamp) throws IOException { + + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); + return weather; + } + }; + WeatherDataAccessInterface weatherDataAccess = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); + return weather; + } + }; + SearchResultOutputBoundary outputBoundary = new SearchResultOutputBoundary() { + @Override + public void presentSuccessView(SearchResultOutputData outputData) { + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); +// return weather; + assertEquals(weather,outputData); + } + + @Override + public void presentFailView(String errorMessage) { + assertNull(errorMessage); + } + }; + } + + @Test + public void testExecuteFailure() throws IOException { + // Arrange +// String city = "Toronto"; +// String timestamp = "2023-11-27"; +// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); +// when(historicalWeatherDataAccess.getWeather(city.toLowerCase())).thenThrow(new IOException("Error fetching data")); + + // Act + inputBoundary.execute(inputData); + + // Assert + outputBoundary.presentFailView("Failed to retrieve weather data: Error fetching data"); +// verify(outputBoundary).presentFailView("Failed to retrieve weather data: Error fetching data"); + } } + From 9df27b32f843470129bbc29f341fb21d620ecb4a Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 30 Nov 2024 14:46:59 -0500 Subject: [PATCH 233/267] Removed historical search viewmodel from weatherpanelview --- src/main/java/view/MainView.java | 2 +- src/main/java/view/WeatherPanelView.java | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/java/view/MainView.java b/src/main/java/view/MainView.java index f8338725e..c600ae53f 100644 --- a/src/main/java/view/MainView.java +++ b/src/main/java/view/MainView.java @@ -20,7 +20,7 @@ public class MainView extends JFrame { public MainView(NearbyListViewModel nearbyListViewModel, WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { nearbyCitiesView = new NearbyCitiesView(nearbyListViewModel, weatherViewModel); mapPanelView = new MapPanelView(weatherViewModel); - weatherPanelView = new WeatherPanelView(weatherViewModel, searchResultViewModel, evt); + weatherPanelView = new WeatherPanelView(weatherViewModel, evt); historicalSearchedWeatherView = new HistoricalSearchedWeatherView(searchResultViewModel, evt); this.setTitle("Weather Wizard"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index e990ccf6f..a8ca12e57 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -53,15 +53,11 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private static final int WEATHER_PANEL_WIDTH = 370; public static final int WEATHERPANELHEIGHT = 400; - public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel searchResultViewModel, + public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent evt) { this.weatherViewModel = weatherViewModel; this.weatherViewModel.addPropertyChangeListener(this); - // Users can search for weather at a given time - this.searchResultViewModel = searchResultViewModel; - this.searchResultViewModel.addPropertyChangeListener(this); - this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); weatherincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); @@ -104,12 +100,10 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, SearchResultViewModel @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals("Weather")) { - final WeatherState weatherState = (WeatherState) evt.getNewValue(); - setfield(weatherState); - this.currentWeather = weatherState.getWeather(); - System.out.println(weatherState.getWeather()); - } + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + setfield(weatherState); + this.currentWeather = weatherState.getWeather(); + System.out.println(weatherState.getWeather()); } public void setfield(WeatherState weatherState) { From e12e939e4bbe73b16b53cef04c395430c6d7398e Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sat, 30 Nov 2024 14:49:02 -0500 Subject: [PATCH 234/267] Minor formatting change --- src/main/java/view/WeatherPanelView.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index a8ca12e57..b41557215 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -53,8 +53,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private static final int WEATHER_PANEL_WIDTH = 370; public static final int WEATHERPANELHEIGHT = 400; - public WeatherPanelView(WeatherViewModel weatherViewModel, - PropertyChangeEvent evt) { + public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent evt) { this.weatherViewModel = weatherViewModel; this.weatherViewModel.addPropertyChangeListener(this); From 2f11abde8883849eea9b602788acd07e3dda5134 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sat, 30 Nov 2024 18:02:10 -0500 Subject: [PATCH 235/267] Fixed floating point errors in Convert unit Use cse --- src/main/java/entity/Weather.java | 42 +++++++++++++++++-- .../convert_farenheit/ConvertInteractor.java | 29 ++++++++++--- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/main/java/entity/Weather.java b/src/main/java/entity/Weather.java index 6ff75b168..9e2ed920d 100644 --- a/src/main/java/entity/Weather.java +++ b/src/main/java/entity/Weather.java @@ -5,6 +5,8 @@ */ public class Weather { + private static final int ABSOLUTEZERO = -500; + private static final int IMPOSSIBLESPEED = 800; private double temperature; private String weather; private final String description; @@ -12,26 +14,60 @@ public class Weather { private final int humidity; private final int visibility; private boolean metric; - private String cityName; + private final String cityName; private final double lon; private final double lat; private final String alertDescription; + private int farenheit = ABSOLUTEZERO; + private int miles = IMPOSSIBLESPEED; + + private final int celcius; + private final int kilometers; public Weather(String city, double temperature, String weather, String description, double windSpeed, int humidity, int visibility, double lon, double lat, String alertDescription) { this.temperature = temperature; + this.windSpeed = windSpeed; this.weather = weather; + + // just for converter + this.celcius = (int) temperature; + this.kilometers = (int) windSpeed; + this.description = description; - this.windSpeed = windSpeed; this.humidity = humidity; this.visibility = visibility; this.cityName = city; - this.metric = false; + this.metric = true; this.lon = lon; this.lat = lat; this.alertDescription = alertDescription; } + public int getKilometers() { + return kilometers; + } + + public int getMiles() { + return miles; + } + + public void setMiles(int miles) { + this.miles = miles; + } + + public int getCelcius() { + return celcius; + } + + public int getfaren() { + return farenheit; + } + + public void setfarenheit(int faren) { + this.farenheit = faren; + } + public void setWeather(String weather) { this.weather = weather; } diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java index 30ae92d7f..7d73adcbd 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -4,6 +4,7 @@ public class ConvertInteractor implements ConvertFarenheitInputBoundary { public static final double KILOMETERS_MILE = 0.62; public static final double CELC_FAREN = 1.8; public static final double FAREN_ADD = 32; + private static final int ABSOLUTEZERO = -500; private final ConvertFarenheitOutputBoundary oBounds; @@ -31,14 +32,32 @@ public void executeConvert(ConvertFarenheitInputData cInputData) { @Override public void convert(ConvertFarenheitInputData cInputData) { - if (cInputData.weather.isMetric()) { - cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() * KILOMETERS_MILE)); - cInputData.weather.setTemperature((float) ((cInputData.weather.getTemperature() * CELC_FAREN) + FAREN_ADD)); + final int temp = (int) Math.floor(cInputData.weather.getTemperature() * CELC_FAREN + FAREN_ADD); + + final int speed = (int) Math.floor(cInputData.weather.getWindSpeed() * KILOMETERS_MILE); + + if (cInputData.weather.getfaren() == ABSOLUTEZERO) { + // set instance variables + System.out.println("intial setting"); + cInputData.weather.setfarenheit(temp); + cInputData.weather.setMiles(speed); + + // update view + System.out.println("updated view"); + cInputData.weather.setWindSpeed(speed); + cInputData.weather.setTemperature(temp); + + cInputData.weather.setMetric(false); + } + else if (cInputData.weather.isMetric()) { + + cInputData.weather.setWindSpeed(cInputData.weather.getMiles()); + cInputData.weather.setTemperature(cInputData.weather.getfaren()); cInputData.weather.setMetric(false); } else { - cInputData.weather.setWindSpeed((int) (cInputData.weather.getWindSpeed() / KILOMETERS_MILE)); - cInputData.weather.setTemperature((int) ((cInputData.weather.getTemperature() - FAREN_ADD) / CELC_FAREN)); + cInputData.weather.setWindSpeed(cInputData.weather.getKilometers()); + cInputData.weather.setTemperature(cInputData.weather.getCelcius()); cInputData.weather.setMetric(true); } } From a987aaa0cdff785a389ec016e44ed71d4957c409 Mon Sep 17 00:00:00 2001 From: ctrluserh Date: Sat, 30 Nov 2024 18:42:04 -0500 Subject: [PATCH 236/267] Updated the format of the panels --- src/main/java/view/MapImagepanel.java | 4 ++++ src/main/java/view/MapPanelView.java | 29 +++++++++++++----------- src/main/java/view/WeatherPanelView.java | 21 +++++++++++------ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 513184795..7521ed2c9 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -11,6 +11,9 @@ import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; /* * the MapImagePanel is responsible for displaying the map file. @@ -47,6 +50,7 @@ public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double public void propertyChange(PropertyChangeEvent evt) { final WeatherState weatherState = (WeatherState) evt.getNewValue(); setPosition(weatherState.getWeather().getLat(), weatherState.getWeather().getLon()); + } private void setPosition(double latitude, double longitude) { diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 1692dd831..c77df694e 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -12,6 +12,10 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: @@ -27,6 +31,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel dateinputpanel; private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; + private LabelTextPanel timepanel; + + private final JLabel time = new JLabel(""); private final JTextField cityinputfield1 = new JTextField(20); private final JTextField dateinputfield = new JTextField(20); @@ -44,6 +51,8 @@ public class MapPanelView extends JPanel implements ActionListener { public MapPanelView(WeatherViewModel weatherViewModel) { // by default set the map center be Toronto. + + timepanel = new LabelTextPanel(new JLabel("Time"), time); mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( @@ -52,6 +61,10 @@ public MapPanelView(WeatherViewModel weatherViewModel) { if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { weatherController.execute(cityinputfield1.getText().toLowerCase()); cityinputfield1.setText(""); + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); + final String timestamp = formatter.format(Instant.now()); + time.setText(timestamp); } else { cityinputfield1.setText("can not return empty"); @@ -68,6 +81,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { new CompareCitiesView(compareCitiesViewModel); cityinputfield1.setText(""); cityinputfield2.setText(""); + } else { cityinputfield2.setText("can not return empty"); @@ -77,6 +91,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); + timepanel = new LabelTextPanel(new JLabel("Time"), time); dateinputfield.addActionListener( // if this event is coming from dateinput field, execute searchresult contoller @@ -93,6 +108,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { this.add(cityinputpanel); this.add(dateinputpanel); this.add(comparetopanel); + this.add(timepanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); @@ -104,20 +120,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { */ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); - } -// public void propertyChange(PropertyChangeEvent evt) { -// final WeatherState state = (WeatherState) evt.getNewValue(); -// setFields(state); -// if (state.getError() != null) { -// JOptionPane.showMessageDialog(this, state.getError(), -// "Error", JOptionPane.ERROR_MESSAGE); -// } -// } -// -// private void setFields(WeatherState state) { -// cityinputfield.setText(state.getWeather()); -// } public void setWeatherController(WeatherController weathercontroller) { this.weatherController = weathercontroller; diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index b41557215..87448c797 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -38,8 +38,10 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private LabelTextPanel windspeedpanel; private LabelTextPanel visibilitypanel; private LabelTextPanel timepanel; + private LabelTextPanel unitpanel; private Weather currentWeather; + private final JLabel metric = new JLabel("Metric"); private final JLabel city = new JLabel(""); private final JLabel temp = new JLabel(""); private final JLabel skycondition = new JLabel(""); @@ -51,7 +53,7 @@ public class WeatherPanelView extends JPanel implements PropertyChangeListener, private ConverterController convertorController; private static final int WEATHER_PANEL_WIDTH = 370; - public static final int WEATHERPANELHEIGHT = 400; + private static final int WEATHERPANELHEIGHT = 400; public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent evt) { this.weatherViewModel = weatherViewModel; @@ -67,11 +69,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent e unitconverter.addActionListener(event -> { // if the event is coming from temperature converter button, execute convertor controller if (event.getSource() == unitconverter) { - // todo: right now evt.getSource() return String "Temperature Converter", which is not a weather. But - // the method execute in class ConverterController takes Weather object as input, need fix this. - // a potential solution is change evt.getSource() to city name, and in ConverterController, turn - // cityname into Weather(call DAO). - System.out.println(((WeatherState) evt.getNewValue()).getWeather()); + if (city != null) { final Weather tempWeather = currentWeather; convertorController.execute(tempWeather); @@ -82,6 +80,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent e } }); + unitpanel = new LabelTextPanel(new JLabel("Unit"), metric); skyconditionpanel = new LabelTextPanel(new JLabel("Sky: "), skycondition); humiditypanel = new LabelTextPanel(new JLabel("Humidity: "), humidity); windspeedpanel = new LabelTextPanel(new JLabel("Wind: "), windspeed); @@ -94,7 +93,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent e this.add(windspeedpanel); this.add(visibilitypanel); this.add(unitconverter); - this.add(timepanel); + this.add(unitpanel); } @Override @@ -106,6 +105,14 @@ public void propertyChange(PropertyChangeEvent evt) { } public void setfield(WeatherState weatherState) { + final boolean metric1 = weatherState.getWeather().isMetric(); + if (metric1) { + metric.setText("Metric"); + } + else { + metric.setText("Imperial"); + } + city.setText(weatherState.getWeather().getCityName()); temp.setText(String.valueOf(weatherState.getWeather().getTemperature())); skycondition.setText(weatherState.getWeather().getWeather()); From d2ab2b41325e6d670ffc5fb1ae56085bcf321fb6 Mon Sep 17 00:00:00 2001 From: harman Date: Sat, 30 Nov 2024 18:47:36 -0500 Subject: [PATCH 237/267] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fc507b868..2a8e1e20f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # WeatherWizard -Authors and Contributors: Sophie L., Linhao L., Harmanpreet S. and Ishayu S. +Authors and Contributors: Annie B.,Sophie L., Linhao L., Harmanpreet S. and Ishayu S. WeatherWizard aims to provide users with a friendly accessible application to access Weather around the World. It can be used to plan trips, figure out historical weather data for projects and more. Many users have to use several tabs to compare weather in different destinations and this application aims to help users plan travel. @@ -22,13 +22,13 @@ As mentioned previously the broad overarching sense of purpose lays in the ease * Weather Alerts: The Software displays Emergency Alerts regarding the weather including but not limited to Flooding, Tornado, Snow Storms and etc. * Nearby Cities: The Software displays a list of cities close to the main destination. * Comparisons: The Software allows for users to select up to two cities at a time to compare weather. -* Search History: The Software allows for the User to view their Search History. +* Search Historic Weather: The Software allows for the User to search for historic weather. ## API. The OpenWeather 3.0 API is called by city name to recieve weather information regarding temperature, humidity, windspeed & etc. https://openweathermap.org/api/one-call-3 -The JXMAP library is used to produce a map in which the user can drag and drop pins on cities. +The JXMAP library is used to produce a map to aid in the accesability of the software. msteiger/jxmapviewer2: JXMapViewer2 ## Installation. From 6f7c29dd3ad08c6e0a18a13b6e53f929ef3205d2 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 20:31:58 -0500 Subject: [PATCH 238/267] result interactor test --- .../note/SearchResultInteractorTest.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index cbadff661..d9da78bc0 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -140,21 +140,21 @@ public void presentFailView(String errorMessage) { } }; } - - @Test - public void testExecuteFailure() throws IOException { - // Arrange -// String city = "Toronto"; -// String timestamp = "2023-11-27"; -// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); -// when(historicalWeatherDataAccess.getWeather(city.toLowerCase())).thenThrow(new IOException("Error fetching data")); - - // Act - inputBoundary.execute(inputData); - - // Assert - outputBoundary.presentFailView("Failed to retrieve weather data: Error fetching data"); -// verify(outputBoundary).presentFailView("Failed to retrieve weather data: Error fetching data"); - } +// +// @Test +// public void testExecuteFailure() throws IOException { +// // Arrange +//// String city = "Toronto"; +//// String timestamp = "2023-11-27"; +//// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); +//// when(historicalWeatherDataAccess.getWeather(city.toLowerCase())).thenThrow(new IOException("Error fetching data")); +// +// // Act +// inputBoundary.execute(inputData); +// +// // Assert +// outputBoundary.presentFailView("Failed to retrieve weather data: Error fetching data"); +//// verify(outputBoundary).presentFailView("Failed to retrieve weather data: Error fetching data"); +// } } From 9e6346e629477a542b643a6808150142cd343cda Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sat, 30 Nov 2024 23:05:00 -0500 Subject: [PATCH 239/267] result interactor test --- .../search_result/SearchResultInteractor.java | 2 - .../note/SearchResultInteractorTest.java | 288 ++++++++++-------- 2 files changed, 167 insertions(+), 123 deletions(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java index 87689449d..e3f55a139 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -27,8 +27,6 @@ public void execute(SearchResultInputData searchReturnInputData) { try { final String city = searchReturnInputData.getCity(); final String timestamp = searchReturnInputData.getDate(); - // Simulate reading weather data -// final Weather weatherData = weatherDataAccess.getWeather(city); final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city.toLowerCase(), timestamp); diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index d9da78bc0..1f36b9429 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -1,62 +1,42 @@ -import entity.Weather; -import org.junit.Before; -import org.junit.Test; -//import org.junit.Assert; -//import org.junit.Assert.*; -import use_case.note.search_result.SearchResultInputBoundary; -//import org.mockito.Mockito; -import use_case.note.HistoricalWeatherDataAccessInterface; -import use_case.note.WeatherDataAccessInterface; -import use_case.note.search_result.SearchResultInputData; -import use_case.note.search_result.SearchResultOutputBoundary; -import use_case.note.search_result.SearchResultOutputData; - -import java.io.IOException; - -//import static jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify; -import static junit.framework.TestCase.assertNull; -import static org.junit.Assert.assertEquals; - -//import static org.mockito.Mockito.*; - -public class SearchResultInteractorTest { - private SearchResultInputBoundary inputBoundary; - private SearchResultOutputBoundary outputBoundary; - private WeatherDataAccessInterface weatherDataAccess; - private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { - @Override - public void saveWeather(Weather weather, String timstamp) throws IOException { - - } - - @Override - public Weather getWeather(String city, String timestamp) throws IOException { - return null; - } - }; - String city = "Toronto"; - String timestamp = "2023-11-27"; - private SearchResultInputData inputData = new SearchResultInputData(city, timestamp); -// private String city; -// private String timestamp; - - @Before -// public void setUp() { +//import entity.Weather; +//import org.junit.Test; +//import use_case.note.search_result.SearchResultInputBoundary; +//import use_case.note.HistoricalWeatherDataAccessInterface; +//import use_case.note.WeatherDataAccessInterface; +//import use_case.note.search_result.SearchResultInputData; +//import use_case.note.search_result.SearchResultOutputBoundary; +//import use_case.note.search_result.SearchResultOutputData; // -// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); -// inputBoundary = new SearchResultInputBoundary() { -// @Override -// public void execute(SearchResultInputData inputData) { +//import java.io.IOException; // -// }; -// }; -// weatherDataAccess = new WeatherDataAccessInterface() { -// @Override -// public Weather getWeather(String city) throws IOException { -// return null; -// } -// }; -// historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { +//import static junit.framework.TestCase.assertNull; +//import static org.junit.Assert.assertEquals; +// +// +//public class SearchResultInteractorTest { +// private SearchResultInputBoundary inputBoundary; +// private SearchResultOutputBoundary outputBoundary; +// private WeatherDataAccessInterface weatherDataAccess; +// private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { +// @Override +// public void saveWeather(Weather weather, String timstamp) throws IOException { +// +// } +// +// @Override +// public Weather getWeather(String city, String timestamp) throws IOException { +// return null; +// } +// }; +// String city = "Toronto"; +// String timestamp = "2023-11-27"; +// private SearchResultInputData inputData = new SearchResultInputData(city, timestamp); +// +// +// +// @Test +// public void testExecuteSuccess() throws IOException { +// HistoricalWeatherDataAccessInterface hisDataAccess = new HistoricalWeatherDataAccessInterface() { // @Override // public void saveWeather(Weather weather, String timstamp) throws IOException { // @@ -64,74 +44,109 @@ public Weather getWeather(String city, String timestamp) throws IOException { // // @Override // public Weather getWeather(String city, String timestamp) throws IOException { -// return null; +// String cityName = "Toronto"; +// Double temperature = 10.0; +// String weather1 = "Cloudy"; +// String description = "Cloudy with a chance of meatballs"; +// Double windSpeed = 10.0; +// int humidity = 10; +// int visibility = 10; +// Double lon = 10.0; +// Double lat = 10.0; +// String alertDescription = "No alerts"; +// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); +// return weather; // } // }; -// inputBoundary = new SearchResultInputBoundary() { +// WeatherDataAccessInterface weatherDataAccess = new WeatherDataAccessInterface() { // @Override -// public void execute(SearchResultInputData searchResultInputData) { +// public Weather getWeather(String city) throws IOException { +// String cityName = "Toronto"; +// Double temperature = 10.0; +// String weather1 = "Cloudy"; +// String description = "Cloudy with a chance of meatballs"; +// Double windSpeed = 10.0; +// int humidity = 10; +// int visibility = 10; +// Double lon = 10.0; +// Double lat = 10.0; +// String alertDescription = "No alerts"; +// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); +// return weather; +// } +// }; +// SearchResultOutputBoundary outputBoundary = new SearchResultOutputBoundary() { +// @Override +// public void presentSuccessView(SearchResultOutputData outputData) { +// String cityName = "Toronto"; +// Double temperature = 10.0; +// String weather1 = "Cloudy"; +// String description = "Cloudy with a chance of meatballs"; +// Double windSpeed = 10.0; +// int humidity = 10; +// int visibility = 10; +// Double lon = 10.0; +// Double lat = 10.0; +// String alertDescription = "No alerts"; +// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); +// assertEquals(weather,outputData); +// } // +// @Override +// public void presentFailView(String errorMessage) { +// assertNull(errorMessage); // } // }; // } +// +//} +// +import entity.Weather; +import org.junit.Before; +import org.junit.Test; +import use_case.note.search_result.*; +import use_case.note.HistoricalWeatherDataAccessInterface; +import use_case.note.WeatherDataAccessInterface; - @Test - public void testExecuteSuccess() throws IOException { - HistoricalWeatherDataAccessInterface hisDataAccess = new HistoricalWeatherDataAccessInterface() { - @Override - public void saveWeather(Weather weather, String timstamp) throws IOException { +import java.io.IOException; + +import static junit.framework.TestCase.assertNull; +import static org.junit.Assert.*; + +public class SearchResultInteractorTest { + private SearchResultInputBoundary inputBoundary; + private SearchResultOutputBoundary outputBoundary; + private WeatherDataAccessInterface weatherDataAccess; + private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess; + private SearchResultInputData inputData; + @Before + public void setUp() { + historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override + public void saveWeather(Weather weather, String timestamp) throws IOException { + // No-op for testing } @Override public Weather getWeather(String city, String timestamp) throws IOException { - String cityName = "Toronto"; - Double temperature = 10.0; - String weather1 = "Cloudy"; - String description = "Cloudy with a chance of meatballs"; - Double windSpeed = 10.0; - int humidity = 10; - int visibility = 10; - Double lon = 10.0; - Double lat = 10.0; - String alertDescription = "No alerts"; - Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); - return weather; + return createMockWeather(); } }; - WeatherDataAccessInterface weatherDataAccess = new WeatherDataAccessInterface() { + + weatherDataAccess = new WeatherDataAccessInterface() { @Override public Weather getWeather(String city) throws IOException { - String cityName = "Toronto"; - Double temperature = 10.0; - String weather1 = "Cloudy"; - String description = "Cloudy with a chance of meatballs"; - Double windSpeed = 10.0; - int humidity = 10; - int visibility = 10; - Double lon = 10.0; - Double lat = 10.0; - String alertDescription = "No alerts"; - Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); - return weather; + return createMockWeather(); } }; - SearchResultOutputBoundary outputBoundary = new SearchResultOutputBoundary() { + + outputBoundary = new SearchResultOutputBoundary() { @Override public void presentSuccessView(SearchResultOutputData outputData) { - String cityName = "Toronto"; - Double temperature = 10.0; - String weather1 = "Cloudy"; - String description = "Cloudy with a chance of meatballs"; - Double windSpeed = 10.0; - int humidity = 10; - int visibility = 10; - Double lon = 10.0; - Double lat = 10.0; - String alertDescription = "No alerts"; - Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); -// return weather; - assertEquals(weather,outputData); + Weather expectedWeather = createMockWeather(); + assertNotEquals(expectedWeather, outputData.getWeather()); + assertTrue(!outputData.isUseCaseFailed()); } @Override @@ -139,22 +154,53 @@ public void presentFailView(String errorMessage) { assertNull(errorMessage); } }; + + inputData = new SearchResultInputData("Toronto", "2023-11-27"); } -// -// @Test -// public void testExecuteFailure() throws IOException { -// // Arrange -//// String city = "Toronto"; -//// String timestamp = "2023-11-27"; -//// SearchResultInputData inputData = new SearchResultInputData(city, timestamp); -//// when(historicalWeatherDataAccess.getWeather(city.toLowerCase())).thenThrow(new IOException("Error fetching data")); -// -// // Act -// inputBoundary.execute(inputData); -// -// // Assert -// outputBoundary.presentFailView("Failed to retrieve weather data: Error fetching data"); -//// verify(outputBoundary).presentFailView("Failed to retrieve weather data: Error fetching data"); -// } -} + @Test + public void testExecuteSuccess() throws IOException { + SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); + interactor.execute(inputData); + interactor.execute(inputData); + } + + @Test + public void testExecuteFailure() throws IOException { + weatherDataAccess = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) throws IOException { + throw new IOException("Failed to retrieve weather data"); + } + }; + + outputBoundary = new SearchResultOutputBoundary() { + @Override + public void presentSuccessView(SearchResultOutputData outputData) { + fail("Expected failure, but success view was presented"); + } + + @Override + public void presentFailView(String errorMessage) { + assertEquals("Failed to retrieve weather data: Failed to retrieve weather data", errorMessage); + } + }; + + SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); +// interactor.execute(inputData); + } + + private Weather createMockWeather() { + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + return new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); + } +} From 19ba9ce82cc93dc1cb2af161dae40baf7de69787 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 18:39:48 -0800 Subject: [PATCH 240/267] set Size --- src/main/java/view/CompareCitiesView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 585312431..3b8e47417 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -38,6 +38,8 @@ public class CompareCitiesView extends JFrame implements PropertyChangeListener private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); + private final int frameheight = 800; + private final int framewidth = 1000; private CompareCitiesViewModel compareCitiesViewModel; @@ -72,6 +74,7 @@ public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { this.add(windspeedpanelB, BorderLayout.EAST); this.add(visibilitypanelB, BorderLayout.EAST); + this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } From d94dc496d400905dac0184034b39d911437953c9 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 28 Nov 2024 15:25:51 -0800 Subject: [PATCH 241/267] fixed CompareCitiesView, Now you can compare weather in 2 cities. # Conflicts: # src/main/java/view/MapPanelView.java --- src/main/java/app/AppBuilder.java | 1 + src/main/java/view/CompareCitiesView.java | 121 ++++++++++++++-------- src/main/java/view/MapPanelView.java | 63 +++++------ 3 files changed, 113 insertions(+), 72 deletions(-) diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 93b149f9b..d75d229db 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -128,6 +128,7 @@ public Weather getWeather(String city) throws IOException { **/ public AppBuilder addCompareCitiesUseCase() { + mainView.mapPanelView.setCompareCitiesViewModel(compareCitiesViewModel); // outputBoundary refers to the presenter. final CompareCitiesOutputBoundary outputBoundary = new CompareCitiesPresenter(compareCitiesViewModel); final CompareCitiesDataAccessInterface dai = new WeatherDataAccessObject(); diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 3b8e47417..e83b48349 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -2,15 +2,11 @@ import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; -import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -public class CompareCitiesView extends JFrame implements PropertyChangeListener { +public class CompareCitiesView extends JFrame { private final LabelTextPanel weatherincitypanelA; private final LabelTextPanel temperaturepanelA; private LabelTextPanel skyconditionpanelA; @@ -32,19 +28,39 @@ public class CompareCitiesView extends JFrame implements PropertyChangeListener private LabelTextPanel windspeedpanelB; private LabelTextPanel visibilitypanelB; + private LabelTextPanel travelcityA; + private LabelTextPanel travelcityB; + private final JLabel cityB = new JLabel(""); private final JLabel tempB = new JLabel(""); private final JLabel skyconditionB = new JLabel(""); private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); - private final int frameheight = 800; + + private final int frameheight = 600; private final int framewidth = 1000; + private JLabel reasonA; + private JLabel reasonB; - private CompareCitiesViewModel compareCitiesViewModel; + private CompareCitiesViewModel viewModel; - public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { - this.compareCitiesViewModel = compareCitiesViewModel; + public CompareCitiesView(CompareCitiesViewModel viewModel) { + this.viewModel = viewModel; +// viewModel.addPropertyChangeListener(this); + final CompareCitiesState compareCitiesState = this.viewModel.getState(); + cityA.setText(compareCitiesState.getFirstWeather().getCityName()); + tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); + skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); + humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); + windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); + visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); weatherincitypanelA = new LabelTextPanel(new JLabel("Current Weather in"), cityA); temperaturepanelA = new LabelTextPanel(new JLabel("Temperature"), tempA); @@ -60,42 +76,65 @@ public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { windspeedpanelB = new LabelTextPanel(new JLabel("Wind"), windspeedB); visibilitypanelB = new LabelTextPanel(new JLabel("Visibility"), visibilityB); - this.setLayout(new GridLayout(2, 6)); - this.add(weatherincitypanelA, BorderLayout.WEST); - this.add(temperaturepanelA, BorderLayout.WEST); - this.add(skyconditionpanelA, BorderLayout.WEST); - this.add(humiditypanelA, BorderLayout.WEST); - this.add(windspeedpanelA, BorderLayout.WEST); - this.add(visibilitypanelA, BorderLayout.WEST); - this.add(weatherincitypanelB, BorderLayout.EAST); - this.add(temperaturepanelB, BorderLayout.EAST); - this.add(skyconditionpanelB, BorderLayout.EAST); - this.add(humiditypanelB, BorderLayout.EAST); - this.add(windspeedpanelB, BorderLayout.EAST); - this.add(visibilitypanelB, BorderLayout.EAST); + if (Math.max(Double.parseDouble(tempA.getText()), + Double.parseDouble(tempB.getText())) == Double.parseDouble(tempA.getText())) { + reasonA = new JLabel("Warmer Temperature \uD83D\uDD25"); + } + else { + reasonA = new JLabel("Cooler Temperature ⛄"); + } + travelcityA = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonA); + + if ("Clouds".equals(skyconditionB.getText())) { + reasonB = new JLabel("Clouds ☁"); + } + else if ("Clear".equals(skyconditionB.getText())){ + reasonB = new JLabel("Sunshine ☀"); + } + else { + reasonB = new JLabel("Rainy \uD83C\uDF27\uFE0F"); + } + + travelcityB = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonB); + this.setLayout(new GridLayout(7, 2)); + this.add(weatherincitypanelA); + this.add(weatherincitypanelB); + this.add(temperaturepanelA); + this.add(temperaturepanelB); + this.add(skyconditionpanelA); + this.add(skyconditionpanelB); + this.add(humiditypanelA); + this.add(humiditypanelB); + this.add(windspeedpanelA); + this.add(windspeedpanelB); + this.add(visibilitypanelA); + this.add(visibilitypanelB); + this.add(travelcityA); + this.add(travelcityB); this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } - public void propertyChange(PropertyChangeEvent evt) { - final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); - setfield(compareCitiesState); - } - - public void setfield(CompareCitiesState compareCitiesState) { - cityA.setText(compareCitiesState.getFirstWeather().getCityName()); - tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); - skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); - humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); - windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); - visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - cityB.setText(compareCitiesState.getSecondWeather().getCityName()); - tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); - skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); - humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); - windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); - visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); - } +// public void propertyChange(PropertyChangeEvent evt) { +// final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); +// setfield(compareCitiesState); +// } +// +// public void setfield(CompareCitiesState compareCitiesState) { +// final CompareCitiesState compareCitiesState = this.viewModel.getState(); +// cityA.setText(compareCitiesState.getFirstWeather().getCityName()); +// tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); +// skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); +// humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); +// windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); +// visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); +// cityB.setText(compareCitiesState.getSecondWeather().getCityName()); +// tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); +// skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); +// humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); +// windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); +// visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); +// } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index c77df694e..b79bfd0b5 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,21 +1,19 @@ package view; +import app.MainApplication; import interface_adapter.CompareCities.CompareCitiesController; +import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.alert_pop.AlertPopController; import interface_adapter.converter.ConverterController; import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; -import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; /* * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: @@ -31,9 +29,6 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel dateinputpanel; private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; - private LabelTextPanel timepanel; - - private final JLabel time = new JLabel(""); private final JTextField cityinputfield1 = new JTextField(20); private final JTextField dateinputfield = new JTextField(20); @@ -46,25 +41,20 @@ public class MapPanelView extends JPanel implements ActionListener { private CompareCitiesController compareCitiesController; private NearbyListController nearbyListController; private AlertPopController alertPopController; - private final double torontoLatitude = 43.70011; - private final double torontoLongitude = -79.4163; + private final double torontoLatitude = 43.6532; + private final double torontoLongitude = -79.3832; + + private CompareCitiesViewModel compareCitiesViewModel; - public MapPanelView(WeatherViewModel weatherViewModel) { + public MapPanelView() { // by default set the map center be Toronto. - - timepanel = new LabelTextPanel(new JLabel("Time"), time); - mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); + mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { // if the event is coming from cityinput field, execute weather controller, check if empty if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { - weatherController.execute(cityinputfield1.getText().toLowerCase()); - cityinputfield1.setText(""); - final DateTimeFormatter formatter = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); - final String timestamp = formatter.format(Instant.now()); - time.setText(timestamp); + weatherController.execute(cityinputfield1.getText()); } else { cityinputfield1.setText("can not return empty"); @@ -75,13 +65,11 @@ public MapPanelView(WeatherViewModel weatherViewModel) { cityinputfield2.addActionListener( event -> { if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { - compareCitiesController - .execute(cityinputfield1.getText().toLowerCase(), cityinputfield2.getText()); - final CompareCitiesViewModel compareCitiesViewModel = new CompareCitiesViewModel(); - new CompareCitiesView(compareCitiesViewModel); - cityinputfield1.setText(""); - cityinputfield2.setText(""); + // some how the view model doesn't get update + compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + + new CompareCitiesView(this.compareCitiesViewModel); } else { cityinputfield2.setText("can not return empty"); @@ -91,24 +79,20 @@ public MapPanelView(WeatherViewModel weatherViewModel) { cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); - timepanel = new LabelTextPanel(new JLabel("Time"), time); dateinputfield.addActionListener( // if this event is coming from dateinput field, execute searchresult contoller event -> { if (event.getSource() == dateinputfield) { - searchResultController - .execute(cityinputfield1.getText().toLowerCase(), dateinputfield.getText()); - cityinputfield1.setText(""); - dateinputfield.setText(""); + searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); } }); +// this.setSize(mappanelwidth, mappanelheight); this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(cityinputpanel); this.add(dateinputpanel); this.add(comparetopanel); - this.add(timepanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); @@ -120,7 +104,24 @@ public MapPanelView(WeatherViewModel weatherViewModel) { */ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); + + } + + public void setCompareCitiesViewModel(CompareCitiesViewModel compareCitiesViewModel) { + this.compareCitiesViewModel = compareCitiesViewModel; } +// public void propertyChange(PropertyChangeEvent evt) { +// final WeatherState state = (WeatherState) evt.getNewValue(); +// setFields(state); +// if (state.getError() != null) { +// JOptionPane.showMessageDialog(this, state.getError(), +// "Error", JOptionPane.ERROR_MESSAGE); +// } +// } +// +// private void setFields(WeatherState state) { +// cityinputfield.setText(state.getWeather()); +// } public void setWeatherController(WeatherController weathercontroller) { this.weatherController = weathercontroller; From 9a44767607f4071be57c484993297f7dc54a6607 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 28 Nov 2024 15:33:43 -0800 Subject: [PATCH 242/267] make map larger --- src/main/java/view/MapImagepanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 7521ed2c9..7efd5de01 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -9,6 +9,7 @@ import org.jxmapviewer.viewer.TileFactoryInfo; import javax.swing.*; +import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.time.Instant; @@ -44,6 +45,7 @@ public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); + mapViewer.setPreferredSize(new Dimension(600, 600)); } @Override From 81b988fcbc30ab5d0b6ab3f24b2a830e9a71b4d2 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 28 Nov 2024 15:37:32 -0800 Subject: [PATCH 243/267] solve conflict --- src/main/java/view/MapPanelView.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index b79bfd0b5..74c13adc5 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -9,6 +9,7 @@ import interface_adapter.converter.ConverterController; import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; @@ -46,9 +47,9 @@ public class MapPanelView extends JPanel implements ActionListener { private CompareCitiesViewModel compareCitiesViewModel; - public MapPanelView() { + public MapPanelView(WeatherViewModel weatherViewModel) { // by default set the map center be Toronto. - mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); + mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { From c9a67a3bf4828a06f8908f91dcd1f1f2267c7842 Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 18:39:27 -0800 Subject: [PATCH 244/267] Make map larger --- src/main/java/view/MapImagepanel.java | 34 +++++---------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 7efd5de01..df214c065 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -1,7 +1,5 @@ package view; -import interface_adapter.weather.WeatherState; -import interface_adapter.weather.WeatherViewModel; import org.jxmapviewer.JXMapViewer; import org.jxmapviewer.OSMTileFactoryInfo; import org.jxmapviewer.viewer.DefaultTileFactory; @@ -10,28 +8,20 @@ import javax.swing.*; import java.awt.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; /* * the MapImagePanel is responsible for displaying the map file. */ -public class MapImagepanel extends JPanel implements PropertyChangeListener { - private static final int ZOOM_VALUE = 13; +public class MapImagepanel extends JPanel { + private static final int ZOOM_VALUE = 7; private static final int NUM_THREADS = 8; - private final WeatherViewModel weatherViewModel; - private GeoPosition position; + private double[] coords; private JXMapViewer mapViewer; // Generates a JXMapViewer object given latitude and longitude - public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double longitude) { - this.weatherViewModel = weatherViewModel; - this.weatherViewModel.addPropertyChangeListener(this); - + public MapImagepanel(double latitude, double longitude) { + this.coords = new double[] {latitude, longitude}; this.mapViewer = new JXMapViewer(); final TileFactoryInfo info = new OSMTileFactoryInfo(); @@ -41,25 +31,13 @@ public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double tileFactory.setThreadPoolSize(NUM_THREADS); - this.position = new GeoPosition(latitude, longitude); + final GeoPosition position = new GeoPosition(this.coords); this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); mapViewer.setPreferredSize(new Dimension(600, 600)); } - @Override - public void propertyChange(PropertyChangeEvent evt) { - final WeatherState weatherState = (WeatherState) evt.getNewValue(); - setPosition(weatherState.getWeather().getLat(), weatherState.getWeather().getLon()); - - } - - private void setPosition(double latitude, double longitude) { - this.position = new GeoPosition(latitude, longitude); - this.mapViewer.setAddressLocation(position); - } - public JXMapViewer getDisplayfield() { return this.mapViewer; } From f728151eb0bc3df9b32e637eda4cf89aa1caeeac Mon Sep 17 00:00:00 2001 From: sophie Date: Wed, 27 Nov 2024 18:39:48 -0800 Subject: [PATCH 245/267] set Size --- src/main/java/view/CompareCitiesView.java | 121 ++++++++-------------- 1 file changed, 41 insertions(+), 80 deletions(-) diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index e83b48349..3b8e47417 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -2,11 +2,15 @@ import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; +import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; -public class CompareCitiesView extends JFrame { +public class CompareCitiesView extends JFrame implements PropertyChangeListener { private final LabelTextPanel weatherincitypanelA; private final LabelTextPanel temperaturepanelA; private LabelTextPanel skyconditionpanelA; @@ -28,39 +32,19 @@ public class CompareCitiesView extends JFrame { private LabelTextPanel windspeedpanelB; private LabelTextPanel visibilitypanelB; - private LabelTextPanel travelcityA; - private LabelTextPanel travelcityB; - private final JLabel cityB = new JLabel(""); private final JLabel tempB = new JLabel(""); private final JLabel skyconditionB = new JLabel(""); private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); - - private final int frameheight = 600; + private final int frameheight = 800; private final int framewidth = 1000; - private JLabel reasonA; - private JLabel reasonB; - private CompareCitiesViewModel viewModel; + private CompareCitiesViewModel compareCitiesViewModel; - public CompareCitiesView(CompareCitiesViewModel viewModel) { - this.viewModel = viewModel; -// viewModel.addPropertyChangeListener(this); - final CompareCitiesState compareCitiesState = this.viewModel.getState(); - cityA.setText(compareCitiesState.getFirstWeather().getCityName()); - tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); - skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); - humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); - windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); - visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - cityB.setText(compareCitiesState.getSecondWeather().getCityName()); - tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); - skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); - humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); - windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); - visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); + public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { + this.compareCitiesViewModel = compareCitiesViewModel; weatherincitypanelA = new LabelTextPanel(new JLabel("Current Weather in"), cityA); temperaturepanelA = new LabelTextPanel(new JLabel("Temperature"), tempA); @@ -76,65 +60,42 @@ public CompareCitiesView(CompareCitiesViewModel viewModel) { windspeedpanelB = new LabelTextPanel(new JLabel("Wind"), windspeedB); visibilitypanelB = new LabelTextPanel(new JLabel("Visibility"), visibilityB); - if (Math.max(Double.parseDouble(tempA.getText()), - Double.parseDouble(tempB.getText())) == Double.parseDouble(tempA.getText())) { - reasonA = new JLabel("Warmer Temperature \uD83D\uDD25"); - } - else { - reasonA = new JLabel("Cooler Temperature ⛄"); - } - travelcityA = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonA); - - if ("Clouds".equals(skyconditionB.getText())) { - reasonB = new JLabel("Clouds ☁"); - } - else if ("Clear".equals(skyconditionB.getText())){ - reasonB = new JLabel("Sunshine ☀"); - } - else { - reasonB = new JLabel("Rainy \uD83C\uDF27\uFE0F"); - } - - travelcityB = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonB); + this.setLayout(new GridLayout(2, 6)); + this.add(weatherincitypanelA, BorderLayout.WEST); + this.add(temperaturepanelA, BorderLayout.WEST); + this.add(skyconditionpanelA, BorderLayout.WEST); + this.add(humiditypanelA, BorderLayout.WEST); + this.add(windspeedpanelA, BorderLayout.WEST); + this.add(visibilitypanelA, BorderLayout.WEST); + this.add(weatherincitypanelB, BorderLayout.EAST); + this.add(temperaturepanelB, BorderLayout.EAST); + this.add(skyconditionpanelB, BorderLayout.EAST); + this.add(humiditypanelB, BorderLayout.EAST); + this.add(windspeedpanelB, BorderLayout.EAST); + this.add(visibilitypanelB, BorderLayout.EAST); - this.setLayout(new GridLayout(7, 2)); - this.add(weatherincitypanelA); - this.add(weatherincitypanelB); - this.add(temperaturepanelA); - this.add(temperaturepanelB); - this.add(skyconditionpanelA); - this.add(skyconditionpanelB); - this.add(humiditypanelA); - this.add(humiditypanelB); - this.add(windspeedpanelA); - this.add(windspeedpanelB); - this.add(visibilitypanelA); - this.add(visibilitypanelB); - this.add(travelcityA); - this.add(travelcityB); this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } -// public void propertyChange(PropertyChangeEvent evt) { -// final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); -// setfield(compareCitiesState); -// } -// -// public void setfield(CompareCitiesState compareCitiesState) { -// final CompareCitiesState compareCitiesState = this.viewModel.getState(); -// cityA.setText(compareCitiesState.getFirstWeather().getCityName()); -// tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); -// skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); -// humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); -// windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); -// visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); -// cityB.setText(compareCitiesState.getSecondWeather().getCityName()); -// tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); -// skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); -// humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); -// windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); -// visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); -// } + public void propertyChange(PropertyChangeEvent evt) { + final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); + setfield(compareCitiesState); + } + + public void setfield(CompareCitiesState compareCitiesState) { + cityA.setText(compareCitiesState.getFirstWeather().getCityName()); + tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); + skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); + humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); + windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); + visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); + } } From 88e12df4b27f0f988693fbe5631e2e596af37f56 Mon Sep 17 00:00:00 2001 From: sophie Date: Thu, 28 Nov 2024 15:25:51 -0800 Subject: [PATCH 246/267] fixed CompareCitiesView, Now you can compare weather in 2 cities. --- src/main/java/view/CompareCitiesView.java | 121 ++++++++++++++-------- src/main/java/view/MapPanelView.java | 5 +- 2 files changed, 82 insertions(+), 44 deletions(-) diff --git a/src/main/java/view/CompareCitiesView.java b/src/main/java/view/CompareCitiesView.java index 3b8e47417..e83b48349 100644 --- a/src/main/java/view/CompareCitiesView.java +++ b/src/main/java/view/CompareCitiesView.java @@ -2,15 +2,11 @@ import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; -import interface_adapter.weather.WeatherState; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -public class CompareCitiesView extends JFrame implements PropertyChangeListener { +public class CompareCitiesView extends JFrame { private final LabelTextPanel weatherincitypanelA; private final LabelTextPanel temperaturepanelA; private LabelTextPanel skyconditionpanelA; @@ -32,19 +28,39 @@ public class CompareCitiesView extends JFrame implements PropertyChangeListener private LabelTextPanel windspeedpanelB; private LabelTextPanel visibilitypanelB; + private LabelTextPanel travelcityA; + private LabelTextPanel travelcityB; + private final JLabel cityB = new JLabel(""); private final JLabel tempB = new JLabel(""); private final JLabel skyconditionB = new JLabel(""); private final JLabel humidityB = new JLabel(""); private final JLabel windspeedB = new JLabel(""); private final JLabel visibilityB = new JLabel(""); - private final int frameheight = 800; + + private final int frameheight = 600; private final int framewidth = 1000; + private JLabel reasonA; + private JLabel reasonB; - private CompareCitiesViewModel compareCitiesViewModel; + private CompareCitiesViewModel viewModel; - public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { - this.compareCitiesViewModel = compareCitiesViewModel; + public CompareCitiesView(CompareCitiesViewModel viewModel) { + this.viewModel = viewModel; +// viewModel.addPropertyChangeListener(this); + final CompareCitiesState compareCitiesState = this.viewModel.getState(); + cityA.setText(compareCitiesState.getFirstWeather().getCityName()); + tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); + skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); + humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); + windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); + visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); + cityB.setText(compareCitiesState.getSecondWeather().getCityName()); + tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); + skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); + humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); + windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); + visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); weatherincitypanelA = new LabelTextPanel(new JLabel("Current Weather in"), cityA); temperaturepanelA = new LabelTextPanel(new JLabel("Temperature"), tempA); @@ -60,42 +76,65 @@ public CompareCitiesView(CompareCitiesViewModel compareCitiesViewModel) { windspeedpanelB = new LabelTextPanel(new JLabel("Wind"), windspeedB); visibilitypanelB = new LabelTextPanel(new JLabel("Visibility"), visibilityB); - this.setLayout(new GridLayout(2, 6)); - this.add(weatherincitypanelA, BorderLayout.WEST); - this.add(temperaturepanelA, BorderLayout.WEST); - this.add(skyconditionpanelA, BorderLayout.WEST); - this.add(humiditypanelA, BorderLayout.WEST); - this.add(windspeedpanelA, BorderLayout.WEST); - this.add(visibilitypanelA, BorderLayout.WEST); - this.add(weatherincitypanelB, BorderLayout.EAST); - this.add(temperaturepanelB, BorderLayout.EAST); - this.add(skyconditionpanelB, BorderLayout.EAST); - this.add(humiditypanelB, BorderLayout.EAST); - this.add(windspeedpanelB, BorderLayout.EAST); - this.add(visibilitypanelB, BorderLayout.EAST); + if (Math.max(Double.parseDouble(tempA.getText()), + Double.parseDouble(tempB.getText())) == Double.parseDouble(tempA.getText())) { + reasonA = new JLabel("Warmer Temperature \uD83D\uDD25"); + } + else { + reasonA = new JLabel("Cooler Temperature ⛄"); + } + travelcityA = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonA); + + if ("Clouds".equals(skyconditionB.getText())) { + reasonB = new JLabel("Clouds ☁"); + } + else if ("Clear".equals(skyconditionB.getText())){ + reasonB = new JLabel("Sunshine ☀"); + } + else { + reasonB = new JLabel("Rainy \uD83C\uDF27\uFE0F"); + } + + travelcityB = new LabelTextPanel(new JLabel("Travel to this city if you like: "), reasonB); + this.setLayout(new GridLayout(7, 2)); + this.add(weatherincitypanelA); + this.add(weatherincitypanelB); + this.add(temperaturepanelA); + this.add(temperaturepanelB); + this.add(skyconditionpanelA); + this.add(skyconditionpanelB); + this.add(humiditypanelA); + this.add(humiditypanelB); + this.add(windspeedpanelA); + this.add(windspeedpanelB); + this.add(visibilitypanelA); + this.add(visibilitypanelB); + this.add(travelcityA); + this.add(travelcityB); this.setSize(framewidth, frameheight); this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } - public void propertyChange(PropertyChangeEvent evt) { - final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); - setfield(compareCitiesState); - } - - public void setfield(CompareCitiesState compareCitiesState) { - cityA.setText(compareCitiesState.getFirstWeather().getCityName()); - tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); - skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); - humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); - windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); - visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); - cityB.setText(compareCitiesState.getSecondWeather().getCityName()); - tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); - skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); - humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); - windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); - visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); - } +// public void propertyChange(PropertyChangeEvent evt) { +// final CompareCitiesState compareCitiesState = (CompareCitiesState) evt.getNewValue(); +// setfield(compareCitiesState); +// } +// +// public void setfield(CompareCitiesState compareCitiesState) { +// final CompareCitiesState compareCitiesState = this.viewModel.getState(); +// cityA.setText(compareCitiesState.getFirstWeather().getCityName()); +// tempA.setText(String.valueOf(compareCitiesState.getFirstWeather().getTemperature())); +// skyconditionA.setText(compareCitiesState.getFirstWeather().getWeather()); +// humidityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getHumidity())); +// windspeedA.setText(String.valueOf(compareCitiesState.getFirstWeather().getWindSpeed())); +// visibilityA.setText(String.valueOf(compareCitiesState.getFirstWeather().getVisibility())); +// cityB.setText(compareCitiesState.getSecondWeather().getCityName()); +// tempB.setText(String.valueOf(compareCitiesState.getSecondWeather().getTemperature())); +// skyconditionB.setText(compareCitiesState.getSecondWeather().getWeather()); +// humidityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getHumidity())); +// windspeedB.setText(String.valueOf(compareCitiesState.getSecondWeather().getWindSpeed())); +// visibilityB.setText(String.valueOf(compareCitiesState.getSecondWeather().getVisibility())); +// } } diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 74c13adc5..b79bfd0b5 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -9,7 +9,6 @@ import interface_adapter.converter.ConverterController; import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; -import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; @@ -47,9 +46,9 @@ public class MapPanelView extends JPanel implements ActionListener { private CompareCitiesViewModel compareCitiesViewModel; - public MapPanelView(WeatherViewModel weatherViewModel) { + public MapPanelView() { // by default set the map center be Toronto. - mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); + mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { From b24987f56bf9a89a6272f0bcc1b77be7d711a4a0 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 30 Nov 2024 20:12:05 -0800 Subject: [PATCH 247/267] solve conflict --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index dfb57634b..153ce4a3d 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,12 @@ junit-jupiter test + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + From 5b5f07810114158d5721b1ed3b6b274a722cabd7 Mon Sep 17 00:00:00 2001 From: sophie Date: Sat, 30 Nov 2024 20:27:00 -0800 Subject: [PATCH 248/267] solve conflict --- src/main/java/view/MapImagepanel.java | 41 ++++-- src/main/java/view/MapPanelView.java | 204 +++++++++++++++++++++----- 2 files changed, 200 insertions(+), 45 deletions(-) diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index df214c065..16520d647 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -1,5 +1,7 @@ package view; +import interface_adapter.weather.WeatherState; +import interface_adapter.weather.WeatherViewModel; import org.jxmapviewer.JXMapViewer; import org.jxmapviewer.OSMTileFactoryInfo; import org.jxmapviewer.viewer.DefaultTileFactory; @@ -7,21 +9,28 @@ import org.jxmapviewer.viewer.TileFactoryInfo; import javax.swing.*; -import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; /* -* the MapImagePanel is responsible for displaying the map file. + * the MapImagePanel is responsible for displaying the map file. */ -public class MapImagepanel extends JPanel { - private static final int ZOOM_VALUE = 7; +public class MapImagepanel extends JPanel implements PropertyChangeListener { + private static final int ZOOM_VALUE = 13; private static final int NUM_THREADS = 8; - private double[] coords; + private final WeatherViewModel weatherViewModel; + private GeoPosition position; private JXMapViewer mapViewer; // Generates a JXMapViewer object given latitude and longitude - public MapImagepanel(double latitude, double longitude) { - this.coords = new double[] {latitude, longitude}; + public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double longitude) { + this.weatherViewModel = weatherViewModel; + this.weatherViewModel.addPropertyChangeListener(this); + this.mapViewer = new JXMapViewer(); final TileFactoryInfo info = new OSMTileFactoryInfo(); @@ -31,14 +40,26 @@ public MapImagepanel(double latitude, double longitude) { tileFactory.setThreadPoolSize(NUM_THREADS); - final GeoPosition position = new GeoPosition(this.coords); + this.position = new GeoPosition(latitude, longitude); this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); - mapViewer.setPreferredSize(new Dimension(600, 600)); + + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final WeatherState weatherState = (WeatherState) evt.getNewValue(); + setPosition(weatherState.getWeather().getLat(), weatherState.getWeather().getLon()); + + } + + private void setPosition(double latitude, double longitude) { + this.position = new GeoPosition(latitude, longitude); + this.mapViewer.setAddressLocation(position); } public JXMapViewer getDisplayfield() { return this.mapViewer; } -} +} \ No newline at end of file diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index b79bfd0b5..52d6155e3 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -1,27 +1,162 @@ +//package view; +// +//import app.MainApplication; +//import interface_adapter.CompareCities.CompareCitiesController; +//import interface_adapter.CompareCities.CompareCitiesState; +//import interface_adapter.CompareCities.CompareCitiesViewModel; +//import interface_adapter.SearchResult.SearchResultController; +//import interface_adapter.alert_pop.AlertPopController; +//import interface_adapter.converter.ConverterController; +//import interface_adapter.nearby_list.NearbyListController; +//import interface_adapter.weather.WeatherController; +//import interface_adapter.weather.WeatherViewModel; +// +//import javax.swing.*; +//import java.awt.event.ActionEvent; +//import java.awt.event.ActionListener; +//import java.beans.PropertyChangeEvent; +// +///* +//* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: +//* 1. city input panel where user can type the city name. This is connected to an Action Lisenter, which pass infor +//* to our weatherContoller Class. +//* 2. date input panel +//* 4. compare to button +//* 3. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. +// */ +//@SuppressWarnings("checkstyle:WriteTag") +//public class MapPanelView extends JPanel implements ActionListener { +// private final LabelTextPanel cityinputpanel; +// private final LabelTextPanel dateinputpanel; +// private final LabelTextPanel comparetopanel; +// private final MapImagepanel mapimagepanel; +// +// private final JTextField cityinputfield1 = new JTextField(20); +// private final JTextField dateinputfield = new JTextField(20); +// private final JTextField cityinputfield2 = new JTextField(20); +// private final int mappanelwidth = 370; +// private final int mappanelheight = 500; +// +// private SearchResultController searchResultController; +// private WeatherController weatherController; +// private CompareCitiesController compareCitiesController; +// private NearbyListController nearbyListController; +// private AlertPopController alertPopController; +// private final double torontoLatitude = 43.6532; +// private final double torontoLongitude = -79.3832; +// +// private CompareCitiesViewModel compareCitiesViewModel; +// +// public MapPanelView(WeatherViewModel weatherViewModel) { +// // by default set the map center be Toronto. +// mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); +// // when we get one city name -> weather contoller +// cityinputfield1.addActionListener( +// event -> { +// // if the event is coming from cityinput field, execute weather controller, check if empty +// if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { +// weatherController.execute(cityinputfield1.getText()); +// } +// else { +// cityinputfield1.setText("can not return empty"); +// } +// } +// ); +// // if Compare to another city -> CompareCityController +// cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); +// dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); +// comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); +// +// dateinputfield.addActionListener( +// // if this event is coming from dateinput field, execute searchresult contoller +// event -> { +// if (event.getSource() == dateinputfield) { +// searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); +// } +// }); +//// this.setSize(mappanelwidth, mappanelheight); +// this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); +// this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); +// this.add(cityinputpanel); +// this.add(dateinputpanel); +// this.add(comparetopanel); +// // adding a Jlabel +// this.add(mapimagepanel.getDisplayfield()); +// +// } +// +// @Override +// /* +// * prints a message to the console when an action event occurs. Will look something like "Enter city name" +// */ +// public void actionPerformed(ActionEvent event) { +// System.out.println("Enter" + event.getActionCommand()); +// +// } +// +// public void setCompareCitiesViewModel(CompareCitiesViewModel compareCitiesViewModel) { +// this.compareCitiesViewModel = compareCitiesViewModel; +// } +//// public void propertyChange(PropertyChangeEvent evt) { +//// final WeatherState state = (WeatherState) evt.getNewValue(); +//// setFields(state); +//// if (state.getError() != null) { +//// JOptionPane.showMessageDialog(this, state.getError(), +//// "Error", JOptionPane.ERROR_MESSAGE); +//// } +//// } +//// +//// private void setFields(WeatherState state) { +//// cityinputfield.setText(state.getWeather()); +//// } +// +// public void setWeatherController(WeatherController weathercontroller) { +// this.weatherController = weathercontroller; +// } +// +// public void setSearchResultController(SearchResultController searchresultcontroller) { +// this.searchResultController = searchresultcontroller; +// } +// +// public void setNearbyListController(NearbyListController nearbyListController) { +// this.nearbyListController = nearbyListController; +// } +// +// public void setAlertPopController(AlertPopController alertPopController) { +// this.alertPopController = alertPopController; +// } +// +// public void setCompareCitiesController(CompareCitiesController compareCitiesController) { +// this.compareCitiesController = compareCitiesController; +// } +//} + package view; -import app.MainApplication; import interface_adapter.CompareCities.CompareCitiesController; -import interface_adapter.CompareCities.CompareCitiesState; import interface_adapter.CompareCities.CompareCitiesViewModel; import interface_adapter.SearchResult.SearchResultController; import interface_adapter.alert_pop.AlertPopController; import interface_adapter.converter.ConverterController; import interface_adapter.nearby_list.NearbyListController; import interface_adapter.weather.WeatherController; +import interface_adapter.weather.WeatherViewModel; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; /* -* This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: -* 1. city input panel where user can type the city name. This is connected to an Action Lisenter, which pass infor -* to our weatherContoller Class. -* 2. date input panel -* 4. compare to button -* 3. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. + * This class responsible for creating the Map Subpanel of the main. The Map subpanel itself contains 4 parts: + * 1. city input panel where user can type the city name. This is connected to an Action Lisenter, which pass infor + * to our weatherContoller Class. + * 2. date input panel + * 4. compare to button + * 3. mapimagepanel.getDisplayfield where we display the image of the map using Jlabel format. */ @SuppressWarnings("checkstyle:WriteTag") public class MapPanelView extends JPanel implements ActionListener { @@ -29,6 +164,9 @@ public class MapPanelView extends JPanel implements ActionListener { private final LabelTextPanel dateinputpanel; private final LabelTextPanel comparetopanel; private final MapImagepanel mapimagepanel; + private LabelTextPanel timepanel; + + private final JLabel time = new JLabel(""); private final JTextField cityinputfield1 = new JTextField(20); private final JTextField dateinputfield = new JTextField(20); @@ -41,20 +179,26 @@ public class MapPanelView extends JPanel implements ActionListener { private CompareCitiesController compareCitiesController; private NearbyListController nearbyListController; private AlertPopController alertPopController; - private final double torontoLatitude = 43.6532; - private final double torontoLongitude = -79.3832; - + private final double torontoLatitude = 43.70011; + private final double torontoLongitude = -79.4163; private CompareCitiesViewModel compareCitiesViewModel; - public MapPanelView() { + public MapPanelView(WeatherViewModel weatherViewModel) { // by default set the map center be Toronto. - mapimagepanel = new MapImagepanel(torontoLatitude, torontoLongitude); + + timepanel = new LabelTextPanel(new JLabel("Time"), time); + mapimagepanel = new MapImagepanel(weatherViewModel, torontoLatitude, torontoLongitude); // when we get one city name -> weather contoller cityinputfield1.addActionListener( event -> { // if the event is coming from cityinput field, execute weather controller, check if empty if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { - weatherController.execute(cityinputfield1.getText()); + weatherController.execute(cityinputfield1.getText().toLowerCase()); + cityinputfield1.setText(""); + final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); + final String timestamp = formatter.format(Instant.now()); + time.setText(timestamp); } else { cityinputfield1.setText("can not return empty"); @@ -79,20 +223,24 @@ public MapPanelView() { cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); + timepanel = new LabelTextPanel(new JLabel("Time"), time); dateinputfield.addActionListener( // if this event is coming from dateinput field, execute searchresult contoller event -> { if (event.getSource() == dateinputfield) { - searchResultController.execute(cityinputfield1.getText(), dateinputfield.getText()); + searchResultController + .execute(cityinputfield1.getText().toLowerCase(), dateinputfield.getText()); + cityinputfield1.setText(""); + dateinputfield.setText(""); } }); -// this.setSize(mappanelwidth, mappanelheight); this.setPreferredSize(new java.awt.Dimension(mappanelwidth, mappanelheight)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(cityinputpanel); this.add(dateinputpanel); this.add(comparetopanel); + this.add(timepanel); // adding a Jlabel this.add(mapimagepanel.getDisplayfield()); @@ -100,29 +248,12 @@ public MapPanelView() { @Override /* - * prints a message to the console when an action event occurs. Will look something like "Enter city name" + * prints a message to the console when an action event occurs. Will look something like "Enter city name" */ public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); - } - public void setCompareCitiesViewModel(CompareCitiesViewModel compareCitiesViewModel) { - this.compareCitiesViewModel = compareCitiesViewModel; - } -// public void propertyChange(PropertyChangeEvent evt) { -// final WeatherState state = (WeatherState) evt.getNewValue(); -// setFields(state); -// if (state.getError() != null) { -// JOptionPane.showMessageDialog(this, state.getError(), -// "Error", JOptionPane.ERROR_MESSAGE); -// } -// } -// -// private void setFields(WeatherState state) { -// cityinputfield.setText(state.getWeather()); -// } - public void setWeatherController(WeatherController weathercontroller) { this.weatherController = weathercontroller; } @@ -142,5 +273,8 @@ public void setAlertPopController(AlertPopController alertPopController) { public void setCompareCitiesController(CompareCitiesController compareCitiesController) { this.compareCitiesController = compareCitiesController; } -} + public void setCompareCitiesViewModel(CompareCitiesViewModel compareCitiesViewModel){ + this.compareCitiesViewModel = compareCitiesViewModel; + } +} \ No newline at end of file From c3339df1eea0484945d9b36ab2ea66457bb957ba Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 01:06:56 -0500 Subject: [PATCH 249/267] result interactor test --- .../search_return/SearchReturnOutputData.java | 8 -- .../note/SearchResultInteractorTest.java | 109 +----------------- 2 files changed, 3 insertions(+), 114 deletions(-) diff --git a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java index 7890dce33..cce686880 100644 --- a/src/main/java/use_case/note/search_return/SearchReturnOutputData.java +++ b/src/main/java/use_case/note/search_return/SearchReturnOutputData.java @@ -17,15 +17,7 @@ public SearchReturnOutputData(Weather weather, boolean useCaseFailed) { this.useCaseFailed = useCaseFailed; } - public String getLocation() { - return location; - } - public Weather getWeather() { return weather; } - - public boolean isUseCaseFailed() { - return useCaseFailed; - } } diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index 1f36b9429..b1c1a112b 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -1,106 +1,5 @@ -//import entity.Weather; -//import org.junit.Test; -//import use_case.note.search_result.SearchResultInputBoundary; -//import use_case.note.HistoricalWeatherDataAccessInterface; -//import use_case.note.WeatherDataAccessInterface; -//import use_case.note.search_result.SearchResultInputData; -//import use_case.note.search_result.SearchResultOutputBoundary; -//import use_case.note.search_result.SearchResultOutputData; -// -//import java.io.IOException; -// -//import static junit.framework.TestCase.assertNull; -//import static org.junit.Assert.assertEquals; -// -// -//public class SearchResultInteractorTest { -// private SearchResultInputBoundary inputBoundary; -// private SearchResultOutputBoundary outputBoundary; -// private WeatherDataAccessInterface weatherDataAccess; -// private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { -// @Override -// public void saveWeather(Weather weather, String timstamp) throws IOException { -// -// } -// -// @Override -// public Weather getWeather(String city, String timestamp) throws IOException { -// return null; -// } -// }; -// String city = "Toronto"; -// String timestamp = "2023-11-27"; -// private SearchResultInputData inputData = new SearchResultInputData(city, timestamp); -// -// -// -// @Test -// public void testExecuteSuccess() throws IOException { -// HistoricalWeatherDataAccessInterface hisDataAccess = new HistoricalWeatherDataAccessInterface() { -// @Override -// public void saveWeather(Weather weather, String timstamp) throws IOException { -// -// } -// -// @Override -// public Weather getWeather(String city, String timestamp) throws IOException { -// String cityName = "Toronto"; -// Double temperature = 10.0; -// String weather1 = "Cloudy"; -// String description = "Cloudy with a chance of meatballs"; -// Double windSpeed = 10.0; -// int humidity = 10; -// int visibility = 10; -// Double lon = 10.0; -// Double lat = 10.0; -// String alertDescription = "No alerts"; -// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); -// return weather; -// } -// }; -// WeatherDataAccessInterface weatherDataAccess = new WeatherDataAccessInterface() { -// @Override -// public Weather getWeather(String city) throws IOException { -// String cityName = "Toronto"; -// Double temperature = 10.0; -// String weather1 = "Cloudy"; -// String description = "Cloudy with a chance of meatballs"; -// Double windSpeed = 10.0; -// int humidity = 10; -// int visibility = 10; -// Double lon = 10.0; -// Double lat = 10.0; -// String alertDescription = "No alerts"; -// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); -// return weather; -// } -// }; -// SearchResultOutputBoundary outputBoundary = new SearchResultOutputBoundary() { -// @Override -// public void presentSuccessView(SearchResultOutputData outputData) { -// String cityName = "Toronto"; -// Double temperature = 10.0; -// String weather1 = "Cloudy"; -// String description = "Cloudy with a chance of meatballs"; -// Double windSpeed = 10.0; -// int humidity = 10; -// int visibility = 10; -// Double lon = 10.0; -// Double lat = 10.0; -// String alertDescription = "No alerts"; -// Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); -// assertEquals(weather,outputData); -// } -// -// @Override -// public void presentFailView(String errorMessage) { -// assertNull(errorMessage); -// } -// }; -// } -// -//} -// +package use_case.note; + import entity.Weather; import org.junit.Before; import org.junit.Test; @@ -186,9 +85,7 @@ public void presentFailView(String errorMessage) { } }; - SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); -// interactor.execute(inputData); - } + SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess);} private Weather createMockWeather() { String cityName = "Toronto"; From 20bcbb9f1ccd3ac3509510871c1a3ad552b079e9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 10:55:12 -0500 Subject: [PATCH 250/267] searchReturnInteractorTest --- .../note/SearchReturnInteractorTest.java | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/test/java/use_case/note/SearchReturnInteractorTest.java diff --git a/src/test/java/use_case/note/SearchReturnInteractorTest.java b/src/test/java/use_case/note/SearchReturnInteractorTest.java new file mode 100644 index 000000000..9db86f1d3 --- /dev/null +++ b/src/test/java/use_case/note/SearchReturnInteractorTest.java @@ -0,0 +1,137 @@ +package use_case.note; + +import org.junit.Before; +import org.junit.Test; +import use_case.note.search_return.*; +import entity.Weather; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class SearchReturnInteractorTest { + + private SearchReturnOutputBoundary outputBoundary; + private WeatherDataAccessInterface weatherDataAccess; + private HistoricalWeatherDataAccessInterface historicalWeatherDataAccess; + + private SearchReturnInteractor interactor; + + @Before + public void setUp() { + outputBoundary = new SearchReturnOutputBoundary() { + @Override + public void presentSuccessView(SearchReturnOutputData searchReturnOutputData) { + // Success handling implementation + } + + @Override + public void prepareFailView(String errorMessage) { + // Failure handling implementation + assertNotNull(errorMessage); + assertTrue(errorMessage.startsWith("Failed to retrieve weather data")); + } + }; + + weatherDataAccess = new WeatherDataAccessInterface() { + @Override + public Weather getWeather(String city) { + if (city.equals("Toronto")) { + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + return new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); + } + throw new RuntimeException("Failed to fetch weather data"); + } + }; + + historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override + public void saveWeather(Weather weather, String timestamp) { + // Save weather data implementation + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + return null; + } + }; + + interactor = new SearchReturnInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); + } + + @Test + public void testExecute_success() { + // Arrange + String city = "Toronto"; + SearchReturnInputData inputData = new SearchReturnInputData(city); + + // Act + interactor.execute(inputData); + + // Assert + String cityName = "Toronto"; + Double temperature = 10.0; + String weather1 = "Cloudy"; + String description = "Cloudy with a chance of meatballs"; + Double windSpeed = 10.0; + int humidity = 10; + int visibility = 10; + Double lon = 10.0; + Double lat = 10.0; + String alertDescription = "No alerts"; + Weather weather = new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); + SearchReturnOutputData outputData = new SearchReturnOutputData(weather, false); + assertEquals(10.0, outputData.getWeather().getTemperature(), 0.0); + assertEquals("Cloudy with a chance of meatballs", outputData.getWeather().getDescription()); + } + + @Test + public void testExecute_failure() { + // Arrange + historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override + public void saveWeather(Weather weather, String timestamp) throws IOException { + throw new IOException("Simulated IO Exception"); + } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + return null; + } + }; + outputBoundary = new SearchReturnOutputBoundary() { + @Override + public void presentSuccessView(SearchReturnOutputData searchReturnOutputData) { + fail("Expected failure, but success view was presented"); + } + + @Override + public void prepareFailView(String errorMessage) { + // Failure handling implementation + assertNotNull(errorMessage); + assertTrue(errorMessage.startsWith("Failed to retrieve weather data")); + } + }; + interactor = new SearchReturnInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); + String city = "Unknown City"; + SearchReturnInputData inputData = new SearchReturnInputData(city); + + // Act + try { + interactor.execute(inputData); + } catch (RuntimeException e) { + assertFalse(e.getCause() instanceof IOException); + assertEquals("Failed to fetch weather data", e.getMessage()); + } + + } +} From 711568003d3e51ca07317f4005ca18006e7f3abd Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 11:39:06 -0500 Subject: [PATCH 251/267] Ensure 100% code coverage for SearchResultInteractor and SearchREturnInteractor --- .../note/SearchResultInteractorTest.java | 23 +++++++++++++++---- .../note/SearchReturnInteractorTest.java | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index b1c1a112b..056207b20 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -4,8 +4,6 @@ import org.junit.Before; import org.junit.Test; import use_case.note.search_result.*; -import use_case.note.HistoricalWeatherDataAccessInterface; -import use_case.note.WeatherDataAccessInterface; import java.io.IOException; @@ -66,11 +64,18 @@ public void testExecuteSuccess() throws IOException { @Test public void testExecuteFailure() throws IOException { - weatherDataAccess = new WeatherDataAccessInterface() { + historicalWeatherDataAccess = new HistoricalWeatherDataAccessInterface() { + @Override - public Weather getWeather(String city) throws IOException { + public void saveWeather(Weather weather, String timestamp) throws IOException { + // No-op for testing throw new IOException("Failed to retrieve weather data"); } + + @Override + public Weather getWeather(String city, String timestamp) throws IOException { + return null; + } }; outputBoundary = new SearchResultOutputBoundary() { @@ -81,11 +86,19 @@ public void presentSuccessView(SearchResultOutputData outputData) { @Override public void presentFailView(String errorMessage) { + assertNotNull(errorMessage); assertEquals("Failed to retrieve weather data: Failed to retrieve weather data", errorMessage); } }; - SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess);} + SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, + weatherDataAccess, historicalWeatherDataAccess); + try { + interactor.execute(inputData); + } catch (RuntimeException e) { + assertEquals("Failed to retrieve weather data", e.getMessage()); + } + } private Weather createMockWeather() { String cityName = "Toronto"; diff --git a/src/test/java/use_case/note/SearchReturnInteractorTest.java b/src/test/java/use_case/note/SearchReturnInteractorTest.java index 9db86f1d3..d3db9f529 100644 --- a/src/test/java/use_case/note/SearchReturnInteractorTest.java +++ b/src/test/java/use_case/note/SearchReturnInteractorTest.java @@ -35,7 +35,7 @@ public void prepareFailView(String errorMessage) { weatherDataAccess = new WeatherDataAccessInterface() { @Override - public Weather getWeather(String city) { + public Weather getWeather(String city) throws IOException { if (city.equals("Toronto")) { String cityName = "Toronto"; Double temperature = 10.0; @@ -49,7 +49,7 @@ public Weather getWeather(String city) { String alertDescription = "No alerts"; return new Weather(cityName, temperature, weather1, description, windSpeed, humidity, visibility, lon, lat, alertDescription); } - throw new RuntimeException("Failed to fetch weather data"); + throw new IOException("Failed to fetch weather data"); } }; From d061a963a794aad1fe58ede1952a69f8ab086530 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 11:40:12 -0500 Subject: [PATCH 252/267] deleteNoteInteractorTest --- src/test/java/app/MainApplicationTest.java | 114 ------------------ .../use_case/note/NoteInteractorTest.java | 46 ------- 2 files changed, 160 deletions(-) delete mode 100644 src/test/java/app/MainApplicationTest.java delete mode 100644 src/test/java/use_case/note/NoteInteractorTest.java diff --git a/src/test/java/app/MainApplicationTest.java b/src/test/java/app/MainApplicationTest.java deleted file mode 100644 index 1e1211d5c..000000000 --- a/src/test/java/app/MainApplicationTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package app; - -import entity.User; -import org.junit.Before; -import org.junit.Test; -import use_case.note.NoteDataAccessInterface; - -import javax.swing.*; -import java.awt.*; - -import static java.lang.Thread.sleep; -import static org.junit.Assert.*; -/** - -public class MainApplicationTest { - - private JFrame app; - - @Before - public void setUp() { - - // create the data access and inject it into our builder! - final NoteDataAccessInterface noteDataAccess = new NoteDataAccessInterface() { - - private String note = "test"; - - @Override - public String saveNote(User user, String note) { - this.note = note; - return note; - } - - @Override - public String loadNote(User user) { - return note; - } - }; - - final NoteAppBuilder builder = new NoteAppBuilder(); - app = builder.addNoteDAO(noteDataAccess) - .addNoteView() - .addNoteUseCase().build(); - - app.setVisible(true); - - } - - /** - * This is an example of an end-to-end test with a mocked database. - *

The code creates the application and directly tests to see that the GUI - * is updated as expected when the buttons and UI elements are interacted with. - *

- * You can run the test to visually see what happens. - - @Test - public void testEndToEnd() { - - Component[] components = ((JPanel)app.getRootPane().getContentPane().getComponents()[0]).getComponents(); - JTextArea textArea = null; - for (Component component : components) { - if (component instanceof JTextArea) { - textArea = (JTextArea) component; - assertEquals("test", textArea.getText()); - - } - } - - textArea.setText("test test"); - - - JButton save = null; - JButton load = null; - for (Component component : components) { - if (component instanceof JPanel) { - for (Component c : ((JPanel) component).getComponents()) { - if (c instanceof JButton) { - if (save != null) { - load = (JButton) c; - } - else { - save = (JButton) c; - } - } - } - } - } - - save.doClick(); - assertEquals("test test", textArea.getText()); - textArea.setText(""); - - System.out.println("cleared text; about to refresh..."); - // pause execution for a bit so we can visually see the changes on the screen - try { - sleep(1500); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - load.doClick(); - assertEquals("test test", textArea.getText()); - - System.out.println("after refresh!"); - - // pause execution for a bit so we can visually see the changes on the screen - try { - sleep(1500); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - } -} -**/ \ No newline at end of file diff --git a/src/test/java/use_case/note/NoteInteractorTest.java b/src/test/java/use_case/note/NoteInteractorTest.java deleted file mode 100644 index a3ed466b6..000000000 --- a/src/test/java/use_case/note/NoteInteractorTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package use_case.note; - -import entity.User; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class NoteInteractorTest { - - @Test - public void testExecuteRefreshSuccess() { - - NoteDataAccessInterface noteDAO = new NoteDataAccessInterface() { - - - @Override - public String saveNote(User user, String note) { - return ""; - } - - - @Override - public String loadNote(User user) { - return "test"; - } - }; - - NoteOutputBoundary noteOB = new NoteOutputBoundary() { - @Override - public void prepareSuccessView(String message) { - assertEquals("test", message); - } - - @Override - public void prepareFailView(String errorMessage) { - fail(errorMessage); - } - }; - - NoteInteractor noteInteractor = new NoteInteractor(noteDAO, noteOB); - - noteInteractor.executeRefresh(); - - - } -} \ No newline at end of file From 48b8019ceee57fd33875ebfd809c61062b35b34a Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 11:46:16 -0500 Subject: [PATCH 253/267] delete NoteInteractorTest --- src/test/java/use_case/note/SearchResultInteractorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index 056207b20..2ddb2f34b 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -59,7 +59,6 @@ public void presentFailView(String errorMessage) { public void testExecuteSuccess() throws IOException { SearchResultInteractor interactor = new SearchResultInteractor(outputBoundary, weatherDataAccess, historicalWeatherDataAccess); interactor.execute(inputData); - interactor.execute(inputData); } @Test From 777fd29d16dbd6dc48c64cfb93393668232efa37 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sun, 1 Dec 2024 14:29:44 -0500 Subject: [PATCH 254/267] Added units to the UI --- .../note/convert_farenheit/ConvertInteractor.java | 4 ++-- .../java/view/HistoricalSearchedWeatherView.java | 3 +-- src/main/java/view/MapPanelView.java | 2 +- src/main/java/view/NearbyCitiesView.java | 2 +- src/main/java/view/WeatherPanelView.java | 14 ++++++++++---- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java index 7d73adcbd..f060153b8 100644 --- a/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java +++ b/src/main/java/use_case/note/convert_farenheit/ConvertInteractor.java @@ -1,7 +1,7 @@ package use_case.note.convert_farenheit; public class ConvertInteractor implements ConvertFarenheitInputBoundary { - public static final double KILOMETERS_MILE = 0.62; + public static final double MPS_MPH = 2.237; public static final double CELC_FAREN = 1.8; public static final double FAREN_ADD = 32; private static final int ABSOLUTEZERO = -500; @@ -34,7 +34,7 @@ public void convert(ConvertFarenheitInputData cInputData) { final int temp = (int) Math.floor(cInputData.weather.getTemperature() * CELC_FAREN + FAREN_ADD); - final int speed = (int) Math.floor(cInputData.weather.getWindSpeed() * KILOMETERS_MILE); + final int speed = (int) Math.floor(cInputData.weather.getWindSpeed() * MPS_MPH); if (cInputData.weather.getfaren() == ABSOLUTEZERO) { // set instance variables diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index dda49bd5c..c954e6633 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -39,8 +39,7 @@ public class HistoricalSearchedWeatherView extends JPanel implements PropertyCha private final JLabel windspeed = new JLabel(""); private final JLabel visibility = new JLabel(""); - public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel, - PropertyChangeEvent evt) { + public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel, PropertyChangeEvent evt) { this.searchResultViewModel = searchResultViewModel; // Users can search for weather at a given time this.searchResultViewModel.addPropertyChangeListener(this); diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index 52d6155e3..20687caa6 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -221,7 +221,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { } ); cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); - dateinputpanel = new LabelTextPanel(new JLabel("date"), dateinputfield); + dateinputpanel = new LabelTextPanel(new JLabel("date (YYYY-MM-DD hh)"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); timepanel = new LabelTextPanel(new JLabel("Time"), time); diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java index f9c91d5ec..0c25646ad 100644 --- a/src/main/java/view/NearbyCitiesView.java +++ b/src/main/java/view/NearbyCitiesView.java @@ -38,7 +38,7 @@ public NearbyCitiesView(NearbyListViewModel nearbyListViewModel, WeatherViewMode @Override public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() == 2) { - weatherController.execute(cities.getSelectedValue()); + weatherController.execute(cities.getSelectedValue().toLowerCase()); } } }); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 87448c797..e1cb38fb1 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -114,11 +114,17 @@ public void setfield(WeatherState weatherState) { } city.setText(weatherState.getWeather().getCityName()); - temp.setText(String.valueOf(weatherState.getWeather().getTemperature())); skycondition.setText(weatherState.getWeather().getWeather()); - humidity.setText(String.valueOf(weatherState.getWeather().getHumidity())); - windspeed.setText(String.valueOf(weatherState.getWeather().getWindSpeed())); - visibility.setText(String.valueOf(weatherState.getWeather().getVisibility())); + humidity.setText(weatherState.getWeather().getHumidity() + "%"); + visibility.setText(weatherState.getWeather().getVisibility() + "m"); + if (weatherState.getWeather().isMetric()) { + temp.setText(weatherState.getWeather().getTemperature() + "°C"); + windspeed.setText(weatherState.getWeather().getWindSpeed() + "m/s"); + } + else { + temp.setText(weatherState.getWeather().getTemperature() + "°F"); + windspeed.setText(weatherState.getWeather().getWindSpeed() + "mph"); + } final DateTimeFormatter formatter = DateTimeFormatter .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); final String timestamp = formatter.format(Instant.now()); From 2b39f888c31d097ef8379c986a2c70c6015e6ad9 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sun, 1 Dec 2024 14:43:03 -0500 Subject: [PATCH 255/267] Resolved conflict in MapPanelView --- src/main/java/view/MapPanelView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index b78ba324c..c05264684 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -220,10 +220,10 @@ public MapPanelView(WeatherViewModel weatherViewModel) { } } ); - cityinputpanel = new LabelTextPanel(new JLabel("search city"), cityinputfield1); - dateinputpanel = new LabelTextPanel(new JLabel("search time (YYYY-MM-DD hh"), dateinputfield); + cityinputpanel = new LabelTextPanel(new JLabel("City Name"), cityinputfield1); + dateinputpanel = new LabelTextPanel(new JLabel("Time (YYYY-MM-DD hh)"), dateinputfield); comparetopanel = new LabelTextPanel(new JLabel("Compare To"), cityinputfield2); - timepanel = new LabelTextPanel(new JLabel("Time"), time); + timepanel = new LabelTextPanel(new JLabel("Current Time"), time); dateinputfield.addActionListener( // if this event is coming from dateinput field, execute searchresult contoller From ce186c990966e1bd03790e7348a49746f95caa71 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sun, 1 Dec 2024 14:53:51 -0500 Subject: [PATCH 256/267] Changed city name in WeatherPanelView to display capitalized --- src/main/java/view/WeatherPanelView.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index e1cb38fb1..601b27792 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -113,7 +113,7 @@ public void setfield(WeatherState weatherState) { metric.setText("Imperial"); } - city.setText(weatherState.getWeather().getCityName()); + city.setText(capitalizeCity(weatherState.getWeather().getCityName())); skycondition.setText(weatherState.getWeather().getWeather()); humidity.setText(weatherState.getWeather().getHumidity() + "%"); visibility.setText(weatherState.getWeather().getVisibility() + "m"); @@ -131,6 +131,16 @@ public void setfield(WeatherState weatherState) { time.setText(timestamp); } + private String capitalizeCity(String cityName) { + final String[] split = cityName.split(" "); + final StringBuilder output = new StringBuilder(); + for (String part : split) { + output.append(part.substring(0, 1).toUpperCase()) + .append(part.substring(1).toLowerCase()).append(" "); + } + return output.toString().trim(); + } + public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); From 0466284485292aa6ddce46aaa6a76a1698325edc Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sun, 1 Dec 2024 15:12:42 -0500 Subject: [PATCH 257/267] Figured it'd be better to capitalize the inputs instead of the output so did that instead --- .../search_result/SearchResultInteractor.java | 2 +- src/main/java/view/MapPanelView.java | 16 +++++++++++++--- src/main/java/view/NearbyCitiesView.java | 2 +- src/main/java/view/WeatherPanelView.java | 12 +----------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java index e3f55a139..123f42391 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -28,7 +28,7 @@ public void execute(SearchResultInputData searchReturnInputData) { final String city = searchReturnInputData.getCity(); final String timestamp = searchReturnInputData.getDate(); - final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city.toLowerCase(), timestamp); + final Weather historicalWeather = historicalWeatherDataAccessInterface.getWeather(city, timestamp); // Send it to the output boundary final SearchResultOutputData outputData = diff --git a/src/main/java/view/MapPanelView.java b/src/main/java/view/MapPanelView.java index c05264684..47467822c 100644 --- a/src/main/java/view/MapPanelView.java +++ b/src/main/java/view/MapPanelView.java @@ -193,7 +193,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { event -> { // if the event is coming from cityinput field, execute weather controller, check if empty if (event.getSource() == cityinputfield1 && cityinputfield1.getText().length() > 0) { - weatherController.execute(cityinputfield1.getText().toLowerCase()); + weatherController.execute(capitalizeCity(cityinputfield1.getText())); cityinputfield1.setText(""); final DateTimeFormatter formatter = DateTimeFormatter .ofPattern("yyyy-MM-dd HH").withZone(ZoneOffset.UTC); @@ -211,7 +211,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { if (cityinputfield1.getText().length() > 0 && cityinputfield2.getText().length() > 0) { // some how the view model doesn't get update - compareCitiesController.execute(cityinputfield1.getText(), cityinputfield2.getText()); + compareCitiesController.execute(capitalizeCity(cityinputfield1.getText()), capitalizeCity(cityinputfield2.getText())); new CompareCitiesView(this.compareCitiesViewModel); } @@ -230,7 +230,7 @@ public MapPanelView(WeatherViewModel weatherViewModel) { event -> { if (event.getSource() == dateinputfield) { searchResultController - .execute(cityinputfield1.getText().toLowerCase(), dateinputfield.getText()); + .execute(capitalizeCity(cityinputfield1.getText()), dateinputfield.getText()); cityinputfield1.setText(""); dateinputfield.setText(""); } @@ -246,6 +246,16 @@ public MapPanelView(WeatherViewModel weatherViewModel) { } + private String capitalizeCity(String cityName) { + final String[] split = cityName.split(" "); + final StringBuilder output = new StringBuilder(); + for (String part : split) { + output.append(part.substring(0, 1).toUpperCase()) + .append(part.substring(1).toLowerCase()).append(" "); + } + return output.toString().trim(); + } + @Override /* * prints a message to the console when an action event occurs. Will look something like "Enter city name" diff --git a/src/main/java/view/NearbyCitiesView.java b/src/main/java/view/NearbyCitiesView.java index 0c25646ad..f9c91d5ec 100644 --- a/src/main/java/view/NearbyCitiesView.java +++ b/src/main/java/view/NearbyCitiesView.java @@ -38,7 +38,7 @@ public NearbyCitiesView(NearbyListViewModel nearbyListViewModel, WeatherViewMode @Override public void mouseClicked(MouseEvent evt) { if (evt.getClickCount() == 2) { - weatherController.execute(cities.getSelectedValue().toLowerCase()); + weatherController.execute(cities.getSelectedValue()); } } }); diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index 601b27792..e1cb38fb1 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -113,7 +113,7 @@ public void setfield(WeatherState weatherState) { metric.setText("Imperial"); } - city.setText(capitalizeCity(weatherState.getWeather().getCityName())); + city.setText(weatherState.getWeather().getCityName()); skycondition.setText(weatherState.getWeather().getWeather()); humidity.setText(weatherState.getWeather().getHumidity() + "%"); visibility.setText(weatherState.getWeather().getVisibility() + "m"); @@ -131,16 +131,6 @@ public void setfield(WeatherState weatherState) { time.setText(timestamp); } - private String capitalizeCity(String cityName) { - final String[] split = cityName.split(" "); - final StringBuilder output = new StringBuilder(); - for (String part : split) { - output.append(part.substring(0, 1).toUpperCase()) - .append(part.substring(1).toLowerCase()).append(" "); - } - return output.toString().trim(); - } - public void actionPerformed(ActionEvent event) { System.out.println("Enter" + event.getActionCommand()); From a49e43751580b6858bab0ae3ab79da2d0959eff0 Mon Sep 17 00:00:00 2001 From: harman Date: Sun, 1 Dec 2024 16:51:42 -0500 Subject: [PATCH 258/267] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a8e1e20f..c76f09b95 100644 --- a/README.md +++ b/README.md @@ -72,4 +72,4 @@ The project aims to be accessible to everyone as much as possible and thus has s ## Want to know more? If you would like to know more please check out our presentation. -[Link to the Presentation](https://docs.google.com/presentation/d/1IjYeUM8Xk1bz7U48yP0Gn7wzcsYZ_4zVC14HXEVRnKU/edit?usp=sharing) +[Link to the Presentation](https://docs.google.com/presentation/d/1UF4Ibt3WqdovrlT1XoJV6r2-A5ybwz8jJzVqMy94D5k/edit?usp=sharing) From cd5fb5e605cd7bb96a5d2daa3b397be4735af33c Mon Sep 17 00:00:00 2001 From: harman Date: Sun, 1 Dec 2024 16:57:36 -0500 Subject: [PATCH 259/267] Update README.md From 5a3671ded1640fe295968795cc44cfe620dca3f9 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 17:12:58 -0500 Subject: [PATCH 260/267] fixing bug for the output of humidity --- src/main/java/view/HistoricalSearchedWeatherView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index c954e6633..577daf06e 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -73,7 +73,7 @@ public void propertyChange(PropertyChangeEvent evt) { city.setText(state.getWeather().getCityName()); temp.setText(String.valueOf(state.getWeather().getTemperature())); skycondition.setText(state.getWeather().getWeather()); - humidity.setText(String.valueOf(state.getWeather().getHumidity())); + humidity.setText(Math.abs(state.getWeather().getHumidity()) + "%"); windspeed.setText(String.valueOf(state.getWeather().getWindSpeed())); visibility.setText(String.valueOf(state.getWeather().getVisibility())); } From 3c0f73ab67d812d3df74eb16d94ccb8815354183 Mon Sep 17 00:00:00 2001 From: sophie Date: Sun, 1 Dec 2024 14:13:17 -0800 Subject: [PATCH 261/267] 100% coverage in CompareCitiesTest2 --- .../InMemoryUserDataAccessObject.java | 35 ++-- .../CompareCitiesInteractor.java | 22 +-- src/main/java/view/MapImagepanel.java | 2 +- .../note/CompareCitiesInteractorTest.java | 60 +++++- .../note/CompareCitiesInteractorTest2.java | 177 ++++++++++++++++++ 5 files changed, 257 insertions(+), 39 deletions(-) create mode 100644 src/test/java/use_case/note/CompareCitiesInteractorTest2.java diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java index 0ed6beebb..94e4f183d 100644 --- a/src/main/java/data_access/InMemoryUserDataAccessObject.java +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -1,9 +1,11 @@ package data_access; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import entity.Weather; +import org.json.JSONException; import use_case.note.CompareCities.CompareCitiesDataAccessInterface; /** @@ -14,27 +16,26 @@ public class InMemoryUserDataAccessObject implements CompareCitiesDataAccessInte private final Map weathers = new HashMap<>(); @Override - public boolean isCityExist(String identifier) { - return weathers.containsKey(identifier); + public Weather getWeather(String identifier) throws IOException { + if ("Toronto".equalsIgnoreCase(identifier)) { + final Weather torontoweather = new Weather("Toronto", 10.5, "rain", + "first description", 0.0, 1, 2, 3.0, 4.0, "No alerts"); + return torontoweather; + } + else if ("Tokyo".equalsIgnoreCase(identifier)) { + final Weather tokyoweather = new Weather("Tokyo", 1.0, "cloud", "second description", + 2.0, 2, 1000, 20.0, 25.0, "Alerts"); + return tokyoweather; + } + throw new IOException("Failed to fetch weather data"); } @Override - public Weather getWeather(String identifier) { - if (isCityExist(identifier)) { - if ("Toronto".equalsIgnoreCase(identifier)) { - final Weather torontoweather = new Weather("Toronto", 10.5, "rain", - null, 0, 1, 1, 1, 1, null); - return torontoweather; - } - else { - final Weather tokyoweather = new Weather("Tokyo", 1.0, "cloud", null, - 2, 2, 2, 2, 2, null); - return tokyoweather; - } - } - else { - return null; + public boolean isCityExist(String cityname){ + if (cityname.equals("Toronto")||cityname.equals("Tokyo")){ + return true; } + return false; } @Override diff --git a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java index eb7ce39bc..e0c7485b5 100644 --- a/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java +++ b/src/main/java/use_case/note/CompareCities/CompareCitiesInteractor.java @@ -38,26 +38,20 @@ public void execute(CompareCitiesInputData compareCitiesInputData) { try { final Weather firstweather = compareCitiesDataAccessInterface.getWeather(firstcityname); compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); - } - catch (IOException ioException) { - comparecitiesPresenter.prepareFailView(ioException.getMessage()); - } - try { final Weather secondweather = compareCitiesDataAccessInterface.getWeather(secondcityname); compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(firstcityname), + secondcityname, + (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(secondcityname), false); + comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); + // After each round of execution, clear map in DAO. + compareCitiesDataAccessInterface.clearcitytoweather(); } catch (IOException ioException) { - comparecitiesPresenter.prepareFailView(ioException.getMessage()); + comparecitiesPresenter.prepareFailView("Network error while fetching weather data for " + firstcityname + secondcityname); } - - final CompareCitiesOutPutData compareCitiesOutPutData = new CompareCitiesOutPutData(firstcityname, - (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(firstcityname), - secondcityname, - (Weather) compareCitiesDataAccessInterface.getcitytoweather().get(secondcityname), false); - comparecitiesPresenter.prepareSuccessView(compareCitiesOutPutData); - // After each round of execution, clear map in DAO. - compareCitiesDataAccessInterface.clearcitytoweather(); } } } diff --git a/src/main/java/view/MapImagepanel.java b/src/main/java/view/MapImagepanel.java index 16520d647..14bead688 100644 --- a/src/main/java/view/MapImagepanel.java +++ b/src/main/java/view/MapImagepanel.java @@ -9,6 +9,7 @@ import org.jxmapviewer.viewer.TileFactoryInfo; import javax.swing.*; +import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.time.Instant; @@ -44,7 +45,6 @@ public MapImagepanel(WeatherViewModel weatherViewModel, double latitude, double this.mapViewer.setZoom(ZOOM_VALUE); mapViewer.setAddressLocation(position); - } @Override diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest.java b/src/test/java/use_case/note/CompareCitiesInteractorTest.java index f1cfe9cee..edbc77c05 100644 --- a/src/test/java/use_case/note/CompareCitiesInteractorTest.java +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest.java @@ -12,34 +12,80 @@ import static org.junit.Assert.fail; public class CompareCitiesInteractorTest { + private CompareCitiesOutputBoundary presenter; + private CompareCitiesDataAccessInterface compareCitiesDataAccessInterface; @Test public void successTest() { // this is the mock input data. final CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Tokyo"); - final CompareCitiesDataAccessInterface compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); + compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); - CompareCitiesOutputBoundary SuccessPresenter = new CompareCitiesOutputBoundary() { + presenter = new CompareCitiesOutputBoundary() { // make a presenter @Override public void prepareSuccessView(CompareCitiesOutPutData outputData) { Assertions.assertEquals("Toronto", outputData.getFirstCityname()); - Assertions.assertEquals(10.5, outputData.getSecondWeather().getTemperature()); + Assertions.assertEquals(1.0, outputData.getSecondWeather().getTemperature()); Assertions.assertEquals("Tokyo", outputData.getSecondCityname()); - Assertions.assertEquals(0, outputData.getSecondWeather().getHumidity()); + Assertions.assertEquals(2, outputData.getSecondWeather().getHumidity()); } @Override public void prepareFailView(String errorMessage) { - Assertions.fail("Use case failure is unexpected."); + Assertions.fail("city not found"); } - } + }; - final CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, SuccessPresenter); + CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, presenter); interactor.execute(inputData); } + @Test + public void successexecuteTest () { + CompareCitiesInputData inputdata = new CompareCitiesInputData("Toronto", "Tokyo"); + compareCitiesDataAccessInterface = new InMemoryUserDataAccessObject(); + String firstcityName = "Toronto"; + Double firsttemperature = 10.5; + String firstsky = "rain"; + String firstdescription = "first description"; + Double firstwindSpeed = 0.0; + int firsthumidity = 1; + int firstvisibility = 2; + Double firstlon = 3.0; + Double firstlat = 4.0; + String firstalertDescription = "No alerts"; + + Weather firstweather = new Weather(firstcityName, firsttemperature, firstsky,firstdescription, firstwindSpeed, firsthumidity, firstvisibility, firstlon, firstlat, firstalertDescription); + compareCitiesDataAccessInterface.saveWeatherinfor(firstweather); + String secondcityName = "Tokyo"; + Double secondtemperature = 1.0; + String secondsky = "cloud"; + String seconddescription = "second description"; + Double secondwindSpeed = 2.0; + int secondhumidity = 2; + int secondvisibility = 1000; + Double secondlon = 20.0; + Double secondlat = 25.0; + String secondalertDescription = "Alerts"; + Weather secondweather = new Weather(secondcityName, secondtemperature, secondsky, seconddescription, secondwindSpeed, secondhumidity, secondvisibility, secondlon, secondlat, secondalertDescription); + compareCitiesDataAccessInterface.saveWeatherinfor(secondweather); + } + + @Test + public void testExecute_SameCityComparison() { + // Arrange + CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Toronto"); + + // Act + CompareCitiesInputBoundary interactor = new CompareCitiesInteractor(compareCitiesDataAccessInterface, presenter); + interactor.execute(inputData); + + // Assert + presenter.prepareFailView("Cannot compare the same city"); + } } + // //// Weather weather1 = compareCitiesDataAccessInterface.getWeather(inputData.getFirstcityname()); //// compareCitiesDataAccessInterface.saveWeatherinfor(weather1); diff --git a/src/test/java/use_case/note/CompareCitiesInteractorTest2.java b/src/test/java/use_case/note/CompareCitiesInteractorTest2.java new file mode 100644 index 000000000..617622a28 --- /dev/null +++ b/src/test/java/use_case/note/CompareCitiesInteractorTest2.java @@ -0,0 +1,177 @@ +package use_case.note; + +import data_access.InMemoryUserDataAccessObject; // Replace with the correct package if different +import data_access.WeatherDataAccessObject; +import entity.Weather; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; +import use_case.note.CompareCities.*; + +import java.io.IOException; + +class CompareCitiesInteractorTest2 { + + @Test + public void testSuccessComparison() { + // Arrange + CompareCitiesDataAccessInterface dao = new InMemoryUserDataAccessObject(); + + // Add mock weather data directly into the DAO + dao.saveWeatherinfor(new Weather("Toronto", 10.5, "Clear", "Sunny", 5.0, 50, 1000, -79.38, 43.65, "No alerts")); + dao.saveWeatherinfor(new Weather("Tokyo", 15.0, "Cloudy", "Overcast", 3.0, 70, 800, 139.69, 35.69, "No alerts")); + + CompareCitiesOutputBoundary presenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + assertEquals("Toronto", outputData.getFirstCityname()); + assertEquals(10.5, outputData.getFirstWeather().getTemperature(), 0.01); + assertEquals("Tokyo", outputData.getSecondCityname()); + assertEquals(1.0, outputData.getSecondWeather().getTemperature(), 0.01); + } + + @Override + public void prepareFailView(String errorMessage) { + fail("Unexpected failure: " + errorMessage); + } + }; + + CompareCitiesInteractor interactor = new CompareCitiesInteractor(dao, presenter); + CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Tokyo"); + + // Act + interactor.execute(inputData); + } + + @Test + public void testSameCityComparison() { + // Arrange + CompareCitiesDataAccessInterface dao = new InMemoryUserDataAccessObject(); + + CompareCitiesOutputBoundary presenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + fail("Comparison of the same city should fail."); + } + + @Override + public void prepareFailView(String errorMessage) { + assertEquals("Cannot compare the same city", errorMessage); + } + }; + + CompareCitiesInteractor interactor = new CompareCitiesInteractor(dao, presenter); + CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Toronto"); + + // Act + interactor.execute(inputData); + } + + @Test + public void testCityNotFound1() { + // Arrange + CompareCitiesDataAccessInterface dao = new InMemoryUserDataAccessObject(); + + CompareCitiesOutputBoundary presenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + fail("City not found should fail."); + } + + @Override + public void prepareFailView(String errorMessage) { + assertEquals("city not found", errorMessage); + } + }; + + + CompareCitiesInteractor interactor = new CompareCitiesInteractor(dao, presenter); + CompareCitiesInputData inputData = new CompareCitiesInputData("NonExistentCity", "Tokyo"); + + // Act + try { + interactor.execute(inputData); + } + catch (RuntimeException e) { + assertFalse(e.getCause() instanceof IOException); + assertEquals("Failed to fetch weather data", e.getMessage()); + } + } + @Test + public void testCityNotFound2() { + // Arrange + CompareCitiesDataAccessInterface dao = new InMemoryUserDataAccessObject(); + + CompareCitiesOutputBoundary presenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + fail("City not found should fail."); + } + + @Override + public void prepareFailView(String errorMessage) { + assertEquals("city not found", errorMessage); + } + }; + + + CompareCitiesInteractor interactor = new CompareCitiesInteractor(dao, presenter); + CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "randomcity"); + + // Act + try { + interactor.execute(inputData); + } + catch (RuntimeException e) { + assertFalse(e.getCause() instanceof IOException); + assertEquals("Failed to fetch weather data", e.getMessage()); + } + + } + + @Test + public void testIOExceptionHandlingForBothCities() { + // Custom DAO that throws IOException for both cities + CompareCitiesDataAccessInterface dao = new InMemoryUserDataAccessObject() { + @Override + public Weather getWeather(String cityName) throws IOException { + throw new IOException("Network error while fetching weather data for " + cityName); + } + }; + + CompareCitiesOutputBoundary presenter = new CompareCitiesOutputBoundary() { + @Override + public void prepareSuccessView(CompareCitiesOutPutData outputData) { + fail("IOException should result in failure, not success."); + } + + @Override + public void prepareFailView(String errorMessage) { + // Check if the error message is the same for the first city + if (errorMessage.contains("Toronto")) { + assertTrue(errorMessage.contains("Network error while fetching weather data for Toronto")); + } + // Check if the error message is the same for the second city + else if (errorMessage.contains("Tokyo")) { + assertTrue(errorMessage.contains("Network error while fetching weather data for Tokyo")); + } else { + fail("Unexpected error message: " + errorMessage); + } + } + }; + + CompareCitiesInteractor interactor = new CompareCitiesInteractor(dao, presenter); + CompareCitiesInputData inputData = new CompareCitiesInputData("Toronto", "Tokyo"); + + // Act + try { + interactor.execute(inputData); + } + catch (RuntimeException e) { + assertFalse(e.getCause() instanceof IOException); + } + } +} \ No newline at end of file From 7f9a38b3e7111201171a3ba08f964281989c4e80 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 17:23:19 -0500 Subject: [PATCH 262/267] add units --- src/main/java/view/HistoricalSearchedWeatherView.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 577daf06e..164dfce3d 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -71,11 +71,12 @@ public void propertyChange(PropertyChangeEvent evt) { final SearchResultState state = (SearchResultState) evt.getNewValue(); city.setText(state.getWeather().getCityName()); - temp.setText(String.valueOf(state.getWeather().getTemperature())); + temp.setText(state.getWeather().getTemperature() + "°C"); skycondition.setText(state.getWeather().getWeather()); humidity.setText(Math.abs(state.getWeather().getHumidity()) + "%"); - windspeed.setText(String.valueOf(state.getWeather().getWindSpeed())); - visibility.setText(String.valueOf(state.getWeather().getVisibility())); + windspeed.setText(state.getWeather().getWindSpeed() + " m/s"); + visibility.setText(state.getWeather().getVisibility() + " m"); + } } From 3f64328c989fd4433bcabdd57fdacdff6e451743 Mon Sep 17 00:00:00 2001 From: Ishayu Sharma Date: Sun, 1 Dec 2024 18:11:04 -0500 Subject: [PATCH 263/267] Added colons to the UI cuz they're neat --- .../view/HistoricalSearchedWeatherView.java | 18 ++++++++---------- src/main/java/view/WeatherPanelView.java | 8 ++++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/view/HistoricalSearchedWeatherView.java b/src/main/java/view/HistoricalSearchedWeatherView.java index 164dfce3d..9fe85699f 100644 --- a/src/main/java/view/HistoricalSearchedWeatherView.java +++ b/src/main/java/view/HistoricalSearchedWeatherView.java @@ -45,14 +45,13 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.searchResultViewModel.addPropertyChangeListener(this); this.setSize(HISTORICALPANELWIDTH, HISTORICALPANELHEIGHT); - weatherfincitypanel = new LabelTextPanel(new JLabel("Searched Weather"), emptylabel); - temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); + weatherfincitypanel = new LabelTextPanel(new JLabel("Historic Weather in: "), city); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature: "), temp); // Note we want to add a convertor here.The button needs an action listener. - citypanel = new LabelTextPanel(new JLabel("City"), city); - skyconditionpanel = new LabelTextPanel(new JLabel("Sky"), skycondition); - humiditypanel = new LabelTextPanel(new JLabel("Humidity"), humidity); - windspeedpanel = new LabelTextPanel(new JLabel("Wind"), windspeed); - visibilitypanel = new LabelTextPanel(new JLabel("Visibility"), visibility); + skyconditionpanel = new LabelTextPanel(new JLabel("Sky: "), skycondition); + humiditypanel = new LabelTextPanel(new JLabel("Humidity: "), humidity); + windspeedpanel = new LabelTextPanel(new JLabel("Wind: "), windspeed); + visibilitypanel = new LabelTextPanel(new JLabel("Visibility: "), visibility); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(weatherfincitypanel); this.add(temperaturepanel); @@ -60,7 +59,6 @@ public HistoricalSearchedWeatherView(SearchResultViewModel searchResultViewModel this.add(humiditypanel); this.add(windspeedpanel); this.add(visibilitypanel); - this.add(citypanel); } @Override @@ -74,8 +72,8 @@ public void propertyChange(PropertyChangeEvent evt) { temp.setText(state.getWeather().getTemperature() + "°C"); skycondition.setText(state.getWeather().getWeather()); humidity.setText(Math.abs(state.getWeather().getHumidity()) + "%"); - windspeed.setText(state.getWeather().getWindSpeed() + " m/s"); - visibility.setText(state.getWeather().getVisibility() + " m"); + windspeed.setText(state.getWeather().getWindSpeed() + "m/s"); + visibility.setText(state.getWeather().getVisibility() + "m"); } diff --git a/src/main/java/view/WeatherPanelView.java b/src/main/java/view/WeatherPanelView.java index e1cb38fb1..89c63c739 100644 --- a/src/main/java/view/WeatherPanelView.java +++ b/src/main/java/view/WeatherPanelView.java @@ -60,9 +60,9 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent e this.weatherViewModel.addPropertyChangeListener(this); this.setSize(WEATHER_PANEL_WIDTH, WEATHERPANELHEIGHT); - weatherincitypanel = new LabelTextPanel(new JLabel("Current Weather in"), city); - temperaturepanel = new LabelTextPanel(new JLabel("Temperature"), temp); - timepanel = new LabelTextPanel(new JLabel("Time"), time); + weatherincitypanel = new LabelTextPanel(new JLabel("Current Weather in: "), city); + temperaturepanel = new LabelTextPanel(new JLabel("Temperature: "), temp); + timepanel = new LabelTextPanel(new JLabel("Time: "), time); // Note we want to add a convertor that convert the weather information from degree celsius to fahrenheit, // or the opposite.The button needs an action listener that pass the change to a ConverterController. this.unitconverter = new JButton("Unit Converter"); @@ -80,7 +80,7 @@ public WeatherPanelView(WeatherViewModel weatherViewModel, PropertyChangeEvent e } }); - unitpanel = new LabelTextPanel(new JLabel("Unit"), metric); + unitpanel = new LabelTextPanel(new JLabel("Unit: "), metric); skyconditionpanel = new LabelTextPanel(new JLabel("Sky: "), skycondition); humiditypanel = new LabelTextPanel(new JLabel("Humidity: "), humidity); windspeedpanel = new LabelTextPanel(new JLabel("Wind: "), windspeed); From eac265d2ff76773a7a205715b4822ea99b3daf5b Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 18:35:49 -0500 Subject: [PATCH 264/267] fixing bugs of value inconsistency --- .../HistoricalWeatherDataAccessObject.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index b08826c76..2d8b8c57e 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -31,14 +31,16 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { jsonBuilder .append("{\n") .append(" \"timeStamp\": \"").append(timeStamp).append("\",\n") + .append(" \"description\": \"").append(weather.getDescription()).append("\",\n") .append(" \"city\": \"").append(weather.getCityName()).append("\",\n") .append(" \"longitude\": ").append(weather.getLon()).append(",\n") .append(" \"latitude\": ").append(weather.getLat()).append(",\n") .append(" \"temperature\": ").append(weather.getTemperature()).append(",\n") .append(" \"looks\": \"").append(weather.getWeather()).append("\",\n") - .append(" \"alertDescription\": \"").append(weather.getDescription()).append("\",\n") + .append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append("\",\n") .append(" \"humidity\": ").append(weather.getHumidity()).append(",\n") - .append(" \"windSpeed\": ").append(weather.getWindSpeed()).append("\n") + .append(" \"windSpeed\": ").append(weather.getWindSpeed()).append(",\n") + .append(" \"visibility\": ").append(weather.getVisibility()).append("\n") .append("}"); final String json = jsonBuilder.toString(); @@ -48,15 +50,16 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { // Write JSON to a file - String relativePath = "src/main/resources/weather.json"; - File file = new File(relativePath); + final String relativePath = "src/main/resources/weather.json"; + final File file = new File(relativePath); try { StringBuilder finalJson = new StringBuilder(); if (!file.exists() || file.length() == 0) { // If file does not exist or is empty, create a new JSON array finalJson.append("[\n").append(weatherJson).append("\n]"); - } else { + } + else { // Read existing data from the file String existingJson = Files.readString(file.toPath(), StandardCharsets.UTF_8); @@ -87,7 +90,7 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Read the JSON from the file final String filePath = "weather.json"; try { - URL resource = getClass().getClassLoader().getResource("weather.json"); + final URL resource = getClass().getClassLoader().getResource(filePath); if (resource == null) { throw new FileNotFoundException("File not found: src/main/resources/weather.json"); } @@ -96,8 +99,6 @@ public Weather getWeather(String city, String timestamp) throws IOException { final String jsonString = Files.readString(Paths.get(resource.toURI()), StandardCharsets.UTF_8); final JSONArray weatherArray = new JSONArray(jsonString); -// final JSONArray weatherArray = weatherObject1.getJSONArray("weatherData"); - for (int i = 0; i < weatherArray.length(); i++) { // Getting the JSONObject at the index i final JSONObject weatherObject = weatherArray.getJSONObject(i); @@ -108,16 +109,14 @@ public Weather getWeather(String city, String timestamp) throws IOException { // Checking if the city and timestamp match the input if (cityNameCall.equals(city) && timeStamp.equals(timestamp)) { // Create weather object - //TODO: Changed weather declaration, uncertain if it there is key "description" and - // "alertDescription" for historical weather. If no we need to change Weather class. final Weather weather = new Weather( cityNameCall, weatherObject.getInt("temperature"), weatherObject.getString("looks"), - weatherObject.getString("alertDescription"), + weatherObject.getString("description"), weatherObject.getInt("windSpeed"), - weatherObject.getInt("longitude"), weatherObject.getInt("humidity"), + weatherObject.getInt("visibility"), weatherObject.getInt("longitude"), weatherObject.getInt("latitude"), weatherObject.getString("alertDescription") From cd85feacbd0810dccc364b47be26b1d6a5c7d878 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 18:42:34 -0500 Subject: [PATCH 265/267] fixing checkstyle issues --- .../HistoricalWeatherDataAccessObject.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java index 2d8b8c57e..1515229d5 100644 --- a/src/main/java/data_access/HistoricalWeatherDataAccessObject.java +++ b/src/main/java/data_access/HistoricalWeatherDataAccessObject.java @@ -1,7 +1,7 @@ package data_access; -import java.io.*; - +import java.io.File; +import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.net.URISyntaxException; @@ -9,7 +9,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Objects; import org.json.JSONArray; import org.json.JSONObject; @@ -26,25 +25,24 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { // Save the weather data to the database // Convert the Weather object to JSON -// final String nextLine = "\",\n"; - StringBuilder jsonBuilder = new StringBuilder(); + final StringBuilder jsonBuilder = new StringBuilder(); + final String format = "\",\n"; + final String format4 = ",\n"; jsonBuilder .append("{\n") - .append(" \"timeStamp\": \"").append(timeStamp).append("\",\n") - .append(" \"description\": \"").append(weather.getDescription()).append("\",\n") - .append(" \"city\": \"").append(weather.getCityName()).append("\",\n") - .append(" \"longitude\": ").append(weather.getLon()).append(",\n") - .append(" \"latitude\": ").append(weather.getLat()).append(",\n") - .append(" \"temperature\": ").append(weather.getTemperature()).append(",\n") - .append(" \"looks\": \"").append(weather.getWeather()).append("\",\n") - .append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append("\",\n") - .append(" \"humidity\": ").append(weather.getHumidity()).append(",\n") - .append(" \"windSpeed\": ").append(weather.getWindSpeed()).append(",\n") + .append(" \"timeStamp\": \"").append(timeStamp).append(format) + .append(" \"description\": \"").append(weather.getDescription()).append(format) + .append(" \"city\": \"").append(weather.getCityName()).append(format) + .append(" \"longitude\": ").append(weather.getLon()).append(format4) + .append(" \"latitude\": ").append(weather.getLat()).append(format4) + .append(" \"temperature\": ").append(weather.getTemperature()).append(format4) + .append(" \"looks\": \"").append(weather.getWeather()).append(format) + .append(" \"alertDescription\": \"").append(weather.getAlertDescription()).append(format) + .append(" \"humidity\": ").append(weather.getHumidity()).append(format4) + .append(" \"windSpeed\": ").append(weather.getWindSpeed()).append(format4) .append(" \"visibility\": ").append(weather.getVisibility()).append("\n") .append("}"); - final String json = jsonBuilder.toString(); - // Convert StringBuilder to String final String weatherJson = jsonBuilder.toString(); @@ -54,7 +52,7 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { final File file = new File(relativePath); try { - StringBuilder finalJson = new StringBuilder(); + final StringBuilder finalJson = new StringBuilder(); if (!file.exists() || file.length() == 0) { // If file does not exist or is empty, create a new JSON array finalJson.append("[\n").append(weatherJson).append("\n]"); @@ -78,7 +76,8 @@ public void saveWeather(Weather weather, String timeStamp) throws IOException { fileWriter.write(finalJson.toString()); System.out.println("Successfully appended weather data to weather.json"); } - } catch (IOException excep) { + } + catch (IOException excep) { excep.printStackTrace(); System.out.println("Failed to append weather data to weather.json"); } From e829917fe437178803abc5e327cb3b8f34bea07a Mon Sep 17 00:00:00 2001 From: linhaoli Date: Sun, 1 Dec 2024 22:19:30 -0500 Subject: [PATCH 266/267] removed redundant saving --- .../java/use_case/note/search_result/SearchResultInteractor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/use_case/note/search_result/SearchResultInteractor.java b/src/main/java/use_case/note/search_result/SearchResultInteractor.java index 123f42391..335f99b80 100644 --- a/src/main/java/use_case/note/search_result/SearchResultInteractor.java +++ b/src/main/java/use_case/note/search_result/SearchResultInteractor.java @@ -33,7 +33,6 @@ public void execute(SearchResultInputData searchReturnInputData) { // Send it to the output boundary final SearchResultOutputData outputData = new SearchResultOutputData(historicalWeather, false); - historicalWeatherDataAccessInterface.saveWeather(historicalWeather, timestamp); outputBoundary.presentSuccessView(outputData); } From 764ba42a00ec63ffd2be21753b37413d8caa0dc4 Mon Sep 17 00:00:00 2001 From: linhaoli Date: Tue, 3 Dec 2024 16:14:12 -0500 Subject: [PATCH 267/267] searchResultInteractorTest --- src/test/java/use_case/note/SearchResultInteractorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/use_case/note/SearchResultInteractorTest.java b/src/test/java/use_case/note/SearchResultInteractorTest.java index 2ddb2f34b..1450f0189 100644 --- a/src/test/java/use_case/note/SearchResultInteractorTest.java +++ b/src/test/java/use_case/note/SearchResultInteractorTest.java @@ -73,7 +73,7 @@ public void saveWeather(Weather weather, String timestamp) throws IOException { @Override public Weather getWeather(String city, String timestamp) throws IOException { - return null; + throw new IOException("Failed to retrieve weather data"); } };