Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI test #18

Merged
merged 9 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions doc/ManualUI.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
= Manual UI

Manual UI testing is essential for modern applications. User experience and interface presentation are crucial factors when choosing applications among dozens of similar options available to users.

Running the application was the first test, during which we needed to identify UI issues such as disallowed or unclear instructions and ambiguous user interactions.

After the initial testing, we discovered 5 major issues that needed fixing.

== Data type error

Input values were added to a list without validation, with no restrictions on characters. To fix this, we updated the function that handles input parameters to only accept allowed names. The updated function restricts inputs to only include lowercase and uppercase letters (A-Z) and numbers, excluding whitespace.

image::pictures/typeError.png[width=250]

== Field widths

There were no restrictions on the length of input values (player name), allowing names of any length to be added to the player list. To fix this, we introduced an additional check to ensure that player names can be a maximum of 10 characters long.

image::pictures/unlimitedChars.png[width=250]

== Navigational elements

During application runtime, there was no option to exit because it used full-screen mode without an exit or close button. To implement an exit option, we created a CloseButton class, accessible from the main menu and during gameplay, allowing the application to be closed at any time.

image::pictures/exitInMenu.png[width=400]

image::pictures/exitGame.png[width=400]

== Error logging

The application did not properly log information or errors. To fix this, we introduced Loggers using the _java.util.logging.Logger_ class, which logs all significant events. Several classes were modified to incorporate this logging functionality.

== Menu items

In the main menu, the _Start_ button was always clickable, even when no map was selected or there weren't enough players. Instructions for the user were unclear about what needed to be completed to start the game. To improve clarity in user interaction, the _Start_ button in the main menu is now only clickable when the conditions required to start the game are met (map selected, sufficient players).

image::pictures/waiting.png[alt="Waiting for a player",width=500]

== Summary

