From ae043ccb2fd57163866b9c6f332c49205eb99b1d Mon Sep 17 00:00:00 2001 From: Thastertyn Date: Fri, 26 May 2023 22:09:04 +0200 Subject: [PATCH] Version 1.0 - entire UI is in cz, added config manager and help dialog, fixed bugs --- .gitignore | 44 ++- pom.xml | 4 +- src/main/java/xyz/thastertyn/App.java | 14 +- .../java/xyz/thastertyn/Config/Config.java | 273 ++++++++++++++++++ .../thastertyn/Login/CredentialsInput.java | 45 +-- .../thastertyn/Login/LocalCredentials.java | 162 ----------- .../xyz/thastertyn/Login/LoginController.java | 66 ++++- .../xyz/thastertyn/Scrape/AbsenceList.java | 7 - .../xyz/thastertyn/Scrape/Downloader.java | 8 + .../UserInterface/Content/AbsenceList.java | 8 +- .../UserInterface/Content/JecnaContent.java | 7 +- .../UserInterface/Content/Marks.java | 32 +- .../UserInterface/Content/Reports.java | 14 +- .../UserInterface/Dialogs/EscapeDialog.java | 25 +- .../UserInterface/Dialogs/HelpDialog.java | 70 +++++ .../UserInterface/Dialogs/OptionsDialog.java | 38 ++- .../Listeners/WindowSwitchListener.java | 69 ++++- .../thastertyn/UserInterface/MainWindow.java | 3 +- src/test/java/xyz/thastertyn/ConfigTest.java | 82 ++++++ 19 files changed, 696 insertions(+), 275 deletions(-) create mode 100644 src/main/java/xyz/thastertyn/Config/Config.java delete mode 100644 src/main/java/xyz/thastertyn/Login/LocalCredentials.java create mode 100644 src/main/java/xyz/thastertyn/UserInterface/Dialogs/HelpDialog.java create mode 100644 src/test/java/xyz/thastertyn/ConfigTest.java diff --git a/.gitignore b/.gitignore index 02fc84b..9e274ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,44 @@ +# ---> Java +# Compiled class file *.class -jecnak-tui.jar + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +# ---> Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2e66d96..9eee0f6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,11 +6,11 @@ xyz.thastertyn jecnak-tui - 1.0-SNAPSHOT + 1.0 jecnak-tui - http://www.example.com + https://gitea.thastertyn.xyz/Thastertyn/jecnak-tui UTF-8 diff --git a/src/main/java/xyz/thastertyn/App.java b/src/main/java/xyz/thastertyn/App.java index e5744ea..89ab0e8 100644 --- a/src/main/java/xyz/thastertyn/App.java +++ b/src/main/java/xyz/thastertyn/App.java @@ -4,13 +4,13 @@ import xyz.thastertyn.UserInterface.MainWindow; /** * Hello world! - * + * */ public class App { - public static void main(String[] args) { - System.out.println("Hello World!"); - - MainWindow window = new MainWindow(); - window.run(); - } + public static void main(String[] args) { + System.out.println("Hello World!"); + + MainWindow window = new MainWindow(); + window.run(); + } } diff --git a/src/main/java/xyz/thastertyn/Config/Config.java b/src/main/java/xyz/thastertyn/Config/Config.java new file mode 100644 index 0000000..9048864 --- /dev/null +++ b/src/main/java/xyz/thastertyn/Config/Config.java @@ -0,0 +1,273 @@ +package xyz.thastertyn.Config; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import xyz.thastertyn.Types.Credentials; + +/** + * Config parser for key value pairs with support for # comments + */ +public class Config { + + private String path; + + private File configFile; + private File configPath; + + private boolean configExists = false; + private boolean isDataLoaded = false; + + private boolean hasReadFailed = false; + private boolean hasWriteFailed = false; + + private HashMap configData = new HashMap<>(); + + private static Config config = new Config(); + + //Tries finding appropriate path to the file + public Config() + { + if(System.getProperty("os.name").equals("Linux")) + { + // /home/user/.local/share/jecnak/... + path = System.getProperty("user.home") + "/.config/jecnak/"; + }else if(System.getProperty("os.name").contains("Windows")) + { + // C:\Users\\user\AppData\Roaming\... + path = System.getenv("APPDATA") + "\\jecnak\\"; + }else{ + configExists = false; + } + + configPath = new File(path); + configFile = new File(configPath, "config.conf"); + + if(!configFile.exists()) + { + createConfigFile(); + } + + configExists = true; + + try{ + readConfig(); + }catch(ConfigurationException e) + { + hasReadFailed = true; + } + } + + /** + * When no file exists, it is created together with it's directory + * @return true or false whether the action succeeded. {@link #hasWriteFailed} is set to true if false is returned + */ + private boolean createConfigFile() + { + try{ + configPath.mkdirs(); + configFile.createNewFile(); + return true; + }catch(IOException e) + { + hasWriteFailed = true; + return false; + } + } + + /** + * Tries reading the config file and parse it into {@link #configData} + * @throws ConfigurationException when a syntax error in the config is found, i.e. "user=" missing the value or just random gibberish + */ + private void readConfig() throws ConfigurationException + { + try { + BufferedReader reader = new BufferedReader(new FileReader(configFile)); + + String line = ""; + int lineNum = 1; + + while((line = reader.readLine()) != null) + { + if(line.matches("^\\s*#.*")) + { + configData.put("comment" + lineNum, line); + }else{ + String[] data = line.split("="); + + // Check if key or value are null or emtpy and if yes, call that a syntax error + if((data[0] == null || data[0].trim().isBlank()) || (data[1] == null ||data[1].trim().isBlank())) + { + reader.close(); + hasReadFailed = true; + throw new ConfigurationException("Syntax Error on line " + lineNum + "\n" + "-> " + line); + }else{ + configData.put(data[0], data[1]); + } + } + lineNum++; + } + + isDataLoaded = true; + reader.close(); + } catch (IOException e) { + hasReadFailed = true; + e.printStackTrace(); + } + } + + /** + * Checks if a key is stored in {@link #configData} + * @param key String key + * @return true or false if it exists or not + */ + public boolean checkIfExists(String key) + { + return configData.containsKey(key); + } + + /** + * Shortcut for checking credentials specifically. Just runs {@link #checkIfExists(String)} for user and pass keys + * @return true or false if they exist or not + */ + public boolean checkIfCredentialsExist() + { + return (checkIfExists("user") && checkIfExists("pass")); + } + + /** + * Tries getting the credentials, should be combined with {@link #checkIfCredentialsExist()} to assure no null values are returned + * @return {@link Credentials} containing the username and password + * @throws ConfigurationException when {@link #readConfig()} fails to read the config file, meaning nothing is loaded at all. Basically force the check if nothing is returned. + */ + public Credentials getCredentials() throws ConfigurationException + { + return new Credentials(getConfig("user"), getConfig("pass")); + } + + /** + * Gets a specific key from {@link #configData} + * @param key to get + * @return value assigned to the key + * @throws ConfigurationException when {@link #readConfig()} fails to read to force addressing the possibility of no data + */ + public String getConfig(String key) throws ConfigurationException + { + if(!configExists) + { + return ""; + } + + if(!isDataLoaded) + { + readConfig(); + } + + if(!hasReadFailed) + { + String value = configData.get(key); + return (value == null) ? "" : value; + }else{ + return ""; + } + } + + /** + * Adds a key and value to {@link #configData} + * @param key + * @param value + * @return {@code this} for the ability to chain these methods + */ + public Config addConfig(String key, String value) + { + configData.put(key, value); + return this; + } + + /** + * Removes a key from {@link #configData} + * @param key + * @return {@code this} for the ability to chain these methods + */ + public Config removeConfig(String key) + { + configData.remove(key); + return this; + } + + /** + * Removes credentials from {@link #configData} + * @return {@code this} for the ability to chain these methods + */ + public Config removeCredentials() + { + configData.remove("user"); + configData.remove("pass"); + return this; + } + + /** + * Tries writting current state of {@link #configData} to {@link #configFile} + * @return true or false whether it succeeded or not + */ + public boolean writeConfig() + { + if(hasWriteFailed) + { + return false; + } + + if(!configFile.exists()) + { + createConfigFile(); + } + + StringBuilder finalString = new StringBuilder(); + + for(Map.Entry entry : configData.entrySet()) + { + if(entry.getKey().matches("comment[0-9]+")) + { + finalString.append(entry.getValue() + "\n"); + }else{ + finalString.append(entry.getKey() + "=" + entry.getValue() + "\n"); + } + } + + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(configFile)); + + writer.write(finalString.toString()); + + writer.close(); + return true; + } catch (IOException e) { + e.printStackTrace(); + hasWriteFailed = true; + return false; + } + } + + + public String getPath() + { + return configFile.getAbsolutePath(); + } + + /** + * Singleton + * @return {@link #config} + */ + public static Config getInstance() + { + return config; + } +} diff --git a/src/main/java/xyz/thastertyn/Login/CredentialsInput.java b/src/main/java/xyz/thastertyn/Login/CredentialsInput.java index f038b01..be580f6 100644 --- a/src/main/java/xyz/thastertyn/Login/CredentialsInput.java +++ b/src/main/java/xyz/thastertyn/Login/CredentialsInput.java @@ -1,6 +1,7 @@ package xyz.thastertyn.Login; import java.util.Arrays; +import java.util.Optional; import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.gui2.Button; @@ -30,21 +31,20 @@ public class CredentialsInput extends DialogWindow { private String user; private String pass; + private boolean wasCanceled = false; + private CheckBox remember; public CredentialsInput() { - super("Login"); + super("Prihlaseni"); this.user = null; this.pass = null; this.username = new TextBox(); this.password = new TextBox().setMask('*'); this.remember = new CheckBox(); - Panel buttonPanel = new Panel(); - buttonPanel - .setLayoutManager( - new GridLayout(2).setHorizontalSpacing(1)) + Panel buttonPanel = new Panel(new GridLayout(2).setHorizontalSpacing(1)) .addComponent( new Button(LocalizedString.OK.toString(), this::onOK) .setLayoutData(GridLayout.createLayoutData( @@ -55,17 +55,15 @@ public class CredentialsInput extends DialogWindow { .addComponent( new Button(LocalizedString.Cancel.toString(), this::onCancel)); - Panel mainPanel = new Panel() - .setLayoutManager(new GridLayout(1) + Panel mainPanel = new Panel(new GridLayout(1) .setLeftMarginSize(1) .setRightMarginSize(1)); - mainPanel.addComponent(new Label("Enter your username and password")); + mainPanel.addComponent(new Label("Zadej sve jmeno a heslo")); mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); - Panel userPanel = new Panel() - .setLayoutManager(new GridLayout(3)) + Panel userPanel = new Panel(new GridLayout(3)) .setLayoutData( GridLayout.createLayoutData( GridLayout.Alignment.FILL, @@ -80,7 +78,7 @@ public class CredentialsInput extends DialogWindow { true, false)); - userPanel.addComponent(new Label("Username: ")) + userPanel.addComponent(new Label("Jmeno: ")) .addComponent(username) .addTo(mainPanel); @@ -92,29 +90,27 @@ public class CredentialsInput extends DialogWindow { false)) .addTo(mainPanel); - Panel passPanel = new Panel() - .setLayoutManager(new GridLayout(3)) + Panel passPanel = new Panel(new GridLayout(3)) .setLayoutData(GridLayout.createLayoutData( GridLayout.Alignment.FILL, Alignment.CENTER, true, false)); - passPanel.addComponent(new Label("Password: ")) + passPanel.addComponent(new Label("Heslo: ")) .addComponent(password) .addTo(mainPanel); - if(!LocalCredentials.getInstance().checkForExistingCredentials()) + if(!xyz.thastertyn.Config.Config.getInstance().checkIfCredentialsExist()) { - Panel rememberPanel = new Panel() - .setLayoutManager(new GridLayout(3)) + Panel rememberPanel = new Panel(new GridLayout(3)) .setLayoutData(GridLayout.createLayoutData( GridLayout.Alignment.FILL, Alignment.CENTER, true, false)); - rememberPanel.addComponent(new Label("Rembember?")) + rememberPanel.addComponent(new Label("Zapamatovat?")) .addComponent(remember) .addTo(mainPanel); } @@ -142,7 +138,7 @@ public class CredentialsInput extends DialogWindow { if (user.isEmpty() || pass.isEmpty()) { - MessageDialog.showMessageDialog(getTextGUI(), getTitle(), "Username and password cannot be blank", + MessageDialog.showMessageDialog(getTextGUI(), getTitle(), "Uzivatelske jmeno a heslo nemohou byt prazdne", MessageDialogButton.OK); return; } @@ -152,6 +148,7 @@ public class CredentialsInput extends DialogWindow { public void onCancel() { close(); + wasCanceled = true; } /** @@ -159,8 +156,14 @@ public class CredentialsInput extends DialogWindow { * @return {@link InputtedCredentials} with username first, password second and whether to store the credentials third */ @Override - public InputtedCredentials showDialog(WindowBasedTextGUI textGUI) { + public Optional showDialog(WindowBasedTextGUI textGUI) { super.showDialog(textGUI); - return new InputtedCredentials(user, pass, remember.isChecked()); + + if(wasCanceled) + { + return Optional.empty(); + } + + return Optional.of(new InputtedCredentials(user, pass, remember.isChecked())); } } diff --git a/src/main/java/xyz/thastertyn/Login/LocalCredentials.java b/src/main/java/xyz/thastertyn/Login/LocalCredentials.java deleted file mode 100644 index a05cb51..0000000 --- a/src/main/java/xyz/thastertyn/Login/LocalCredentials.java +++ /dev/null @@ -1,162 +0,0 @@ -package xyz.thastertyn.Login; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; - -import xyz.thastertyn.Types.Credentials; - -public class LocalCredentials { - - private static LocalCredentials localCredentials = new LocalCredentials(); - - private String path; - - private File credentialsFile; - private File credentialsPath; - - /** - * Checks for already saved credentials, at least if its file exists
- * for Windows it checks {@code AppData\Roaming\jecnak\credemtials.txt}
- * for Linux it checks {@code ~/.local/share/jecnak/credentials.txt}
- * @return - *
    - *
  • {@code true} a file exists
  • - *
  • {@code false} doesn't exist
  • - *
- */ - public boolean checkForExistingCredentials() - { - if(System.getProperty("os.name").equals("Linux")) - { - // /home/user/.local/share/jecnak/... - path = System.getProperty("user.home") + "/.local/share/jecnak/"; - }else if(System.getProperty("os.name").contains("Windows")) - { - // C:\Users\\user\AppData\Roaming\... - path = System.getenv("APPDATA") + "\\jecnak\\"; - }else{ - return false; - } - - credentialsPath = new File(path); - credentialsFile = new File(credentialsPath, "credentials.txt"); - - if(!credentialsFile.exists()) - { - return false; - } - - return true; - } - - /** - * Try reading the credentails from a local file - * @return String[] with username on index 0, and password on index 1,
- * can also return null if credentials are corrupted, inaccessible, etc. - */ - public Credentials getCredentialsFile() - { - // TODO Use hashmap instead of array - String user = null; - String pass = null; - - if(credentialsFile == null) - { - return null; - } - - try { - BufferedReader reader = new BufferedReader(new FileReader(credentialsFile)); - - String line = ""; - while((line = reader.readLine()) != null) - { - String[] currentValue = line.split("="); - - if(currentValue[0].equals("user")) - { - user = currentValue[1]; - }else if(currentValue[0].equals("pass")) - { - pass = currentValue[1]; - } - } - - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - - if(user == null || pass == null) - { - return null; - } - - return new Credentials(user, pass); - } - - /** - * appends the current credentials to the file - * @param credentials the array containing username and password. Username is on index 0, password on index 1 - * @return - */ - public boolean saveCredentials(Credentials credentials) - { - if(credentialsFile == null) - { - return false; - } - - if(!credentialsFile.exists()) - { - try{ - credentialsPath.mkdirs(); - credentialsFile.createNewFile(); - }catch(IOException e) - { - return false; - } - } - - try { - BufferedWriter writer = new BufferedWriter(new FileWriter(credentialsFile)); - writer.append(String.format( - "user=%s\npass=%s\n", - credentials.getUsername(), - credentials.getPassword())); - - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - - return true; - } - - /** - * Deletes the credentials file - * @return - */ - public boolean deleteCredentials() - { - credentialsFile.delete(); - return true; - } - - /** - * Returns a single instance to prevent creating and loading the files all over again when not much has changed - * @return {@link LocalCredentials} instance - */ - public static LocalCredentials getInstance() - { - return localCredentials; - } - -} - diff --git a/src/main/java/xyz/thastertyn/Login/LoginController.java b/src/main/java/xyz/thastertyn/Login/LoginController.java index c05a15e..58c5a33 100644 --- a/src/main/java/xyz/thastertyn/Login/LoginController.java +++ b/src/main/java/xyz/thastertyn/Login/LoginController.java @@ -2,25 +2,29 @@ package xyz.thastertyn.Login; import java.io.IOException; import java.net.UnknownHostException; +import java.util.Optional; import java.util.concurrent.TimeoutException; +import javax.naming.ConfigurationException; import javax.security.auth.login.CredentialException; import com.googlecode.lanterna.gui2.WindowBasedTextGUI; import com.googlecode.lanterna.gui2.dialogs.MessageDialog; import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton; +import xyz.thastertyn.Config.Config; +import xyz.thastertyn.Scrape.Downloader; import xyz.thastertyn.Types.Credentials; import xyz.thastertyn.Types.InputtedCredentials; /** - * Merges the functionality of {@link LocalCredentials}, {@link CredentialsInput}, and {@link Login} + * Merges the functionality of {@link Config}, {@link CredentialsInput}, and {@link Login} */ public class LoginController { private WindowBasedTextGUI textGUI; private xyz.thastertyn.Login.CredentialsInput dialog; - private LocalCredentials localCredentials = LocalCredentials.getInstance(); + private Config config = Config.getInstance(); private xyz.thastertyn.Login.Login login = new xyz.thastertyn.Login.Login(); public LoginController(WindowBasedTextGUI textGUI) @@ -37,30 +41,60 @@ public class LoginController { */ public void login(boolean forceGUI) { - Credentials credentials; - - if(!forceGUI && localCredentials.checkForExistingCredentials()) + if(forceGUI || !config.checkIfCredentialsExist()) { - credentials = localCredentials.getCredentialsFile(); + Optional optional = loginUsingGui(); + + if(optional.isEmpty()) + { + if(!Downloader.isInitialized()) + { + System.exit(0); + } + + return; + } + + useCredentials(optional.get()); }else{ - credentials = loginUsingGui(); + try{ + useCredentials(config.getCredentials()); + }catch(ConfigurationException e) { + e.printStackTrace(); + login(true); + } } - - useCredentials(credentials); } - public Credentials loginUsingGui() + public Optional loginUsingGui() { dialog = new CredentialsInput(); - InputtedCredentials credentials = dialog.showDialog(textGUI); + Optional credentialsOptional = dialog.showDialog(textGUI); - if(credentials.save()) + if(credentialsOptional.isEmpty()) { - localCredentials.saveCredentials(credentials.getCredentials()); + if(!Downloader.isInitialized()) + { + System.exit(0); + } + return Optional.empty(); } - return credentials.getCredentials(); + InputtedCredentials inputtedCredentials = credentialsOptional.get(); + + if(inputtedCredentials.save()) + { + config.addConfig("user", inputtedCredentials.getUsername()); + config.addConfig("pass", inputtedCredentials.getPassword()); + + if(!config.writeConfig()) + { + MessageDialog.showMessageDialog(textGUI, "Failed to save credentials", "Something has gone wrong while saving your credentials", MessageDialogButton.OK); + } + } + + return Optional.of(inputtedCredentials.getCredentials()); } /** @@ -86,7 +120,9 @@ public class LoginController { e.getMessage(), MessageDialogButton.OK); // The credentials were most likely tampered with after save, just get rid of them and save them another time - LocalCredentials.getInstance().deleteCredentials(); + Config.getInstance() + .removeCredentials() + .writeConfig(); login(true); } catch (IOException e) { diff --git a/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java b/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java index 31d643b..6a3a238 100644 --- a/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java +++ b/src/main/java/xyz/thastertyn/Scrape/AbsenceList.java @@ -2,9 +2,7 @@ package xyz.thastertyn.Scrape; import java.io.IOException; import java.time.LocalDate; -import java.time.Month; import java.util.ArrayList; -import java.util.Arrays; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -17,7 +15,6 @@ import xyz.thastertyn.Types.Options; public class AbsenceList extends JecnaScrape { private ArrayList data; - private Choice currentChoice; private Options schoolYearOptions; @@ -30,8 +27,6 @@ public class AbsenceList extends JecnaScrape { @Override public void download(Choice choice) throws IOException { - currentChoice = choice; - parse(String.format( "https://www.spsejecna.cz/absence/student?schoolYearId=%s", choice.getChoices().get(0))); @@ -64,8 +59,6 @@ public class AbsenceList extends JecnaScrape { boolean isDefault = e.hasAttr("selected"); schoolYearOptions.addOption(new Option(e.text(), e.attr("value"), isDefault)); } - - currentChoice = new Choice(Arrays.asList(schoolYearOptions.getOptions().get(0).getValue())); } /** diff --git a/src/main/java/xyz/thastertyn/Scrape/Downloader.java b/src/main/java/xyz/thastertyn/Scrape/Downloader.java index edf3759..f06a2af 100644 --- a/src/main/java/xyz/thastertyn/Scrape/Downloader.java +++ b/src/main/java/xyz/thastertyn/Scrape/Downloader.java @@ -10,6 +10,8 @@ public class Downloader { private static String JsessionId; + private static boolean isInitialized = false; + /** * Provide a general Jsoup Connection for simplicity with some predefined values and JSessionId already set * @param url @@ -46,5 +48,11 @@ public class Downloader { public static void setJSessionId(String newJsessionId) { JsessionId = newJsessionId; + isInitialized = true; + } + + public static boolean isInitialized() + { + return isInitialized; } } diff --git a/src/main/java/xyz/thastertyn/UserInterface/Content/AbsenceList.java b/src/main/java/xyz/thastertyn/UserInterface/Content/AbsenceList.java index c9747df..6de2f2f 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Content/AbsenceList.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Content/AbsenceList.java @@ -17,9 +17,8 @@ public class AbsenceList extends JecnaContent{ public AbsenceList(UpdateListener listener) { super(listener); - this.mainPanel = new Panel() - .setLayoutManager(new GridLayout(1)); - this.borderLabel = new Label("Omluvny L."); + this.mainPanel = new Panel(new GridLayout(1)); + this.borderLabel = new Label("Absence"); super.scraper = omluvnyList; } @@ -29,8 +28,7 @@ public class AbsenceList extends JecnaContent{ this.mainPanel.removeAllComponents(); ArrayList a = omluvnyList.getData(); - Panel content = new Panel() - .setLayoutManager(new LinearLayout(Direction.VERTICAL)) + Panel content = new Panel(new LinearLayout(Direction.VERTICAL)) .addTo(mainPanel); for(xyz.thastertyn.Types.AbsenceList omluvnyList : a) diff --git a/src/main/java/xyz/thastertyn/UserInterface/Content/JecnaContent.java b/src/main/java/xyz/thastertyn/UserInterface/Content/JecnaContent.java index d6b0338..519f7da 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Content/JecnaContent.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Content/JecnaContent.java @@ -1,6 +1,7 @@ package xyz.thastertyn.UserInterface.Content; import java.io.IOException; +import java.util.Optional; import com.googlecode.lanterna.gui2.Label; import com.googlecode.lanterna.gui2.Panel; @@ -77,11 +78,11 @@ public abstract class JecnaContent { OptionsDialog dialog = new OptionsDialog(scraper.getOptions()); - Choice choice = dialog.showDialog(textGUI); + Optional choice = dialog.showDialog(textGUI); - if(choice != null) + if(choice.isPresent()) { - download(choice); + download(choice.get()); } } diff --git a/src/main/java/xyz/thastertyn/UserInterface/Content/Marks.java b/src/main/java/xyz/thastertyn/UserInterface/Content/Marks.java index b5dda4f..05e411f 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Content/Marks.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Content/Marks.java @@ -12,6 +12,7 @@ import com.googlecode.lanterna.gui2.Label; import com.googlecode.lanterna.gui2.LayoutData; import com.googlecode.lanterna.gui2.LinearLayout; import com.googlecode.lanterna.gui2.Panel; +import com.googlecode.lanterna.gui2.Separator; import xyz.thastertyn.Types.FinalMark; import xyz.thastertyn.Types.Subject; @@ -26,6 +27,7 @@ public class Marks extends JecnaContent { private final TextColor.RGB DOSTATECNY = new TextColor.RGB(255,102,0); private final TextColor.RGB NEDOSTATECNY = new TextColor.RGB(255,48,48); private final TextColor.RGB NEHODNOCEN = new TextColor.RGB(0,0,0); + private final TextColor.RGB UVOLNEN = new TextColor.RGB(28, 107, 255); private final LayoutData ALIGN_LEFT = GridLayout.createLayoutData( GridLayout.Alignment.BEGINNING, @@ -45,8 +47,7 @@ public class Marks extends JecnaContent { { super(listener); - this.mainPanel = new Panel() - .setLayoutManager(new GridLayout(3)); + this.mainPanel = new Panel(new GridLayout(5)); this.borderLabel = new Label("Znamky"); super.scraper = this.marks; } @@ -65,31 +66,40 @@ public class Marks extends JecnaContent { colors.put(3, new SimpleTheme(ANSI.BLACK, DOBRY)); colors.put(4, new SimpleTheme(ANSI.BLACK, DOSTATECNY)); colors.put(5, new SimpleTheme(ANSI.BLACK, NEDOSTATECNY)); + colors.put(0, new SimpleTheme(ANSI.BLACK, ANSI.WHITE)); colors.put(-1, new SimpleTheme(ANSI.WHITE, NEHODNOCEN)); colors.put(-2, new SimpleTheme(ANSI.WHITE, NEHODNOCEN)); + colors.put(-3, new SimpleTheme(ANSI.WHITE, UVOLNEN)); + colors.put(-4, new SimpleTheme(ANSI.BLACK, NEDOSTATECNY)); + colors.put(-5, new SimpleTheme(ANSI.BLACK, ANSI.WHITE)); // Column for subject names - Panel subjectNames = new Panel() - .setLayoutManager(new LinearLayout(Direction.VERTICAL)) + Panel subjectNames = new Panel(new LinearLayout(Direction.VERTICAL)) .setLayoutData(ALIGN_LEFT) .addTo(mainPanel); - + + Panel emptySpaceLeft = new Panel(new LinearLayout(Direction.VERTICAL)) + .addTo(mainPanel); + // Column for marks - Panel marks = new Panel() - .setLayoutManager(new LinearLayout(Direction.VERTICAL)) + Panel marks = new Panel(new LinearLayout(Direction.VERTICAL)) .setLayoutData(ALIGN_LEFT) .addTo(mainPanel); + Panel emptySpaceRight = new Panel(new LinearLayout(Direction.VERTICAL)) + .setLayoutData(ALIGN_RIGHT) + .addTo(mainPanel); + // Column for final mark - Panel finalMarks = new Panel() - .setLayoutManager(new LinearLayout(Direction.VERTICAL)) + Panel finalMarks = new Panel(new LinearLayout(Direction.VERTICAL)) .setLayoutData(ALIGN_RIGHT) .addTo(mainPanel); for(Subject subject : subjects) { - Panel individualMarks = new Panel() - .setLayoutManager(new LinearLayout(Direction.HORIZONTAL)) + emptySpaceLeft.addComponent(new Separator(Direction.VERTICAL)); + emptySpaceRight.addComponent(new Separator(Direction.VERTICAL)); + Panel individualMarks = new Panel(new LinearLayout(Direction.HORIZONTAL)) .addTo(marks); if(subject.getMarks().isEmpty()) diff --git a/src/main/java/xyz/thastertyn/UserInterface/Content/Reports.java b/src/main/java/xyz/thastertyn/UserInterface/Content/Reports.java index 75d5075..ea4747d 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Content/Reports.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Content/Reports.java @@ -1,5 +1,6 @@ package xyz.thastertyn.UserInterface.Content; +import java.io.IOException; import java.util.ArrayList; import com.googlecode.lanterna.TextColor.ANSI; @@ -8,6 +9,9 @@ import com.googlecode.lanterna.gui2.GridLayout; import com.googlecode.lanterna.gui2.Label; import com.googlecode.lanterna.gui2.LinearLayout; import com.googlecode.lanterna.gui2.Panel; +import com.googlecode.lanterna.gui2.WindowBasedTextGUI; +import com.googlecode.lanterna.gui2.dialogs.MessageDialog; +import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton; import xyz.thastertyn.UserInterface.Listeners.UpdateListener; @@ -18,7 +22,7 @@ public class Reports extends JecnaContent { public Reports(UpdateListener listener) { super(listener); - this.mainPanel = new Panel().setLayoutManager(new GridLayout(1) + this.mainPanel = new Panel(new GridLayout(1) .setLeftMarginSize(1) .setRightMarginSize(1)); this.borderLabel = new Label("Sdeleni R."); @@ -34,7 +38,7 @@ public class Reports extends JecnaContent { for(xyz.thastertyn.Types.Reports reports : reportsList) { - Panel row = new Panel().setLayoutManager(new LinearLayout(Direction.HORIZONTAL)); + Panel row = new Panel(new LinearLayout(Direction.HORIZONTAL)); Label checkmark = new Label(""); Label text = new Label(reports.getText()); @@ -53,4 +57,10 @@ public class Reports extends JecnaContent { .addTo(mainPanel); } } + + @Override + public void showOptions(WindowBasedTextGUI textGUI) throws IOException { + + MessageDialog.showMessageDialog(textGUI, "Zadny vyber", "Zde neni co vybirat", MessageDialogButton.OK); + } } diff --git a/src/main/java/xyz/thastertyn/UserInterface/Dialogs/EscapeDialog.java b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/EscapeDialog.java index c9ecf60..c9ab0eb 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Dialogs/EscapeDialog.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/EscapeDialog.java @@ -11,7 +11,7 @@ import com.googlecode.lanterna.gui2.Window; import com.googlecode.lanterna.gui2.WindowBasedTextGUI; import com.googlecode.lanterna.gui2.dialogs.DialogWindow; -import xyz.thastertyn.Login.LocalCredentials; +import xyz.thastertyn.Config.Config; import xyz.thastertyn.Login.LoginController; import xyz.thastertyn.UserInterface.Listeners.ContentResetListener; @@ -26,18 +26,16 @@ public class EscapeDialog extends DialogWindow { this.textGUI = textGUI; this.resetListener = resetListener; - Panel mainPanel = new Panel() - .setLayoutManager(new GridLayout(1) + Panel mainPanel = new Panel( + new GridLayout(1) .setLeftMarginSize(1) .setRightMarginSize(1)); - new Panel() - .setLayoutManager( - new LinearLayout(Direction.VERTICAL)) - .addComponent(new Button("Return", this::onReturn)) - .addComponent(new Button("Logout", this::onLogout)) - .addComponent(new Button("Delete stored login", this::onDeleteLogin)) - .addComponent(new Button("Exit", this::onExit)) + new Panel(new LinearLayout(Direction.VERTICAL)) + .addComponent(new Button("Zpet", this::onReturn)) + .addComponent(new Button("Odhlasit", this::onLogout)) + .addComponent(new Button("Smazat ulozene udaje", this::onDeleteLogin)) + .addComponent(new Button("Ukoncit", this::onExit)) .addTo(mainPanel); setHints(Arrays.asList(Window.Hint.CENTERED)); @@ -52,7 +50,9 @@ public class EscapeDialog extends DialogWindow { public void onDeleteLogin() { close(); - LocalCredentials.getInstance().deleteCredentials(); + Config.getInstance() + .removeCredentials() + .writeConfig(); LoginController controller = new LoginController(textGUI); controller.loginUsingGui(); resetListener.reset(); @@ -74,7 +74,6 @@ public class EscapeDialog extends DialogWindow { @Override public Object showDialog(WindowBasedTextGUI textGUI) { - super.showDialog(textGUI); - return null; + return super.showDialog(textGUI); } } diff --git a/src/main/java/xyz/thastertyn/UserInterface/Dialogs/HelpDialog.java b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/HelpDialog.java new file mode 100644 index 0000000..b5d67e6 --- /dev/null +++ b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/HelpDialog.java @@ -0,0 +1,70 @@ +package xyz.thastertyn.UserInterface.Dialogs; + +import java.util.Arrays; + +import com.googlecode.lanterna.gui2.Button; +import com.googlecode.lanterna.gui2.CheckBox; +import com.googlecode.lanterna.gui2.Direction; +import com.googlecode.lanterna.gui2.EmptySpace; +import com.googlecode.lanterna.gui2.GridLayout; +import com.googlecode.lanterna.gui2.Label; +import com.googlecode.lanterna.gui2.LinearLayout; +import com.googlecode.lanterna.gui2.LocalizedString; +import com.googlecode.lanterna.gui2.Panel; +import com.googlecode.lanterna.gui2.Window; +import com.googlecode.lanterna.gui2.WindowBasedTextGUI; +import com.googlecode.lanterna.gui2.dialogs.DialogWindow; + + +public class HelpDialog extends DialogWindow { + + CheckBox box = new CheckBox("Znovu nezobrazovat"); + + public HelpDialog(boolean startupScreen) + { + super("Napoveda"); + + Panel mainPanel = new Panel(new GridLayout(1) + .setLeftMarginSize(1) + .setRightMarginSize(1)); + + new Panel(new LinearLayout(Direction.VERTICAL)) + .addComponent(new Label("- Pro pohyb mezi okny pouzij 'Tab' a 'Shift + Tab'.")) + .addComponent(new Label("- Pokud je pritomen posuvnik, pouzij sipky pro posun.")) + .addComponent(new Label("- Stiskni 'Space' pro specifikaci, napr skolniho roku, nebo pololeti.")) + .addComponent(new Label("- Stiskni 'Escape' pro odhlaseni, smazani udaju a konec.")) + .addComponent(new Label("- Nema smysl klikat mysi, vse je v terminalu.")) + .addComponent(new EmptySpace()) + .addComponent(new Label("Kdykoliv stiskni F1 pro zobrazeni tohoto okna.")) + .addTo(mainPanel); + + if(startupScreen) + { + mainPanel.addComponent(box); + } + + new Panel() + .addComponent( + new Button(LocalizedString.OK.toString(), this::onOK) + .setLayoutData(GridLayout.createLayoutData( + GridLayout.Alignment.CENTER, + GridLayout.Alignment.CENTER, + true, + false))) + .addTo(mainPanel); + + setHints(Arrays.asList(Window.Hint.CENTERED)); + setComponent(mainPanel); + } + + public void onOK() + { + close(); + } + + @Override + public Boolean showDialog(WindowBasedTextGUI textGUI) { + super.showDialog(textGUI); + return box.isChecked(); + } +} diff --git a/src/main/java/xyz/thastertyn/UserInterface/Dialogs/OptionsDialog.java b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/OptionsDialog.java index 4aebbec..4c21ef3 100644 --- a/src/main/java/xyz/thastertyn/UserInterface/Dialogs/OptionsDialog.java +++ b/src/main/java/xyz/thastertyn/UserInterface/Dialogs/OptionsDialog.java @@ -3,6 +3,7 @@ package xyz.thastertyn.UserInterface.Dialogs; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import com.googlecode.lanterna.gui2.Button; @@ -27,13 +28,21 @@ public class OptionsDialog extends DialogWindow { public OptionsDialog(Options[] options) { - super("Choose from below"); + super("Vyber si"); boxs = new ArrayList<>(); - for(Options o : options) + for(int i = 0; i < options.length; i++) { - boxs.add(new ComboBox