The user interface is a critical aspect of the application. In our application, there were no security risks, and the goal was merely to enhance the user experience. Finding the issues is easy, but often it is challenging to determine how to fix them.
Binary file added doc/pictures/exitGame.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/pictures/exitInMenu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/pictures/typeError.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/pictures/unlimitedChars.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/pictures/waiting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/macaroni/actions/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@
import macaroni.model.element.Element;
import macaroni.model.element.Pipe;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Felhasználói interakciók kezelésére használt osztály.
*/
public abstract class Action {

// Logger inicializálása
private static final Logger LOGGER = Logger.getLogger(Action.class.getName());

/**
* Minden esetben hamissal tér vissza.
*
* @param element az elem, amin action-t szeretnénk végezni.
* @return Minden esetben hamissal tér vissza.
*/
public boolean doAction(Element element) {
log("doAction(Element) metódus meghívása");
return false;
}

Expand All @@ -24,6 +31,16 @@ public boolean doAction(Element element) {
* @param pipe a cső, amin action-t szeretnénk végezni.
*/
public boolean doAction(Pipe pipe) {
log("doAction(Pipe) metódus meghívása");
return doAction((Element) pipe);
}

/**
* Logolás készítése.
*
* @param message a logolandó üzenet
*/
private void log(String message) {
LOGGER.log(Level.INFO, message);
}
}
7 changes: 5 additions & 2 deletions src/macaroni/actions/DetachPipeAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import macaroni.model.element.ActiveElement;
import macaroni.model.element.Pipe;
import macaroni.views.PipeView;
import java.util.logging.Logger;
import java.util.logging.Level;


/**
* Cső aktív elemről való lekötési interakciót kezelő osztály.
*/
public class DetachPipeAction extends Action {

private static final Logger logger = Logger.getLogger(DetachPipeAction.class.getName());
/**
* A szerelő, aki az akciót végzi
*/
Expand Down Expand Up @@ -41,7 +44,7 @@ public DetachPipeAction(Plumber actor, ActiveElement activeElement) {
public boolean doAction(Pipe pipe) {
var success = actor.detachPipe(activeElement, pipe);
if (success) {
System.out.println("Detach pipe success");
logger.info("Detach pipe success");
var detachedPipeView = (PipeView) ViewRepository.getViewOfObject(pipe);
detachedPipeView.replaceEndpointPos(
ViewRepository.getViewOfObject(activeElement).getPosition(),
Expand Down
7 changes: 5 additions & 2 deletions src/macaroni/actions/MoveAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
import macaroni.model.element.Element;
import macaroni.views.CharacterView;
import macaroni.views.PipeView;
import java.util.logging.Logger;
import java.util.logging.Level;


/**
* Mozgási interakciót kezelő osztály.
*/
public class MoveAction extends Action {

private static final Logger logger = Logger.getLogger(MoveAction.class.getName());
/**
* A karakter, ami a mozgást végzi.
*/
Expand All @@ -36,7 +39,7 @@ public MoveAction(Character actor) {
public boolean doAction(Element element) {
var locationBeforeMove = actor.getLocation();
var success = actor.moveTo(element);
System.out.println("Move success: " + success);
logger.info("Move success: " + success);
if (success) {
var characterView = (CharacterView) ViewRepository.getViewOfObject(actor);
characterView.setPosition(ViewRepository.getViewOfObject(element).getPosition());
Expand Down
11 changes: 10 additions & 1 deletion src/macaroni/actions/SetPumpInputAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
import macaroni.model.element.Pump;
import macaroni.views.PumpView;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Pumpa bemeneti csőállítási interakciót kezelő osztály.
*/
public class SetPumpInputAction extends Action {

/**
* Logger inicializálása
*/
private static final Logger LOGGER = Logger.getLogger(SetPumpInputAction.class.getName());

/**
* A karakter, aki az akciót végzi
*/
Expand All @@ -24,7 +32,7 @@ public class SetPumpInputAction extends Action {
* Létrehoz egy SetPumpInputAction példányt.
*
* @param actor A karakter, aki az akciót végzi
* @param pump A pumpa, amin az akciót végzi
* @param pump A pumpa, amin az akciót végzi
*/
public SetPumpInputAction(Character actor, Pump pump) {
this.actor = actor;
Expand All @@ -43,6 +51,7 @@ public boolean doAction(Pipe pipe) {
if (success) {
var pumpView = (PumpView) ViewRepository.getViewOfObject(pump);
pumpView.setInputPipePos(ViewRepository.getViewOfObject(pipe).getPosition());
LOGGER.log(Level.INFO, "Pump input pipe set successfully");
}
return success;
}
Expand Down
12 changes: 11 additions & 1 deletion src/macaroni/actions/SetPumpOutputAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
import macaroni.model.element.Pump;
import macaroni.views.PumpView;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Pumpa kimeneti csőállítási interakciót kezelő osztály.
*/
public class SetPumpOutputAction extends Action {

/**
* Logger inicializálása
*/
private static final Logger LOGGER = Logger.getLogger(SetPumpOutputAction.class.getName());

/**
* A karakter, aki az akciót végzi
*/
Expand All @@ -24,7 +32,7 @@ public class SetPumpOutputAction extends Action {
* Létrehoz egy SetPumpOutputAction példányt.
*
* @param actor A karakter, aki az akciót végzi
* @param pump A pumpa, amin az akciót végzi
* @param pump A pumpa, amin az akciót végzi
*/
public SetPumpOutputAction(Character actor, Pump pump) {
this.actor = actor;
Expand All @@ -43,6 +51,8 @@ public boolean doAction(Pipe pipe) {
if (success) {
var pumpView = (PumpView) ViewRepository.getViewOfObject(pump);
pumpView.setOutputPipePos(ViewRepository.getViewOfObject(pipe).getPosition());
// Fontos esemény logolása
LOGGER.log(Level.INFO, "Pump output pipe set successfully");
}
return success;
}
Expand Down
28 changes: 12 additions & 16 deletions src/macaroni/app/App.java
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
package macaroni.app;

/**
* Represents the main application
*/
import java.util.logging.Logger;
import java.util.logging.Level;

public final class App {
/**
* number of frames per second
*/
private static final Logger logger = Logger.getLogger(App.class.getName());

private final long FPS = 60;
/**
* shows whether the app is currently running
*/
boolean running = false;
/**
* the window of the application
*/
private final Window window = new Window();

/**
* Runs the application
*/
public void run() {
logger.info("Application started.");
running = true;
window.open();

long lastLoopTime = System.currentTimeMillis();

while (running) {
if (window.shouldClose()) {
logger.info("Window should close. Stopping application.");
running = false;
}

window.repaint();

long currentLoopTime = System.currentTimeMillis();
long sleepTime = 1000 / FPS - (currentLoopTime - lastLoopTime);
if (sleepTime >= 0) {
try {
logger.fine("Sleeping for " + sleepTime + " ms.");
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Thread was interrupted. Stopping application.", e);
running = false;
}
}
lastLoopTime = currentLoopTime;
}

window.close();
logger.info("Application stopped.");
}
}
29 changes: 16 additions & 13 deletions src/macaroni/app/gameView/GameMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;


/**
* the game menu of the application
*/
public final class GameMenu extends JPanel {

private static final Logger logger = Logger.getLogger(GameMenu.class.getName());
/**
* the game over screen
*/
Expand Down Expand Up @@ -146,7 +149,7 @@ public void processMousePress(MouseEvent e) {
int x = (int) (e.getX() - dragger.getTransform().getTranslateX());
int y = (int) (e.getY() - dragger.getTransform().getTranslateY());

System.out.println("Mouse pressed: x: " + x + ", y: " + y);
logger.info("Mouse pressed: x: " + x + ", y: " + y);
if (selectedAction != null) {
View foundView = null;
// go through active elements
Expand All @@ -162,7 +165,7 @@ public void processMousePress(MouseEvent e) {

// go through pipes if no active element found
if (foundView == null) {
System.out.println("Couldn't find active elements, searching for pipes...");
logger.warning("Couldn't find active elements, searching for pipes...");
for (View view : ViewRepository.getFiltered(v -> v instanceof PipeView)) {
if (view.isInside(x, y)) {
foundView = view;
Expand All @@ -172,15 +175,15 @@ public void processMousePress(MouseEvent e) {
}

if (foundView != null) {
System.out.println("View found: " + foundView);
logger.fine("View found: " + foundView);
selectView(foundView);
} else {
System.out.println("No view found");
logger.warning("No view found");
actionFailed(false);
}
selectedAction = null;
} else {
System.out.println("Selected action is null");
logger.warning("Selected action is null");
dragger.mousePressed(e);
}
}
Expand All @@ -191,7 +194,7 @@ public void processMousePress(MouseEvent e) {
* @param view the view
*/
private void selectView(View view) {
System.out.println("Trying action on view: " + view);
logger.info("Trying action on view: " + view);
if (view.select(selectedAction)) {
actionSuccess();
} else {
Expand Down Expand Up @@ -257,7 +260,7 @@ private void stepGame() {
* Handles the success of an action
*/
private void actionSuccess() {
System.out.println("Action success");
logger.info("Action success");
stepGame();
}

Expand Down Expand Up @@ -317,7 +320,7 @@ public void doPickUpPumpAction() {
ModelObjectFactory.setCisternCreatePumpName("cisternCreatedPump" + cisternCreatePumpCounter);
if (p.pickUpPump(c)) {
cisternCreatePumpCounter++;
System.out.println("Pick up Pump success");
logger.info("Pick up Pump success");
actionSuccess();
} else {
actionFailed(false);
Expand All @@ -338,7 +341,7 @@ public void doAttachPipeAction() {
ViewRepository.getViewOfObject(p).getPosition(),
ViewRepository.getViewOfObject(ae).getPosition()
);
System.out.println("Attach pipe success");
logger.info("Attach pipe success");
actionSuccess();
} else {
actionFailed(false);
Expand Down Expand Up @@ -411,7 +414,7 @@ public void doPlacePumpAction() {
ViewRepository.add(createdPipe, pipeView);

pipeCreatePipeCounter++;
System.out.println("Place Pump success");
logger.info("Place Pump success");
actionSuccess();
} else {
actionFailed(false);
Expand All @@ -429,7 +432,7 @@ public void doBananaPipeAction() {
var createdEffect = (BananaEffect) p.getEffect();
ViewRepository.add(createdEffect, new BananaEffectView(
ViewRepository.getViewOfObject(p).getPosition(), createdEffect));
System.out.println("Banana Pipe success");
logger.info("Banana Pipe success");
actionSuccess();
} else {
actionFailed(false);
Expand All @@ -447,7 +450,7 @@ public void doTechnokolPipeAction() {
var createdEffect = (TechnokolEffect) p.getEffect();
ViewRepository.add(createdEffect, new TechnokolEffectView(
ViewRepository.getViewOfObject(p).getPosition(), createdEffect));
System.out.println("Technokol Pipe success");
logger.info("Technokol Pipe success");
actionSuccess();
} else {
actionFailed(false);
Expand Down
Loading