diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51467e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +TamoStudy/.project + +*.class +bin/ +.classpath +.project +.github/workflows/firebase-hosting-merge.yml +.github/workflows/firebase-hosting-pull-request.yml +TamoStudy Web/.firebaserc +TamoStudy Web/firebase.json +.DS_Store +*.jar +TamoStudy/.idea/vcs.xml +TamoStudy/.idea/misc.xml diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..9f6ece8 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3cee068 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 narlock + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README Assets/5Interval.png b/README Assets/5Interval.png new file mode 100644 index 0000000..77be663 Binary files /dev/null and b/README Assets/5Interval.png differ diff --git a/README Assets/Achievements.png b/README Assets/Achievements.png new file mode 100644 index 0000000..ee0dfc3 Binary files /dev/null and b/README Assets/Achievements.png differ diff --git a/README Assets/CustomInterval.png b/README Assets/CustomInterval.png new file mode 100644 index 0000000..487db5b Binary files /dev/null and b/README Assets/CustomInterval.png differ diff --git a/README Assets/DiscordRPC.png b/README Assets/DiscordRPC.png new file mode 100644 index 0000000..466018c Binary files /dev/null and b/README Assets/DiscordRPC.png differ diff --git a/README Assets/Inventory.png b/README Assets/Inventory.png new file mode 100644 index 0000000..ccfe545 Binary files /dev/null and b/README Assets/Inventory.png differ diff --git a/README Assets/Pomodoro.png b/README Assets/Pomodoro.png new file mode 100644 index 0000000..ab558c2 Binary files /dev/null and b/README Assets/Pomodoro.png differ diff --git a/README Assets/ProfileLoader.png b/README Assets/ProfileLoader.png new file mode 100644 index 0000000..4ec3f5f Binary files /dev/null and b/README Assets/ProfileLoader.png differ diff --git a/README Assets/Settings.png b/README Assets/Settings.png new file mode 100644 index 0000000..cb7df86 Binary files /dev/null and b/README Assets/Settings.png differ diff --git a/README Assets/Shop.png b/README Assets/Shop.png new file mode 100644 index 0000000..03c8654 Binary files /dev/null and b/README Assets/Shop.png differ diff --git a/README Assets/Statistics.png b/README Assets/Statistics.png new file mode 100644 index 0000000..08574de Binary files /dev/null and b/README Assets/Statistics.png differ diff --git a/README Assets/Stopwatch.png b/README Assets/Stopwatch.png new file mode 100644 index 0000000..20505e9 Binary files /dev/null and b/README Assets/Stopwatch.png differ diff --git a/README Assets/TamoHistory.png b/README Assets/TamoHistory.png new file mode 100644 index 0000000..044efba Binary files /dev/null and b/README Assets/TamoHistory.png differ diff --git a/README Assets/TamoStudy.icns b/README Assets/TamoStudy.icns new file mode 100644 index 0000000..8387c4f Binary files /dev/null and b/README Assets/TamoStudy.icns differ diff --git a/README Assets/WelcomeScreen.png b/README Assets/WelcomeScreen.png new file mode 100644 index 0000000..135981f Binary files /dev/null and b/README Assets/WelcomeScreen.png differ diff --git a/README Assets/instagramApp.png b/README Assets/instagramApp.png new file mode 100644 index 0000000..e0af715 Binary files /dev/null and b/README Assets/instagramApp.png differ diff --git a/README Assets/patreonApp.png b/README Assets/patreonApp.png new file mode 100644 index 0000000..35170fa Binary files /dev/null and b/README Assets/patreonApp.png differ diff --git a/README Assets/twitterApp.png b/README Assets/twitterApp.png new file mode 100644 index 0000000..9c64b41 Binary files /dev/null and b/README Assets/twitterApp.png differ diff --git a/README Assets/youtubeApp.png b/README Assets/youtubeApp.png new file mode 100644 index 0000000..2d0fadc Binary files /dev/null and b/README Assets/youtubeApp.png differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8f5791 --- /dev/null +++ b/README.md @@ -0,0 +1,206 @@ + + +Instagram + +YouTube +TamoStudy logo + +# TamoStudy + +[![Latest Release](https://img.shields.io/github/v/release/narlock/TamoStudy)](https://github.com/narlock/TamoStudy/releases/) +[![Downloads](https://img.shields.io/github/downloads/narlock/TamoStudy/total.svg)](https://github.com/narlock/TamoStudy/releases/) +[![Latest Commit](https://img.shields.io/github/last-commit/narlock/TamoStudy)](https://github.com/narlock/TamoStudy/commits/main) +[![Discord](https://discordapp.com/api/guilds/821757961830793236/widget.png?style=shield)](https://discord.gg/eEbEYbXaNS) + +**TamoStudy** is a free, open source work and study timer designed to enhance productivity, incorporating an enjoyable virtual pet to motivate users to concentrate on their tasks. Programmed utilizing **Java 8**, development for this application began in January of 2021. + +## 🚀 **Features** + +### 👋 **Welcome Screen** + +An improved program launcher. Allows the user to select either local study and the soon-to-be-developed online study. + +

+ +

+ +Global settings can be change using the cog at the top-right including resetting the default profile, setting the global language, and to receive update notifications. + +### 👥 **Local Profile Loader** + +

+ +

+ +### ⏰ **Focus Timers** + +Simple, customizable countdown timers for deep focus work. +> **Note** +> Selecting the 'Peaceful' difficulty will allow you to 'pause' the timer during focus sessions. This is shown in the Pomodoro image below. If you select any other difficulty, you will not get this option, as shown in the remaining timer images. + +- *Pomodoro*: The popular *[pomodoro technique](https://en.wikipedia.org/wiki/Pomodoro_Technique)* that breaks work into intervals. For a number of sessions, focus for a specified amount of time, then take a break for a specified amount of time. + +

+ +

+ +- *Custom Interval Countdown*: Customize the number of minutes and the number of a seconds in a single focus session. + +

+ +

+ +- *5-Interval Countdown*: Easily choose a focus time from a selection of factors of 5 minutes. + +

+ +

+ +- *Stopwatch*: A standard stopwatch timer which counts up. The implementation in TamoStudy counts the amount of cycles (100 minutes) studied. The timer will appear back to 0 minutes and 0 seconds after each cycle. + +

+ +

+ +Upon completing focus sessions, you will receive Tamo Tokens! With Tamo Tokens, you can purchase food for your virtual pet and additional customization! To keep your Tamo happy, you must complete your desired focus sessions! + +### 🛍️ **Shop** + +Meet Kath, the owner of the TamoStudy shop! Kath provides the user access to food to feed their tamo as well as backgrounds and borders for customization! + +

+ +

+ +- Beside the Tamo Token lies the price of the specified item. +- Food Item Guide: + - Onigiri replenishes 1 hunger point. + - Chicken plate replenishes 2 hunger points. + - Cheesecake replenishes 10 hunger points. +- Purchasing an item will allow it to appear in the user's inventory. + +### 🌇 **Inventory** + +The user's inventory allows for items to be stored and used when the user desires. The user can utilize the "Select" button next to the background of their choice to apply the background to their Tamo! If the user selects a food item, they can utilize the "Feed" button to feed the Tamo. This view also allows the user to read up on the items they have in their inventory. + +

+ +

+ +### 📈 **Statistics** + +- View your statistics while using TamoStudy! + +

+ +

+ +- TamoStudy tracks daily, monthly, and all-time focus. The user can highlight over the boxes at the bottom to track how long they have studied in the past. + +### 🥇 **Achievements** + +- Unlock achievements during your use of TamoStudy! + +

+ +

+ +- The following is a list of achievements you can earn in TamoStudy: + 1. **The Beginning** - Achieve total focus time of 24 hours. + 2. **Nothing can stop us!** - Achieve total focus time of 72 hours. + 3. **Never give up!** - Achieve total focus time of 240 hours. + 4. **Focus Ascension** - Achieve total focus time of 1200 hours. + 5. **Cosmetics** - Purchase and change your Tamo's border. + 6. **Scenery Change** - Purchase and change your Tamo's background. + 7. **From the Beginning** - Update profile from previous TamoStudy release. + 8. **Tamo Full** - Achieve maximum Tamo hunger. + 9. **Tamo Love** - Achieve maximum Tamo happiness. + 10. **Dedicated** - Focus for 1+ hours for 3 days consecutively. + 11. **Building Consistency** - Focus for 1+ hours for 7 days consecutively. + 12. **Tamo Scholar** - Focus for 1+ hours for 30 days consecutively. + +### ⚙️ **Settings** + +- Change the settings of TamoStudy to match your preferences! + +

+ +

+ +- For Windows users only, there is an option to toggle Discord Rich Presence. + +### 📖 **Tamo History** + +- Upon a Tamo being deceased, a new feature has been introduced where you can view your previous Tamos. + +

+ +

+ +### 🤖 Discord Rich Presence +This implementation utilizes the [DiscordRPC JAR](https://github.com/Vatuu/discord-rpc). Discord Rich Presence is only supported on **Windows** devices. Development in the future will be explored so that macOS devices are supported. +- This feature can be enabled or disabled on Windows devices in the settings menu. A refresh of the application may need to be taken depending on whether you turn it on or off. +- The following is a collection of images that your status can be expected to show while using TamoStudy with Discord Rich Presence: + +

+ +

+ +- Note: If your computer is utilizing a lot of RAM / CPU power while using TamoStudy, it is recommended that you turn off the Discord RPC feature from the settings menu to improve performance. + +## 🛠️ **Setup TamoStudy** + +### 📃 Requirements + +1. Supported Operating Systems + + TamoStudy has been tested on the following operating systems: + - Windows XP, 10, 11 + - Linux (Ubuntu 20.04 LTS) + - macOS (Monterary, Ventura) + +2. Java Runtime Environment + + TamoStudy was developed utilizing the Java programming language. An installation of the Java Runtime Environment is required to run Java applications. TamoStudy runs on Java 8. A download for Java can be found [here](https://www.java.com/en/download/). + +### 🛜 **Downloading TamoStudy** + +To download TamoStudy, read through the download page [here](https://github.com/narlock/TamoStudy/releases) and select the proper TamoStudy file to download corresponding to your operating system from this page. This file contains the entire application and can be opened utilizing the Java Runtime Environment. + +- **Windows** + - Download the `TamoStudy.exe` file. + - Upon opening for the first time, you will be required to give permission to open this application through the Windows Smart Screen. Simply allow trust the program to run. + +- **Mac OS** + - Download the `TamoStudy.MacOS.zip` file. + - Extract the contents of the zip file. + - Open the application, then given permissions by searching **Gatekeeper** in Settings. Trust the application, then re-open the application. + +- **Linux** + - There is no native Linux binary for TamoStudy. Instead, Linux users can utilize the `TamoStudy.JAR` file (which Windows & MacOS can both utilize as well if they choose to). + - Upon download, you will need to provide execute permissions to run the program. + +## 💡 **Original Concept Idea** + +I wanted a way to record the amount of time I spent focused every day. At the time, I was cleaning through my room and found my Tamagotchi that I used to play with when I was very young. I thought that implementing a Tamagotchi-like pet into a focus timer would be a good idea. The more I focus and get my work done, the more upgrades and new things I can do with the virtual pet (in my project, it's called a Tamo). + +Project plans to include a GUI in which a user can create a username and password along with give a name for their Tamo. The user can re-load this information so they can load where they left off in their studies. (Keeping the total amount of time they have focused, and their previous Tamo alive) + +The Focus GUI will have a set timer (minutes and seconds) the user can choose. When the user begins the Focus session, the timer will count down (this is the time where the user will work). After the timer is up, the session will be completed, and the Tamo will gain experience and happiness, and the user will gain money. + +## 🌟 **Contributors** + +Thank you for everyone that has created a pull request to support the development of TamoStudy! + +- [Shorent](http://github.com/Shorent) - Development (Web) +- [Alyksett](http://github.com/Alyksett) - Development (Main) +- [britthubs](http://github.com/britthubs) - Translation (Main) +- [tokisuno](http://github.com/tokisuno) - Translation (Main) + +And everyone else that has contributed outside of GitHub pull requests! + +
+

+TamoStudy was created on January 30th, 2021 as a personal and free app! • Developed by narlock
+TamoStudy software applications reached over 1,000 total downloads on August 29th, 2022
+

diff --git a/TamoStudy/.classpath b/TamoStudy/.classpath new file mode 100644 index 0000000..065c9d0 --- /dev/null +++ b/TamoStudy/.classpath @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/TamoStudy/.gitignore b/TamoStudy/.gitignore new file mode 100644 index 0000000..a7d9507 --- /dev/null +++ b/TamoStudy/.gitignore @@ -0,0 +1,3 @@ +/bin/ +*.class +bin/ \ No newline at end of file diff --git a/TamoStudy/.idea/.gitignore b/TamoStudy/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/TamoStudy/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/TamoStudy/.project b/TamoStudy/.project new file mode 100644 index 0000000..9ff6e54 --- /dev/null +++ b/TamoStudy/.project @@ -0,0 +1,28 @@ + + + TamoStudy + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + + + 1671906157267 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/TamoStudy/.settings/org.eclipse.jdt.core.prefs b/TamoStudy/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..057be7e --- /dev/null +++ b/TamoStudy/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/TamoStudy/assets/ACHIEVEMENT_0.png b/TamoStudy/assets/ACHIEVEMENT_0.png new file mode 100644 index 0000000..bc03dfc Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_0.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_1.png b/TamoStudy/assets/ACHIEVEMENT_1.png new file mode 100644 index 0000000..5b63344 Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_1.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_10.png b/TamoStudy/assets/ACHIEVEMENT_10.png new file mode 100644 index 0000000..a116040 Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_10.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_11.png b/TamoStudy/assets/ACHIEVEMENT_11.png new file mode 100644 index 0000000..10a680d Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_11.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_2.png b/TamoStudy/assets/ACHIEVEMENT_2.png new file mode 100644 index 0000000..3f1b052 Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_2.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_3.png b/TamoStudy/assets/ACHIEVEMENT_3.png new file mode 100644 index 0000000..80dea4f Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_3.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_4.png b/TamoStudy/assets/ACHIEVEMENT_4.png new file mode 100644 index 0000000..bc8d766 Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_4.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_5.png b/TamoStudy/assets/ACHIEVEMENT_5.png new file mode 100644 index 0000000..4a41cda Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_5.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_6.png b/TamoStudy/assets/ACHIEVEMENT_6.png new file mode 100644 index 0000000..b5d09db Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_6.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_7.png b/TamoStudy/assets/ACHIEVEMENT_7.png new file mode 100644 index 0000000..180bc1a Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_7.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_8.png b/TamoStudy/assets/ACHIEVEMENT_8.png new file mode 100644 index 0000000..837a5b3 Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_8.png differ diff --git a/TamoStudy/assets/ACHIEVEMENT_9.png b/TamoStudy/assets/ACHIEVEMENT_9.png new file mode 100644 index 0000000..c2d94cb Binary files /dev/null and b/TamoStudy/assets/ACHIEVEMENT_9.png differ diff --git a/TamoStudy/assets/ADD.png b/TamoStudy/assets/ADD.png new file mode 100644 index 0000000..cac2c30 Binary files /dev/null and b/TamoStudy/assets/ADD.png differ diff --git a/TamoStudy/assets/ARROW_LEFT.png b/TamoStudy/assets/ARROW_LEFT.png new file mode 100644 index 0000000..19cc090 Binary files /dev/null and b/TamoStudy/assets/ARROW_LEFT.png differ diff --git a/TamoStudy/assets/ARROW_RIGHT.png b/TamoStudy/assets/ARROW_RIGHT.png new file mode 100644 index 0000000..3dae4fd Binary files /dev/null and b/TamoStudy/assets/ARROW_RIGHT.png differ diff --git a/TamoStudy/assets/BACKGROUND_0.png b/TamoStudy/assets/BACKGROUND_0.png new file mode 100644 index 0000000..383d38f Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_0.png differ diff --git a/TamoStudy/assets/BACKGROUND_0_INV.png b/TamoStudy/assets/BACKGROUND_0_INV.png new file mode 100644 index 0000000..51da212 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_0_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_0_SHOP.png b/TamoStudy/assets/BACKGROUND_0_SHOP.png new file mode 100644 index 0000000..57ab39f Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_0_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_1.png b/TamoStudy/assets/BACKGROUND_1.png new file mode 100644 index 0000000..4258b50 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_1.png differ diff --git a/TamoStudy/assets/BACKGROUND_1_INV.png b/TamoStudy/assets/BACKGROUND_1_INV.png new file mode 100644 index 0000000..f38d8f8 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_1_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_1_SHOP.png b/TamoStudy/assets/BACKGROUND_1_SHOP.png new file mode 100644 index 0000000..ef2fb9f Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_1_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_2.png b/TamoStudy/assets/BACKGROUND_2.png new file mode 100644 index 0000000..4341936 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_2.png differ diff --git a/TamoStudy/assets/BACKGROUND_2_INV.png b/TamoStudy/assets/BACKGROUND_2_INV.png new file mode 100644 index 0000000..c94a7dd Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_2_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_2_SHOP.png b/TamoStudy/assets/BACKGROUND_2_SHOP.png new file mode 100644 index 0000000..377bdcd Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_2_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_3.png b/TamoStudy/assets/BACKGROUND_3.png new file mode 100644 index 0000000..eb6a1c8 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_3.png differ diff --git a/TamoStudy/assets/BACKGROUND_3_INV.png b/TamoStudy/assets/BACKGROUND_3_INV.png new file mode 100644 index 0000000..2182c64 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_3_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_3_SHOP.png b/TamoStudy/assets/BACKGROUND_3_SHOP.png new file mode 100644 index 0000000..a182b02 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_3_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_4.png b/TamoStudy/assets/BACKGROUND_4.png new file mode 100644 index 0000000..c19ed7a Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_4.png differ diff --git a/TamoStudy/assets/BACKGROUND_4_INV.png b/TamoStudy/assets/BACKGROUND_4_INV.png new file mode 100644 index 0000000..71d0cd7 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_4_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_4_SHOP.png b/TamoStudy/assets/BACKGROUND_4_SHOP.png new file mode 100644 index 0000000..280bf0a Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_4_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_5.png b/TamoStudy/assets/BACKGROUND_5.png new file mode 100644 index 0000000..f8735fd Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_5.png differ diff --git a/TamoStudy/assets/BACKGROUND_5_INV.png b/TamoStudy/assets/BACKGROUND_5_INV.png new file mode 100644 index 0000000..293b524 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_5_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_5_SHOP.png b/TamoStudy/assets/BACKGROUND_5_SHOP.png new file mode 100644 index 0000000..110af19 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_5_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_6.png b/TamoStudy/assets/BACKGROUND_6.png new file mode 100644 index 0000000..d5d27c0 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_6.png differ diff --git a/TamoStudy/assets/BACKGROUND_6_INV.png b/TamoStudy/assets/BACKGROUND_6_INV.png new file mode 100644 index 0000000..288db81 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_6_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_6_SHOP.png b/TamoStudy/assets/BACKGROUND_6_SHOP.png new file mode 100644 index 0000000..ba341eb Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_6_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_7.png b/TamoStudy/assets/BACKGROUND_7.png new file mode 100644 index 0000000..1c39951 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_7.png differ diff --git a/TamoStudy/assets/BACKGROUND_7_INV.png b/TamoStudy/assets/BACKGROUND_7_INV.png new file mode 100644 index 0000000..fca8fcc Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_7_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_7_SHOP.png b/TamoStudy/assets/BACKGROUND_7_SHOP.png new file mode 100644 index 0000000..1aaaa5f Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_7_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_8.png b/TamoStudy/assets/BACKGROUND_8.png new file mode 100644 index 0000000..1581acd Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_8.png differ diff --git a/TamoStudy/assets/BACKGROUND_8_INV.png b/TamoStudy/assets/BACKGROUND_8_INV.png new file mode 100644 index 0000000..0518334 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_8_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_8_SHOP.png b/TamoStudy/assets/BACKGROUND_8_SHOP.png new file mode 100644 index 0000000..785a1e3 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_8_SHOP.png differ diff --git a/TamoStudy/assets/BACKGROUND_9.png b/TamoStudy/assets/BACKGROUND_9.png new file mode 100644 index 0000000..7a2ef59 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_9.png differ diff --git a/TamoStudy/assets/BACKGROUND_9_INV.png b/TamoStudy/assets/BACKGROUND_9_INV.png new file mode 100644 index 0000000..8b40a04 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_9_INV.png differ diff --git a/TamoStudy/assets/BACKGROUND_9_SHOP.png b/TamoStudy/assets/BACKGROUND_9_SHOP.png new file mode 100644 index 0000000..994d223 Binary files /dev/null and b/TamoStudy/assets/BACKGROUND_9_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_BLACK.png b/TamoStudy/assets/BORDER_BLACK.png new file mode 100644 index 0000000..a0cfaa5 Binary files /dev/null and b/TamoStudy/assets/BORDER_BLACK.png differ diff --git a/TamoStudy/assets/BORDER_BLACK_INV.png b/TamoStudy/assets/BORDER_BLACK_INV.png new file mode 100644 index 0000000..a749980 Binary files /dev/null and b/TamoStudy/assets/BORDER_BLACK_INV.png differ diff --git a/TamoStudy/assets/BORDER_BLACK_SHOP.png b/TamoStudy/assets/BORDER_BLACK_SHOP.png new file mode 100644 index 0000000..0821866 Binary files /dev/null and b/TamoStudy/assets/BORDER_BLACK_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_BLUE.png b/TamoStudy/assets/BORDER_BLUE.png new file mode 100644 index 0000000..71eca0d Binary files /dev/null and b/TamoStudy/assets/BORDER_BLUE.png differ diff --git a/TamoStudy/assets/BORDER_BLUE_INV.png b/TamoStudy/assets/BORDER_BLUE_INV.png new file mode 100644 index 0000000..e68da09 Binary files /dev/null and b/TamoStudy/assets/BORDER_BLUE_INV.png differ diff --git a/TamoStudy/assets/BORDER_BLUE_SHOP.png b/TamoStudy/assets/BORDER_BLUE_SHOP.png new file mode 100644 index 0000000..80fbc07 Binary files /dev/null and b/TamoStudy/assets/BORDER_BLUE_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_CODE.png b/TamoStudy/assets/BORDER_CODE.png new file mode 100644 index 0000000..f4da970 Binary files /dev/null and b/TamoStudy/assets/BORDER_CODE.png differ diff --git a/TamoStudy/assets/BORDER_CODE_INV.png b/TamoStudy/assets/BORDER_CODE_INV.png new file mode 100644 index 0000000..8e3c749 Binary files /dev/null and b/TamoStudy/assets/BORDER_CODE_INV.png differ diff --git a/TamoStudy/assets/BORDER_CODE_SHOP.png b/TamoStudy/assets/BORDER_CODE_SHOP.png new file mode 100644 index 0000000..0e33b5f Binary files /dev/null and b/TamoStudy/assets/BORDER_CODE_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_COTTONCANDY.png b/TamoStudy/assets/BORDER_COTTONCANDY.png new file mode 100644 index 0000000..39b1026 Binary files /dev/null and b/TamoStudy/assets/BORDER_COTTONCANDY.png differ diff --git a/TamoStudy/assets/BORDER_COTTONCANDY_INV.png b/TamoStudy/assets/BORDER_COTTONCANDY_INV.png new file mode 100644 index 0000000..60f5557 Binary files /dev/null and b/TamoStudy/assets/BORDER_COTTONCANDY_INV.png differ diff --git a/TamoStudy/assets/BORDER_COTTONCANDY_SHOP.png b/TamoStudy/assets/BORDER_COTTONCANDY_SHOP.png new file mode 100644 index 0000000..c05d0ed Binary files /dev/null and b/TamoStudy/assets/BORDER_COTTONCANDY_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_GOLD.png b/TamoStudy/assets/BORDER_GOLD.png new file mode 100644 index 0000000..a458c10 Binary files /dev/null and b/TamoStudy/assets/BORDER_GOLD.png differ diff --git a/TamoStudy/assets/BORDER_GOLD_INV.png b/TamoStudy/assets/BORDER_GOLD_INV.png new file mode 100644 index 0000000..94bd202 Binary files /dev/null and b/TamoStudy/assets/BORDER_GOLD_INV.png differ diff --git a/TamoStudy/assets/BORDER_GOLD_SHOP.png b/TamoStudy/assets/BORDER_GOLD_SHOP.png new file mode 100644 index 0000000..818060e Binary files /dev/null and b/TamoStudy/assets/BORDER_GOLD_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_MINT.png b/TamoStudy/assets/BORDER_MINT.png new file mode 100644 index 0000000..3f04bc3 Binary files /dev/null and b/TamoStudy/assets/BORDER_MINT.png differ diff --git a/TamoStudy/assets/BORDER_MINT_INV.png b/TamoStudy/assets/BORDER_MINT_INV.png new file mode 100644 index 0000000..06f8616 Binary files /dev/null and b/TamoStudy/assets/BORDER_MINT_INV.png differ diff --git a/TamoStudy/assets/BORDER_MINT_SHOP.png b/TamoStudy/assets/BORDER_MINT_SHOP.png new file mode 100644 index 0000000..079d0d8 Binary files /dev/null and b/TamoStudy/assets/BORDER_MINT_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_PURPLE.png b/TamoStudy/assets/BORDER_PURPLE.png new file mode 100644 index 0000000..9ecff0c Binary files /dev/null and b/TamoStudy/assets/BORDER_PURPLE.png differ diff --git a/TamoStudy/assets/BORDER_PURPLE_INV.png b/TamoStudy/assets/BORDER_PURPLE_INV.png new file mode 100644 index 0000000..6a705d2 Binary files /dev/null and b/TamoStudy/assets/BORDER_PURPLE_INV.png differ diff --git a/TamoStudy/assets/BORDER_PURPLE_SHOP.png b/TamoStudy/assets/BORDER_PURPLE_SHOP.png new file mode 100644 index 0000000..768c573 Binary files /dev/null and b/TamoStudy/assets/BORDER_PURPLE_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_RAINBOW.png b/TamoStudy/assets/BORDER_RAINBOW.png new file mode 100644 index 0000000..fe37afc Binary files /dev/null and b/TamoStudy/assets/BORDER_RAINBOW.png differ diff --git a/TamoStudy/assets/BORDER_RAINBOW_INV.png b/TamoStudy/assets/BORDER_RAINBOW_INV.png new file mode 100644 index 0000000..c939582 Binary files /dev/null and b/TamoStudy/assets/BORDER_RAINBOW_INV.png differ diff --git a/TamoStudy/assets/BORDER_RAINBOW_SHOP.png b/TamoStudy/assets/BORDER_RAINBOW_SHOP.png new file mode 100644 index 0000000..ac06802 Binary files /dev/null and b/TamoStudy/assets/BORDER_RAINBOW_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_RED.png b/TamoStudy/assets/BORDER_RED.png new file mode 100644 index 0000000..c035c4f Binary files /dev/null and b/TamoStudy/assets/BORDER_RED.png differ diff --git a/TamoStudy/assets/BORDER_RED_INV.png b/TamoStudy/assets/BORDER_RED_INV.png new file mode 100644 index 0000000..1d98435 Binary files /dev/null and b/TamoStudy/assets/BORDER_RED_INV.png differ diff --git a/TamoStudy/assets/BORDER_RED_SHOP.png b/TamoStudy/assets/BORDER_RED_SHOP.png new file mode 100644 index 0000000..72a0cd5 Binary files /dev/null and b/TamoStudy/assets/BORDER_RED_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_RUBY.png b/TamoStudy/assets/BORDER_RUBY.png new file mode 100644 index 0000000..693818b Binary files /dev/null and b/TamoStudy/assets/BORDER_RUBY.png differ diff --git a/TamoStudy/assets/BORDER_RUBY_INV.png b/TamoStudy/assets/BORDER_RUBY_INV.png new file mode 100644 index 0000000..c14b33d Binary files /dev/null and b/TamoStudy/assets/BORDER_RUBY_INV.png differ diff --git a/TamoStudy/assets/BORDER_RUBY_SHOP.png b/TamoStudy/assets/BORDER_RUBY_SHOP.png new file mode 100644 index 0000000..9803d42 Binary files /dev/null and b/TamoStudy/assets/BORDER_RUBY_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_SKYLINE.png b/TamoStudy/assets/BORDER_SKYLINE.png new file mode 100644 index 0000000..2d770d7 Binary files /dev/null and b/TamoStudy/assets/BORDER_SKYLINE.png differ diff --git a/TamoStudy/assets/BORDER_SKYLINE_INV.png b/TamoStudy/assets/BORDER_SKYLINE_INV.png new file mode 100644 index 0000000..0d180f9 Binary files /dev/null and b/TamoStudy/assets/BORDER_SKYLINE_INV.png differ diff --git a/TamoStudy/assets/BORDER_SKYLINE_SHOP.png b/TamoStudy/assets/BORDER_SKYLINE_SHOP.png new file mode 100644 index 0000000..59e5e6e Binary files /dev/null and b/TamoStudy/assets/BORDER_SKYLINE_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_STRAWLEMON.png b/TamoStudy/assets/BORDER_STRAWLEMON.png new file mode 100644 index 0000000..3a19339 Binary files /dev/null and b/TamoStudy/assets/BORDER_STRAWLEMON.png differ diff --git a/TamoStudy/assets/BORDER_STRAWLEMON_INV.png b/TamoStudy/assets/BORDER_STRAWLEMON_INV.png new file mode 100644 index 0000000..0e804d1 Binary files /dev/null and b/TamoStudy/assets/BORDER_STRAWLEMON_INV.png differ diff --git a/TamoStudy/assets/BORDER_STRAWLEMON_SHOP.png b/TamoStudy/assets/BORDER_STRAWLEMON_SHOP.png new file mode 100644 index 0000000..38a7d85 Binary files /dev/null and b/TamoStudy/assets/BORDER_STRAWLEMON_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_SUNSET.png b/TamoStudy/assets/BORDER_SUNSET.png new file mode 100644 index 0000000..528fa46 Binary files /dev/null and b/TamoStudy/assets/BORDER_SUNSET.png differ diff --git a/TamoStudy/assets/BORDER_SUNSET_INV.png b/TamoStudy/assets/BORDER_SUNSET_INV.png new file mode 100644 index 0000000..f7f9ddb Binary files /dev/null and b/TamoStudy/assets/BORDER_SUNSET_INV.png differ diff --git a/TamoStudy/assets/BORDER_SUNSET_SHOP.png b/TamoStudy/assets/BORDER_SUNSET_SHOP.png new file mode 100644 index 0000000..1e7e47c Binary files /dev/null and b/TamoStudy/assets/BORDER_SUNSET_SHOP.png differ diff --git a/TamoStudy/assets/BORDER_TEAL.png b/TamoStudy/assets/BORDER_TEAL.png new file mode 100644 index 0000000..776d917 Binary files /dev/null and b/TamoStudy/assets/BORDER_TEAL.png differ diff --git a/TamoStudy/assets/BORDER_TEAL_INV.png b/TamoStudy/assets/BORDER_TEAL_INV.png new file mode 100644 index 0000000..62f2352 Binary files /dev/null and b/TamoStudy/assets/BORDER_TEAL_INV.png differ diff --git a/TamoStudy/assets/BORDER_TEAL_SHOP.png b/TamoStudy/assets/BORDER_TEAL_SHOP.png new file mode 100644 index 0000000..296ce44 Binary files /dev/null and b/TamoStudy/assets/BORDER_TEAL_SHOP.png differ diff --git a/TamoStudy/assets/DARK_MODE.png b/TamoStudy/assets/DARK_MODE.png new file mode 100644 index 0000000..6974b8b Binary files /dev/null and b/TamoStudy/assets/DARK_MODE.png differ diff --git a/TamoStudy/assets/DISCORD.png b/TamoStudy/assets/DISCORD.png new file mode 100644 index 0000000..a1f212f Binary files /dev/null and b/TamoStudy/assets/DISCORD.png differ diff --git a/TamoStudy/assets/FAVICON.png b/TamoStudy/assets/FAVICON.png new file mode 100644 index 0000000..fcc2d6a Binary files /dev/null and b/TamoStudy/assets/FAVICON.png differ diff --git a/TamoStudy/assets/FOOD_1.png b/TamoStudy/assets/FOOD_1.png new file mode 100644 index 0000000..e42060f Binary files /dev/null and b/TamoStudy/assets/FOOD_1.png differ diff --git a/TamoStudy/assets/FOOD_10.png b/TamoStudy/assets/FOOD_10.png new file mode 100644 index 0000000..5d70c01 Binary files /dev/null and b/TamoStudy/assets/FOOD_10.png differ diff --git a/TamoStudy/assets/FOOD_10_INV.png b/TamoStudy/assets/FOOD_10_INV.png new file mode 100644 index 0000000..268a52f Binary files /dev/null and b/TamoStudy/assets/FOOD_10_INV.png differ diff --git a/TamoStudy/assets/FOOD_1_INV.png b/TamoStudy/assets/FOOD_1_INV.png new file mode 100644 index 0000000..4a4092b Binary files /dev/null and b/TamoStudy/assets/FOOD_1_INV.png differ diff --git a/TamoStudy/assets/FOOD_3.png b/TamoStudy/assets/FOOD_3.png new file mode 100644 index 0000000..9be936b Binary files /dev/null and b/TamoStudy/assets/FOOD_3.png differ diff --git a/TamoStudy/assets/FOOD_3_INV.png b/TamoStudy/assets/FOOD_3_INV.png new file mode 100644 index 0000000..61bc101 Binary files /dev/null and b/TamoStudy/assets/FOOD_3_INV.png differ diff --git a/TamoStudy/assets/GITHUB.png b/TamoStudy/assets/GITHUB.png new file mode 100644 index 0000000..3901c49 Binary files /dev/null and b/TamoStudy/assets/GITHUB.png differ diff --git a/TamoStudy/assets/GRAY.png b/TamoStudy/assets/GRAY.png new file mode 100644 index 0000000..8680fcb Binary files /dev/null and b/TamoStudy/assets/GRAY.png differ diff --git a/TamoStudy/assets/GREEN_1.png b/TamoStudy/assets/GREEN_1.png new file mode 100644 index 0000000..fc71c08 Binary files /dev/null and b/TamoStudy/assets/GREEN_1.png differ diff --git a/TamoStudy/assets/GREEN_2.png b/TamoStudy/assets/GREEN_2.png new file mode 100644 index 0000000..072e840 Binary files /dev/null and b/TamoStudy/assets/GREEN_2.png differ diff --git a/TamoStudy/assets/GREEN_3.png b/TamoStudy/assets/GREEN_3.png new file mode 100644 index 0000000..c656465 Binary files /dev/null and b/TamoStudy/assets/GREEN_3.png differ diff --git a/TamoStudy/assets/GREEN_4.png b/TamoStudy/assets/GREEN_4.png new file mode 100644 index 0000000..8f89d2f Binary files /dev/null and b/TamoStudy/assets/GREEN_4.png differ diff --git a/TamoStudy/assets/HAPPY.png b/TamoStudy/assets/HAPPY.png new file mode 100644 index 0000000..f75276f Binary files /dev/null and b/TamoStudy/assets/HAPPY.png differ diff --git a/TamoStudy/assets/HEART.png b/TamoStudy/assets/HEART.png new file mode 100644 index 0000000..2e759a0 Binary files /dev/null and b/TamoStudy/assets/HEART.png differ diff --git a/TamoStudy/assets/HUNGER.png b/TamoStudy/assets/HUNGER.png new file mode 100644 index 0000000..8454ea6 Binary files /dev/null and b/TamoStudy/assets/HUNGER.png differ diff --git a/TamoStudy/assets/ICON.png b/TamoStudy/assets/ICON.png new file mode 100644 index 0000000..09ed934 Binary files /dev/null and b/TamoStudy/assets/ICON.png differ diff --git a/TamoStudy/assets/INFO.png b/TamoStudy/assets/INFO.png new file mode 100644 index 0000000..b051102 Binary files /dev/null and b/TamoStudy/assets/INFO.png differ diff --git a/TamoStudy/assets/INFO_GOOD.png b/TamoStudy/assets/INFO_GOOD.png new file mode 100644 index 0000000..0a488df Binary files /dev/null and b/TamoStudy/assets/INFO_GOOD.png differ diff --git a/TamoStudy/assets/INSTAGRAM.png b/TamoStudy/assets/INSTAGRAM.png new file mode 100644 index 0000000..f38f9da Binary files /dev/null and b/TamoStudy/assets/INSTAGRAM.png differ diff --git a/TamoStudy/assets/INSTAGRAM_ICON.png b/TamoStudy/assets/INSTAGRAM_ICON.png new file mode 100644 index 0000000..9aa0f5f Binary files /dev/null and b/TamoStudy/assets/INSTAGRAM_ICON.png differ diff --git a/TamoStudy/assets/KATH_MSG.png b/TamoStudy/assets/KATH_MSG.png new file mode 100644 index 0000000..2cd377c Binary files /dev/null and b/TamoStudy/assets/KATH_MSG.png differ diff --git a/TamoStudy/assets/KATH_SHOP.png b/TamoStudy/assets/KATH_SHOP.png new file mode 100644 index 0000000..da43879 Binary files /dev/null and b/TamoStudy/assets/KATH_SHOP.png differ diff --git a/TamoStudy/assets/MINUS.png b/TamoStudy/assets/MINUS.png new file mode 100644 index 0000000..0c84e04 Binary files /dev/null and b/TamoStudy/assets/MINUS.png differ diff --git a/TamoStudy/assets/NARLOCK_ICON.png b/TamoStudy/assets/NARLOCK_ICON.png new file mode 100644 index 0000000..3b8c1e6 Binary files /dev/null and b/TamoStudy/assets/NARLOCK_ICON.png differ diff --git a/TamoStudy/assets/ONIGIRI.png b/TamoStudy/assets/ONIGIRI.png new file mode 100644 index 0000000..fece6e3 Binary files /dev/null and b/TamoStudy/assets/ONIGIRI.png differ diff --git a/TamoStudy/assets/PAC_ALARM.wav b/TamoStudy/assets/PAC_ALARM.wav new file mode 100644 index 0000000..5e4ba59 Binary files /dev/null and b/TamoStudy/assets/PAC_ALARM.wav differ diff --git a/TamoStudy/assets/SETTINGS.png b/TamoStudy/assets/SETTINGS.png new file mode 100644 index 0000000..3c48935 Binary files /dev/null and b/TamoStudy/assets/SETTINGS.png differ diff --git a/TamoStudy/assets/SOFT_ALARM.wav b/TamoStudy/assets/SOFT_ALARM.wav new file mode 100644 index 0000000..e1d7f42 Binary files /dev/null and b/TamoStudy/assets/SOFT_ALARM.wav differ diff --git a/TamoStudy/assets/STAR.png b/TamoStudy/assets/STAR.png new file mode 100644 index 0000000..683a465 Binary files /dev/null and b/TamoStudy/assets/STAR.png differ diff --git a/TamoStudy/assets/SUN_MODE.png b/TamoStudy/assets/SUN_MODE.png new file mode 100644 index 0000000..136cdac Binary files /dev/null and b/TamoStudy/assets/SUN_MODE.png differ diff --git a/TamoStudy/assets/TAMOSTUDY_ICON.png b/TamoStudy/assets/TAMOSTUDY_ICON.png new file mode 100644 index 0000000..002ed64 Binary files /dev/null and b/TamoStudy/assets/TAMOSTUDY_ICON.png differ diff --git a/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE.gif b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE.gif new file mode 100644 index 0000000..83bacde Binary files /dev/null and b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE.gif differ diff --git a/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_LARGE.gif b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_LARGE.gif new file mode 100644 index 0000000..bb8f002 Binary files /dev/null and b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_LARGE.gif differ diff --git a/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_SMALL.gif b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_SMALL.gif new file mode 100644 index 0000000..b87cabb Binary files /dev/null and b/TamoStudy/assets/TAMOSTUDY_LOGO_IMAGE_SMALL.gif differ diff --git a/TamoStudy/assets/TAMO_FOCUS_0.png b/TamoStudy/assets/TAMO_FOCUS_0.png new file mode 100644 index 0000000..842aba8 Binary files /dev/null and b/TamoStudy/assets/TAMO_FOCUS_0.png differ diff --git a/TamoStudy/assets/TAMO_FOCUS_1.png b/TamoStudy/assets/TAMO_FOCUS_1.png new file mode 100644 index 0000000..d50216e Binary files /dev/null and b/TamoStudy/assets/TAMO_FOCUS_1.png differ diff --git a/TamoStudy/assets/TAMO_FOCUS_2.png b/TamoStudy/assets/TAMO_FOCUS_2.png new file mode 100644 index 0000000..6b0ffcf Binary files /dev/null and b/TamoStudy/assets/TAMO_FOCUS_2.png differ diff --git a/TamoStudy/assets/TAMO_FOCUS_3.png b/TamoStudy/assets/TAMO_FOCUS_3.png new file mode 100644 index 0000000..046ce45 Binary files /dev/null and b/TamoStudy/assets/TAMO_FOCUS_3.png differ diff --git a/TamoStudy/assets/TAMO_FOCUS_4.png b/TamoStudy/assets/TAMO_FOCUS_4.png new file mode 100644 index 0000000..ca28e55 Binary files /dev/null and b/TamoStudy/assets/TAMO_FOCUS_4.png differ diff --git a/TamoStudy/assets/TAMO_HAPPY_0.png b/TamoStudy/assets/TAMO_HAPPY_0.png new file mode 100644 index 0000000..99b42c4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HAPPY_0.png differ diff --git a/TamoStudy/assets/TAMO_HAPPY_1.png b/TamoStudy/assets/TAMO_HAPPY_1.png new file mode 100644 index 0000000..99b42c4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HAPPY_1.png differ diff --git a/TamoStudy/assets/TAMO_HAPPY_2.png b/TamoStudy/assets/TAMO_HAPPY_2.png new file mode 100644 index 0000000..97dc491 Binary files /dev/null and b/TamoStudy/assets/TAMO_HAPPY_2.png differ diff --git a/TamoStudy/assets/TAMO_HAPPY_3.png b/TamoStudy/assets/TAMO_HAPPY_3.png new file mode 100644 index 0000000..99b42c4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HAPPY_3.png differ diff --git a/TamoStudy/assets/TAMO_HAPPY_4.png b/TamoStudy/assets/TAMO_HAPPY_4.png new file mode 100644 index 0000000..4e5204b Binary files /dev/null and b/TamoStudy/assets/TAMO_HAPPY_4.png differ diff --git a/TamoStudy/assets/TAMO_HUNGRY_0.png b/TamoStudy/assets/TAMO_HUNGRY_0.png new file mode 100644 index 0000000..5430ed4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HUNGRY_0.png differ diff --git a/TamoStudy/assets/TAMO_HUNGRY_1.png b/TamoStudy/assets/TAMO_HUNGRY_1.png new file mode 100644 index 0000000..5430ed4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HUNGRY_1.png differ diff --git a/TamoStudy/assets/TAMO_HUNGRY_2.png b/TamoStudy/assets/TAMO_HUNGRY_2.png new file mode 100644 index 0000000..fd0b998 Binary files /dev/null and b/TamoStudy/assets/TAMO_HUNGRY_2.png differ diff --git a/TamoStudy/assets/TAMO_HUNGRY_3.png b/TamoStudy/assets/TAMO_HUNGRY_3.png new file mode 100644 index 0000000..5430ed4 Binary files /dev/null and b/TamoStudy/assets/TAMO_HUNGRY_3.png differ diff --git a/TamoStudy/assets/TAMO_HUNGRY_4.png b/TamoStudy/assets/TAMO_HUNGRY_4.png new file mode 100644 index 0000000..4bc3e7d Binary files /dev/null and b/TamoStudy/assets/TAMO_HUNGRY_4.png differ diff --git a/TamoStudy/assets/TAMO_NORMAL_0.png b/TamoStudy/assets/TAMO_NORMAL_0.png new file mode 100644 index 0000000..5bf2951 Binary files /dev/null and b/TamoStudy/assets/TAMO_NORMAL_0.png differ diff --git a/TamoStudy/assets/TAMO_NORMAL_1.png b/TamoStudy/assets/TAMO_NORMAL_1.png new file mode 100644 index 0000000..5bf2951 Binary files /dev/null and b/TamoStudy/assets/TAMO_NORMAL_1.png differ diff --git a/TamoStudy/assets/TAMO_NORMAL_2.png b/TamoStudy/assets/TAMO_NORMAL_2.png new file mode 100644 index 0000000..4fc690e Binary files /dev/null and b/TamoStudy/assets/TAMO_NORMAL_2.png differ diff --git a/TamoStudy/assets/TAMO_NORMAL_3.png b/TamoStudy/assets/TAMO_NORMAL_3.png new file mode 100644 index 0000000..5bf2951 Binary files /dev/null and b/TamoStudy/assets/TAMO_NORMAL_3.png differ diff --git a/TamoStudy/assets/TAMO_NORMAL_4.png b/TamoStudy/assets/TAMO_NORMAL_4.png new file mode 100644 index 0000000..c2ddef1 Binary files /dev/null and b/TamoStudy/assets/TAMO_NORMAL_4.png differ diff --git a/TamoStudy/assets/TAMO_SAD_0.png b/TamoStudy/assets/TAMO_SAD_0.png new file mode 100644 index 0000000..508d982 Binary files /dev/null and b/TamoStudy/assets/TAMO_SAD_0.png differ diff --git a/TamoStudy/assets/TAMO_SAD_1.png b/TamoStudy/assets/TAMO_SAD_1.png new file mode 100644 index 0000000..508d982 Binary files /dev/null and b/TamoStudy/assets/TAMO_SAD_1.png differ diff --git a/TamoStudy/assets/TAMO_SAD_2.png b/TamoStudy/assets/TAMO_SAD_2.png new file mode 100644 index 0000000..9c6e925 Binary files /dev/null and b/TamoStudy/assets/TAMO_SAD_2.png differ diff --git a/TamoStudy/assets/TAMO_SAD_3.png b/TamoStudy/assets/TAMO_SAD_3.png new file mode 100644 index 0000000..508d982 Binary files /dev/null and b/TamoStudy/assets/TAMO_SAD_3.png differ diff --git a/TamoStudy/assets/TAMO_SAD_4.png b/TamoStudy/assets/TAMO_SAD_4.png new file mode 100644 index 0000000..c2f2258 Binary files /dev/null and b/TamoStudy/assets/TAMO_SAD_4.png differ diff --git a/TamoStudy/assets/TAMO_TOKEN.png b/TamoStudy/assets/TAMO_TOKEN.png new file mode 100644 index 0000000..2ee6c9d Binary files /dev/null and b/TamoStudy/assets/TAMO_TOKEN.png differ diff --git a/TamoStudy/assets/TITLE_ICON.png b/TamoStudy/assets/TITLE_ICON.png new file mode 100644 index 0000000..240e064 Binary files /dev/null and b/TamoStudy/assets/TITLE_ICON.png differ diff --git a/TamoStudy/assets/TOP_MENU.png b/TamoStudy/assets/TOP_MENU.png new file mode 100644 index 0000000..9fd7b1f Binary files /dev/null and b/TamoStudy/assets/TOP_MENU.png differ diff --git a/TamoStudy/assets/TRAD_ALARM.wav b/TamoStudy/assets/TRAD_ALARM.wav new file mode 100644 index 0000000..81b5d40 Binary files /dev/null and b/TamoStudy/assets/TRAD_ALARM.wav differ diff --git a/TamoStudy/assets/TWITTER_ICON.png b/TamoStudy/assets/TWITTER_ICON.png new file mode 100644 index 0000000..292d555 Binary files /dev/null and b/TamoStudy/assets/TWITTER_ICON.png differ diff --git a/TamoStudy/assets/YOUTUBE_ICON.png b/TamoStudy/assets/YOUTUBE_ICON.png new file mode 100644 index 0000000..0c59740 Binary files /dev/null and b/TamoStudy/assets/YOUTUBE_ICON.png differ diff --git a/TamoStudy/src/TamoStudy.java b/TamoStudy/src/TamoStudy.java new file mode 100644 index 0000000..d04ef0f --- /dev/null +++ b/TamoStudy/src/TamoStudy.java @@ -0,0 +1,20 @@ +import gui.WelcomeGUI; +import resources.Debug; + +/** + * Runner - TamoStudy + * + * @author Anthony Narlock (narlock) + * + * @brief The main class that instantiates + * the welcome GUI for TamoStudy + */ + +public class TamoStudy { + + public static void main(String[] args) { + Debug.info("TamoStudy.main", "TamoStudy program starting to run."); + new WelcomeGUI(); + } + +} diff --git a/TamoStudy/src/components/border/BubbleBorder.java b/TamoStudy/src/components/border/BubbleBorder.java new file mode 100644 index 0000000..4deeb0e --- /dev/null +++ b/TamoStudy/src/components/border/BubbleBorder.java @@ -0,0 +1,117 @@ +package components.border; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.Area; +import java.awt.geom.RoundRectangle2D; + +import javax.swing.border.AbstractBorder; + +/** + * Found on the web, then modified + * + * @author narlock + * @author http://stackoverflow.com/questions/15025092/border-with-rounded-corners-transparency + * + * @brief Creates a curved border for JComponent + * + */ +public class BubbleBorder extends AbstractBorder +{ + + public Color color; + public int thickness = 4; + public int radii = 8; + public int pointerSize = 7; + private Insets insets = null; + private BasicStroke stroke = null; + private int strokePad; + private int pointerPad = 4; + public boolean left = true; + RenderingHints hints; + + public BubbleBorder(Color color) + { + new BubbleBorder(color, 4, 8, 7); + } + + public BubbleBorder(Color color, int thickness, int radii, int pointerSize) + { + this.thickness = thickness; + this.radii = radii; + this.pointerSize = pointerSize; + this.color = color; + + stroke = new BasicStroke(thickness); + strokePad = thickness / 2; + + hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + int pad = radii + strokePad; + int bottomPad = pad + pointerSize + strokePad; + insets = new Insets(pad, pad, bottomPad, pad); + } + + public BubbleBorder(Color color, int thickness, int radii, int pointerSize, boolean left) + { + this(color, thickness, radii, pointerSize); + this.left = left; + } + + @Override + public Insets getBorderInsets(Component c) + { + return insets; + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) + { + return getBorderInsets(c); + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) + { + + Graphics2D g2 = (Graphics2D) g; + + int bottomLineY = height - thickness - pointerSize; + + RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(0 + strokePad, 0 + strokePad, width - thickness, bottomLineY, + radii, radii); + + Polygon pointer = new Polygon(); + + Area area = new Area(bubble); + area.add(new Area(pointer)); + + g2.setRenderingHints(hints); + + // Paint the BG color of the parent, everywhere outside the clip + // of the text bubble. + Component parent = c.getParent(); + if (parent != null) + { + Color bg = parent.getBackground(); + Rectangle rect = new Rectangle(0, 0, width, height); + Area borderRegion = new Area(rect); + borderRegion.subtract(area); + g2.setClip(borderRegion); + g2.setColor(bg); + g2.fillRect(0, 0, width, height); + g2.setClip(null); + } + + g2.setColor(color); + g2.setStroke(stroke); + g2.draw(area); + } +} \ No newline at end of file diff --git a/TamoStudy/src/components/border/TextBubbleBorder.java b/TamoStudy/src/components/border/TextBubbleBorder.java new file mode 100644 index 0000000..4a2ae3c --- /dev/null +++ b/TamoStudy/src/components/border/TextBubbleBorder.java @@ -0,0 +1,133 @@ +package components.border; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.Area; +import java.awt.geom.RoundRectangle2D; + +import javax.swing.border.AbstractBorder; + +/** + * Found on the web, then modified + * + * @author http://stackoverflow.com/questions/15025092/border-with-rounded-corners-transparency + * + */ +public class TextBubbleBorder extends AbstractBorder +{ + + private Color color; + private int thickness = 4; + private int radii = 8; + private int pointerSize = 7; + private Insets insets = null; + private BasicStroke stroke = null; + private int strokePad; + private int pointerPad = 4; + private boolean left = true; + RenderingHints hints; + + public TextBubbleBorder(Color color) + { + new TextBubbleBorder(color, 4, 8, 7); + } + + public TextBubbleBorder(Color color, int thickness, int radii, int pointerSize) + { + this.thickness = thickness; + this.radii = radii; + this.pointerSize = pointerSize; + this.color = color; + + stroke = new BasicStroke(thickness); + strokePad = thickness / 2; + + hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + int pad = radii + strokePad; + int bottomPad = pad + pointerSize + strokePad; + insets = new Insets(pad, pad, bottomPad, pad); + } + + public TextBubbleBorder(Color color, int thickness, int radii, int pointerSize, boolean left) + { + this(color, thickness, radii, pointerSize); + this.left = left; + } + + @Override + public Insets getBorderInsets(Component c) + { + return insets; + } + + @Override + public Insets getBorderInsets(Component c, Insets insets) + { + return getBorderInsets(c); + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) + { + + Graphics2D g2 = (Graphics2D) g; + + int bottomLineY = height - thickness - pointerSize; + + RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(0 + strokePad, 0 + strokePad, width - thickness, bottomLineY, + radii, radii); + + Polygon pointer = new Polygon(); + + if (left) + { + // left point + pointer.addPoint(strokePad + radii + pointerPad + 80, bottomLineY); + // right point + pointer.addPoint(strokePad + radii + pointerPad + pointerSize + 80, bottomLineY); + // bottom point + pointer.addPoint(strokePad + radii + pointerPad + (pointerSize / 2) + 80, height - strokePad); + } + else + { + // left point + pointer.addPoint(width - (strokePad + radii + pointerPad), bottomLineY); + // right point + pointer.addPoint(width - (strokePad + radii + pointerPad + pointerSize), bottomLineY); + // bottom point + pointer.addPoint(width - (strokePad + radii + pointerPad + (pointerSize / 2)), height - strokePad); + } + + Area area = new Area(bubble); + area.add(new Area(pointer)); + + g2.setRenderingHints(hints); + + // Paint the BG color of the parent, everywhere outside the clip + // of the text bubble. + Component parent = c.getParent(); + if (parent != null) + { + Color bg = parent.getBackground(); + Rectangle rect = new Rectangle(0, 0, width, height); + Area borderRegion = new Area(rect); + borderRegion.subtract(area); + g2.setClip(borderRegion); + g2.setColor(bg); + g2.fillRect(0, 0, width, height); + g2.setClip(null); + } + + g2.setColor(color); + g2.setStroke(stroke); + g2.draw(area); + } +} \ No newline at end of file diff --git a/TamoStudy/src/components/panel/AchievementPanel.java b/TamoStudy/src/components/panel/AchievementPanel.java new file mode 100644 index 0000000..de0417a --- /dev/null +++ b/TamoStudy/src/components/panel/AchievementPanel.java @@ -0,0 +1,87 @@ +package components.panel; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.GridLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import model.GuiSize; +import model.language.Language; +import resources.Achievements; +import resources.Theme; + +/** + * AchievementPanel + * @author narlock + * @brief An individual achievement represented as a panel. + * The achievement panel will contain components + * + */ +public class AchievementPanel extends JPanel { + + private static final long serialVersionUID = 4615565255974024312L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GuiSize guiSize; + private Language language; + private Theme theme; + private int indicator; + private boolean earned; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JLabel achievementIconLabel; + + private JPanel achievementTextPanel; + private JLabel achievementTitleLabel; + private JLabel achievementDescriptionLabel; + + public AchievementPanel(Theme theme, GuiSize guiSize, Language language, int indicator, boolean earned) { + this.guiSize = guiSize; + this.language = language; + this.indicator = indicator; + this.earned = earned; + this.theme = theme; + + initializeComponents(); + initializePanel(); + } + + public void initializeComponents() { + achievementIconLabel = new JLabel(Achievements.getAchievementIconByIndicator(earned, indicator, guiSize)); + achievementTextPanel = new JPanel(new GridLayout(2, 1)); + achievementTitleLabel = new JLabel(Achievements.getAchievementTitleByIndicator(indicator, language)); + achievementTitleLabel.setFont(guiSize.achievementTitleLabelFont); + achievementTitleLabel.setForeground(theme.textColor); + achievementDescriptionLabel = new JLabel(Achievements.getAchievementDescriptionByIndicator(indicator, language)); + achievementDescriptionLabel.setFont(guiSize.achievementDescriptionLabelFont); + achievementDescriptionLabel.setForeground(theme.textColor); + + achievementTextPanel.setBackground(theme.mainColor); + achievementTextPanel.add(achievementTitleLabel); + achievementTextPanel.add(achievementDescriptionLabel); + } + + public void initializePanel() { + this.setBackground(theme.mainColor); + this.add(achievementIconLabel, BorderLayout.WEST); + this.add(achievementTextPanel, BorderLayout.CENTER); + } + + + + +} diff --git a/TamoStudy/src/components/panel/ChangeGlobalSettingsPanel.java b/TamoStudy/src/components/panel/ChangeGlobalSettingsPanel.java new file mode 100644 index 0000000..a46f696 --- /dev/null +++ b/TamoStudy/src/components/panel/ChangeGlobalSettingsPanel.java @@ -0,0 +1,241 @@ +package components.panel; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import gui.WelcomeGUI; +import io.GlobalSettingsJsonManager; +import model.GlobalSettings; +import model.language.Language; +import resources.Debug; +import resources.Theme; + +public class ChangeGlobalSettingsPanel extends JPanel { + + private static final long serialVersionUID = 7788124824526423171L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private WelcomeGUI welcomeGUI; + private GlobalSettingsJsonManager globalSettingsJsonManager; + private GlobalSettings globalSettings; + private Language language; + private Theme theme; + + /* + * ################################## + * ################################## + * SELECTION COMPONENTS + * ################################## + * ################################## + */ + private JLabel messageLabel; + + private JPanel settingsPanel; + private JPanel languagePanel; + private JLabel languageLabel; + private JComboBox languageBox; + private JPanel resetDefaultLocalProfilePanel; + private JLabel resetDefaultLocalProfileLabel; + private JButton resetDefaultLocalProfileButton; + private JPanel receiveUpdateNotificationsPanel; + private JLabel receiveUpdateNotificationsLabel; + private JButton receiveUpdateNotificationsButton; + + private JButton saveChangesButton; + + public ChangeGlobalSettingsPanel(WelcomeGUI welcomeGUI) { + this.welcomeGUI = welcomeGUI; + + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + addComponentsToPanel(); + } + + private void initializeAttributes() { + globalSettingsJsonManager = welcomeGUI.getGlobalSettingsJsonManager(); + globalSettings = welcomeGUI.getGlobalSettings(); + Debug.info("ChangeGlobalSettingsPanel.initializeAttributes", "globalSettings=" + globalSettings.toString()); + language = globalSettings.getLanguage(); + theme = Theme.DARK; + } + + private void initializeComponents() { + messageLabel = new JLabel(language.globalSettingsText); + + settingsPanel = new JPanel(new GridBagLayout()); + + languagePanel = new JPanel(new GridBagLayout()); + languageLabel = new JLabel(language.languageText); + languageBox = new JComboBox<>(); + languageBox.addItem(language.englishText); + languageBox.addItem(language.spanishText); +// languageBox.addItem(language.hindiText); +// languageBox.addItem(language.portugueseText); +// languageBox.addItem(language.japaneseText); +// languageBox.addItem(language.germanText); +// languageBox.addItem(language.frenchText); +// languageBox.addItem(language.turkishText); +// languageBox.addItem(language.mandarinChineseText); +// languageBox.addItem(language.dutchText); +// languageBox.addItem(language.koreanText); +// languageBox.addItem(language.russianText); +// languageBox.addItem(language.hungarianText); +// languageBox.addItem(language.romanianText); + + resetDefaultLocalProfilePanel = new JPanel(new GridBagLayout()); + resetDefaultLocalProfileLabel = new JLabel(language.resetDefaultProfileText); + resetDefaultLocalProfileButton = new JButton(language.resetText); + + receiveUpdateNotificationsPanel = new JPanel(new GridBagLayout()); + receiveUpdateNotificationsLabel = new JLabel(language.updateNotificationsText); + + receiveUpdateNotificationsButton = new JButton(); + if(globalSettings.getReceiveUpdateNotifications()) { + receiveUpdateNotificationsButton.setText(language.onText); + Theme.primaryVisualButton(receiveUpdateNotificationsButton); + } else { + receiveUpdateNotificationsButton.setText(language.offText); + Theme.secondaryVisualButton(receiveUpdateNotificationsButton);; + } + + + saveChangesButton = new JButton(language.saveText); + } + + private void initializeComponentVisuals() { + this.setPreferredSize(new Dimension(500, 400)); + this.setLayout(new GridBagLayout()); + this.setBackground(theme.mainColor); + + messageLabel.setFont(theme.fontBoldReg); + messageLabel.setForeground(Color.WHITE); + + settingsPanel.setBackground(theme.subColor); + settingsPanel.setBorder(Theme.SUB_BORDER); + + languagePanel.setBackground(theme.subColor); + languageLabel.setFont(theme.fontBoldRegSmall); + languageLabel.setForeground(Color.WHITE); + languageBox.setSelectedIndex(Language.getIndexFromLanguage(language)); + + resetDefaultLocalProfilePanel.setBackground(theme.subColor); + resetDefaultLocalProfileLabel.setFont(theme.fontBoldRegSmall); + resetDefaultLocalProfileLabel.setForeground(Color.WHITE); + Theme.primaryVisualButton(resetDefaultLocalProfileButton); + + receiveUpdateNotificationsPanel.setBackground(theme.subColor); + receiveUpdateNotificationsLabel.setFont(theme.fontBoldRegSmall); + receiveUpdateNotificationsLabel.setForeground(Color.WHITE); + + Theme.successVisualButton(saveChangesButton); + } + + private void initializeComponentActions() { + languageBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Language selectedLanguage = Language.getLanguageFromBox(languageBox.getSelectedIndex()); + Debug.info("ChangeGlobalSettingsPanel.languageBox.actionPerformed", "Changing language to " + selectedLanguage.toString()); + globalSettings.setLanguage(selectedLanguage); + } + }); + + resetDefaultLocalProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + messageLabel.setText(language.defaultProfileReset); + messageLabel.setForeground(Theme.PRIMARY); + + globalSettings.setDefaultLocalProfile(-1); + } + }); + + receiveUpdateNotificationsButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(globalSettings.getReceiveUpdateNotifications()) { + globalSettings.setReceiveUpdateNotifications(false); + receiveUpdateNotificationsButton.setText(language.offText); + Theme.secondaryVisualButton(receiveUpdateNotificationsButton); + } else { + globalSettings.setReceiveUpdateNotifications(true); + receiveUpdateNotificationsButton.setText(language.onText); + Theme.primaryVisualButton(receiveUpdateNotificationsButton); + } + } + }); + + saveChangesButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + messageLabel.setText(language.settingsSavedText); + messageLabel.setForeground(Theme.SUCCESS); + + globalSettingsJsonManager.writeJsonToFile(globalSettings); + Debug.info("ChangeGlobalSettingsPanel.saveChangesButton.actionPerformed", "Saved new globalSettings=" + globalSettings); + + welcomeGUI.resetGui(); + } + + }); + } + + private void addComponentsToPanel() { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + + languagePanel.add(languageLabel); + languagePanel.add(Box.createHorizontalStrut(10)); + languagePanel.add(languageBox); + + resetDefaultLocalProfilePanel.add(resetDefaultLocalProfileLabel); + resetDefaultLocalProfilePanel.add(Box.createHorizontalStrut(20)); + resetDefaultLocalProfilePanel.add(resetDefaultLocalProfileButton); + + receiveUpdateNotificationsPanel.add(receiveUpdateNotificationsLabel); + receiveUpdateNotificationsPanel.add(Box.createHorizontalStrut(20)); + receiveUpdateNotificationsPanel.add(receiveUpdateNotificationsButton); + + // Settings Panel + settingsPanel.add(languagePanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(20), innergbcv); + settingsPanel.add(resetDefaultLocalProfilePanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(20), innergbcv); + settingsPanel.add(receiveUpdateNotificationsPanel, innergbcv); + + this.add(messageLabel, gbcv); + this.add(Box.createVerticalStrut(20), gbcv); + this.add(settingsPanel, gbcv); + this.add(Box.createVerticalStrut(20), gbcv); + this.add(saveChangesButton, gbcv); + } +} diff --git a/TamoStudy/src/components/panel/HoursInPastPanel.java b/TamoStudy/src/components/panel/HoursInPastPanel.java new file mode 100644 index 0000000..dd501b7 --- /dev/null +++ b/TamoStudy/src/components/panel/HoursInPastPanel.java @@ -0,0 +1,167 @@ +package components.panel; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.LookAndFeel; +import javax.swing.plaf.basic.BasicPopupMenuUI; + +import model.GuiSize; +import model.language.Language; +import model.time.DailyFocusEntry; +import resources.Theme; +import util.Utils; + +/** + * HoursInPastPanel + * @author narlock + * @brief JPanel that displays the amount of hours studied + * in the past 354 days. + */ +public class HoursInPastPanel extends JPanel { + + private static final long serialVersionUID = 6373302726491243044L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private List dateList; + private List focusEntries; + private GuiSize guiSize; + private Theme theme; + private Language language; + + public HoursInPastPanel(Language language, Theme theme, List focusEntries, GuiSize guiSize) { + this.focusEntries = focusEntries; + this.guiSize = guiSize; + this.theme = theme; + this.dateList = getDateList(); + this.language = language; + + initializePanel(); + } + + public void initializePanel() { + int gridRowCount = 7; + int gridColCount = 26; + this.setBackground(theme.mainColor); + this.setBorder(guiSize.messageBorder); + this.setLayout(new GridLayout(gridRowCount, gridColCount)); + this.setPreferredSize(guiSize.hoursInPastDimension); + addDaysToPanel(); + } + + public void addDaysToPanel() { + // Get previous + for (LocalDate date : dateList) { + boolean dateExists = false; + + for (DailyFocusEntry entry : focusEntries) { + if (entry.getDay().equals((long) date.getDayOfMonth()) && + entry.getMonth().equals((long) date.getMonthValue()) && + entry.getYear().equals((long) date.getYear())) { + dateExists = true; + + // add since it exists - add popup to show time during that day + JLabel dateLabel = new JLabel(); + dateLabel.setIcon(chooseIconByTime(entry.getTime())); + + // Popup + final JPopupMenu popupMenu = new JPopupMenu("Test Popup"); + JLabel popupMessageLabel = new JLabel(" " + Utils.convertSecondsToHours(entry.getTime()) + " " + language.hoursOnText + " " + date.getDayOfWeek() + ", " + date.getMonth() + " " + date.getDayOfMonth() + ", " + date.getYear() + " "); + + popupMessageLabel.setForeground(theme.textColor); + popupMenu.setBackground(theme.layerColor); + popupMenu.add(popupMessageLabel); + + dateLabel.addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + popupMenu.show(dateLabel, e.getX() - 120, e.getY() - 50); + } + }); + + this.add(dateLabel); + break; + } + } + + if (!dateExists) { + + // add since it does not exist - add popup to show time during that day + JLabel dateLabel = new JLabel(guiSize.grayIcon); + final JPopupMenu popupMenu = new JPopupMenu("Test Popup"); + JLabel popupMessageLabel = new JLabel(" 0.0" + " " + language.hoursOnText + " " + date.getDayOfWeek() + ", " + date.getMonth() + " " + date.getDayOfMonth() + ", " + date.getYear() + " "); + + popupMessageLabel.setForeground(theme.textColor); + popupMenu.setBackground(theme.layerColor); + + // popup + popupMenu.add(popupMessageLabel); + dateLabel.addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + popupMenu.show(dateLabel, e.getX() - 120, e.getY() - 50); + } + }); + + this.add(dateLabel); + } + } + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public List getDateList() { + Date currentDate = Utils.today(); + LocalDate localCurrentDate = currentDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + List dateList = new ArrayList<>(); + + for (int i = 0; i < 182; i++) { + dateList.add(localCurrentDate.minusDays(i)); + } + + return dateList; + } + + public ImageIcon chooseIconByTime(long time) { + double hours = Utils.convertSecondsToHours(time); + + if(hours < 1) { + return guiSize.grayIcon; + } else if(hours >= 1 && hours < 3) { + return guiSize.green1Icon; + } else if(hours >= 3 && hours < 5) { + return guiSize.green2Icon; + } else if(hours >= 5 && hours < 10) { + return guiSize.green3Icon; + } else { + return guiSize.green4Icon; + } + } +} diff --git a/TamoStudy/src/components/panel/InventoryItemPanel.java b/TamoStudy/src/components/panel/InventoryItemPanel.java new file mode 100644 index 0000000..671d396 --- /dev/null +++ b/TamoStudy/src/components/panel/InventoryItemPanel.java @@ -0,0 +1,229 @@ +package components.panel; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import resources.Achievements; +import resources.Debug; +import resources.Items; +import resources.Theme; +import state.InventoryState; + +public class InventoryItemPanel extends JPanel { + + private static final long serialVersionUID = -6379471515355369571L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private TamoStudyGUI tsGui; + private InventoryState inventoryState; + private Profile profile; + private GuiSize guiSize; + private Theme theme; + private Language language; + private String type; + private int indicator; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JLabel itemTitleLabel; + private JLabel itemIconLabel; + + private JPanel itemDescriptionPanel; + private JLabel itemDescriptionLabel; + + private JButton itemActionButton; + + public InventoryItemPanel(TamoStudyGUI tsGui, InventoryState inventoryState, String type, int indicator) { + this.tsGui = tsGui; + this.inventoryState = inventoryState; + this.profile = tsGui.getProfile(); + this.guiSize = tsGui.getGuiSize(); + this.language = tsGui.getProfile().getSettings().getLanguage(); + this.theme = profile.getSettings().getTheme(); + + this.type = type; + this.indicator = indicator; + + initializeComponents(); + initializePanel(); + } + + public void initializeComponents() { + if(type.equals("FOOD")) { + initializeFoodItemPanel(); + } else if(type.equals("BACKGROUND")) { + initializeBackgroundItemPanel(); + } else if(type.equals("BORDER")) { + initializeBorderItemPanel(); + } + } + + public void initializeFoodItemPanel() { + itemTitleLabel = new JLabel(Items.getFoodTitleByIndicator(indicator, language)); + itemTitleLabel.setFont(guiSize.settingsChoiceBoldFont); + itemTitleLabel.setForeground(theme.textColor); + itemIconLabel = new JLabel(Items.getFoodIconByIndicator(indicator, guiSize)); + itemDescriptionPanel = new JPanel(); + itemDescriptionPanel.setBackground(theme.subColor); + itemDescriptionPanel.setBorder(guiSize.settingsPanelBorder); + itemDescriptionLabel = new JLabel(Items.getFoodDescriptionByIndicator(indicator, language)); + itemDescriptionLabel.setFont(guiSize.settingsChoiceBoldFont); + itemDescriptionLabel.setForeground(theme.textColor); + itemDescriptionPanel.add(itemDescriptionLabel); + itemActionButton = new JButton(language.feedTamoText); + + itemActionButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Debug.info("InventoryItemPanel.itemActionButton.actionPerformed", "Feeding Tamo"); + + // Consume food and add hunger points + int hungerToAdd = Items.getFoodHungerByIndicator(indicator); + if(profile.getTamo().getHunger() + hungerToAdd >= 10) { + profile.getTamo().setHunger(10); + } else { + profile.getTamo().setHunger(profile.getTamo().getHunger() + hungerToAdd); + } + + // Remove food from inventory + int indexToRemove = -1; + List foodInventoryList = new ArrayList<>(profile.getFoodInventoryList()); + + // This will iterate through and delete one of the foods that match, since + // the profile can have more than one instance of the food item. + for(int i = 0; i < foodInventoryList.size(); i++) { + if(foodInventoryList.get(i) == indicator) { + indexToRemove = i; + } + } + Debug.info("InventoryItemPanel.itemActionButton.actionPerformed", "indexToRemove=" + indexToRemove); + foodInventoryList.remove(indexToRemove); + profile.setFoodInventoryList(foodInventoryList); + + // Earn Tamo Full achievement if applicable + if(profile.getTamo().getHunger() >= 10) { + Achievements.earn(tsGui, 7); + } + + // Update JSON + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + + // Call changeInventory + // TODO call an animation from inventory state to say something like "Tamo Hunger 8/10" and fade to background color. + inventoryState.changeInventory(); + } + }); + } + + public void initializeBackgroundItemPanel() { + itemTitleLabel = new JLabel(Items.getBackgroundTitleByIndicator(indicator, language)); + itemTitleLabel.setFont(guiSize.settingsChoiceBoldFont); + itemTitleLabel.setForeground(theme.textColor); + itemIconLabel = new JLabel(Items.getBackgroundIconByIndicator(indicator, guiSize)); + itemDescriptionPanel = new JPanel(); + itemDescriptionPanel.setBackground(theme.subColor); + itemDescriptionPanel.setBorder(guiSize.settingsPanelBorder); + itemDescriptionLabel = new JLabel(Items.getBackgroundDescriptionByIndicator(indicator, language)); + itemDescriptionLabel.setForeground(theme.textColor); + itemDescriptionLabel.setFont(guiSize.settingsChoiceBoldFont); + itemDescriptionPanel.add(itemDescriptionLabel); + itemActionButton = new JButton(language.setBackgroundText); + + itemActionButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Debug.info("InventoryItemPanel.itemActionButton.actionPerformed", "Setting Background"); + + // Set Background + profile.setBackgroundIndicator(indicator); + + // Earn Background achievement if applicable + if(indicator != 0) { + Achievements.earn(tsGui, 5); + } + + // Update JSON + // TODO Add animation that background was set: "Background sunset set!" and fade to background color. + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + } + }); + } + + public void initializeBorderItemPanel() { + itemTitleLabel = new JLabel(Items.getBorderTitleByIndicator(indicator, language)); + itemTitleLabel.setFont(guiSize.settingsChoiceBoldFont); + itemTitleLabel.setForeground(theme.textColor); + itemIconLabel = new JLabel(Items.getBorderIconByIndicator(indicator, guiSize)); + itemDescriptionPanel = new JPanel(); + itemDescriptionPanel.setBackground(theme.subColor); + itemDescriptionPanel.setBorder(guiSize.settingsPanelBorder); + itemDescriptionLabel = new JLabel(Items.getBorderDescriptionByIndicator(indicator, language)); + itemDescriptionLabel.setFont(guiSize.settingsChoiceBoldFont); + itemDescriptionLabel.setForeground(theme.textColor); + itemDescriptionPanel.add(itemDescriptionLabel); + itemActionButton = new JButton(language.setBorderText); + + itemActionButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Debug.info("InventoryItemPanel.itemActionButton.actionPerformed", "Setting Border"); + + // Set backgrounds + profile.setBorderIndicator(indicator); + + // Earn Background achievement if applicable + if(indicator != 0) { + Achievements.earn(tsGui, 4); + } + + // Update JSON + // TODO Add animation that border was set: "Border black set!" and fade to background color. + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + } + }); + } + + public void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + this.setLayout(new GridBagLayout()); + this.setBackground(theme.mainColor); + + this.add(itemTitleLabel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(itemIconLabel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(itemDescriptionPanel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(itemActionButton, gbcv); + } +} diff --git a/TamoStudy/src/components/panel/KathPanel.java b/TamoStudy/src/components/panel/KathPanel.java new file mode 100644 index 0000000..b9823be --- /dev/null +++ b/TamoStudy/src/components/panel/KathPanel.java @@ -0,0 +1,130 @@ +package components.panel; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Image; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import model.GuiSize; +import model.language.Language; +import resources.Debug; +import resources.Theme; + +public class KathPanel extends JPanel { + + private static final long serialVersionUID = 1209578719406725927L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Theme theme; + private GuiSize guiSize; + private Language language; + public int shopIndicator; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + public Image kathImage; + public JLabel messageLabel; + + public KathPanel(Theme theme, GuiSize guiSize, Language language) { + this.guiSize = guiSize; + this.language = language; + shopIndicator = 0; + this.theme = theme; + + messageLabel = new JLabel(); + + initializeAttributes(); + initializeComponents(); + initializePanel(); + + } + + public void initializeAttributes() { + Debug.info("KathPanel.initializeAttributes", "shopIndicator = " + shopIndicator); + + if(shopIndicator == 0) { + messageLabel.setText(language.welcomeToTheShopText); + + this.setPreferredSize(guiSize.kathShopDimension); + this.setBackground(new Color(153, 236, 255)); + this.setBorder(guiSize.messageBorder); + } else if(shopIndicator == 1) { + messageLabel.setText(language.hereAreOurFoodOptionsText); + + this.setPreferredSize(guiSize.kathMsgDimension); + this.setBackground(theme.subColor); + this.setBorder(javax.swing.BorderFactory.createEmptyBorder()); + } else if(shopIndicator == 2) { + messageLabel.setText(language.whatBackgroundsCanIHelpFindText); + + this.setPreferredSize(guiSize.kathMsgDimension); + this.setBackground(theme.subColor); + this.setBorder(javax.swing.BorderFactory.createEmptyBorder()); + } else if(shopIndicator == 3) { + messageLabel.setText(language.whatBordersCanIHelpFindText); + + this.setPreferredSize(guiSize.kathMsgDimension); + this.setBackground(theme.subColor); + this.setBorder(javax.swing.BorderFactory.createEmptyBorder()); + } else if(shopIndicator == 4) { + messageLabel.setText(language.letsCustomizeFocusTimerText); + + this.setPreferredSize(guiSize.kathMsgDimension); + this.setBackground(theme.subColor); + this.setBorder(javax.swing.BorderFactory.createEmptyBorder()); + } + } + + public void initializeComponents() { + messageLabel.setOpaque(true); + messageLabel.setForeground(Color.black); + messageLabel.setBackground(Color.white); + messageLabel.setBorder(guiSize.messageBorder); + messageLabel.setFont(guiSize.kathMessageFont); + } + + public void initializePanel() { + this.add(messageLabel); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + if(shopIndicator == 0) { + kathImage = guiSize.getKathImage(0); // Kath Image starts at shop + g.drawImage(kathImage, 0, guiSize.kathImageOffset, this); + } else { + kathImage = guiSize.getKathImage(1); // Kath Image + g.drawImage(kathImage, 0, guiSize.kathImageOffset, this); + } + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public int getKathCenterX() { + int backgroundImageWidth = this.getX(); + int tamoImageWidth = kathImage.getWidth(this); + int number = (tamoImageWidth + tamoImageWidth) / 2; + + return (backgroundImageWidth - number) / 2; + } +} diff --git a/TamoStudy/src/components/panel/LongBreakSetPanel.java b/TamoStudy/src/components/panel/LongBreakSetPanel.java new file mode 100644 index 0000000..0cc8f84 --- /dev/null +++ b/TamoStudy/src/components/panel/LongBreakSetPanel.java @@ -0,0 +1,50 @@ +package components.panel; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Map; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import resources.Theme; + +public class LongBreakSetPanel extends JPanel { + + private static final long serialVersionUID = 2942049508629442065L; + private JLabel longBreakTitle; + + public LongBreakSetPanel(Theme theme, Map sessions) { + longBreakTitle = new JLabel("Select Session for Long Break"); + longBreakTitle.setForeground(Color.WHITE); + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + this.setLayout(new GridBagLayout()); + + this.add(longBreakTitle, gbcv); + for(int i = 1; i < sessions.size(); i++) { + final int index = i; + + JCheckBox longBreakCheckBox = new JCheckBox("" + i); + longBreakCheckBox.setForeground(Color.WHITE); + longBreakCheckBox.setBackground(theme.mainColor); + longBreakCheckBox.setSelected(sessions.get(index) == 1); + longBreakCheckBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(longBreakCheckBox.isSelected()) { + sessions.put(index, 1); + } else { + sessions.put(index, 0); + } + } + }); + this.add(longBreakCheckBox, gbcv); + } + } +} diff --git a/TamoStudy/src/components/panel/ProfileSelectionPanel.java b/TamoStudy/src/components/panel/ProfileSelectionPanel.java new file mode 100644 index 0000000..4b05ca5 --- /dev/null +++ b/TamoStudy/src/components/panel/ProfileSelectionPanel.java @@ -0,0 +1,617 @@ +package components.panel; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import gui.TamoStudyGUI; +import gui.WelcomeGUI; +import io.ProfileJsonManager; +import model.language.Language; +import model.profile.Profile; +import resources.Debug; +import resources.Theme; +import util.Utils; + +public class ProfileSelectionPanel extends JPanel { + + private static final long serialVersionUID = -3861540929503194485L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private WelcomeGUI welcomeGUI; + private ProfileJsonManager profileJsonManager; + private List profiles; + private Theme theme; + private Language language; + + /* + * ################################## + * ################################## + * SELECTION COMPONENTS + * ################################## + * ################################## + */ + private JLabel messageLabel; + private boolean foundProfiles; + + private JPanel createButtonPanel; + private JButton createNewProfileButton; + private JButton importProfileButton; + + private JPanel selectProfilePanel; + private JLabel selectProfileLabel; + private JComboBox profilesBox; + private JCheckBox assignDefaultProfile; + + private JPanel profileOptionsButtonPanel; + private JButton loadProfileButton; + private JButton deleteProfileButton; + + /* + * ################################## + * ################################## + * CREATION COMPONENTS + * ################################## + * ################################## + */ + private JLabel createProfileLabel; + + private JPanel createProfilePanel; + private JLabel enterUsernameLabel; + private JPanel enterUsernamePanel; + private JTextField enterUsernameTextField; + private JLabel enterTamoNameLabel; + private JPanel enterTamoNamePanel; + private JTextField enterTamoNameTextField; + private JPanel languagePanel; + private JLabel languageLabel; + private JComboBox languageBox; + private JPanel difficultyPanel; + private JLabel difficultyLabel; + private JComboBox difficultyBox; + private JPanel focusModePanel; + private JLabel focusModeLabel; + private JComboBox focusModeBox; + + private JPanel createProfileButtonPanel; + private JButton confirmCreateProfileButton; + private JButton cancelCreateProfileButton; + + public ProfileSelectionPanel(WelcomeGUI welcomeGUI) { + this.welcomeGUI = welcomeGUI; + + initializeAttributes(); + initializeComponents(); + initializeComponentActions(); + addInitialComponentsToPanel(); + } + + private void initializeAttributes() { + profileJsonManager = new ProfileJsonManager(); + profiles = profileJsonManager.readJson(); + theme = Theme.DARK; + language = welcomeGUI.getGlobalSettings().getLanguage(); + } + + /* + * ################################## + * ################################## + * SELECTION MENU + * ################################## + * ################################## + */ + + private void initializeInitialMode() { + initializeAttributes(); + initializeComponents(); + initializeComponentActions(); + addInitialComponentsToPanel(); + } + + private void initializeComponents() { + foundProfiles = !profiles.isEmpty(); + + messageLabel = new JLabel(); + if(!foundProfiles) { + messageLabel.setText(language.noProfilesText); + } else { + messageLabel.setText(language.welcomeBackText); + } + + createButtonPanel = new JPanel(); + createNewProfileButton = new JButton(language.createNewProfileText); + importProfileButton = new JButton(language.importProfileText); + + selectProfilePanel = new JPanel(); + selectProfilePanel.setBackground(theme.subColor); + selectProfileLabel = new JLabel(language.chooseProfileText); + profilesBox = new JComboBox<>(); + if(foundProfiles) { + for(Profile profile : profiles) { + profilesBox.addItem(profile.getName()); + } + } + assignDefaultProfile = new JCheckBox(language.loadProfileAutomaticallyText); + assignDefaultProfile.setBackground(theme.subColor); + + profileOptionsButtonPanel = new JPanel(); + loadProfileButton = new JButton(language.loadProfileText); + deleteProfileButton = new JButton(language.deleteProfileText); + + initializeComponentVisuals(); + } + + private void initializeComponentActions() { + createNewProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // Remove all components from this + removeAllComponents(); + + // Enter Create Mode + initializeCreateMode(); + } + + }); + + importProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = new JFileChooser(); + int returnValue = fileChooser.showOpenDialog(null); + + if (returnValue == JFileChooser.APPROVE_OPTION) { + String[] contents = Utils.decrypt(Utils.readFile(fileChooser.getSelectedFile())).split(","); + + try { + // Ensure that the file is from Beta v4.0 - v4.2 + boolean sizeCheck = contents.length == 21; + boolean versionCheck = contents[0].equals("b4.0"); + + if(sizeCheck && versionCheck) { + /** + * A Beta v4.2 button should meet the following requirements + * + * [0] version + * [1] username + * [2] joinDateString + * [3] lastLoginDateString + * [4] tamoTokens + * [5] totalTime + * [6] bgIndicator + * [7] themeIndicator + * [8] strikes + * [9] tamoName + * [10] tamoHappiness + * [11] tamoHunger + * [12] tamoId + * [13] languageIndicator + * [14] ahmString + * [15] invString + * [16] focusMode + * [17] sessionSoundIndicator + * [18] backgroundSoundIndicator + * [19] difficulty + * [20] showAhmNotifications + */ + Profile profile = new Profile( + contents[1], + contents[2], + contents[3], + Long.parseLong(contents[5]), + Long.parseLong(contents[4]), + Long.parseLong(contents[6]), + Long.parseLong(contents[8]), + contents[9], + Long.parseLong(contents[10]), + Long.parseLong(contents[11]), + Long.parseLong(contents[12]), + Long.parseLong(contents[13]), + contents[14], + contents[15], + Long.parseLong(contents[16]), + Long.parseLong(contents[17]), + Long.parseLong(contents[19]), + (contents[20].equals("0") ? false : true) + ); + Debug.info("ProfileSelectionPanel.importProfileButton.actionPerformed", "Loaded Beta v4.2 profile: " + profile.toString()); + + // Add Profile to Profiles List and update profiles.json + List allProfiles = new ArrayList<>(); + for(Profile aProfile : profiles) { + allProfiles.add(aProfile); + } + allProfiles.add(profile); + profileJsonManager.writeJsonToFile(allProfiles); + + // Revalidate GUI + removeAllComponents(); + initializeInitialMode(); + } + else throw new Exception(); + + } catch (Exception e1) { + Debug.error("ProfileSelectionPanel.importProfileButton.actionPerformed", "Selected file failed index access check"); + setMessageLabelError(language.invalidProfileFileText); + e1.printStackTrace(); + } + + } + } + + }); + + loadProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int profileIndex = profilesBox.getSelectedIndex(); + if(assignDefaultProfile.isSelected()) { + welcomeGUI.getGlobalSettings().setDefaultLocalProfile(profileIndex); + welcomeGUI.getGlobalSettingsJsonManager().writeJsonToFile(welcomeGUI.getGlobalSettings()); + } + new TamoStudyGUI(profiles, profileIndex); + close(); + } + + }); + + deleteProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Profile profile = profiles.get(profilesBox.getSelectedIndex()); + + int result = JOptionPane.showConfirmDialog(getRootPane(), + language.confirmDeleteProfileText + " " + profile.getName() + ".", + language.areYouSureText, + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + new ImageIcon(getClass().getClassLoader().getResource("INFO.png")) + ); + + if (result == JOptionPane.YES_OPTION) { + profiles.removeIf(p -> p.getId() == profile.getId() && p.getName().equals(profile.getName())); + profileJsonManager.writeJsonToFile(profiles); + + // Revalidate GUI + removeAllComponents(); + initializeInitialMode(); + } + + } + + }); + } + + private void initializeComponentVisuals() { + this.setPreferredSize(new Dimension(500, 450)); + this.setBackground(theme.mainColor); + this.setLayout(new GridBagLayout()); + + messageLabel.setFont(theme.fontBoldReg); + messageLabel.setForeground(Color.WHITE); + + createButtonPanel.setBackground(theme.mainColor); + createButtonPanel.setLayout(new GridBagLayout()); + + Theme.primaryVisualButton(createNewProfileButton); + Theme.secondaryVisualButton(importProfileButton); + + selectProfilePanel.setLayout(new GridBagLayout()); + selectProfilePanel.setBackground(theme.subColor); + selectProfilePanel.setBorder(Theme.SUB_BORDER); + + selectProfileLabel.setFont(theme.fontBoldReg); + selectProfileLabel.setForeground(Color.WHITE); + + assignDefaultProfile.setForeground(Color.WHITE); + assignDefaultProfile.setBackground(theme.subColor); + + profileOptionsButtonPanel.setLayout(new GridBagLayout()); + profileOptionsButtonPanel.setBackground(theme.subColor); + Theme.successVisualButton(loadProfileButton); + Theme.dangerVisualButton(deleteProfileButton); + } + + private void addInitialComponentsToPanel() { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + createButtonPanel.add(createNewProfileButton, gbcv); + createButtonPanel.add(Box.createVerticalStrut(20), gbcv); + createButtonPanel.add(importProfileButton, gbcv); + + this.add(messageLabel, gbcv); + + selectProfilePanel.add(selectProfileLabel, gbcv); + selectProfilePanel.add(Box.createVerticalStrut(20), gbcv); + selectProfilePanel.add(profilesBox, gbcv); + selectProfilePanel.add(assignDefaultProfile, gbcv); + selectProfilePanel.add(Box.createVerticalStrut(20), gbcv); + + profileOptionsButtonPanel.add(loadProfileButton, gbch); + profileOptionsButtonPanel.add(Box.createHorizontalStrut(20), gbch); + profileOptionsButtonPanel.add(deleteProfileButton, gbch); + + + selectProfilePanel.add(profileOptionsButtonPanel, gbcv); + + if(foundProfiles) { + this.add(Box.createVerticalStrut(20), gbcv); + this.add(selectProfilePanel, gbcv); + } + + this.add(Box.createVerticalStrut(40), gbcv); + this.add(createButtonPanel, gbcv); + } + + /* + * ################################## + * ################################## + * CREATION MENU + * ################################## + * ################################## + */ + + private void initializeCreateMode() { + initializeCreateComponents(); + initializeCreateComponentActions(); + addCreateModeComponentsToPanel(); + } + + private void initializeCreateComponents() { + createProfileLabel = new JLabel(language.createProfileText); + + createProfilePanel = new JPanel(); + + enterUsernamePanel = new JPanel(); + enterUsernameLabel = new JLabel(language.usernameText); + enterUsernameTextField = new JTextField(10); + + enterTamoNamePanel = new JPanel(); + enterTamoNameLabel = new JLabel(language.tamoNameText); + enterTamoNameTextField = new JTextField(10); + + languagePanel = new JPanel(); + languageLabel = new JLabel(language.languageText); + languageBox = new JComboBox<>(); + languageBox.addItem(language.englishText); + languageBox.addItem(language.spanishText); +// languageBox.addItem(language.hindiText); +// languageBox.addItem(language.portugueseText); +// languageBox.addItem(language.japaneseText); +// languageBox.addItem(language.germanText); +// languageBox.addItem(language.frenchText); +// languageBox.addItem(language.turkishText); +// languageBox.addItem(language.mandarinChineseText); +// languageBox.addItem(language.dutchText); +// languageBox.addItem(language.koreanText); +// languageBox.addItem(language.russianText); +// languageBox.addItem(language.hungarianText); +// languageBox.addItem(language.romanianText); +// + difficultyPanel = new JPanel(); + difficultyLabel = new JLabel(language.difficultyText); + difficultyBox = new JComboBox<>(); + difficultyBox.addItem(language.peacefulText); + difficultyBox.addItem(language.challengingText); + difficultyBox.addItem(language.ironManText); + + focusModePanel = new JPanel(); + focusModeLabel = new JLabel(language.focusModeText); + focusModeBox = new JComboBox<>(); + focusModeBox.addItem(language.pomodoroText); + focusModeBox.addItem(language.customCountdownText); + focusModeBox.addItem(language.fiveMinIntervalCountdownText); + focusModeBox.addItem(language.stopwatchText); + focusModeBox.addItem("Pomodoro with Long Breaks"); + + createProfileButtonPanel = new JPanel(); + confirmCreateProfileButton = new JButton(language.createText); + cancelCreateProfileButton = new JButton(language.cancelText); + + initializeCreateComponentVisuals(); + } + + private void initializeCreateComponentActions() { + confirmCreateProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // Validate Form Fields + boolean validForm = false; + + if(enterUsernameTextField.getText().trim().isEmpty() + || enterTamoNameTextField.getText().trim().isEmpty()) { + setCreationMessage(language.mustEnterValidNameText); + } else { + validForm = true; + } + + if(validForm) { + // Add Profile to Profiles + Profile profile = new Profile(enterUsernameTextField.getText(), + Language.getLanguageFromBox(languageBox.getSelectedIndex()), + difficultyBox.getSelectedIndex(), + focusModeBox.getSelectedIndex(), + enterTamoNameTextField.getText() + ); + + // Write / Update Profiles to profiles.json + List allProfiles = new ArrayList<>(); + for(Profile aProfile : profiles) { + allProfiles.add(aProfile); + } + allProfiles.add(profile); + profileJsonManager.writeJsonToFile(allProfiles); + + // Revalidate GUI + removeAllComponents(); + initializeInitialMode(); + } + } + + }); + + cancelCreateProfileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + removeAllComponents(); + + initializeInitialMode(); + } + + }); + } + + private void initializeCreateComponentVisuals() { + createProfileLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("INFO_GOOD.png"))); + createProfileLabel.setFont(theme.fontBoldReg); + createProfileLabel.setForeground(Color.WHITE); + + createProfilePanel.setLayout(new GridBagLayout()); + createProfilePanel.setBackground(theme.subColor); + createProfilePanel.setBorder(Theme.SUB_BORDER); + + enterUsernamePanel.setLayout(new GridBagLayout()); + enterUsernamePanel.setBackground(theme.subColor); + enterUsernameLabel.setFont(theme.fontBoldRegSmall); + enterUsernameLabel.setForeground(Color.WHITE); + + enterTamoNamePanel.setLayout(new GridBagLayout()); + enterTamoNamePanel.setBackground(theme.subColor); + enterTamoNameLabel.setFont(theme.fontBoldRegSmall); + enterTamoNameLabel.setForeground(Color.WHITE); + + languagePanel.setLayout(new GridBagLayout()); + languagePanel.setBackground(theme.subColor); + languageLabel.setFont(theme.fontBoldRegSmall); + languageLabel.setForeground(Color.WHITE); + + difficultyPanel.setLayout(new GridBagLayout()); + difficultyPanel.setBackground(theme.subColor); + difficultyLabel.setFont(theme.fontBoldRegSmall); + difficultyLabel.setForeground(Color.WHITE); + + focusModePanel.setLayout(new GridBagLayout()); + focusModePanel.setBackground(theme.subColor); + focusModeLabel.setFont(theme.fontBoldRegSmall); + focusModeLabel.setForeground(Color.WHITE); + + createProfileButtonPanel.setLayout(new GridBagLayout()); + createProfileButtonPanel.setBackground(theme.mainColor); + Theme.primaryVisualButton(confirmCreateProfileButton); + Theme.secondaryVisualButton(cancelCreateProfileButton); + } + + private void addCreateModeComponentsToPanel() { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + + // Sub Panels + enterUsernamePanel.add(enterUsernameLabel); + enterUsernamePanel.add(enterUsernameTextField); + + enterTamoNamePanel.add(enterTamoNameLabel); + enterTamoNamePanel.add(enterTamoNameTextField); + + languagePanel.add(languageLabel); + languagePanel.add(languageBox); + + difficultyPanel.add(difficultyLabel); + difficultyPanel.add(difficultyBox); + + focusModePanel.add(focusModeLabel); + focusModePanel.add(focusModeBox); + + // Create Profile Panel + createProfilePanel.add(enterUsernamePanel, innergbcv); + createProfilePanel.add(Box.createVerticalStrut(10), innergbcv); + createProfilePanel.add(enterTamoNamePanel, innergbcv); + createProfilePanel.add(Box.createVerticalStrut(10), innergbcv); + createProfilePanel.add(languagePanel, innergbcv); + createProfilePanel.add(Box.createVerticalStrut(10), innergbcv); + createProfilePanel.add(difficultyPanel, innergbcv); + createProfilePanel.add(Box.createVerticalStrut(10), innergbcv); + createProfilePanel.add(focusModePanel, innergbcv); + + // Button Panel + createProfileButtonPanel.add(confirmCreateProfileButton, gbch); + createProfileButtonPanel.add(Box.createHorizontalStrut(20), gbch); + createProfileButtonPanel.add(cancelCreateProfileButton, gbch); + + this.add(createProfileLabel, gbcv); + this.add(Box.createVerticalStrut(20), gbcv); + this.add(createProfilePanel, gbcv); + this.add(Box.createVerticalStrut(20), gbcv); + this.add(createProfileButtonPanel, gbcv); + + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + private void removeAllComponents() { + this.removeAll(); + this.repaint(); + this.revalidate(); + } + + private void close() { + Debug.info("ProfileSelectionPanel.close", "Closing WelcomeGUI and ProfileSelectionPanel"); + welcomeGUI.dispose(); + welcomeGUI.removeAll(); + } + + private void setMessageLabelError(String message) { + messageLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + messageLabel.setText(message); + messageLabel.setForeground(Theme.DANGER); + } + + private void setCreationMessage(String message) { + createProfileLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + createProfileLabel.setText(message); + createProfileLabel.setForeground(Theme.DANGER); + } +} diff --git a/TamoStudy/src/components/panel/SetPanel.java b/TamoStudy/src/components/panel/SetPanel.java new file mode 100644 index 0000000..48d7cdd --- /dev/null +++ b/TamoStudy/src/components/panel/SetPanel.java @@ -0,0 +1,493 @@ +package components.panel; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import model.language.Language; +import resources.Debug; +import resources.Theme; + +public class SetPanel extends JPanel { + + private static final long serialVersionUID = -4533299272357080931L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + TimerPanel timerPanel; + long focusMode; + Language language; + Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + + // Pomodoro Mode + private JPanel pomoNumberOfSessionsPanel; + private JLabel pomoNumberOfSessionsLabel; + public JComboBox pomoNumberOfSessionsBox; + private JPanel pomoSessionLengthPanel; + private JLabel pomoSessionLengthLabel; + public JComboBox pomoSessionLengthBox; + private JPanel pomoBreakLengthPanel; + private JLabel pomoBreakLengthLabel; + public JComboBox pomoBreakLengthBox; + + // TODO Pomodoro Mode + Long Break + private JPanel pomoLongBreakSelectionPanel; + private JLabel pomoLongBreakSessions; + public JButton pomoLongBreakSetButton; // TODO change dynamically based off of settings + public Map sessions; + private JPanel pomoLongBreakLengthPanel; + private JLabel pomoLongBreakLengthLabel; + public JComboBox pomoLongBreakLengthBox; + + // Custom Countdown Mode + private JPanel customMinuteLengthPanel; + private JLabel customMinuteLengthLabel; + public JComboBox customMinuteLengthBox; + private JPanel customSecondLengthPanel; + private JLabel customSecondLengthLabel; + public JComboBox customSecondLengthBox; + + // 5 Minute Countdown Interval Mode + private JPanel fiveLengthPanel; + private JLabel fiveLengthLabel; + public JComboBox fiveLengthBox; + + // Stop watch contains no components + + public SetPanel(Theme theme, TimerPanel timerPanel, long focusMode, Language language) { + this.timerPanel = timerPanel; + this.focusMode = focusMode; + this.language = language; + this.theme = theme; + sessions = new HashMap<>(); + + initializeComponents(); + initializePanel(); + } + + public void initializeComponents() { + switch((int) focusMode) { + case 0: + // Pomodoro + initializePomodoroSetComponents(); + break; + case 1: + // Custom Countdown + initializeCustomCountdownSetComponents(); + break; + case 2: + // Five Min Interval Countdown + initializeFiveIntervalCountdownSetComponents(); + break; + case 3: + // Stopwatch + initializeStopwatchComponents(); + break; + case 4: + // Pomodoro with Long Breaks + initializePomodoroSetComponents(); + initializePomodoroLongBreakSetComponents(); + break; + default: + initializePomodoroSetComponents(); + break; + } + } + + public void initializePanel() { + this.setBackground(timerPanel.getTheme().mainColor); + this.setBorder(timerPanel.getGuiSize().settingsPanelBorder); + } + + /* + * ################################## + * ################################## + * POMODORO SETUP + * ################################## + * ################################## + */ + public void initializePomodoroSetComponents() { + // Initialize Components + pomoNumberOfSessionsPanel = new JPanel(); + pomoNumberOfSessionsPanel.setBackground(theme.mainColor); + + pomoNumberOfSessionsLabel = new JLabel(language.pomoNumberOfSessionsText); + pomoNumberOfSessionsBox = new JComboBox<>(); + + for(int i = 1; i <= 16; i++) { + pomoNumberOfSessionsBox.addItem(i); + } + + pomoSessionLengthPanel = new JPanel(); + pomoSessionLengthPanel.setBackground(theme.mainColor); + + pomoSessionLengthLabel = new JLabel(language.pomoSessionLengthText); + pomoSessionLengthBox = new JComboBox<>(); + + pomoBreakLengthPanel = new JPanel(); + pomoBreakLengthPanel.setBackground(theme.mainColor); + + pomoBreakLengthLabel = new JLabel(language.pomoBreakLengthText); + pomoBreakLengthBox = new JComboBox<>(); + + for(int i = 5; i <= 95; i = i + 5) { + if(i == 5) { + pomoSessionLengthBox.addItem("0" + i + ":00"); + pomoBreakLengthBox.addItem("0" + i + ":00"); + } + else { + pomoSessionLengthBox.addItem(i + ":00"); + pomoBreakLengthBox.addItem(i + ":00"); + } + } + + // Component Visuals + pomoNumberOfSessionsLabel.setForeground(timerPanel.getTheme().textColor); + pomoNumberOfSessionsLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + pomoNumberOfSessionsPanel.add(pomoNumberOfSessionsLabel); + pomoNumberOfSessionsPanel.add(pomoNumberOfSessionsBox); + + pomoSessionLengthLabel.setForeground(timerPanel.getTheme().textColor); + pomoSessionLengthLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + pomoSessionLengthPanel.add(pomoSessionLengthLabel); + pomoSessionLengthPanel.add(pomoSessionLengthBox); + + pomoBreakLengthLabel.setForeground(timerPanel.getTheme().textColor); + pomoBreakLengthLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + pomoBreakLengthPanel.add(pomoBreakLengthLabel); + pomoBreakLengthPanel.add(pomoBreakLengthBox); + + // Add Components to set panel + this.setLayout(new GridBagLayout()); + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + this.add(pomoNumberOfSessionsPanel, innergbcv); + this.add(pomoSessionLengthPanel, innergbcv); + this.add(pomoBreakLengthPanel, innergbcv); + + initializePomodoroComponentActions(); + } + + public void initializePomodoroComponentActions() { + pomoSessionLengthBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + timerPanel.minuteTimeLabel.setText(((String) pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) pomoSessionLengthBox.getSelectedItem()).substring(3)); + } + + }); + // Initialize Values + timerPanel.minuteTimeLabel.setText(((String) pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) pomoSessionLengthBox.getSelectedItem()).substring(3)); + } + + /* + * ################################## + * ################################## + * CUSTOM COUNTDOWN SETUP + * ################################## + * ################################## + */ + public void initializeCustomCountdownSetComponents() { + // Initialize Components + customMinuteLengthPanel = new JPanel(); + customMinuteLengthPanel.setBackground(theme.mainColor); + + customMinuteLengthLabel = new JLabel(language.minutesText); + customMinuteLengthBox = new JComboBox<>(); + + for(int i = 0; i <= 99; i++) { + if(i < 10) { + customMinuteLengthBox.addItem("0" + i); + } else { + customMinuteLengthBox.addItem("" + i); + } + } + + customSecondLengthPanel = new JPanel(); + customSecondLengthPanel.setBackground(theme.mainColor); + + customSecondLengthLabel = new JLabel(language.secondsText); + customSecondLengthBox = new JComboBox<>(); + + for(int i = 1; i <= 59; i++) { + if(i < 10) { + customSecondLengthBox.addItem("0" + i); + } + else { + customSecondLengthBox.addItem("" + i); + } + + } + + // Initalize Component Visual + customMinuteLengthLabel.setForeground(timerPanel.getTheme().textColor); + customMinuteLengthLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + customMinuteLengthPanel.add(customMinuteLengthLabel); + customMinuteLengthPanel.add(customMinuteLengthBox); + + customSecondLengthLabel.setForeground(timerPanel.getTheme().textColor); + customSecondLengthLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + customSecondLengthPanel.add(customSecondLengthLabel); + customSecondLengthPanel.add(customSecondLengthBox); + + // Add Components to set panel + this.setLayout(new GridBagLayout()); + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + this.add(customMinuteLengthPanel, innergbcv); + this.add(customSecondLengthPanel, innergbcv); + + timerPanel.minuteTimeLabel.setText(((String) customMinuteLengthBox.getSelectedItem())); + timerPanel.secondTimeLabel.setText(((String) customSecondLengthBox.getSelectedItem())); + + initializeCustomCountdownComponentActions(); + } + + public void initializeCustomCountdownComponentActions() { + customMinuteLengthBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + timerPanel.minuteTimeLabel.setText(((String) customMinuteLengthBox.getSelectedItem())); + } + }); + + customSecondLengthBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + timerPanel.secondTimeLabel.setText(((String) customSecondLengthBox.getSelectedItem())); + } + }); + } + + /* + * ################################## + * ################################## + * FIVE MIN INTERVAL SETUP + * ################################## + * ################################## + */ + public void initializeFiveIntervalCountdownSetComponents() { + // Initialize Components + fiveLengthPanel = new JPanel(); + fiveLengthPanel.setBackground(theme.mainColor); + + fiveLengthLabel = new JLabel(language.durationText); + fiveLengthBox = new JComboBox<>(); + + for(int i = 5; i <= 95; i = i + 5) { + if(i == 5) + fiveLengthBox.addItem("0" + i + ":00"); + else + fiveLengthBox.addItem(i + ":00"); + } + + // Initalize Component Visual + fiveLengthLabel.setForeground(timerPanel.getTheme().textColor); + fiveLengthLabel.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + fiveLengthPanel.add(fiveLengthLabel); + fiveLengthPanel.add(fiveLengthBox); + + // Add Components to set panel + this.setLayout(new GridBagLayout()); + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + this.add(fiveLengthPanel, innergbcv); + initializeFiveIntervalCountdownComponentActions(); + } + + public void initializeFiveIntervalCountdownComponentActions() { + fiveLengthBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + timerPanel.minuteTimeLabel.setText(((String) fiveLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) fiveLengthBox.getSelectedItem()).substring(3)); + } + }); + + // Initialize Values + timerPanel.minuteTimeLabel.setText(((String) fiveLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) fiveLengthBox.getSelectedItem()).substring(3)); + } + + /* + * ################################## + * ################################## + * STOPWATCH SETUP + * ################################## + * ################################## + */ + + /* + * No components are needed for the stop watch setting. + * The stopwatch will essentially count up, and then + * reset when it hits 99:59. After this, the timer will + * go back to 00:00, and the user will gain a 'loop'. + * A loop is defined simply as 99 minutes and 59 seconds + * studied. Since our timer can't display more than that, + * we will just count is as a loop to the user. + */ + + public void initializeStopwatchComponents() { + // Nothing at the moment + } + + /* + * ################################## + * ################################## + * POMODORO LONG BREAK SETUP + * ################################## + * ################################## + */ + public void initializePomodoroLongBreakSetComponents() { + /* + * TODO + * + * This will be called in addition to the regular pomodoro components. + * In here we will want to add the long break components and add them + * to this. + */ + pomoLongBreakSelectionPanel = new JPanel(); + pomoLongBreakSelectionPanel.setBackground(theme.mainColor); + pomoLongBreakSessions = new JLabel("Long Break"); + pomoLongBreakSessions.setForeground(timerPanel.getTheme().textColor); + pomoLongBreakSessions.setFont(timerPanel.getGuiSize().settingsChoiceBoldFont); + pomoLongBreakSetButton = new JButton("Configure"); + pomoLongBreakSelectionPanel.add(pomoLongBreakSessions); + pomoLongBreakSelectionPanel.add(pomoLongBreakSetButton); + + pomoLongBreakLengthPanel = new JPanel(); + pomoLongBreakLengthPanel.setBackground(theme.mainColor); + pomoLongBreakLengthLabel = new JLabel("Long Break Length"); + pomoLongBreakLengthLabel.setForeground(timerPanel.getTheme().textColor); + pomoLongBreakLengthBox = new JComboBox<>(); + for(int i = 5; i <= 95; i = i + 5) { + if(i == 5) { + pomoLongBreakLengthBox.addItem("0" + i + ":00"); + } + else { + pomoLongBreakLengthBox.addItem(i + ":00"); + } + } + pomoLongBreakLengthPanel.add(pomoLongBreakLengthLabel); + pomoLongBreakLengthPanel.add(pomoLongBreakLengthBox); + + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + this.add(pomoLongBreakLengthPanel, innergbcv); + this.add(pomoLongBreakSelectionPanel, innergbcv); + + initializePomodoroLongBreakComponentActions(); + } + + public void initializePomodoroLongBreakComponentActions() { + pomoNumberOfSessionsBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + sessions.clear(); // Ensure sessions is empty + int numberOfSessions = pomoNumberOfSessionsBox.getSelectedIndex() + 1; + for(int i = 1; i <= numberOfSessions; i++) { + sessions.put(i, 0); // 0 represents short break, 1 for long break + } + Debug.info("SetPanel.pomoNumberOfSessionsBox.actionPerfomed", "Pomodoro sessions set to " + sessions.size()); + } + // Long breaks will be set using the long break set box. + }); + + pomoLongBreakSetButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(sessions.size() <= 1) { + JOptionPane.showMessageDialog(getRootPane(), "To configure long break, you must
do more than 1 session.", "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } else { + LongBreakSetPanel longBreakSetPanel = new LongBreakSetPanel(theme, sessions); + JOptionPane.showMessageDialog(getRootPane(), longBreakSetPanel, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + for(int i = 1; i <= sessions.size(); i++) { + System.out.println("sessions[" + i + "] = " + sessions.get(i)); + } + } + + } + + }); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public void toggleOptionButtons(boolean enabled) { + switch((int) focusMode) { + case 0: + // Toggle Pomodoro Options + pomoNumberOfSessionsBox.setEnabled(enabled); + pomoSessionLengthBox.setEnabled(enabled); + pomoBreakLengthBox.setEnabled(enabled); + break; + case 1: + // Toggle Custom Countdown Options + customMinuteLengthBox.setEnabled(enabled); + customSecondLengthBox.setEnabled(enabled); + break; + case 2: + // Toggle Five Min Interval Countdown Options + fiveLengthBox.setEnabled(enabled); + break; + case 3: + break; + case 4: + // Toggle Pomodoro with Long Breaks Options + pomoNumberOfSessionsBox.setEnabled(enabled); + pomoSessionLengthBox.setEnabled(enabled); + pomoBreakLengthBox.setEnabled(enabled); + pomoLongBreakSetButton.setEnabled(enabled); + pomoLongBreakLengthBox.setEnabled(enabled); + break; + default: + // Toggle Pomodoro Options + pomoNumberOfSessionsBox.setEnabled(enabled); + pomoSessionLengthBox.setEnabled(enabled); + pomoBreakLengthBox.setEnabled(enabled); + break; + } + } + +} diff --git a/TamoStudy/src/components/panel/ShopItemPanel.java b/TamoStudy/src/components/panel/ShopItemPanel.java new file mode 100644 index 0000000..8e0c254 --- /dev/null +++ b/TamoStudy/src/components/panel/ShopItemPanel.java @@ -0,0 +1,234 @@ +package components.panel; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import resources.Debug; +import resources.Items; +import resources.Theme; + +public class ShopItemPanel extends JPanel { + + private static final long serialVersionUID = -1261674542186022885L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private TamoStudyGUI tsGui; + private GuiSize guiSize; + private Theme theme; + private Language language; + + private String type; + private int indicator; + private boolean owned; // If the profile owns the item, they cannot buy it, button is disabled. + private int price; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JLabel itemTitleLabel; + private JLabel iconLabel; + private JButton buyButton; + + public ShopItemPanel(TamoStudyGUI tsGui, GuiSize guiSize, Language language, String type, int indicator, boolean owned) { + this.tsGui = tsGui; + this.guiSize = guiSize; + this.language = language; + theme = tsGui.getProfile().getSettings().getTheme(); + + this.type = type; + this.indicator = indicator; + this.owned = owned; + + initializeAttributes(); + initializeComponents(); + initializePanel(); + } + + public void initializeAttributes() { + + } + + public void initializeComponents() { + String itemTitle = getItemTitleByTypeIndicator(type, indicator); + + itemTitleLabel = new JLabel(itemTitle); + itemTitleLabel.setFont(guiSize.kathMessageFont); + itemTitleLabel.setForeground(theme.textColor); + + iconLabel = new JLabel(getItemIconByTypeIndicator(type, indicator)); + + price = getItemPriceByTypeIndicator(type, indicator); + buyButton = new JButton("" + price); + buyButton.setIcon(guiSize.tamoTokenImageIcon); + disableBuyButtonIfOwned(); + + buyButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int tokensAfterPurchase = (int) tsGui.getProfile().getTokens() - price; + + // If the profile can afford the purchase + if(type.equals("FOOD") && tsGui.getProfile().getFoodInventoryList().size() >= 35) { + // Cannot purchase + JOptionPane.showMessageDialog(getRootPane(), language.yourFoodInventoryIsFullText, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } + + else if(!(tokensAfterPurchase < 0)) { + + // Confirm that the user wants to purchase this item? + int result = JOptionPane.showConfirmDialog( + getRootPane(), + language.confirmPurchaseOfText + " " + itemTitle + " (" + type + ")", + "TamoStudy", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + + if(result == JOptionPane.YES_OPTION) { + // If yes, firstly subtract the profile's tokens + tsGui.getProfile().setTokens(tokensAfterPurchase); + + // Secondly, add the item to the profile's inventory + addItemToInventory(type, indicator, tsGui.getProfile()); + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + + // Finally, update the GUI. Tamo tokens, and disable buyButton. + tsGui.updateTamoTokensLabel(); + if(!type.equals("FOOD")) { + buyButton.setEnabled(false); + } else { + disableBuyButtonIfOwned(); + } + + } + } + + else { + JOptionPane.showMessageDialog(getRootPane(), language.notEnoughTamoTokensText, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } + } + }); + } + + public void disableBuyButtonIfOwned() { + if(type.equals("FOOD")) { + // Do nothing, can purchase multiple food + if(tsGui.getProfile().getFoodInventoryList().size() >= 35) { + buyButton.setEnabled(false); + } + } else if(type.equals("BACKGROUND")) { + for(long l : tsGui.getProfile().getBackgroundInventoryList()) { + if((int) l == indicator) { + buyButton.setEnabled(false); + } + } + } else if(type.equals("BORDER")) { + for(long l : tsGui.getProfile().getBorderInventoryList()) { + if((int) l == indicator) { + buyButton.setEnabled(false); + } + } + } + } + + public void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + this.setLayout(new GridBagLayout()); + this.setBackground(theme.mainColor); + this.setBorder(guiSize.settingsPanelBorder); + + this.add(itemTitleLabel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(iconLabel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(buyButton, gbcv); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public String getItemTitleByTypeIndicator(String type, int indicator) { + if(type.equals("FOOD")) { + return Items.getFoodTitleByIndicator(indicator, language); + } else if(type.equals("BACKGROUND")) { + return Items.getBackgroundTitleByIndicator(indicator, language); + } else if(type.equals("BORDER")) { + return Items.getBorderTitleByIndicator(indicator, language); + } + throw new RuntimeException("Unknown type provided to getItemTitleByTypeIndicator"); + } + + public ImageIcon getItemIconByTypeIndicator(String type, int indicator) { + if(type.equals("FOOD")) { + return Items.getFoodIconByIndicator(indicator, guiSize); + } else if(type.equals("BACKGROUND")) { + return Items.getBackgroundIconByIndicator(indicator, guiSize); + } else if(type.equals("BORDER")) { + return Items.getBorderIconByIndicator(indicator, guiSize); + } + throw new RuntimeException("Unknown type provided to getItemIconByTypeIndicator"); + } + + public int getItemPriceByTypeIndicator(String type, int indicator) { + if(type.equals("FOOD")) { + return Items.getFoodPriceByIndicator(indicator); + } else if(type.equals("BACKGROUND")) { + return Items.getBackgroundPriceByIndicator(indicator); + } else if(type.equals("BORDER")) { + return Items.getBorderPriceByIndicator(indicator); + } + throw new RuntimeException("Unknown type provided to getItemPriceByTypeIndicator"); + } + + public void addItemToInventory(String type, int indicator, Profile profile) { + Debug.info("ShopItemPanel.addItemToInventory", "type=" + type + ", type.equals(\"FOOD\")=" + type.equals("FOOD") + "type.equals(\"BACKGROUND\")=" + type.equals("BACKGROUND") + "type.equals(\"BORDER\")=" + type.equals("BORDER")); + + if(type.equals("FOOD")) { + List foodInventoryList = new ArrayList(profile.getFoodInventoryList()); + foodInventoryList.add((long) indicator); + profile.setFoodInventoryList(foodInventoryList); + } else if(type.equals("BACKGROUND")) { + List backgroundInventoryList = new ArrayList(profile.getBackgroundInventoryList()); + backgroundInventoryList.add((long) indicator); + profile.setBackgroundInventoryList(backgroundInventoryList); + } else if(type.equals("BORDER")) { + List borderInventoryList = new ArrayList(profile.getBorderInventoryList()); + borderInventoryList.add((long) indicator); + profile.setBorderInventoryList(borderInventoryList); + } else { + throw new RuntimeException("Unknown type provided to addItemToInventory: " + type); + } + } +} diff --git a/TamoStudy/src/components/panel/ShopPanel.java b/TamoStudy/src/components/panel/ShopPanel.java new file mode 100644 index 0000000..2b02fa3 --- /dev/null +++ b/TamoStudy/src/components/panel/ShopPanel.java @@ -0,0 +1,295 @@ +package components.panel; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JPanel; + +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import resources.Debug; +import resources.Theme; + +public class ShopPanel extends JPanel { + + private static final long serialVersionUID = -2126394001767280760L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private TamoStudyGUI tsGui; + private GuiSize guiSize; + private Language language; + private Theme theme; + private List shopItems; + private int currentShopIndicator; + private int shopPage; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JButton nextButton; + private JButton previousButton; + + public ShopPanel(TamoStudyGUI tsGui, GuiSize guiSize, Language language) { + this.tsGui = tsGui; + this.guiSize = guiSize; + this.language = language; + theme = Theme.DARK; + currentShopIndicator = 0; + shopPage = 0; + + initializeComponents(); + initializePanel(); + } + + public void initializeComponents() { + nextButton = new JButton(guiSize.rightArrowIcon); + addButtonVisual(nextButton); + + nextButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + nextPreviousPage(true); + + } + }); + + previousButton = new JButton(guiSize.leftArrowIcon); + addButtonVisual(previousButton); + + previousButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + nextPreviousPage(false); + + } + }); + } + + public void initializePanel() { + this.setBackground(theme.subColor); + + } + + public void setShop(int shopIndicator) { + switch(shopIndicator) { + case 0: + if(currentShopIndicator != 0) { + this.removeAll(); + this.repaint(); + currentShopIndicator = 0; + shopPage = 0; + + this.revalidate(); + } + + break; + case 1: + if(currentShopIndicator != 1) { + this.removeAll(); + this.repaint(); + + this.add(new ShopItemPanel(tsGui, guiSize, language, "FOOD", 0, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "FOOD", 1, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "FOOD", 2, false)); + + currentShopIndicator = 1; + shopPage = 0; + + this.revalidate(); + } + + break; + case 2: + if(currentShopIndicator != 2) { + this.removeAll(); + this.repaint(); + + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 1, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 2, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 3, false)); + this.add(nextButton); + + currentShopIndicator = 2; + shopPage = 0; + + this.revalidate(); + } + + break; + case 3: + if(currentShopIndicator != 3) { + this.removeAll(); + this.repaint(); + + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 1, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 2, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 3, false)); + this.add(nextButton); + + currentShopIndicator = 3; + shopPage = 0; + + this.revalidate(); + } + + break; + } + + Debug.info("ShopPanel.setShop(" + shopIndicator + ")", "" + this.getComponentCount()); + } + + public void nextPreviousPage(boolean next) { + // If next is true, we are moving forward, otherwise, we are moving back + if(next) { + shopPage++; + } else { + shopPage--; + } + + Debug.info("ShopPanel.nextPreviousPage", "shopPage=" + shopPage + ", currentShopIndicator=" + currentShopIndicator); + + switch(currentShopIndicator) { + case 2: + if(shopPage == 0) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 0 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 1, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 2, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 3, false)); + this.add(nextButton); + + this.revalidate(); + } else if(shopPage == 1) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 1 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 4, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 5, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 6, false)); + this.add(nextButton); + + this.revalidate(); + } else if(shopPage == 2) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 1 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 7, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 8, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BACKGROUND", 9, false)); + this.add(nextButton); + + this.revalidate(); + } else { + + this.removeAll(); + this.repaint(); + } + + break; + case 3: + if(shopPage == 0) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 0 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 1, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 2, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 3, false)); + this.add(nextButton); + + this.revalidate(); + } else if(shopPage == 1) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 1 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 4, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 5, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 6, false)); + this.add(nextButton); + + this.revalidate(); + } else if(shopPage == 2) { + this.removeAll(); + this.repaint(); + + // Add shop options on page 1 + this.add(previousButton); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 7, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 8, false)); + this.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference)); + this.add(new ShopItemPanel(tsGui, guiSize, language, "BORDER", 9, false)); + this.add(nextButton); + + this.revalidate(); + } else { + this.removeAll(); + this.repaint(); + } + + break; + } + + Debug.info("ShopPanel.nextPreviousPage", "" + this.getComponentCount()); + + // If we get to a page with no items, go back to previous/next page + if(this.getComponentCount() == 0) { + if(next) { + nextPreviousPage(false); + } else { + nextPreviousPage(true); + } + } + } + + public void addButtonVisual(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setBorderPainted(false); + button.setFocusPainted(false); + } +} diff --git a/TamoStudy/src/components/panel/TamoGraphicsPanel.java b/TamoStudy/src/components/panel/TamoGraphicsPanel.java new file mode 100644 index 0000000..800766a --- /dev/null +++ b/TamoStudy/src/components/panel/TamoGraphicsPanel.java @@ -0,0 +1,147 @@ +package components.panel; + +import java.awt.Graphics; +import java.awt.Image; + +import javax.swing.JPanel; +import javax.swing.Timer; + +import model.GuiSize; +import model.profile.Tamo; + +public class TamoGraphicsPanel extends JPanel { + + private static final long serialVersionUID = 893329295457663557L; + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GuiSize guiSize; + private Tamo tamo; + private int backgroundIndicator; + private int borderIndicator; + private Timer timer; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private Image borderImage; + private Image backgroundImage; + public Image tamoImage; + + public TamoGraphicsPanel(GuiSize guiSize, Tamo tamo, long backgroundIndicator, long borderIndicator) { + this.guiSize = guiSize; + this.tamo = tamo; + this.backgroundIndicator = (int) backgroundIndicator; + this.borderIndicator = (int) borderIndicator; + + timer = new Timer(1000, e -> repaint()); + initializeAttributes(); + + // If Tamo is happy or normal status, repaint so tamo appears in random location + + } + + /** + * @param tamo + * @param backgroundIndicator + * @param borderIndicator + * @brief Based off of the GUI size, we will initialize our tamoImage, + * backgroundImage, and borderImage + */ + public void initializeAttributes() { + this.setPreferredSize(guiSize.tamoGraphicsPanelDimension); + + tamoImage = guiSize.getTamoImage((int) tamo.getType(), tamo.getStatus(false)); + backgroundImage = guiSize.getBackgroundImage(backgroundIndicator); + borderImage = guiSize.getBorderImage(borderIndicator); + } + + + @Override + public void paint(Graphics g) { + super.paint(g); + + if(tamo.isFocused()) { + tamoImage = guiSize.getTamoImage((int) tamo.getType(), tamo.getStatus(true)); + + if(timer.isRunning()) { + timer.stop(); + } + } + else if(tamo.isFocused() == false && (tamo.getStatus(false) == "HAPPY" || tamo.getStatus(false) == "NORMAL")) { + timer.start(); + } + + g.drawImage(backgroundImage, guiSize.backgroundImageOffset, guiSize.backgroundImageOffset, this); + g.drawImage(tamoImage, getTamoX(), getTamoY(), this); + g.drawImage(borderImage, 0, 0, this); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + + public int getTamoX() { + if(tamo.isFocused() == false && tamo.getStatus(false).equals("HAPPY") || tamo.getStatus(false).equals("NOMRAL")) { + return getTamoRandomX(); + } else { + return getTamoCenterX(); + } + } + + public int getTamoY() { + if(tamo.isFocused() == false && tamo.getStatus(false).equals("HAPPY") || tamo.getStatus(false).equals("NOMRAL")) { + return getTamoRandomY(); + } else { + return getTamoCenterY(); + } + } + + public int getTamoCenterX() { + int backgroundImageWidth = backgroundImage.getWidth(this); + int tamoImageWidth = tamoImage.getWidth(this); + int number = (tamoImageWidth + tamoImageWidth/2) / 2; + + return (backgroundImageWidth - number) / 2; + } + + public int getTamoCenterY() { + int backgroundImageHeight = backgroundImage.getHeight(this); + int tamoImageHeight = tamoImage.getHeight(this); + + return (backgroundImageHeight - tamoImageHeight) / 2; + } + + public int getTamoRandomX() { + int backgroundImageWidth = backgroundImage.getWidth(this); + int tamoImageWidth = tamoImage.getWidth(this); + + return (int) (Math.random() * (backgroundImageWidth - tamoImageWidth)); + } + + public int getTamoRandomY() { + int backgroundImageHeight = backgroundImage.getHeight(this); + int tamoImageHeight = tamoImage.getHeight(this); + return (int) (Math.random() * (backgroundImageHeight - tamoImageHeight)); + } + + public Tamo getTamo() { + return tamo; + } + + public void resetTamoImage() { + tamoImage = guiSize.getTamoImage((int) tamo.getType(), tamo.getStatus(false)); + } +} diff --git a/TamoStudy/src/components/panel/TimerPanel.java b/TamoStudy/src/components/panel/TimerPanel.java new file mode 100644 index 0000000..32fb777 --- /dev/null +++ b/TamoStudy/src/components/panel/TimerPanel.java @@ -0,0 +1,97 @@ +package components.panel; + +import java.awt.Color; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import components.border.BubbleBorder; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import resources.Theme; + +public class TimerPanel extends JPanel { + + private static final long serialVersionUID = 4026276417716279630L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Profile profile; + private Language language; + private GuiSize guiSize; + private Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JPanel timerTimePanel; + public JLabel minuteTimeLabel, colonLabel, secondTimeLabel; + public JLabel subTextLabel; + + public TimerPanel(Profile profile) { + this.profile = profile; + this.language = profile.getSettings().getLanguage(); + this.guiSize = new GuiSize((int) profile.getSettings().getGuiSize()); + this.theme = profile.getSettings().getTheme(); + + initializeAttributes(); + initializePanel(); + } + + public void initializeAttributes() { + timerTimePanel = new JPanel(); + timerTimePanel.setBackground(theme.timerColor); + + minuteTimeLabel = new JLabel("00"); + minuteTimeLabel.setForeground(theme.textColor); + minuteTimeLabel.setFont(guiSize.timerFont); + + colonLabel = new JLabel(":"); + colonLabel.setForeground(theme.textColor); + colonLabel.setFont(guiSize.timerFont); + + secondTimeLabel = new JLabel("00"); + secondTimeLabel.setForeground(theme.textColor); + secondTimeLabel.setFont(guiSize.timerFont); + + timerTimePanel.add(minuteTimeLabel); + timerTimePanel.add(colonLabel); + timerTimePanel.add(secondTimeLabel); + + subTextLabel = new JLabel(language.letsFocusText); + subTextLabel.setForeground(theme.textColor); + subTextLabel.setFont(guiSize.subTextFont); + } + + public void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + this.setLayout(new GridBagLayout()); + this.setBackground(theme.timerColor); + this.setBorder(guiSize.timerBorder); + + this.add(timerTimePanel, gbcv); + this.add(subTextLabel, gbcv); + } + + public Theme getTheme() { + return theme; + } + + public GuiSize getGuiSize() { + return guiSize; + } +} diff --git a/TamoStudy/src/gui/TamoStudyGUI.java b/TamoStudy/src/gui/TamoStudyGUI.java new file mode 100644 index 0000000..d619977 --- /dev/null +++ b/TamoStudy/src/gui/TamoStudyGUI.java @@ -0,0 +1,805 @@ +package gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import io.DailyFocusJsonManager; +import io.MonthFocusJsonManager; +import io.ProfileJsonManager; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import model.profile.ProfileUpdateManager; +import model.profile.Tamo; +import model.time.DailyFocus; +import model.time.DailyFocusEntry; +import model.time.MonthFocus; +import model.time.MonthFocusEntry; +import resources.Constants; +import resources.Debug; +import resources.DiscordRP; +import resources.Theme; +import state.AboutState; +import state.AchievementsState; +import state.DashboardState; +import state.FocusState; +import state.InventoryState; +import state.SettingsState; +import state.ShopState; +import state.State; +import state.StatisticsState; +import state.TamoHistoryState; +import util.Utils; + +public class TamoStudyGUI extends JFrame { + + private static final long serialVersionUID = -1279489061097200797L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private List profiles; + private ProfileJsonManager profileJsonManager; + private int profileIndex; + private Profile profile; + private Language lang; + private DiscordRP discordRP; + private Theme theme; + private GuiSize guiSize; + private ProfileUpdateManager profileUpdateManager; + + private DailyFocusJsonManager dailyFocusJsonManager; + private List dailyFocusList; + private DailyFocus dailyFocus; + private MonthFocusJsonManager monthFocusJsonManager; + private List monthFocusList; + private MonthFocus monthFocus; + + /* + * ################################## + * ################################## + * GUI COMPONENTS + * ################################## + * ################################## + */ + private JPanel topPanel; + private JButton topMenuButton; + private JLabel topNameTokensLabel; + + private JPanel sidePanel; + private JButton dashboardStateButton; + private JButton focusStateButton; + private JButton shopStateButton; + private JButton inventoryStateButton; + private JButton statisticsStateButton; + private JButton achievementsStateButton; + private JButton settingsStateButton; + private JButton tamoHistoryStateButton; + private JButton aboutStateButton; + + private State state; + + /** + * Load TamoStudyGUI Constructor + * @param profiles + * @param profileIndex + */ + public TamoStudyGUI(List profiles, int profileIndex) { + this.profiles = profiles; + this.profileIndex = profileIndex; + this.profile = profiles.get(profileIndex); + this.lang = profile.getSettings().getLanguage(); + Debug.info("TamoStudyGUI", "Initialized with profile=" + profile.toString()); + + initializeAttributes(); + state = new DashboardState(getThis()); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializeFrame(); + + checkForTamoDeath(); + } + + /** + * Reset GUI TamoStudyGUI Constructor + * @param profiles + * @param profileIndex + * @param state + */ + public TamoStudyGUI(List profiles, int profileIndex, int settingsOn) { + this.profiles = profiles; + this.profileIndex = profileIndex; + this.profile = profiles.get(profileIndex); + this.lang = profile.getSettings().getLanguage(); + Debug.info("TamoStudyGUI", "Initialized with profile=" + profile.toString()); + + initializeAttributes(); + state = new SettingsState(getThis()); + + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializeFrame(); + + sidePanel.setVisible(false); + checkForTamoDeath(); + } + + private void initializeAttributes() { + profileJsonManager = new ProfileJsonManager(); + theme = profile.getSettings().getTheme(); + guiSize = new GuiSize((int) profile.getSettings().getGuiSize()); + + profileUpdateManager = new ProfileUpdateManager(this); + + dailyFocusJsonManager = new DailyFocusJsonManager(); + dailyFocusList = dailyFocusJsonManager.readJson(); + + dailyFocus = Utils.searchDailyFocusByProfile(dailyFocusList, profile); + // Create dailyFocus if it does not exist + if(dailyFocus == null) { + dailyFocus = addNewDailyFocusToDailyFocusList(Utils.createDailyFocus(profile)); + } + + monthFocusJsonManager = new MonthFocusJsonManager(); + monthFocusList = monthFocusJsonManager.readJson(); + + monthFocus = Utils.searchMonthFocusByProfile(monthFocusList, profile); + if(monthFocus == null) { + monthFocus = addNewMonthFocusToMonthFocusList(Utils.createMonthFocus(profile)); + } + + if(System.getProperty("os.name").startsWith("Windows") && profile.getSettings().getEnableDiscordRPC()) { + discordRP = new DiscordRP(); + discordRP.start(); + } + } + + private void initializeComponents() { + topPanel = new JPanel(); + topMenuButton = new JButton(lang.menuButtonText); + topNameTokensLabel = new JLabel(profile.getName() + " • " + profile.getTokens()); // TODO Level Progess on the top, along with hours studied today + + sidePanel = new JPanel(); + dashboardStateButton = new JButton(lang.dashboardStateButtonText); + focusStateButton = new JButton(lang.focusStateButtonText); + shopStateButton = new JButton(lang.shopStateButtonText); + inventoryStateButton = new JButton(lang.inventoryStateButtonText); + statisticsStateButton = new JButton(lang.statisticsStateButtonText); + achievementsStateButton = new JButton(lang.achievementsStateButtonText); + settingsStateButton = new JButton(lang.settingsStateButtonText); + tamoHistoryStateButton = new JButton(lang.tamoHistoryText); + aboutStateButton = new JButton(lang.aboutStateButton); + + } + + private void initializeComponentVisuals() { + // Component Visual Attributes + topPanel.setLayout(new BorderLayout()); + topPanel.setBackground(theme.mainColor); + addMenuButtonVisual(topMenuButton); + topMenuButton.setIcon(guiSize.topMenuImageIcon); + + topNameTokensLabel.setFont(guiSize.topMenuFont); + topNameTokensLabel.setForeground(theme.textColor); + topNameTokensLabel.setIcon(guiSize.tamoTokenImageIcon); + topNameTokensLabel.setHorizontalTextPosition(SwingConstants.LEADING); + + sidePanel.setLayout(new GridBagLayout()); + sidePanel.setBackground(theme.mainColor); + addMenuButtonVisual(dashboardStateButton); + addMenuButtonVisual(focusStateButton); + addMenuButtonVisual(shopStateButton); + addMenuButtonVisual(inventoryStateButton); + addMenuButtonVisual(statisticsStateButton); + addMenuButtonVisual(achievementsStateButton); + addMenuButtonVisual(settingsStateButton); + addMenuButtonVisual(tamoHistoryStateButton); + addMenuButtonVisual(aboutStateButton); + + // Component Visual Placement + topPanel.add(topMenuButton, BorderLayout.WEST); + topPanel.add(topNameTokensLabel, BorderLayout.EAST); + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + sidePanel.add(dashboardStateButton, gbcv); + sidePanel.add(focusStateButton, gbcv); + sidePanel.add(createSpaceLabel(), gbcv); + sidePanel.add(shopStateButton, gbcv); + sidePanel.add(inventoryStateButton, gbcv); + sidePanel.add(statisticsStateButton, gbcv); + sidePanel.add(achievementsStateButton, gbcv); + sidePanel.add(createSpaceLabel(), gbcv); + sidePanel.add(settingsStateButton, gbcv); + if(profile.getTamoHistory().size() > 0) { + sidePanel.add(tamoHistoryStateButton, gbcv); + } + sidePanel.add(aboutStateButton, gbcv); + } + + private void initializeComponentActions() { + profileUpdateManager.updateHappyHungerBasedOnTime(); + + /* + * Opens/Closes the Top Menu. + */ + topMenuButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(sidePanel.isVisible()) { + sidePanel.setVisible(false); + } else { + sidePanel.setVisible(true); + } + } + + }); + + /* + * Changes to the Dash board State. + */ + dashboardStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof DashboardState)) { + updateDiscordRPC("Viewing Dashboard...", ""); + changeState(new DashboardState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the focus state. + */ + focusStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof FocusState)) { + updateDiscordRPC("Ready to Focus!", ""); + changeState(new FocusState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the shop state. + */ + shopStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof ShopState)) { + updateDiscordRPC("Browsing Shop...", ""); + changeState(new ShopState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the inventory state. + */ + inventoryStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof InventoryState)) { + updateDiscordRPC("Viewing Inventory...", ""); + changeState(new InventoryState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the statistics state. + */ + statisticsStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof StatisticsState)) { + updateDiscordRPC("Viewing statistics...", ""); + changeState(new StatisticsState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the achievements state. + */ + achievementsStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof AchievementsState)) { + updateDiscordRPC("Viewing achievements...", ""); + changeState(new AchievementsState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the settings state. + */ + settingsStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof SettingsState)) { + updateDiscordRPC("Changing settings...", ""); + changeState(new SettingsState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the Tamo History state. + */ + tamoHistoryStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof TamoHistoryState)) { + updateDiscordRPC("Viewing Tamo History...", ""); + changeState(new TamoHistoryState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + + /* + * Changes to the about state. + */ + aboutStateButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(!(state instanceof AboutState)) { + updateDiscordRPC("Reading about TamoStudy!", ""); + changeState(new AboutState(getThis())); + sidePanel.setVisible(false); + } + } + + }); + } + + private void initializeFrame() { + this.add(topPanel, BorderLayout.NORTH); + this.add(sidePanel, BorderLayout.WEST); + this.add(state, BorderLayout.CENTER); + + this.getContentPane().setBackground(theme.mainColor); + this.setTitle("TamoStudy " + Constants.version); + this.setSize(guiSize.frameSize); + this.setLocationRelativeTo(null); + this.setResizable(false); + this.setIconImage(new ImageIcon(getClass().getClassLoader().getResource("ICON.png")).getImage()); + this.setVisible(true); + + //Check Window Adapter Setting + if(profile.getSettings().getShowProgramCloseMessage()) { + this.addWindowListener(makeExitWindowListener()); + this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + } else { + this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + } + } + + /** + * Enables WindowListener + * Asks user if they are sure they want to exit application + */ + public WindowListener makeExitWindowListener() { + WindowListener exitListener = new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + JLabel label = new JLabel(profile.getSettings().getLanguage().areYouSureYouWantToExitText); + label.setForeground(Color.WHITE); + label.setAlignmentX(JComponent.CENTER_ALIGNMENT); + JPanel confirmPanel = new JPanel(); + confirmPanel.setAlignmentX(JComponent.CENTER_ALIGNMENT); + JCheckBox checkBox = new JCheckBox(); + JLabel confirmLabel = new JLabel(profile.getSettings().getLanguage().dontShowThisMessageAgainText); + confirmLabel.setForeground(Color.WHITE); + + panel.add(label); + confirmPanel.add(checkBox); + confirmPanel.add(confirmLabel); + panel.add(confirmPanel); + + // Ensure if it was changed in settings it closes + if(profile.getSettings().getShowProgramCloseMessage() == false) { + System.exit(0); + } + + int confirm = JOptionPane.showOptionDialog( + rootPane, + panel, + "Exit TamoStudy?", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + new ImageIcon(getClass().getClassLoader().getResource("INFO.png")), + null, + null); + if (confirm == JOptionPane.YES_OPTION) { + if(checkBox.isSelected()) { + profile.getSettings().setShowProgramCloseMessage(false); + profileJsonManager.writeJsonToFile(profiles); + } + System.exit(0); + } + } + }; + return exitListener; + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + + /** + * changeState + * @brief Changes the current State to a new State. + * and repaints the frame to coordinate the update. + * @param newState + */ + public void changeState(State newState) { + this.remove(state); + state = newState; + this.add(state, BorderLayout.CENTER); + this.repaint(); + this.revalidate(); + } + + /** + * resetGui + * @brief Resets the GUI, disposes, and + * creates a new object. + */ + public void resetGui() { + this.setVisible(false); + this.dispose(); + + new TamoStudyGUI(profiles, profileIndex); + } + + /** + * resizeGui + * @brief Helper method for resizing the GUI. + * Disposes of the old GUI, then calls the + * Settings Constructor to create the new GUI. + */ + public void resizeGui() { + this.setVisible(false); + this.dispose(); + + new TamoStudyGUI(profiles, profileIndex, 0); + } + + /** + * addMenuButtonVisual + * @brief Sets Menu button visuals. + * @param button + */ + public void addMenuButtonVisual(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setFont(guiSize.topMenuFont); + button.setForeground(theme.textColor); + button.setBorderPainted(false); + button.setFocusPainted(false); + theme.buttonLayerEnterEffect(button); + } + + public JLabel createSpaceLabel() { + String DIVIDER = (System.getProperty("os.name").startsWith("Linux") || System.getProperty("os.name").startsWith("Windows")) + ? "────────────" : "━━━━━━━"; + + JLabel label = new JLabel(DIVIDER); + label.setFont(guiSize.topMenuFont); + label.setForeground(theme.altTextColor); + return label; + } + + public void disableSidePanelButtons() { + dashboardStateButton.setEnabled(false); + focusStateButton.setEnabled(false); + shopStateButton.setEnabled(false); + inventoryStateButton.setEnabled(false); + statisticsStateButton.setEnabled(false); + achievementsStateButton.setEnabled(false); + settingsStateButton.setEnabled(false); + aboutStateButton.setEnabled(false); + } + + public void enableSidePanelButtons() { + dashboardStateButton.setEnabled(true); + focusStateButton.setEnabled(true); + shopStateButton.setEnabled(true); + inventoryStateButton.setEnabled(true); + statisticsStateButton.setEnabled(true); + achievementsStateButton.setEnabled(true); + settingsStateButton.setEnabled(true); + aboutStateButton.setEnabled(true); + } + + /* + * ################################## + * ################################## + * ACCESSOR METHODS + * ################################## + * ################################## + */ + public TamoStudyGUI getThis() { + return this; + } + + public Theme getTheme() { + return this.theme; + } + + public List getProfiles() { + return this.profiles; + } + + public ProfileJsonManager getProfileJsonManager() { + return this.profileJsonManager; + } + + public Profile getProfile() { + return this.profile; + } + + public DiscordRP getDiscordRP() { + return this.discordRP; + } + + public GuiSize getGuiSize() { + return this.guiSize; + } + public void setGuiSize(GuiSize guiSize) { + this.guiSize = guiSize; + } + + public List getDailyFocusList() { + return dailyFocusList; + } + + public void setDailyFocusList(List dailyFocusList) { + this.dailyFocusList = dailyFocusList; + } + + public DailyFocus getDailyFocus() { + return dailyFocus; + } + + public List getMonthFocusList() { + return monthFocusList; + } + + public void setMonthFocusList(List monthFocusList) { + this.monthFocusList = monthFocusList; + } + + public MonthFocus getMonthFocus() { + return monthFocus; + } + + public DailyFocusJsonManager getDailyFocusJsonManager() { + return dailyFocusJsonManager; + } + + public MonthFocusJsonManager getMonthFocusJsonManager() { + return monthFocusJsonManager; + } + + public ProfileUpdateManager getProfileUpdateManager() { + return profileUpdateManager; + } + + public void setProfileUpdateManager(ProfileUpdateManager profileUpdateManager) { + this.profileUpdateManager = profileUpdateManager; + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public DailyFocus addNewDailyFocusToDailyFocusList(DailyFocus dailyFocus) { + List dailyFocusList = new ArrayList<>(this.dailyFocusList); + try { + dailyFocusList.add(dailyFocus); + this.setDailyFocusList(dailyFocusList); + this.dailyFocusJsonManager.writeJsonToFile(this.dailyFocusList); + return dailyFocus; + } catch (Exception e) { + Debug.error("TamoStudyGUI.addNewDailyFocusToDailyFocusList", "bruh idk what happened"); + e.printStackTrace(); + throw e; + } + } + + public MonthFocus addNewMonthFocusToMonthFocusList(MonthFocus monthFocus) { + List monthFocusList = new ArrayList<>(this.monthFocusList); + try { + monthFocusList.add(monthFocus); + this.setMonthFocusList(monthFocusList); + this.monthFocusJsonManager.writeJsonToFile(this.monthFocusList); + return monthFocus; + } catch (Exception e) { + Debug.error("TamoStudyGUI.addNewMonthFocusToMonthFocusList", "bruh idk what happened"); + e.printStackTrace(); + throw e; + } + } + + public boolean addNewDailyFocusEntryToDailyFocus(DailyFocusEntry dailyFocusEntry) { + List dailyFocusEntriesList = new ArrayList<>(dailyFocus.getDailyFocusEntries()); + try { + dailyFocusEntriesList.add(dailyFocusEntry); + dailyFocus.setDailyFocusEntries(dailyFocusEntriesList); + Debug.info("Length of dailyFocus", "length of daily focus = " + dailyFocus); + return true; + } catch (Exception e) { + Debug.error("TamoStudyGUI.addNewDailyFocusEntryToDailyFocus", "bruh idk what happened"); + e.printStackTrace(); + return false; + } + } + + public boolean addNewMonthFocusEntryToMonthFocus(MonthFocusEntry monthFocusEntry) { + List monthFocusEntriesList = new ArrayList<>(monthFocus.getMonthFocusEntries()); + try { + monthFocusEntriesList.add(monthFocusEntry); + monthFocus.setMonthFocusEntries(monthFocusEntriesList); + return true; + } catch (Exception e) { + Debug.error("TamoStudyGUI.addNewMonthFocusEntryToDailyFocus", "bruh idk what happened"); + e.printStackTrace(); + return false; + } + } + + public void toggleMenuButtons(boolean enabled) { + dashboardStateButton.setEnabled(enabled); + focusStateButton.setEnabled(enabled); + shopStateButton.setEnabled(enabled); + inventoryStateButton.setEnabled(enabled); + statisticsStateButton.setEnabled(enabled); + achievementsStateButton.setEnabled(enabled); + settingsStateButton.setEnabled(enabled); + tamoHistoryStateButton.setEnabled(enabled); + aboutStateButton.setEnabled(enabled); + } + + public void updateTamoTokensLabel() { + topNameTokensLabel.setText(profile.getName() + " • " + profile.getTokens()); + } + + public void checkForTamoDeath() { + + // Check for tamo death + if(profile.getTamo().getStrikes() >= 3) { + // Tamo Death + Tamo deathTamo = new Tamo( + profile.getTamo().getName(), + profile.getTamo().getTime(), + profile.getTamo().getType(), + profile.getTamo().getBirthDateString(), + Utils.todayAsString() + ); + List tamoHistory = new ArrayList<>(profile.getTamoHistory()); + tamoHistory.add(deathTamo); + profile.setTamoHistory(tamoHistory); + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + JPanel newTamoPanel = new JPanel(new GridBagLayout()); + JLabel tamoDeathMessageLabel = new JLabel("" + profile.getTamo().getName() + ", " + profile.getSettings().getLanguage().deathText1 + "

" + profile.getSettings().getLanguage().deathText2 + "

"); + tamoDeathMessageLabel.setForeground(Color.WHITE); + JLabel newTamoNameLabel = new JLabel(profile.getSettings().getLanguage().newTamoNameText); + newTamoNameLabel.setForeground(Color.WHITE); + JTextField newTamoNameTextField = new JTextField(10); + + newTamoPanel.add(tamoDeathMessageLabel, gbcv); + newTamoPanel.add(newTamoNameLabel, gbcv); + newTamoPanel.add(newTamoNameTextField, gbcv); + + + Object[] options = {profile.getSettings().getLanguage().resetText}; + int resultPane = JOptionPane.showOptionDialog(getRootPane(), newTamoPanel, "TamoStudy", JOptionPane.PLAIN_MESSAGE, JOptionPane.QUESTION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png")), options, options[0]); + if(resultPane == 0) { + String newTamoName = (newTamoNameTextField.getText().trim().isEmpty() || newTamoNameTextField.getText().trim().isEmpty()) + ? profile.getTamo().getName() + : newTamoNameTextField.getText(); + Tamo newTamo = new Tamo(newTamoName); + profile.setTamo(newTamo); + } else { + String newTamoName = profile.getTamo().getName(); + Tamo newTamo = new Tamo(newTamoName); + profile.setTamo(newTamo); + } + + profileJsonManager.writeJsonToFile(profiles); + resetGui(); + } + } + + /** + * updateDiscordRPC + * @param line + * @brief Helper method to update the discord RPC presence + */ + public void updateDiscordRPC(String line, String line2) { + // If discord RPC is enabled and on Windows + if(System.getProperty("os.name").startsWith("Windows") && profile.getSettings().getEnableDiscordRPC()) { + + // Create new instance of discordRP if not initialized, otherwise update + if(discordRP == null) { + discordRP = new DiscordRP(); + discordRP.start(line); + } else { + discordRP.update(line, line2); + } + + } + } +} + diff --git a/TamoStudy/src/gui/WelcomeGUI.java b/TamoStudy/src/gui/WelcomeGUI.java new file mode 100644 index 0000000..0a2d537 --- /dev/null +++ b/TamoStudy/src/gui/WelcomeGUI.java @@ -0,0 +1,319 @@ +package gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Desktop; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.URL; +import java.util.List; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.plaf.ColorUIResource; + +import components.panel.ChangeGlobalSettingsPanel; +import components.panel.ProfileSelectionPanel; +import io.GlobalSettingsJsonManager; +import io.ProfileJsonManager; +import model.GlobalSettings; +import model.language.Language; +import model.profile.Profile; +import resources.CheckForUpdates; +import resources.Constants; +import resources.Debug; +import resources.Theme; + +public class WelcomeGUI extends JFrame { + + private static final long serialVersionUID = -8500200649157878440L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GlobalSettingsJsonManager globalSettingsJsonManager; + private GlobalSettings globalSettings; + private Theme theme; + private Language language; + + /* + * ################################## + * ################################## + * GUI COMPONENTS + * ################################## + * ################################## + */ + private JPanel mainPanel; + + private JPanel messageSettingsPanel; + private JButton websiteButton; + private JButton messageButton; + private JButton settingsButton; + + private JLabel tamoStudyLogoImageLabel; + private JPanel buttonPanel; + private JButton localStudyButton, onlineStudyButton; + private JLabel authorLabel; + + public WelcomeGUI() { + initializeAttributes(); + initializeComponents(); + initializeComponentActions(); + initializeFrame(); + + if(globalSettings.getReceiveUpdateNotifications()) + checkForTamoStudyUpdates(); + } + + private void initializeAttributes() { + globalSettingsJsonManager = new GlobalSettingsJsonManager(); + globalSettings = globalSettingsJsonManager.readJson(); + Debug.info("WelcomeGUI.initializeAttributes", "Loaded Global Settings: " + globalSettings.toString()); + theme = Theme.DARK; + language = globalSettings.getLanguage(); + } + + private void initializeComponents() { + // Initialize components, visuals + mainPanel = new JPanel(); + + messageSettingsPanel = new JPanel(); + websiteButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("TITLE_ICON.png"))); + messageButton = new JButton("\t"); + settingsButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource("SETTINGS.png"))); + + tamoStudyLogoImageLabel = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("TAMOSTUDY_LOGO_IMAGE_LARGE.gif"))); + + authorLabel = new JLabel(Constants.version + " • " + language.createdByText + " narlock"); + + buttonPanel = new JPanel(); + localStudyButton = new JButton(language.localStudyText); + onlineStudyButton = new JButton(language.onlineStudyText); + + initializeComponentVisual(); + + // Placement of components on frame and panels + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + +// messageSettingsPanel.add(websiteButton, BorderLayout.WEST); + messageSettingsPanel.add(messageButton, BorderLayout.CENTER); + messageSettingsPanel.add(settingsButton, BorderLayout.EAST); + + buttonPanel.add(localStudyButton, gbch); + buttonPanel.add(Box.createHorizontalStrut(20), gbch); +// buttonPanel.add(onlineStudyButton, gbch); + + this.add(messageSettingsPanel, BorderLayout.NORTH); + mainPanel.add(tamoStudyLogoImageLabel, gbcv); + mainPanel.add(Box.createVerticalStrut(20), gbcv); + mainPanel.add(buttonPanel, gbcv); + mainPanel.add(Box.createVerticalStrut(20), gbcv); + mainPanel.add(authorLabel, gbcv); + + this.add(mainPanel); + } + + private void initializeComponentActions() { + websiteButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://tamostudy.com/").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + + settingsButton.addActionListener(new ActionListener() { + + @SuppressWarnings("static-access") + @Override + public void actionPerformed(ActionEvent e) { + UIManager UI = new UIManager(); + UI.put("OptionPane.background", new ColorUIResource(theme.mainColor)); + UI.put("Panel.background", new ColorUIResource(theme.mainColor)); + UI.put("OptionPane.messageForeground", new ColorUIResource(theme.textColor)); + + System.out.println("global settings text= " + language.globalSettingsText); + Object[] options = {}; + JOptionPane.showOptionDialog(getRootPane(), + new ChangeGlobalSettingsPanel(getThis()), + language.globalSettingsText, + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, null); + } + + }); + + localStudyButton.addActionListener(new ActionListener() { + + @SuppressWarnings("static-access") + @Override + public void actionPerformed(ActionEvent e) { + UIManager UI = new UIManager(); + UI.put("OptionPane.background", new ColorUIResource(theme.mainColor)); + UI.put("Panel.background", new ColorUIResource(theme.mainColor)); + UI.put("OptionPane.messageForeground", new ColorUIResource(Color.WHITE)); + + if(globalSettings.getDefaultLocalProfile() == -1) { + Object[] options = {}; + JOptionPane.showOptionDialog(getRootPane(), + new ProfileSelectionPanel(getThis()), + language.localStudyText, + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, null); + } else { + ProfileJsonManager profileJsonManager = new ProfileJsonManager(); + List profiles = profileJsonManager.readJson(); + new TamoStudyGUI(profiles, (int) globalSettings.getDefaultLocalProfile()); + dispose(); + removeAll(); + } + + } + + }); + } + + private void initializeFrame() { + this.setDefaultCloseOperation(EXIT_ON_CLOSE); + this.getContentPane().setBackground(theme.mainColor); + this.setTitle("TamoStudy " + Constants.version); + this.setSize(650,500); + this.setLocationRelativeTo(null); + this.setResizable(true); + this.setIconImage(new ImageIcon(getClass().getClassLoader().getResource("ICON.png")).getImage()); + this.setVisible(true); + } + + private void checkForTamoStudyUpdates() { + CheckForUpdates checkForUpdates = new CheckForUpdates(); + try { + String updateCheck = checkForUpdates.checkForUpdates(); + if(!(updateCheck == null)) { + messageButton.setForeground(Theme.SUCCESS); + String message = "TamoStudy " + updateCheck + " " + language.updateAvailableDownloadText; + messageButton.setText(message.replaceAll("\"", "")); + + messageButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://github.com/narlock/TamoStudy/releases/").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + } + } catch (Exception e) { + Debug.error("WelcomeGUI.checkForTamoStudyUpdates", "Error occurred when calling checkForUpdates.checkForUpdates"); + e.printStackTrace(); + + messageButton.setForeground(Theme.DANGER); + messageButton.setText(language.unableSearchUpdatesText); + } + } + + /* + * ################################## + * ################################## + * GUI COMPONENT VISUAL METHODS + * ################################## + * ################################## + */ + private void initializeComponentVisual() { + // Panels + mainPanel.setLayout(new GridBagLayout()); + initializePanelVisual(mainPanel); + messageSettingsPanel.setLayout(new BorderLayout()); + initializePanelVisual(messageSettingsPanel); + buttonPanel.setLayout(new GridBagLayout()); + initializePanelVisual(buttonPanel); + + // messageButton + addMenuButtonVisual(websiteButton); + Theme.labelButton(messageButton); + addMenuButtonVisual(settingsButton); + + // authorLabel + authorLabel.setFont(new Font("Tahoma", Font.PLAIN, 12)); + authorLabel.setForeground(new Color(153,153,153)); + + // Buttons + Theme.primaryVisualButton(localStudyButton); + Theme.primaryDisabledVisualButton(onlineStudyButton); + } + + private void initializePanelVisual(JPanel panel) { + panel.setBackground(theme.mainColor); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + + private WelcomeGUI getThis() { + return this; + } + + public void addMenuButtonVisual(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setForeground(theme.textColor); + button.setBorderPainted(false); + button.setFocusPainted(false); + theme.buttonLayerEnterEffect(button); + } + + public void resetGui() { + this.setVisible(false); + this.dispose(); + + new WelcomeGUI(); + } + + /** + * resetToMainMenu + * @brief Revalidates main panel on updates + */ + public void resetToMainMenu() { + // TODO + } + + /* + * ################################## + * ################################## + * ACCESSOR METHODS + * ################################## + * ################################## + */ + + public GlobalSettingsJsonManager getGlobalSettingsJsonManager() { + return globalSettingsJsonManager; + } + + public GlobalSettings getGlobalSettings() { + return globalSettings; + } +} diff --git a/TamoStudy/src/io/DailyFocusJsonManager.java b/TamoStudy/src/io/DailyFocusJsonManager.java new file mode 100644 index 0000000..4abbbe8 --- /dev/null +++ b/TamoStudy/src/io/DailyFocusJsonManager.java @@ -0,0 +1,149 @@ +package io; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import model.time.DailyFocus; +import model.time.DailyFocusEntry; +import resources.Debug; + +public class DailyFocusJsonManager extends JsonManager> { + + public static final String dailyFocusPath = System.getProperty("user.home") + File.separatorChar + "Documents" + File.separatorChar + "TamoStudy" + + File.separatorChar + "dailyfocus.json"; + + @Override + public List readJson() { + Debug.info("DailyFocusJsonManager.readJson", "Attempting to read dailyfocus.json"); + File dailyFocusJsonFile = new File(dailyFocusPath); + + if(dailyFocusJsonFile.exists()) { + JSONParser parser = new JSONParser(); + try { + Reader reader = new FileReader(dailyFocusPath); + JSONArray dailyFocusJsonArray = (JSONArray) parser.parse(reader); + Debug.info("DailyFocusJsonManager.readJson", "Read JSONArray dailyFocusJsonArray. dailyFocusJsonArray.size = " + dailyFocusJsonArray.size()); + return dailyFocusJsonArrayToDailyFocusList(dailyFocusJsonArray); + } catch (IOException | ParseException e) { + Debug.error("DailyFocusJsonManager.readJson", "Exception throw while reading dailyfocus.json"); + e.printStackTrace(); + } + } + + Debug.info("DailyFocusJsonManager.readJson", "No DailyFocus objects were found"); + return Collections.emptyList(); + } + + @Override + public boolean writeJsonToFile(List dailyFocusList) { + try { + File dailyFocusJsonFile = new File(dailyFocusPath); + FileWriter fileWriter = new FileWriter(dailyFocusJsonFile); + JSONArray dailyFocusJson = dailyFocusListToDailyFocusJson(dailyFocusList); + try { + + fileWriter.write(dailyFocusJson.toJSONString()); + return true; + } catch (IOException e) { + Debug.error("DailyFocusJsonManager.writeJsonToFile", "Error occurred writing profiles to dailyfocus.json"); + e.printStackTrace(); + return false; + } finally { + try { + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + Debug.error("DailyFocusJsonManager.writeJsonToFile", "Error occurred while closing file writer."); + e.printStackTrace(); + return false; + } + } + } catch (IOException e) { + Debug.error("DailyFocusJsonManager.writeJsonToFile", "Error occurred while instantiating fileWriter"); + e.printStackTrace(); + return false; + } + } + + /* + * ################################## + * ################################## + * MAPPINGS + * ################################## + * ################################## + */ + + public List dailyFocusJsonArrayToDailyFocusList(JSONArray dailyFocusJsonArray) { + List dailyFocusList = new ArrayList<>(); + for(int i = 0; i < dailyFocusJsonArray.size(); i++) { + dailyFocusList.add(dailyFocusJsonToDailyFocus((JSONObject) dailyFocusJsonArray.get(i))); + } + return dailyFocusList; + } + + @SuppressWarnings("unchecked") + public JSONArray dailyFocusListToDailyFocusJson(List dailyFocusList) { + JSONArray dailyFocusJsonArray = new JSONArray(); + for(DailyFocus dailyFocus : dailyFocusList) { + dailyFocusJsonArray.add(dailyFocusToDailyFocusJson(dailyFocus)); + } + return dailyFocusJsonArray; + } + + public DailyFocus dailyFocusJsonToDailyFocus(JSONObject dailyFocusJson) { + List dailyFocusEntries = new ArrayList<>(); + JSONArray dailyFocusEntriesJsonList = (JSONArray) dailyFocusJson.get("dailyFocusEntries"); + for(int i = 0; i < dailyFocusEntriesJsonList.size(); i++) { + dailyFocusEntries.add(dailyFocusEntryJsonToDailyFocusEntry((JSONObject) dailyFocusEntriesJsonList.get(i))); + } + + return new DailyFocus( + (long) dailyFocusJson.get("profileId"), + dailyFocusEntries + ); + } + + @SuppressWarnings("unchecked") + public JSONObject dailyFocusToDailyFocusJson(DailyFocus dailyFocus) { + JSONObject dailyFocusJson = new JSONObject(); + dailyFocusJson.put("profileId", dailyFocus.getProfileId()); + + JSONArray dailyFocusEntries = new JSONArray(); + for(DailyFocusEntry dailyFocusEntry : dailyFocus.getDailyFocusEntries()) { + dailyFocusEntries.add(dailyFocusEntryToDailyFocusEntryJson(dailyFocusEntry)); + } + dailyFocusJson.put("dailyFocusEntries", dailyFocusEntries); + + return dailyFocusJson; + } + + public DailyFocusEntry dailyFocusEntryJsonToDailyFocusEntry(JSONObject dailyFocusEntryJson) { + return new DailyFocusEntry( + (long) dailyFocusEntryJson.get("day"), + (long) dailyFocusEntryJson.get("month"), + (long) dailyFocusEntryJson.get("year"), + (long) dailyFocusEntryJson.get("time") + ); + } + + @SuppressWarnings("unchecked") + public JSONObject dailyFocusEntryToDailyFocusEntryJson(DailyFocusEntry dailyFocusEntry) { + JSONObject dailyFocusEntryJson = new JSONObject(); + dailyFocusEntryJson.put("day", dailyFocusEntry.getDay()); + dailyFocusEntryJson.put("month", dailyFocusEntry.getMonth()); + dailyFocusEntryJson.put("year", dailyFocusEntry.getYear()); + dailyFocusEntryJson.put("time", dailyFocusEntry.getTime()); + return dailyFocusEntryJson; + } +} diff --git a/TamoStudy/src/io/GlobalSettingsJsonManager.java b/TamoStudy/src/io/GlobalSettingsJsonManager.java new file mode 100644 index 0000000..9eae015 --- /dev/null +++ b/TamoStudy/src/io/GlobalSettingsJsonManager.java @@ -0,0 +1,113 @@ +package io; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import model.GlobalSettings; +import model.language.EnglishLanguage; +import model.language.Language; +import resources.Debug; + +public class GlobalSettingsJsonManager extends JsonManager { + + public static final String globalSettingsPath = System.getProperty("user.home") + File.separatorChar + "Documents" + File.separatorChar + "TamoStudy" + + File.separatorChar + "globalSettings.json"; + + @Override + public GlobalSettings readJson() { + Debug.info("GlobalSettingsJsonManager.readJson", "Attempting to read globalSettings.json"); + File globalSettingsJsonFile = new File(globalSettingsPath); + + if(globalSettingsJsonFile.exists()) { + JSONParser parser = new JSONParser(); + try { + Reader reader = new FileReader(globalSettingsPath); + return globalSettingsJsonToGlobalSettingsModel((JSONObject) parser.parse(reader)); + } catch (IOException | ParseException e) { + Debug.error("GlobalSettingsJsonManager.readJson", "Exception throw while reading globalSettings.json"); + e.printStackTrace(); + } + } else { + try { + //Check if the documents directory exists, if not, create it + File documentsDirectory = new File(documentsPath); + documentsDirectory.mkdir(); //Creates the Documents/ directory if it does not exist. + + //Check if the TamoStudy directory exists, if not, create it + File kaizenDirectory = new File(directoryPath); + kaizenDirectory.mkdir(); //Creates the Documents/TamoStudy/ directory if it does not exist. + + globalSettingsJsonFile.createNewFile(); + writeJsonToFile(new GlobalSettings()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + Debug.info("GlobalSettingsJsonManager.readJson", "No Json file was read, returning new object"); + return new GlobalSettings(); + } + + @Override + public boolean writeJsonToFile(GlobalSettings globalSettings) { + try { + File globalSettingsJsonFile = new File(globalSettingsPath); + FileWriter fileWriter = new FileWriter(globalSettingsJsonFile); + JSONObject globalSettingsJson = globalSettingsModelToGlobalSettingsJson(globalSettings); + try { + + fileWriter.write(globalSettingsJson.toJSONString()); + return true; + } catch (IOException e) { + Debug.error("GlobalSettingsJsonManager.writeJsonToFile", "Error occurred writing global settings to globalSettings.json"); + e.printStackTrace(); + return false; + } finally { + try { + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + Debug.error("GlobalSettingsJsonManager.writeJsonToFile", "Error occurred while closing file writer."); + e.printStackTrace(); + return false; + } + } + } catch (IOException e) { + Debug.error("GlobalSettingsJsonManager.writeJsonToFile", "Error occurred while instantiating fileWriter"); + e.printStackTrace(); + return false; + } + } + + /* + * ################################## + * ################################## + * MAPPINGS + * ################################## + * ################################## + */ + + private GlobalSettings globalSettingsJsonToGlobalSettingsModel(JSONObject globalSettingsJson) { + return new GlobalSettings( + globalSettingsJson.get("language") == null ? new EnglishLanguage() : Language.getLanguage((String) globalSettingsJson.get("language")), + globalSettingsJson.get("defaultLocalProfile") == null ? -1 : (long) globalSettingsJson.get("defaultLocalProfile"), + globalSettingsJson.get("receiveUpdateNotifications") == null ? true : (boolean) globalSettingsJson.get("receiveUpdateNotifications") + ); + } + + @SuppressWarnings("unchecked") + private JSONObject globalSettingsModelToGlobalSettingsJson(GlobalSettings globalSettings) { + JSONObject globalSettingsJson = new JSONObject(); + globalSettingsJson.put("language", globalSettings.getLanguage().toString()); + globalSettingsJson.put("defaultLocalProfile", globalSettings.getDefaultLocalProfile()); + globalSettingsJson.put("receiveUpdateNotifications", globalSettings.getReceiveUpdateNotifications()); + return globalSettingsJson; + } +} diff --git a/TamoStudy/src/io/JsonManager.java b/TamoStudy/src/io/JsonManager.java new file mode 100644 index 0000000..fad3ec3 --- /dev/null +++ b/TamoStudy/src/io/JsonManager.java @@ -0,0 +1,24 @@ +package io; + +import java.io.File; + +public abstract class JsonManager { + + public static final String documentsPath = System.getProperty("user.home") + File.separatorChar + "Documents"; + public static final String directoryPath = System.getProperty("user.home") + File.separatorChar + "Documents" + File.separatorChar + "TamoStudy"; + + /** + * @brief Reads the contents of the JSON and + * creates its representing model object + * @return T : the type of the model based on the JSON Manager + */ + public abstract T readJson(); + + /** + * @brief Writes the contents of the model object + * to its respective JSON file + * @param obj : the model object + * @return true under the condition of successful IO process + */ + public abstract boolean writeJsonToFile(T obj); +} diff --git a/TamoStudy/src/io/MonthFocusJsonManager.java b/TamoStudy/src/io/MonthFocusJsonManager.java new file mode 100644 index 0000000..ed1c51c --- /dev/null +++ b/TamoStudy/src/io/MonthFocusJsonManager.java @@ -0,0 +1,146 @@ +package io; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import model.time.MonthFocus; +import model.time.MonthFocusEntry; +import resources.Debug; + +public class MonthFocusJsonManager extends JsonManager> { + + public static final String monthFocusPath = System.getProperty("user.home") + File.separatorChar + "Documents" + File.separatorChar + "TamoStudy" + + File.separatorChar + "monthfocus.json"; + + @Override + public List readJson() { + Debug.info("MonthFocusJsonMAnager.readJson", "Attempting to read monthfocus.json"); + File monthFocusJsonFile = new File(monthFocusPath); + + if(monthFocusJsonFile.exists()) { + JSONParser parser = new JSONParser(); + try { + Reader reader = new FileReader(monthFocusPath); + JSONArray monthFocusJsonArray = (JSONArray) parser.parse(reader); + Debug.info("MonthFocusJsonManager.readJson", "Read JSONArray monthFocusJsonArray. monthFocusJsonArray.size = " + monthFocusJsonArray.size()); + return monthFocusJsonArrayToMonthFocusList(monthFocusJsonArray); + } catch (IOException | ParseException e) { + Debug.error("MonthFocusJsonManager.readJson", "Exception throw while reading monthfocus.json"); + e.printStackTrace(); + } + } + + Debug.info("MonthFocusJsonManager.readJson", "No MonthFocus objects were found"); + return Collections.emptyList(); + } + + @Override + public boolean writeJsonToFile(List monthFocusList) { + try { + File monthFocusJsonFile = new File(monthFocusPath); + FileWriter fileWriter = new FileWriter(monthFocusJsonFile); + JSONArray monthFocusJson = monthFocusListToMonthFocusJson(monthFocusList); + try { + + fileWriter.write(monthFocusJson.toJSONString()); + return true; + } catch (IOException e) { + Debug.error("MonthFocusJsonManager.writeJsonToFile", "Error occurred writing profiles to monthfocus.json"); + e.printStackTrace(); + return false; + } finally { + try { + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + Debug.error("MonthFocusJsonManager.writeJsonToFile", "Error occurred while closing file writer."); + e.printStackTrace(); + return false; + } + } + } catch (IOException e) { + Debug.error("MonthFocusJsonManager.writeJsonToFile", "Error occurred while instantiating fileWriter"); + e.printStackTrace(); + return false; + } + } + + /* + * ################################## + * ################################## + * MAPPINGS + * ################################## + * ################################## + */ + + public List monthFocusJsonArrayToMonthFocusList(JSONArray monthFocusJsonArray) { + List monthFocusList = new ArrayList<>(); + for(int i = 0; i < monthFocusJsonArray.size(); i++) { + monthFocusList.add(monthFocusJsonToMonthFocus((JSONObject) monthFocusJsonArray.get(i))); + } + return monthFocusList; + } + + @SuppressWarnings("unchecked") + public JSONArray monthFocusListToMonthFocusJson(List monthFocusList) { + JSONArray monthFocusJsonArray = new JSONArray(); + for(MonthFocus monthFocus : monthFocusList) { + monthFocusJsonArray.add(monthFocusToMonthFocusJson(monthFocus)); + } + return monthFocusJsonArray; + } + + public MonthFocus monthFocusJsonToMonthFocus(JSONObject monthFocusJson) { + List monthFocusEntries = new ArrayList<>(); + JSONArray monthFocusEntriesJsonList = (JSONArray) monthFocusJson.get("monthFocusEntries"); + for(int i = 0; i < monthFocusEntriesJsonList.size(); i++) { + monthFocusEntries.add(monthFocusEntryJsonToMonthFocusEntry((JSONObject) monthFocusEntriesJsonList.get(i))); + } + return new MonthFocus( + (long) monthFocusJson.get("profileId"), + monthFocusEntries + ); + } + + @SuppressWarnings("unchecked") + public JSONObject monthFocusToMonthFocusJson(MonthFocus monthFocus) { + JSONObject monthFocusJson = new JSONObject(); + monthFocusJson.put("profileId", monthFocus.getProfileId()); + + JSONArray monthFocusEntries = new JSONArray(); + for(MonthFocusEntry monthFocusEntry : monthFocus.getMonthFocusEntries()) { + monthFocusEntries.add(monthFocusEntryToMonthFocusEntryJson(monthFocusEntry)); + } + monthFocusJson.put("monthFocusEntries", monthFocusEntries); + + return monthFocusJson; + } + + public MonthFocusEntry monthFocusEntryJsonToMonthFocusEntry(JSONObject monthFocusEntryJson) { + return new MonthFocusEntry( + (long) monthFocusEntryJson.get("month"), + (long) monthFocusEntryJson.get("year"), + (long) monthFocusEntryJson.get("time") + ); + } + + @SuppressWarnings("unchecked") + public JSONObject monthFocusEntryToMonthFocusEntryJson(MonthFocusEntry monthFocusEntry) { + JSONObject monthFocusEntryJson = new JSONObject(); + monthFocusEntryJson.put("month", monthFocusEntry.getMonth()); + monthFocusEntryJson.put("year", monthFocusEntry.getYear()); + monthFocusEntryJson.put("time", monthFocusEntry.getTime()); + return monthFocusEntryJson; + } +} diff --git a/TamoStudy/src/io/ProfileJsonManager.java b/TamoStudy/src/io/ProfileJsonManager.java new file mode 100644 index 0000000..bb92e5d --- /dev/null +++ b/TamoStudy/src/io/ProfileJsonManager.java @@ -0,0 +1,254 @@ +package io; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import model.language.Language; +import model.profile.Profile; +import model.profile.ProfileSettings; +import model.profile.Tamo; +import resources.Debug; +import resources.Theme; + +public class ProfileJsonManager extends JsonManager> { + + public static final String profilesPath = System.getProperty("user.home") + File.separatorChar + "Documents" + File.separatorChar + "TamoStudy" + + File.separatorChar + "profiles.json"; + + @Override + public List readJson() { + Debug.info("ProfileJsonManager.readJson", "Attempting to read profiles.json"); + File globalSettingsJsonFile = new File(profilesPath); + + if(globalSettingsJsonFile.exists()) { + JSONParser parser = new JSONParser(); + try { + Reader reader = new FileReader(profilesPath); + JSONArray profilesJsonArray = (JSONArray) parser.parse(reader); + Debug.info("ProfileJsonManager.readJson", "Read JSONArray profilesJsonArray. profilesJsonArray.size = " + profilesJsonArray.size()); + return profilesJsonToProfileList(profilesJsonArray); + } catch (IOException | ParseException e) { + Debug.error("ProfileJsonManager.readJson", "Exception throw while reading profiles.json"); + e.printStackTrace(); + } + } + + Debug.info("ProfileJsonManager.readJson", "No profiles were found"); + return Collections.emptyList(); + } + + @Override + public boolean writeJsonToFile(List profiles) { + try { + File profilesJsonFile = new File(profilesPath); + FileWriter fileWriter = new FileWriter(profilesJsonFile); + JSONArray profilesJson = profileListToProfilesJson(profiles); + try { + + fileWriter.write(profilesJson.toJSONString()); + return true; + } catch (IOException e) { + Debug.error("ProfileJsonManager.writeJsonToFile", "Error occurred writing profiles to profiles.json"); + e.printStackTrace(); + return false; + } finally { + try { + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + Debug.error("ProfileJsonManager.writeJsonToFile", "Error occurred while closing file writer."); + e.printStackTrace(); + return false; + } + } + } catch (IOException e) { + Debug.error("ProfileJsonManager.writeJsonToFile", "Error occurred while instantiating fileWriter"); + e.printStackTrace(); + return false; + } + } + + /* + * ################################## + * ################################## + * MAPPINGS + * ################################## + * ################################## + */ + + public List profilesJsonToProfileList(JSONArray profilesJson) { + List profiles = new ArrayList<>(); + for(int i = 0; i < profilesJson.size(); i++) { + profiles.add(profileJsonToProfileModel((JSONObject) profilesJson.get(i))); + } + return profiles; + } + + @SuppressWarnings("unchecked") + public JSONArray profileListToProfilesJson(List profiles) { + Debug.info("ProfileJsonManager.profileListToProfilesJson", "Attempting conversion... profiles.size = " + profiles.size()); + JSONArray profilesJson = new JSONArray(); + for(Profile profile : profiles) { + profilesJson.add(profileModelToProfileJson(profile)); + } + return profilesJson; + } + + public Profile profileJsonToProfileModel(JSONObject profileJson) { + return new Profile( + (long) profileJson.get("id"), + (String) profileJson.get("name"), + (String) profileJson.get("previousDateString"), + (long) profileJson.get("time"), + (long) profileJson.get("tokens"), + profileSettingsJsonToProfileSettingsModel((JSONObject) profileJson.get("settings")), + (long) profileJson.get("backgroundIndicator"), + (long) profileJson.get("borderIndicator"), + indicatorListJsonToIndicatorList((JSONArray) profileJson.get("achievementList")), + indicatorListJsonToIndicatorList((JSONArray) profileJson.get("foodInventoryList")), + indicatorListJsonToIndicatorList((JSONArray) profileJson.get("backgroundInventoryList")), + indicatorListJsonToIndicatorList((JSONArray) profileJson.get("borderInventoryList")), + tamoJsonToTamoModel((JSONObject) profileJson.get("tamo")), + tamoHistoryJsonToTamoHistoryList((JSONArray) profileJson.get("tamoHistory")) + ); + } + + @SuppressWarnings("unchecked") + public JSONObject profileModelToProfileJson(Profile profile) { + JSONObject profileJson = new JSONObject(); + profileJson.put("id", profile.getId()); + profileJson.put("name", profile.getName()); + profileJson.put("previousDateString", profile.getPreviousDateString()); + profileJson.put("time", profile.getTime()); + profileJson.put("tokens", profile.getTokens()); + profileJson.put("settings", profileSettingsModelToProfileSettingsJson(profile.getSettings())); + profileJson.put("backgroundIndicator", profile.getBackgroundIndicator()); + profileJson.put("borderIndicator", profile.getBorderIndicator()); + profileJson.put("achievementList", indicatorListToIndicatorListJson(profile.getAchievementList())); + profileJson.put("foodInventoryList", indicatorListToIndicatorListJson(profile.getFoodInventoryList())); + profileJson.put("backgroundInventoryList", indicatorListToIndicatorListJson(profile.getBackgroundInventoryList())); + profileJson.put("borderInventoryList", indicatorListToIndicatorListJson(profile.getBorderInventoryList())); + profileJson.put("tamo", tamoModelToTamoJson(profile.getTamo())); + profileJson.put("tamoHistory", tamoHistoryListToTamoHistoryJson(profile.getTamoHistory())); + return profileJson; + } + + public List indicatorListJsonToIndicatorList(JSONArray indicatorListJson) { + List indicatorList = new ArrayList<>(); + for(int i = 0; i < indicatorListJson.size(); i++) { + indicatorList.add((long) indicatorListJson.get(i)); + } + return indicatorList; + } + + @SuppressWarnings("unchecked") + public JSONArray indicatorListToIndicatorListJson(List indicatorList) { + JSONArray indicatorListJson = new JSONArray(); + for(Long indicator : indicatorList) { + indicatorListJson.add(indicator); + } + return indicatorListJson; + } + + public ProfileSettings profileSettingsJsonToProfileSettingsModel(JSONObject profileSettingsJson) { + return new ProfileSettings( + Language.getLanguage((String) profileSettingsJson.get("language")), + (long) profileSettingsJson.get("focusMode"), + (long)profileSettingsJson.get("difficulty"), + (long) profileSettingsJson.get("timerAlarm"), + (long) profileSettingsJson.get("guiSize"), + (boolean) profileSettingsJson.get("receiveNotifications"), + (boolean) profileSettingsJson.get("enableDiscordRPC"), + (boolean) profileSettingsJson.get("showProgramCloseMessage"), + Theme.getTheme((String) profileSettingsJson.get("theme")) + ); + } + + @SuppressWarnings("unchecked") + public JSONObject profileSettingsModelToProfileSettingsJson(ProfileSettings profileSettings) { + JSONObject profileSettingsJson = new JSONObject(); + profileSettingsJson.put("language", profileSettings.getLanguage().toString()); + profileSettingsJson.put("focusMode", profileSettings.getFocusMode()); + profileSettingsJson.put("difficulty", profileSettings.getDifficulty()); + profileSettingsJson.put("timerAlarm", profileSettings.getTimerAlarm()); + profileSettingsJson.put("guiSize", profileSettings.getGuiSize()); + profileSettingsJson.put("receiveNotifications", profileSettings.getReceiveNotifications()); + profileSettingsJson.put("enableDiscordRPC", profileSettings.getEnableDiscordRPC()); + profileSettingsJson.put("showProgramCloseMessage", profileSettings.getShowProgramCloseMessage()); + profileSettingsJson.put("theme", profileSettings.getTheme().type); + return profileSettingsJson; + } + public Tamo tamoJsonToTamoModel(JSONObject tamoJson) { + return new Tamo( + (String) tamoJson.get("name"), + (long) tamoJson.get("time"), + (long) tamoJson.get("type"), + (String) tamoJson.get("birthDateString"), + (long) tamoJson.get("happy"), + (long) tamoJson.get("hunger"), + (long) tamoJson.get("strikes") + ); + } + + @SuppressWarnings("unchecked") + public JSONObject tamoModelToTamoJson(Tamo tamo) { + JSONObject tamoJson = new JSONObject(); + tamoJson.put("name", tamo.getName()); + tamoJson.put("time", tamo.getTime()); + tamoJson.put("type", tamo.getType()); + tamoJson.put("birthDateString", tamo.getBirthDateString()); + tamoJson.put("happy", tamo.getHappy()); + tamoJson.put("hunger", tamo.getHunger()); + tamoJson.put("strikes", tamo.getStrikes()); + return tamoJson; + } + + public List tamoHistoryJsonToTamoHistoryList(JSONArray tamoHistoryJson) { + List tamoHistory = new ArrayList<>(); + for(int i = 0; i < tamoHistoryJson.size(); i++) { + tamoHistory.add(deceasedTamoJsonToDeceasedTamo((JSONObject) tamoHistoryJson.get(i))); + } + return tamoHistory; + } + + @SuppressWarnings("unchecked") + public JSONArray tamoHistoryListToTamoHistoryJson(List tamoHistory) { + JSONArray tamoHistoryJson = new JSONArray(); + for(Tamo tamo : tamoHistory) { + tamoHistoryJson.add(deceasedTamoToDeceasedTamoJson(tamo)); + } + return tamoHistoryJson; + } + + public Tamo deceasedTamoJsonToDeceasedTamo(JSONObject deceasedTamoJson) { + return new Tamo( + (String) deceasedTamoJson.get("name"), + (long) deceasedTamoJson.get("time"), + (long) deceasedTamoJson.get("type"), + (String) deceasedTamoJson.get("birthDateString"), + (String) deceasedTamoJson.get("passDateString") + ); + } + + @SuppressWarnings("unchecked") + public JSONObject deceasedTamoToDeceasedTamoJson(Tamo deceasedTamo) { + JSONObject deceasedTamoJson = new JSONObject(); + deceasedTamoJson.put("name", deceasedTamo.getName()); + deceasedTamoJson.put("time", deceasedTamo.getTime()); + deceasedTamoJson.put("type", deceasedTamo.getType()); + deceasedTamoJson.put("birthDateString", deceasedTamo.getBirthDateString()); + deceasedTamoJson.put("passDateString", deceasedTamo.getPassDateString()); + return deceasedTamoJson; + } +} diff --git a/TamoStudy/src/model/GlobalSettings.java b/TamoStudy/src/model/GlobalSettings.java new file mode 100644 index 0000000..d949668 --- /dev/null +++ b/TamoStudy/src/model/GlobalSettings.java @@ -0,0 +1,81 @@ +package model; + +import model.language.EnglishLanguage; +import model.language.Language; + +/** + * GlobalSettings + * + * @author narlock + * + * @brief Global Settings for the TamoStudy Welcome Screen. + * An instance of this object will be stored for the user to + * create preferences for the welcome screen. + * + * The user will be able to change the welcome screen's + * language to their preference, allow to receive update + * notifications for TamoStudy or not, and finally, choose + * to load a default profile if they do not want to go + * through the local profile loader. + */ +public class GlobalSettings { + + /** + * Language : see model.language + */ + private Language language; + + /** + * Default Local Profile : Long representing the index in profiles.json + */ + private long defaultLocalProfile; + + /* + * Receive Update Notifications : Allows user to be promptly notified of updates. + */ + private Boolean receiveUpdateNotifications; + + public GlobalSettings() { + this.language = new EnglishLanguage(); + this.defaultLocalProfile = -1; + this.receiveUpdateNotifications = true; + } + + public GlobalSettings(Language language, long defaultLocalProfile, Boolean receiveUpdateNotifications) { + super(); + this.language = language; + this.defaultLocalProfile = defaultLocalProfile; + this.receiveUpdateNotifications = receiveUpdateNotifications; + } + + public Language getLanguage() { + return language; + } + + public void setLanguage(Language language) { + this.language = language; + } + + public long getDefaultLocalProfile() { + return defaultLocalProfile; + } + + public void setDefaultLocalProfile(long defaultLocalProfile) { + this.defaultLocalProfile = defaultLocalProfile; + } + + public Boolean getReceiveUpdateNotifications() { + return receiveUpdateNotifications; + } + + public void setReceiveUpdateNotifications(Boolean receiveUpdateNotifications) { + this.receiveUpdateNotifications = receiveUpdateNotifications; + } + + @Override + public String toString() { + return "GlobalSettings [language=" + language + ", defaultLocalProfile=" + defaultLocalProfile + + ", receiveUpdateNotifications=" + receiveUpdateNotifications + "]"; + } + +} diff --git a/TamoStudy/src/model/GuiSize.java b/TamoStudy/src/model/GuiSize.java new file mode 100644 index 0000000..43c064d --- /dev/null +++ b/TamoStudy/src/model/GuiSize.java @@ -0,0 +1,706 @@ +package model; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; + +import javax.swing.GrayFilter; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.border.Border; + +import components.border.BubbleBorder; +import resources.Debug; +import resources.ImageResourceHandler; +import resources.Theme; + +import static resources.Constants.*; + +public class GuiSize { + public int index; + + /* + * ################################## + * ################################## + * GUI ATTRIBUTES + * ################################## + * ################################## + */ + public Dimension frameSize; + public Font sideButtonFont; + public Font topMenuFont; + public ImageIcon topMenuImageIcon; + public ImageIcon tamoTokenImageIcon; + public int buttonBorderRadius; + + /* + * ################################## + * ################################## + * DASHBOARD ATTRIBUTES + * ################################## + * ################################## + */ + public Font statisticsInfoFont; + public Font statisticsInfoFontBold; + public Font versionFont; + public Dimension tamoGraphicsPanelDimension; + public int backgroundImageOffset; + public ImageIcon heartImageIcon; + public ImageIcon onigiriImageIcon; + + /* + * ################################## + * ################################## + * FOCUS / TIMER STATE CONSTANTS + * ################################## + * ################################## + */ + public Font timerFont; + public Font subTextFont; + public BubbleBorder timerBorder; + + /* + * ################################## + * ################################## + * SHOP STATE CONSTANTS + * ################################## + * ################################## + */ + public Dimension kathShopDimension; + public BubbleBorder messageBorder; + public int kathImageOffset; + public Font kathMessageFont; + public Dimension kathMsgDimension; + public ImageIcon leftArrowIcon; + public ImageIcon rightArrowIcon; + + /* + * ################################## + * ################################## + * INVENTORY CONSTANTS + * ################################## + * ################################## + */ + public Dimension itemMenuDimension; + + /* + * ################################## + * ################################## + * STATISTICS CONSTANTS + * ################################## + * ################################## + */ + public Dimension hoursInPastDimension; + public ImageIcon grayIcon; + public ImageIcon green1Icon; + public ImageIcon green2Icon; + public ImageIcon green3Icon; + public ImageIcon green4Icon; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS CONSTANTS + * ################################## + * ################################## + */ + public Font achievementTitleLabelFont; + public Font achievementDescriptionLabelFont; + public Dimension achievementScrollPaneDimension; + + /* + * ################################## + * ################################## + * SETTINGS ATTRIBUTES + * ################################## + * ################################## + */ + public ImageIcon darkModeIcon; + public ImageIcon lightModeIcon; + public Font messageLabelFont; + public Font settingLabelFont; + public Font settingsChoiceFont; + public Font settingsChoiceBoldFont; + public BubbleBorder settingsPanelBorder; + public int settingsHorizontalDifference; + public int settingsVerticalDifference; + public ImageIcon minusImageIcon; + public ImageIcon addImageIcon; + + /* + * ################################## + * ################################## + * ABOUT STATE ATTRIBUTES + * ################################## + * ################################## + */ + public ImageIcon narlockIcon; + public ImageIcon tamoStudyIcon; + public ImageIcon twitterIcon; + public ImageIcon youtubeIcon; + public ImageIcon instagramIcon; + + public GuiSize(int size) { + double scale = getScaleFromSize(size); + index = size; + + frameSize = scaleDimension(GUI_FRAME_SIZE, scale); + sideButtonFont = scaleFont(SIDE_BUTTON_FONT, scale); + topMenuFont = scaleFont(TOP_MENU_FONT, scale); + topMenuImageIcon = scaleImageIcon(TOP_MENU_IMAGE_ICON, scale); + tamoTokenImageIcon = scaleImageIcon(TAMO_TOKEN_IMAGE_ICON, scale); + buttonBorderRadius = scaleInteger(BUTTON_BORDER_RADIUS, scale); + + statisticsInfoFont = scaleFont(STATISTICS_INFO_FONT, scale); + statisticsInfoFontBold = scaleFont(STATISTICS_INFO_FONT_BOLD, scale); + versionFont = scaleFont(VERSION_FONT, scale); + tamoGraphicsPanelDimension = scaleDimension(TAMO_GRAPHICS_PANEL_DIMENSION, scale); + backgroundImageOffset = scaleInteger(BACKGROUND_IMAGE_OFFSET, scale); + heartImageIcon = scaleImageIcon(HEART_IMAGE_ICON, scale * (3.0 / 5.0) ); + onigiriImageIcon = scaleImageIcon(ONIGIRI_IMAGE_ICON, scale * (3.0 / 5.0) ); + + timerFont = scaleFont(TIMER_FONT, scale); + subTextFont = scaleFont(SUB_TEXT_FONT, scale); + timerBorder = scaleBubbleBorder(TIMER_BORDER, scale); + + kathShopDimension = scaleDimension(KATH_SHOP_DIMENSION, scale); + messageBorder = scaleBubbleBorder(new BubbleBorder(Color.BLACK, 3, 10, 0), scale); + kathImageOffset = scaleInteger(KATH_IMAGE_OFFSET, scale); + kathMessageFont = scaleFont(KATH_MESSAGE_FONT, scale); + kathMsgDimension = scaleDimension(KATH_MSG_DIMENSION, scale); + leftArrowIcon = scaleImageIcon(LEFT_ARROW_ICON, scale); + rightArrowIcon = scaleImageIcon(RIGHT_ARROW_ICON, scale); + + itemMenuDimension = scaleDimension(ITEM_MENU_DIMENSION, scale); + + hoursInPastDimension = scaleDimension(HOURS_IN_PAST_DIMENSION, scale); + grayIcon = scaleImageIcon(GRAY_ICON, scale * (2.0 / 4.0)); + green1Icon = scaleImageIcon(GREEN_1_ICON, scale * (2.0 / 4.0)); + green2Icon = scaleImageIcon(GREEN_2_ICON, scale * (2.0 / 4.0)); + green3Icon = scaleImageIcon(GREEN_3_ICON, scale * (2.0 / 4.0)); + green4Icon = scaleImageIcon(GREEN_4_ICON, scale * (2.0 / 4.0)); + + achievementTitleLabelFont = scaleFont(ACHIEVEMENT_TITLE_LABEL_FONT, scale); + achievementDescriptionLabelFont = scaleFont(ACHIEVEMENT_DESCRIPTION_LABEL_FONT, scale); + achievementScrollPaneDimension = scaleDimension(ACHIEVEMENT_SCROLL_PANE_DIMENSION, scale); + + darkModeIcon = scaleImageIcon(DARK_MODE_ICON, scale); + lightModeIcon = scaleImageIcon(LIGHT_MODE_ICON, scale); + messageLabelFont = scaleFont(SETTINGS_MESSAGE_LABEL_FONT, scale); + settingLabelFont = scaleFont(SETTINGS_SETTING_LABEL_FONT, scale); + settingsChoiceFont = scaleFont(SETTINGS_CHOICE_FONT, scale); + settingsChoiceBoldFont = scaleFont(SETTINGS_CHOICE_FONT_BOLD, scale); + settingsPanelBorder = scaleBubbleBorder(Theme.subBorder, scale); + settingsHorizontalDifference = scaleInteger(SETTINGS_HORIZONTAL_COMPONENT_DIFFERENCE, scale); + settingsVerticalDifference = scaleInteger(SETTINGS_VERTICAL_COMPONENT_DIFFERENCE, scale); + minusImageIcon = scaleImageIcon(MINUS_BUTTON_IMAGE_ICON, scale); + addImageIcon = scaleImageIcon(ADD_BUTTON_IMAGE_ICON, scale); + + narlockIcon = scaleImageIcon(NARLOCK_ICON, scale); + tamoStudyIcon = scaleImageIcon(TAMOSTUDY_ICON, scale); + twitterIcon = scaleImageIcon(TWITTER_ICON, scale); + youtubeIcon = scaleImageIcon(YOUTUBE_ICON, scale); + instagramIcon = scaleImageIcon(INSTAGRAM_ICON, scale); + } + + public double getScaleFromSize(int size) { + if(size == 0) { + return (2.0 / 3.0); + } else if(size == 2) { + return 1.5; + } + return 1; + } + + public static double getScaleFromIndex(int size) { + if(size == 0) { + return (2.0 / 3.0); + } else if(size == 2) { + return 1.5; + } + return 1; + } + + public static GuiSize mediumSmallGui() { + return new GuiSize(0); + } + + public static GuiSize mediumGui() { + return new GuiSize(1); + } + + public static GuiSize mediumLargeGui() { + return new GuiSize(2); + } + + /* + * ################################## + * ################################## + * TAMOSTUDY GRAPHICS ATTRIBUTES + * ################################## + * ################################## + */ + + public Image getTamoImage(int indicator, String status) { + double scale = getScaleFromSize(index); + ImageResourceHandler imageResourceHandler = new ImageResourceHandler(); + Image tamoImage = imageResourceHandler.readImageFromUrl("TAMO_" + status + "_" + indicator + ".png"); + Debug.info("GuiSize.getTamoImage", "tamoImage = " + tamoImage + ", index = " + index); + return scaleImage(tamoImage, scale); + } + + public Image getBackgroundImage(long indicator) { + double scale = getScaleFromSize(index); + ImageResourceHandler imageResourceHandler = new ImageResourceHandler(); + Image backgroundImage = imageResourceHandler.readImageFromUrl("BACKGROUND_" + indicator + ".png"); + return scaleImage(backgroundImage, scale); + } + + public Image getBorderImage(long indicator) { + double scale = getScaleFromSize(index); + ImageResourceHandler imageResourceHandler = new ImageResourceHandler(); + String indicatorName = getBorderNameByIndicator(indicator); + + Debug.info("GuiSize.getBorderImage", "Getting border image: BORDER_" + indicatorName + ".png"); + + Image borderImage = imageResourceHandler.readImageFromUrl("BORDER_" + indicatorName + ".png"); + return scaleImage(borderImage, scale); + } + + public ImageIcon getTamoStudyLogoImage() { + if(index == 0) { + // Small Image + return new ImageIcon(getClass().getClassLoader().getResource("TAMOSTUDY_LOGO_IMAGE_SMALL.gif")); + } else if(index == 2) { + // Large Image + return new ImageIcon(getClass().getClassLoader().getResource("TAMOSTUDY_LOGO_IMAGE_LARGE.gif")); + } else { + // Medium Image + return new ImageIcon(getClass().getClassLoader().getResource("TAMOSTUDY_LOGO_IMAGE.gif")); + } + } + + /* + * ################################## + * ################################## + * SHOP GRAPHICS ATTRIBUTES + * ################################## + * ################################## + */ + public Image getKathImage(long indicator) { + double scale = getScaleFromSize(index); + ImageResourceHandler imageResourceHandler = new ImageResourceHandler(); + String indicatorName = indicator == 0 ? "SHOP" : "MSG"; + Image borderImage = imageResourceHandler.readImageFromUrl("KATH_" + indicatorName + ".png"); + return scaleImage(borderImage, scale); + } + + /* + * ################################## + * ################################## + * SCALING METHODS + * ################################## + * ################################## + * + * For scaling to LARGE gui, scale = 1.5 + * For scaling to SMALL gui, scale = (2/3) + */ + public Dimension scaleDimension(Dimension originalDimension, double scale) { + if(scale == 1) { return originalDimension; } + + int scaledWidth = (int) (originalDimension.getWidth() * scale); + int scaledHeight = (int) (originalDimension.getHeight() * scale); + return new Dimension(scaledWidth, scaledHeight); + } + + public static Dimension scaleDimension(Dimension originalDimension, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalDimension; } + + int scaledWidth = (int) (originalDimension.getWidth() * scale); + int scaledHeight = (int) (originalDimension.getHeight() * scale); + return new Dimension(scaledWidth, scaledHeight); + } + + public Font scaleFont(Font originalFont, double scale) { + if(scale == 1) { return originalFont; } + + int scaledSize = (int) (originalFont.getSize() * scale); + Font scaledFont = originalFont.deriveFont((float) scaledSize); + return scaledFont; + } + + public static Font scaleFont(Font originalFont, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalFont; } + + int scaledSize = (int) (originalFont.getSize() * scale); + Font scaledFont = originalFont.deriveFont((float) scaledSize); + return scaledFont; + } + + public BubbleBorder scaleBubbleBorder(BubbleBorder originalBubbleBorder, double scale) { + if(scale == 1) { return originalBubbleBorder; } + + int scaledThickness = (int) Math.round(originalBubbleBorder.thickness * scale); + int scaledRadii = (int) Math.round(originalBubbleBorder.radii * scale); + int scaledPointerSize = (int) Math.round(originalBubbleBorder.pointerSize * scale); + + BubbleBorder scaledBubbleBorder = new BubbleBorder( + originalBubbleBorder.color, + scaledThickness, + scaledRadii, + scaledPointerSize, + originalBubbleBorder.left); + + return scaledBubbleBorder; + } + + public static BubbleBorder scaleBubbleBorder(BubbleBorder originalBubbleBorder, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalBubbleBorder; } + + int scaledThickness = (int) Math.round(originalBubbleBorder.thickness * scale); + int scaledRadii = (int) Math.round(originalBubbleBorder.radii * scale); + int scaledPointerSize = (int) Math.round(originalBubbleBorder.pointerSize * scale); + + BubbleBorder scaledBubbleBorder = new BubbleBorder( + originalBubbleBorder.color, + scaledThickness, + scaledRadii, + scaledPointerSize, + originalBubbleBorder.left); + + return scaledBubbleBorder; + } + + public ImageIcon scaleImageIcon(ImageIcon originalIcon, double scale) { + if(scale == 1) { return originalIcon; } + + Image originalImage = originalIcon.getImage(); + Image scaledImage = scaleImage(originalImage, scale); + ImageIcon scaledIcon = new ImageIcon(scaledImage); + return scaledIcon; + } + + public ImageIcon scaleImageIcon(ImageIcon originalIcon) { + double scale = getScaleFromIndex(this.index); + if(scale == 1) { return originalIcon; } + + Image originalImage = originalIcon.getImage(); + Image scaledImage = scaleImage(originalImage, scale); + ImageIcon scaledIcon = new ImageIcon(scaledImage); + return scaledIcon; + } + public ImageIcon scaleImageIconToGrayscale(ImageIcon originalIcon) { + double scale = getScaleFromIndex(this.index); + if(scale == 1) { return originalIcon; } + + ImageIcon grayIcon = GuiSize.toGrayscale(originalIcon); + + Image originalImage = grayIcon.getImage(); + Image scaledImage = scaleImage(originalImage, scale); + ImageIcon scaledIcon = new ImageIcon(scaledImage); + return scaledIcon; + } + + public static ImageIcon scaleImageIcon(ImageIcon originalIcon, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalIcon; } + + Image originalImage = originalIcon.getImage(); + Image scaledImage = scaleImage(originalImage, guiSize); + ImageIcon scaledIcon = new ImageIcon(scaledImage); + return scaledIcon; + } + + public Image scaleImage(Image originalImage, double scale) { + if(scale == 1) { return originalImage; } + + int scaledWidth = (int) (originalImage.getWidth(null) * scale); + int scaledHeight = (int) (originalImage.getHeight(null) * scale); + Image scaledImage = originalImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH); + return scaledImage; + } + + public static Image scaleImage(Image originalImage, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalImage; } + + int scaledWidth = (int) (originalImage.getWidth(null) * scale); + int scaledHeight = (int) (originalImage.getHeight(null) * scale); + Image scaledImage = originalImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH); + return scaledImage; + } + + public int scaleInteger(int originalInteger, double scale) { + if(scale == 1) { return originalInteger; } + return (int) (originalInteger * scale); + } + + public static int scaleInteger(int originalInteger, GuiSize guiSize) { + double scale = getScaleFromIndex(guiSize.index); + if(scale == 1) { return originalInteger; } + return (int) (originalInteger * scale); + } + + public JButton scaleSuccessJButton(JButton originalButton, double scale) { + BubbleBorder border = scaleBubbleBorder(Theme.SUCCESS_BORDER, scale); + Color backgroundColor = originalButton.getBackground(); + Font font = scaleFont(originalButton.getFont(), scale); + + JButton button = new JButton(originalButton.getText()); + primarySuccessButton(button, border, backgroundColor, font); + return button; + } + + public JButton scaleDangerJButton(JButton originalButton, double scale) { + BubbleBorder border = scaleBubbleBorder(Theme.DANGER_BORDER, scale); + Color backgroundColor = originalButton.getBackground(); + Font font = scaleFont(originalButton.getFont(), scale); + + JButton button = new JButton(originalButton.getText()); + primaryDangerButton(button, border, backgroundColor, font); + return button; + } + + public JButton scalePrimaryJButton(JButton originalButton, double scale) { + BubbleBorder border = scaleBubbleBorder(Theme.PRIMARY_BORDER, scale); + Color backgroundColor = originalButton.getBackground(); + Font font = scaleFont(originalButton.getFont(), scale); + + JButton button = new JButton(originalButton.getText()); + primaryButton(button, border, backgroundColor, font); + return button; + } + + public JButton scaleSecondaryJButton(JButton originalButton, double scale) { + BubbleBorder border = scaleBubbleBorder(Theme.SECONDARY_BORDER, scale); + Color backgroundColor = originalButton.getBackground(); + Font font = scaleFont(originalButton.getFont(), scale); + + JButton button = new JButton(originalButton.getText()); + secondaryButton(button, border, backgroundColor, font); + return button; + } + + /* + * ################################## + * ################################## + * IMAGE HELPER METHODS + * ################################## + * ################################## + */ + public static ImageIcon toGrayscale(ImageIcon originalIcon) { + // Extract the Image from the ImageIcon + Image originalImage = originalIcon.getImage(); + + // Convert the Image to grayscale using GrayFilter + Image grayImage = GrayFilter.createDisabledImage(originalImage); + + // Create a new ImageIcon from the grayscale image + ImageIcon grayscaleIcon = new ImageIcon(grayImage); + + return grayscaleIcon; + } + + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public String getBorderNameByIndicator(long indicator) { + switch((int) indicator) { + case 1: + return "GOLD"; + case 2: + return "RED"; + case 3: + return "MINT"; + case 4: + return "PURPLE"; + case 5: + return "BLUE"; + case 6: + return "STRAWLEMON"; + case 7: + return "SUNSET"; + case 8: + return "TEAL"; + case 9: + return "CODE"; + case 0: + default: + return "BLACK"; + } + } + + public void primarySuccessButton(JButton button, + Border border, + Color backgroundColor, + Font font + ) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(border); + button.setBackground(backgroundColor); + button.setForeground(Color.WHITE); + button.setFont(font); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.SUCCESS_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + } + + @Override + public void mouseExited(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.SUCCESS); + button.setForeground(Color.WHITE); + } + } + + }); + } + + public void primaryDangerButton(JButton button, + Border border, + Color backgroundColor, + Font font + ) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(border); + button.setBackground(backgroundColor); + button.setForeground(Color.WHITE); + button.setFont(font); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.DANGER_ALT); + button.setForeground(new Color(191, 191, 191)); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.DANGER); + button.setForeground(Color.WHITE); + } + } + + }); + } + + public void primaryButton(JButton button, + Border border, + Color backgroundColor, + Font font + ) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(border); + button.setBackground(backgroundColor); + button.setForeground(Color.WHITE); + button.setFont(font); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.PRIMARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.PRIMARY); + button.setForeground(Color.WHITE); + } + } + + }); + } + + public void secondaryButton(JButton button, + Border border, + Color backgroundColor, + Font font + ) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(border); + button.setBackground(backgroundColor); + button.setForeground(Color.WHITE); + button.setFont(font); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.SECONDARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if(button.isEnabled()) { + button.setBackground(Theme.SECONDARY); + button.setForeground(Color.WHITE); + } + } + + }); + } +} diff --git a/TamoStudy/src/model/language/DutchLanguage.java b/TamoStudy/src/model/language/DutchLanguage.java new file mode 100644 index 0000000..3dece2a --- /dev/null +++ b/TamoStudy/src/model/language/DutchLanguage.java @@ -0,0 +1,327 @@ +package model.language; + +/** + * + * @author narlock + * @translator britthubs + * + * TRANSLATOR STEPS: + * 1. Rename the file to YourLanguage.java + * - Where 'Your' is replaced with your language, for example, 'English' would make the file EnglishStrategy.java + * 2. Rename 'EnglishLanguage' on line 25 to YourLanguage + * - Where 'Your' is replaced with your language, for example, 'English' would make the class name EnglishLanguage + * 3. Replace all of the text after each assignment (equals sign '=') for each line with the proper translation. + * - For the `` ones, keep the beginning and ending html tags, and add a `
` tag after roughly every 25-30 + * characters. The EnglishLanguage file provides plenty of examples for each. Complete words, do not cut in the middle. + * - For context, the html tag represents that the text is going to be used as a HTML element. The br element represents + * a 'break line' (where to tell the text to go to the next line) + * - For example, if I wrote `Hello
World the text would appear in a JLabel like: + * Hello + * World + * 4. Replace the @translator tag on line 6 with your alias. + * + */ +public class DutchLanguage extends Language { + public DutchLanguage() { + /* + * ################################## + * ################################## + * WELCOME GUI TEXT + * ################################## + * ################################## + */ + createdByText = "Gemaakt door"; + localStudyText = "Lokaal Studeren"; + onlineStudyText = "Online Studeren"; + unableSearchUpdatesText = "Kan niet zoeken naar updates. Niet verbonden met het internet."; + updateAvailableDownloadText = "is nu beschikbaar. Klik hier om te downloaden!"; // VER ... {} + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + areYouSureYouWantToExitText = "Ben je zeker dat je wil stoppen?"; + dontShowThisMessageAgainText = "Toon dit bericht niet opnieuw"; + exitTamoStudyText = "TamoStudy afsluiten?"; + deathText1 = "die de nodige zorg niet heeft gekregen, is helaas overleden."; + deathText2 = "Vooruitgang van deze Tamo zal worden opgeslaan in de Tamo Geschiedenis."; + newTamoNameText = "Nieuwe Tamo Naam"; + /* + * ################################## + * ################################## + * PROFILE CREATION / SELECTION TEXT + * ################################## + * ################################## + */ + noProfilesText = "Er werden geen lokale profielen gevonden."; + welcomeBackText = "Welkom terug bij TamoStudy!"; + createNewProfileText = "Maak Nieuw Profiel Aan"; + importProfileText = "Importeer Profiel van Beta 4.2"; + chooseProfileText = "Kies Profiel"; + loadProfileAutomaticallyText = "Laad Profiel Automatisch"; + loadProfileText = "Laad Profiel"; + deleteProfileText = "Verwijder Profiel"; + invalidProfileFileText = "Ongeldig Beta v4.2 Profiel"; + confirmDeleteProfileText = "Bevestig verwijdering van profiel"; + areYouSureText = "Ben je zeker?"; + createProfileText = "Maak Nieuw TamoStudy Profiel Aan"; + usernameText = "Gebruikersnaam"; + tamoNameText = "Tamo Naam"; + + languageText = "Taal"; + // Like the language... + englishText = "Engels"; + spanishText = "Spaans"; + hindiText = "Hindi"; + portugueseText = "Portugees"; + japaneseText = "Japans"; + germanText = "Duits"; + frenchText = "Frans"; + turkishText = "Turks"; + mandarinChineseText = "Mandarijns Chinees"; + dutchText = "Nederlands"; + koreanText = "Koreaans"; + russianText = "Russisch"; + hungarianText = "Hongaars"; + romanianText = "Roemeens"; + + difficultyText = "Moeilijkheid"; + peacefulText = "Rustig"; + challengingText = "Uitdagend"; + ironManText = "Iron Man"; + + focusModeText = "Focus Modus"; + pomodoroText = "Pomodoro"; + customCountdownText = "Aangepaste Countdown"; + fiveMinIntervalCountdownText = "5-Min Interval Countdown"; + stopwatchText = "Stopwatch"; + + resetDefaultProfileText = "Herstel Standaard Profiel"; + updateNotificationsText = "Update Meldingen"; + defaultProfileReset = "Standaard Profiel Reset"; + + createText = "Creëer"; + cancelText = "Annuleer"; + mustEnterValidNameText = "Voer een geldige naam in!"; + settingsSavedText = "Instellingen Opgeslaan"; + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + menuButtonText = "Menu"; + dashboardStateButtonText = "Dashboard"; + focusStateButtonText = "Focus"; + shopStateButtonText = "Winkel"; + inventoryStateButtonText = "Inventaris"; + statisticsStateButtonText = "Statistieken"; + achievementsStateButtonText = "Prestaties"; + settingsStateButtonText = "Instellingen"; + tamoHistoryText = "Tamo Geschiedenis"; + aboutStateButton = "Over"; + + /* + * ################################## + * ################################## + * DASHBOARD STATE TEXT + * ################################## + * ################################## + */ + todaysFocusText = "Focus Van Vandaag"; + monthFocusText = "Maandelijkse Focus"; + totalFocusText = "Totale Focus"; + levelText = "Level"; + hoursText = "uren"; + + /* + * ################################## + * ################################## + * FOCUS STATE TEXT + * ################################## + * ################################## + */ + pomoNumberOfSessionsText = "Aantal sessies"; + pomoSessionLengthText = "Duur van de Sessie"; + pomoBreakLengthText = "Duur van de Pauze"; + minutesText = "Minuten"; + secondsText = "Seconden"; + durationText = "Duur"; + letsFocusText = "Laten we Focussen!"; + focusingText = "Aan het focussen!"; + startFocusText = "Start Focus"; + breakFocusText = "Onderbreek Focus"; + pauseFocusText = "Pauzeer Focus"; + resumeFocusText = "Hervat Focus"; + youFocusedForText = "Je was gefocuust voor"; + minutesAndText = "minuten en"; + secondsPeriodText = "seconden."; + focusBrokeText = "Focus Onderbroken"; + focusText = "Focus"; + breakText = "Afbreken"; + focusCompleteText = "Focus Compleet"; + breakOverText = "Pauze is gedaan. Tijd om weer te focussen!"; + + /* + * ################################## + * ################################## + * ITEMS TEXT + * ################################## + * ################################## + */ + onigiriText = "Onigiri"; + chickenPlateText = "Bordje Kip"; + cheesecakeText = "Kaastaart"; + onigiriDescriptionText = "Een traditionele Japanse snack
gemaakt van gekruide rijst
in de vorm van een bol of driehoek,
vaak met een vulling
en omwikkeld in zeewier.

Herstelt 1 hongerpunt."; + chickenPlateDescriptionText = "Een bord met gebakken
kip geserveerd met
een variatie aan gerechten en
bijgerechten.

Herstelt 3 hongerpunten."; + cheesecakeDescriptionText = "Een rijk en romig dessert
gemaakt met een korst van
verkruimelde koekjes of bladerdeeg,
gevuld met een gladde mix van
roomkaas en suiker.

Herstelt 8 hongerpunten."; + + bedroomText = "Slaapkamer"; + sofaText = "Bank"; + sunriseText = "Zonsopkomst"; + nightOutText = "Avondje Uit"; + enigmaText = "Mysterie"; + cozyNightText = "Gezellige Avond"; + studyTimeText = "Studeertijd"; + pleasantBridgeText = "Aangename Brug"; + wisteriaText = "Blauweregen"; + moonText = "Maan"; + + bedroomDescriptionText = "Een serene slaapkamer achtergrond
met een gezellig bed onder
een groot raam dat
natuurlijk licht binnenlaat met
uitzicht op de buitenwereld."; + sofaDescriptionText = "Een rustige kamer versierd met
een stijlvolle rode bank
en als aandachtspunten comfort en
elegantie gepaard met een aangename
en uitnodigende sfeer."; + sunriseDescriptionText = "Een adembenemende achtergrond
die de schoonheid van de zonsopkomst
vastlegt wanneer de zon gracieus
aan de horizon verschijnt."; + nightOutDescriptionText = "Een atmosferische straat
die een perfecte mix van
warmte en rust uitstraalt tijdens
een heerlijk avondje uit."; + enigmaDescriptionText = "omhuld in een aura van
mysterie, gekleurd met diepe
tinten rood, kastanjebruin en grijs."; + cozyNightDescriptionText = "Een serene nachtsetting met een comfortabel bed
uitgerust met een schattige knuffelbeer
die warmte en een comfortabele sfeer uitstraalt,
perfect voor een rustig dutje."; + studyTimeDescriptionText = "Een ideaal studieplekje wacht op je
met een groot houten bureau en een stralende
lamp die rijen aan boeken verlicht
op een omvangrijke boekenkast,
een omgeving die focus uitnodigt."; + pleasantBridgeDescriptionText = "Een serene beboste scène onthult
een prachtige Japanse brug die
gracieus buigt over een rustige rivier,
omringd door een verzachtende
omgeving met de schoonheid van de natuur."; + wisteriaDescriptionText = "In een dromerige scène, bloeien betoverende
Blauweregen bomen, hun
cascaderende paarse bloesems schommelen
zachtjes als de herfstbladeren gracieus
naar beneden dwarrelen
en een prachtig moment in de
natuur vastleggen."; + moonDescriptionText = "Als de ochtendgloren aanbreekt, ontvouwt
zich een prachtig spektakel- een
schitterende blauwe maan hangt in de lucht
en beschildert de wereld in tinten goud
en azuurblauw met haar heldere stralen,
een hemelse harmonie tussen
zonsopkomst en lunaire magie."; + + blackText = "Zwart"; + goldText = "Goud"; + redText = "Rood"; + mintText = "Munt"; + purpleText = "Paars"; + blueText = "Blauw"; + strawberryLemonadeText = "Aardbei Limonade"; + sunsetText = "Zonsondergang"; + tealText = "Appelblauwzeegroen"; + codeText = "Code"; + + solidBackgroundText = "Egale Achtergrond"; + gradientBackgroundText = "Gradiënt Achtergrond"; + rareBackgroundText = "Zeldzame Achtergrond"; + themedBackgroundText = "Thema Achtergrond"; + + /* + * ################################## + * ################################## + * SHOP TEXT + * ################################## + * ################################## + */ + selectShopText = "Selecteer Winkel"; + foodText = "Voeding"; + backgroundsText = "Achtergronden"; + bordersText = "Boorden"; + yourFoodInventoryIsFullText = "Je voedingsinventaris is vol!"; + confirmPurchaseOfText = "Bevestig aankoop van"; + notEnoughTamoTokensText = "Niet genoeg Tamo tokens om de aankoop te vervolledigen."; + + /* + * ################################## + * ################################## + * INVENTORY TEXT + * ################################## + * ################################## + */ + inventoryText = "Inventaris"; + feedTamoText = "Geef Tamo te eten"; + setBackgroundText = "Stel Achtergrond In"; + setBorderText = "Stel Boord In"; + welcomeToTheShopText = "Welkom in de winkel. Waar kan ik je mee helpen?"; + hereAreOurFoodOptionsText = "Hier zijn onze voeding opties!"; + whatBackgroundsCanIHelpFindText = "Welke achtergrond kan ik je helpen zoeken?"; + whatBordersCanIHelpFindText = "Welke boord kan ik je helpen zoeken?"; + letsCustomizeFocusTimerText = "Laten we de focus timer aanpassen!"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + hoursOnText = "uren aan"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + theBeginningText = "Het Begin"; + theBeginningDescText = "Behaal totale focus tijd van 24 uur."; + nothingCanStopUsText = "Niets kan ons tegenhouden!"; + nothingCanStopUsDescText = "Behaal totale focus tijd van 72 uur"; + neverGiveUpText = "Geef nooit op!"; + neverGiveUpDescText = "Behaal totale focus van 240 uur"; + focusAscensionText = "Focus stijging"; + focusAscensionDescText = "Behaal totale focus tijd van 1200 hours"; + cosmeticsText = "Cosmetica"; + cosmeticsDescText = "Koop en pas de boord van jouw Tamo aan."; + sceneryChangeText = "Verandering van omgeving"; + sceneryChangeDescText = "Koop en pas de achtergrond van jouw Tamo aan."; + fromTheBeginningText = "Vanaf het Begin"; + fromTheBeginningDescText = "Update profiel van vorige TamoStudy Release."; + tamoFullText = "Tamo Vol"; + tamoFullDescText = "Behaal maximale Tamo honger."; + tamoLoveText = "Tamo Liefde"; + tamoLoveDescText = "Behaal maximaal Tamo geluk."; + dedicatedText = "Toewijding"; + dedicatedDescText = "Focus voor 1+ uren in 3 achtereenvolgende dagen."; + buildingConsistencyText = "Bouw Consistentie Op"; + buildingConsistencyDescText = "Focus voor 1+ uren in 7 achtereenvolgende dagen."; + tamoScholarText = "Tamo Geleerde"; + tamoScholarDescText = "Focus voor 1+ uren in 30 achtereenvolgende dagen."; + + /* + * ################################## + * ################################## + * SETTINGS STATE TEXT + * ################################## + * ################################## + */ + timerAlarmText = "Timer Alarm"; + noTimerAlarmText = "Geen"; + softAlarmText = "Zacht Alarm"; + traditionalAlarmText = "Traditioneel Alarm"; + pacAlarmText = "Pac Alarm"; + calmAlarmText = "Kalm Alarm"; + bellAlarmText = "Bel Alarm"; + guiSizeText = "Interface Grootte"; + notificationsText = "Meldingen"; + discordRPCText = "Discord RPC"; + exitMessageText = "Uitgang Bericht"; + onText = "AAN"; + offText = "UIT"; + saveText = "Opslaan"; + resetText = "Reset"; + + /* + * ################################## + * ################################## + * ABOUT STATE TEXT + * ################################## + * ################################## + */ + aboutTamoStudyText = "TamoStudy is een werk- en studeertimer ontwikkeld om
productiviteit te verbeteren, met implementatie van een aangenaam
virtueel huisdiertje om gebruikers te
motiveren zich te concentreren op hun taken."; + } +} diff --git a/TamoStudy/src/model/language/EnglishLanguage.java b/TamoStudy/src/model/language/EnglishLanguage.java new file mode 100644 index 0000000..64e49d5 --- /dev/null +++ b/TamoStudy/src/model/language/EnglishLanguage.java @@ -0,0 +1,328 @@ +package model.language; + +/** + * + * @author narlock + * @translator narlock + * + * TRANSLATOR STEPS: + * 1. Rename the file to YourLanguage.java + * - Where 'Your' is replaced with your language, for example, 'English' would make the file EnglishStrategy.java + * 2. Rename 'EnglishLanguage' on line 25 to YourLanguage + * - Where 'Your' is replaced with your language, for example, 'English' would make the class name EnglishLanguage + * 3. Replace all of the text after each assignment (equals sign '=') for each line with the proper translation. + * - For the `` ones, keep the beginning and ending html tags, and add a `
` tag after roughly every 25-30 + * characters. The EnglishLanguage file provides plenty of examples for each. Complete words, do not cut in the middle. + * - For context, the html tag represents that the text is going to be used as a HTML element. The br element represents + * a 'break line' (where to tell the text to go to the next line) + * - For example, if I wrote `Hello
World the text would appear in a JLabel like: + * Hello + * World + * 4. Replace the @translator tag on line 6 with your alias. + * + */ +public class EnglishLanguage extends Language { + public EnglishLanguage() { + /* + * ################################## + * ################################## + * WELCOME GUI TEXT + * ################################## + * ################################## + */ + createdByText = "Created by"; + localStudyText = "Local Study"; + onlineStudyText = "Online Study"; + unableSearchUpdatesText = "Unable to search for updates. Not connected to the Internet."; + updateAvailableDownloadText = "is now available. Click here to download!"; // VER ... {} + globalSettingsText = "Global Settings"; + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + areYouSureYouWantToExitText = "Are you sure you want to exit?"; + dontShowThisMessageAgainText = "Don't show this message again"; + exitTamoStudyText = "Exit TamoStudy?"; + deathText1 = "who did not receive the care it required, has sadly passed away."; + deathText2 = "Progress for this Tamo will be saved in Tamo History."; + newTamoNameText = "New Tamo Name"; + /* + * ################################## + * ################################## + * PROFILE CREATION / SELECTION TEXT + * ################################## + * ################################## + */ + noProfilesText = "No local profiles were found."; + welcomeBackText = "Welcome back to TamoStudy!"; + createNewProfileText = "Create New Profile"; + importProfileText = "Import Profile from Beta 4.2"; + chooseProfileText = "Choose Profile"; + loadProfileAutomaticallyText = "Load Profile Automatically"; + loadProfileText = "Load Profile"; + deleteProfileText = "Delete Profile"; + invalidProfileFileText = "Invalid Beta v4.2 Profile"; + confirmDeleteProfileText = "Confirm deletion of profile"; + areYouSureText = "Are you sure?"; + createProfileText = "Create TamoStudy Profile"; + usernameText = "Username"; + tamoNameText = "Tamo Name"; + + languageText = "Language"; + // Like the language... + englishText = "English"; + spanishText = "Spanish"; + hindiText = "Hindi"; + portugueseText = "Portuguese"; + japaneseText = "Japanese"; + germanText = "German"; + frenchText = "French"; + turkishText = "Turkish"; + mandarinChineseText = "Mandarin Chinese"; + dutchText = "Dutch"; + koreanText = "Korean"; + russianText = "Russian"; + hungarianText = "Hungarian"; + romanianText = "Romanian"; + + difficultyText = "Difficulty"; + peacefulText = "Peaceful"; + challengingText = "Challenging"; + ironManText = "Iron Man"; + + focusModeText = "Focus Mode"; + pomodoroText = "Pomodoro"; + customCountdownText = "Custom Countdown"; + fiveMinIntervalCountdownText = "5-Min Interval Countdown"; + stopwatchText = "Stopwatch"; + + resetDefaultProfileText = "Reset Default Profile"; + updateNotificationsText = "Update Notifications"; + defaultProfileReset = "Default Profile Reset"; + + createText = "Create"; + cancelText = "Cancel"; + mustEnterValidNameText = "Must enter a valid name!"; + settingsSavedText = "Settings Saved"; + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + menuButtonText = "Menu"; + dashboardStateButtonText = "Dashboard"; + focusStateButtonText = "Focus"; + shopStateButtonText = "Shop"; + inventoryStateButtonText = "Inventory"; + statisticsStateButtonText = "Statistics"; + achievementsStateButtonText = "Achievements"; + settingsStateButtonText = "Settings"; + tamoHistoryText = "Tamo History"; + aboutStateButton = "About"; + + /* + * ################################## + * ################################## + * DASHBOARD STATE TEXT + * ################################## + * ################################## + */ + todaysFocusText = "Today's Focus"; + monthFocusText = "Month Focus"; + totalFocusText = "Total Focus"; + levelText = "Level"; + hoursText = "hrs"; + + /* + * ################################## + * ################################## + * FOCUS STATE TEXT + * ################################## + * ################################## + */ + pomoNumberOfSessionsText = "No. Of Sessions"; + pomoSessionLengthText = "Session Length"; + pomoBreakLengthText = "Break Length"; + minutesText = "Minutes"; + secondsText = "Seconds"; + durationText = "Duration"; + letsFocusText = "Lets Focus!"; + focusingText = "Focusing!"; + startFocusText = "Start Focus"; + breakFocusText = "Break Focus"; + pauseFocusText = "Pause Focus"; + resumeFocusText = "Resume Focus"; + youFocusedForText = "You focused for"; + minutesAndText = "minutes and"; + secondsPeriodText = "seconds."; + focusBrokeText = "Focus Broke"; + focusText = "Focus"; + breakText = "Break"; + focusCompleteText = "Focus Complete"; + breakOverText = "Break is over. Time to get back to focus!"; + + /* + * ################################## + * ################################## + * ITEMS TEXT + * ################################## + * ################################## + */ + onigiriText = "Onigiri"; + chickenPlateText = "Chicken Plate"; + cheesecakeText = "Cheesecake"; + onigiriDescriptionText = "A traditional Japanese snack
made of seasoned rice shaped
into a ball or triangle,
often with a filling, and
wrapped in seaweed.

Restores 1 hunger point."; + chickenPlateDescriptionText = "A dish featuring cooked
chicken served with a
variety of sides and
accompaniments.

Restores 3 hunger points."; + cheesecakeDescriptionText = "A rich and creamy dessert
made with a crust of
crushed biscuits or pastry,
filled with a smooth mixture
of cream cheese and sugar.

Restores 8 hunger points."; + + bedroomText = "Bedroom"; + sofaText = "Sofa"; + sunriseText = "Sunrise"; + nightOutText = "Night Out"; + enigmaText = "Enigma"; + cozyNightText = "Cozy Night"; + studyTimeText = "Study Time"; + pleasantBridgeText = "Pleasant Bridge"; + wisteriaText = "Wisteria"; + moonText = "Moon"; + + bedroomDescriptionText = "A serene bedroom backdrop
with a cozy bed placed beneath
a large window, inviting
ample natural light and
a view of the outside world."; + sofaDescriptionText = "A chill room adorned with
a stylish red sofa, creating
a focal point of comfort and
elegance within a pleasant
and inviting ambiance."; + sunriseDescriptionText = "A breathtaking background
capturing the beauty of a
sunrise as the sun gracefully
emerges on the horizon."; + nightOutDescriptionText = "An atomospheric street
exuding a perfect blend of
warmth and chill vibes on
a delightful night out."; + enigmaDescriptionText = "An enigmatic backdrop
enveloped in an aura of
mystery, painted with deep
hues of red, maroon, and gray."; + cozyNightDescriptionText = "A serene night-time setting with a snug bed adorned with a cuddly teddy bear, radiating warmth and comforting vibes, perfect for peaceful slumber."; + studyTimeDescriptionText = "An ideal study haven awaits with
a grand wooden desk, a radiant
lamp illuminating rows of books
on a sizable bookshelf, fostering
an environment conducive to
focused learning."; + pleasantBridgeDescriptionText = "A serene forest scene unfolds,
showcasing a picturesque Japanese
bridge gracefully arched over a
tranquil river, enveloped by the
soothing embrace of nature's
beauty."; + wisteriaDescriptionText = "In a dreamy scene, enchanting
wisteria trees flourish, their
cascading purple blooms swaying
gently as autumn leaves gracefully
descend, painting a picturesque
moment in nature."; + moonDescriptionText = "As dawn breaks, a breathtaking
spectacle unfolds - a magnificent
blue moon hovers in the sky, its
radiant beams painting the world
in hues of gold and azure, a
celestial harmony of sunrise and
lunar magic."; + + blackText = "Black"; + goldText = "Gold"; + redText = "Red"; + mintText = "Mint"; + purpleText = "Purple"; + blueText = "Blue"; + strawberryLemonadeText = "Strawberry Lemonade"; + sunsetText = "Sunset"; + tealText = "Teal"; + codeText = "Code"; + + solidBackgroundText = "Solid Background"; + gradientBackgroundText = "Gradient Background"; + rareBackgroundText = "Rare Background"; + themedBackgroundText = "Themed Background"; + + /* + * ################################## + * ################################## + * SHOP TEXT + * ################################## + * ################################## + */ + selectShopText = "Select Shop"; + foodText = "Food"; + backgroundsText = "Backgrounds"; + bordersText = "Borders"; + yourFoodInventoryIsFullText = "Your Food Inventory is full!"; + confirmPurchaseOfText = "Confirm purchase of"; + notEnoughTamoTokensText = "Not enough Tamo tokens to complete purchase."; + + /* + * ################################## + * ################################## + * INVENTORY TEXT + * ################################## + * ################################## + */ + inventoryText = "Inventory"; + feedTamoText = "Feed Tamo"; + setBackgroundText = "Set Background"; + setBorderText = "Set Border"; + welcomeToTheShopText = "Welcome to the shop. What can I help you find?"; + hereAreOurFoodOptionsText = "Here are our food options!"; + whatBackgroundsCanIHelpFindText = "What background can I help you find?"; + whatBordersCanIHelpFindText = "What borders can I help you find?"; + letsCustomizeFocusTimerText = "Let's customize the focus timer!"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + hoursOnText = "hours on"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + theBeginningText = "The Beginning"; + theBeginningDescText = "Achieve total focus time of 24 hours."; + nothingCanStopUsText = "Nothing can stop us!"; + nothingCanStopUsDescText = "Achieve total focus time of 72 hours"; + neverGiveUpText = "Never give up!"; + neverGiveUpDescText = "Achieve total focus time of 240 hours"; + focusAscensionText = "Focus Ascension"; + focusAscensionDescText = "Achieve total focus time of 1200 hours"; + cosmeticsText = "Cosmetics"; + cosmeticsDescText = "Purchase and change your Tamo's border."; + sceneryChangeText = "Scenery Change"; + sceneryChangeDescText = "Purchase and change your Tamo's background."; + fromTheBeginningText = "From the Beginning"; + fromTheBeginningDescText = "Updated profile from previous TamoStudy Release."; + tamoFullText = "Tamo Full"; + tamoFullDescText = "Achieve maximum Tamo hunger."; + tamoLoveText = "Tamo Love"; + tamoLoveDescText = "Achieve maximum Tamo happiness."; + dedicatedText = "Dedicated"; + dedicatedDescText = "Focus for 1+ hours for 3 days consecutively."; + buildingConsistencyText = "Building Consistency"; + buildingConsistencyDescText = "Focus for 1+ hours for 7 days consecutively."; + tamoScholarText = "Tamo Scholar"; + tamoScholarDescText = "Focus for 1+ hours for 30 days consecutively."; + + /* + * ################################## + * ################################## + * SETTINGS STATE TEXT + * ################################## + * ################################## + */ + timerAlarmText = "Timer Alarm"; + noTimerAlarmText = "None"; + softAlarmText = "Soft Alarm"; + traditionalAlarmText = "Traditional Alarm"; + pacAlarmText = "Pac Alarm"; + calmAlarmText = "Calm Alarm"; + bellAlarmText = "Bell Alarm"; + guiSizeText = "Interface Size"; + notificationsText = "Notifications"; + discordRPCText = "Discord RPC"; + exitMessageText = "Exit Message"; + onText = "ON"; + offText = "OFF"; + saveText = "Save"; + resetText = "Reset"; + + /* + * ################################## + * ################################## + * ABOUT STATE TEXT + * ################################## + * ################################## + */ + aboutTamoStudyText = "TamoStudy is a work and study timer designed to enhance
productivity, incorporating an enjoyable virtual pet to
motivate users to concentrate on their tasks."; + } +} diff --git a/TamoStudy/src/model/language/Language.java b/TamoStudy/src/model/language/Language.java new file mode 100644 index 0000000..7f1024d --- /dev/null +++ b/TamoStudy/src/model/language/Language.java @@ -0,0 +1,372 @@ +package model.language; + +public abstract class Language { + /* + * ################################## + * ################################## + * WELCOME GUI TEXT + * ################################## + * ################################## + */ + public String createdByText; + public String localStudyText; + public String onlineStudyText; + public String unableSearchUpdatesText; + public String updateAvailableDownloadText; + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + public String areYouSureYouWantToExitText; + public String dontShowThisMessageAgainText; + public String exitTamoStudyText; + public String deathText1; + public String deathText2; + public String newTamoNameText; + + /* + * ################################## + * ################################## + * CHANGE GLOBAL SETTINGS TEXT + * ################################## + * ################################## + */ + public String globalSettingsText; + + /* + * ################################## + * ################################## + * PROFILE CREATION / SOME SETTINGS / SELECTION TEXT + * ################################## + * ################################## + */ + public String noProfilesText; + public String welcomeBackText; + public String createNewProfileText; + public String importProfileText; + public String chooseProfileText; + public String loadProfileAutomaticallyText; + public String loadProfileText; + public String deleteProfileText; + public String invalidProfileFileText; + public String confirmDeleteProfileText; + public String areYouSureText; + public String createProfileText; + public String usernameText; + public String tamoNameText; + + public String languageText; + public String englishText; + public String spanishText; + public String hindiText; // macOS Only + public String portugueseText; + public String japaneseText; // macOS Only + public String germanText; + public String frenchText; + public String turkishText; + public String mandarinChineseText; // macOS Only + public String dutchText; + public String koreanText; // macOS Only + public String russianText; + public String hungarianText; + public String romanianText; + + public String difficultyText; + public String peacefulText; + public String challengingText; + public String ironManText; + + public String focusModeText; + public String pomodoroText; + public String customCountdownText; + public String fiveMinIntervalCountdownText; + public String stopwatchText; + + public String resetDefaultProfileText; + public String updateNotificationsText; + public String defaultProfileReset; + + public String createText; + public String cancelText; + public String mustEnterValidNameText; + public String settingsSavedText; + + /* + * ################################## + * ################################## + * MAIN GUI TEXT + * ################################## + * ################################## + */ + public String menuButtonText; + public String dashboardStateButtonText; + public String focusStateButtonText; + public String shopStateButtonText; + public String inventoryStateButtonText; + public String statisticsStateButtonText; + public String achievementsStateButtonText; + public String settingsStateButtonText; + public String tamoHistoryText; + public String aboutStateButton; + + /* + * ################################## + * ################################## + * DASHBOARD STATE TEXT + * ################################## + * ################################## + */ + public String todaysFocusText; + public String monthFocusText; + public String totalFocusText; + public String levelText; + public String hoursText; + + /* + * ################################## + * ################################## + * FOCUS STATE TEXT + * ################################## + * ################################## + */ + public String pomoNumberOfSessionsText; + public String pomoSessionLengthText; + public String pomoBreakLengthText; + public String minutesText; + public String secondsText; + public String durationText; + public String letsFocusText; + public String focusingText; + public String startFocusText; + public String breakFocusText; + public String pauseFocusText; + public String resumeFocusText; + public String youFocusedForText; + public String minutesAndText; + public String secondsPeriodText; + public String focusBrokeText; + public String focusText; + public String breakText; + public String focusCompleteText; + public String breakOverText; + + /* + * ################################## + * ################################## + * ITEMS TEXT + * ################################## + * ################################## + */ + public String onigiriText; + public String chickenPlateText; + public String cheesecakeText; + public String onigiriDescriptionText; + public String chickenPlateDescriptionText; + public String cheesecakeDescriptionText; + + public String bedroomText; + public String sofaText; + public String sunriseText; + public String nightOutText; + public String enigmaText; + public String cozyNightText; + public String studyTimeText; + public String pleasantBridgeText; + public String wisteriaText; + public String moonText; + + public String bedroomDescriptionText; + public String sofaDescriptionText; + public String sunriseDescriptionText; + public String nightOutDescriptionText; + public String enigmaDescriptionText; + public String cozyNightDescriptionText; + public String studyTimeDescriptionText; + public String pleasantBridgeDescriptionText; + public String wisteriaDescriptionText; + public String moonDescriptionText; + + public String blackText; + public String goldText; + public String redText; + public String mintText; + public String purpleText; + public String blueText; + public String strawberryLemonadeText; + public String sunsetText; + public String tealText; + public String codeText; + + public String solidBackgroundText; + public String gradientBackgroundText; + public String rareBackgroundText; + public String themedBackgroundText; + + /* + * ################################## + * ################################## + * SHOP TEXT + * ################################## + * ################################## + */ + public String selectShopText; + public String foodText; + public String backgroundsText; + public String bordersText; + public String yourFoodInventoryIsFullText; + public String confirmPurchaseOfText; + public String notEnoughTamoTokensText; + + /* + * ################################## + * ################################## + * INVENTORY TEXT + * ################################## + * ################################## + */ + public String inventoryText; + public String feedTamoText; + public String setBackgroundText; + public String setBorderText; + public String welcomeToTheShopText; + public String hereAreOurFoodOptionsText; + public String whatBackgroundsCanIHelpFindText; + public String whatBordersCanIHelpFindText; + public String letsCustomizeFocusTimerText; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + public String hoursOnText; + + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + public String theBeginningText; + public String theBeginningDescText; + public String nothingCanStopUsText; + public String nothingCanStopUsDescText; + public String neverGiveUpText; + public String neverGiveUpDescText; + public String focusAscensionText; + public String focusAscensionDescText; + public String cosmeticsText; + public String cosmeticsDescText; + public String sceneryChangeText; + public String sceneryChangeDescText; + public String fromTheBeginningText; + public String fromTheBeginningDescText; + public String tamoFullText; + public String tamoFullDescText; + public String tamoLoveText; + public String tamoLoveDescText; + public String dedicatedText; + public String dedicatedDescText; + public String buildingConsistencyText; + public String buildingConsistencyDescText; + public String tamoScholarText; + public String tamoScholarDescText; + + public String hasEarnedAchievementText; + public String achievementUnlockedText; + public String youHaveEarnedText; + public String tamoTokensText; + + /* + * ################################## + * ################################## + * SETTINGS STATE TEXT + * ################################## + * ################################## + */ + public String timerAlarmText; + public String noTimerAlarmText; + public String softAlarmText; + public String traditionalAlarmText; + public String pacAlarmText; + public String calmAlarmText; + public String bellAlarmText; + public String guiSizeText; + public String notificationsText; + public String discordRPCText; + public String exitMessageText; + public String onText; + public String offText; + public String saveText; + public String resetText; + + /* + * ################################## + * ################################## + * ABOUT STATE TEXT + * ################################## + * ################################## + */ + public String aboutTamoStudyText; + + public static Language getLanguageFromBox(int index) { + Language language; + + switch(index) { + case 0: + language = new EnglishLanguage(); + return language; + case 1: + language = new SpanishLanguage(); + return language; + default: + language = new EnglishLanguage(); + return language; + } + } + + public static int getIndexFromLanguage(Language language) { + if(language instanceof EnglishLanguage) { + return 0; + } + if(language instanceof SpanishLanguage) { + return 1; + } + return 0; + } + + public static Language getLanguage(String languageString) { + Language language; + + switch(languageString) { + case "ENG": + language = new EnglishLanguage(); + return language; + case "SPA": + language = new SpanishLanguage(); + return language; + default: + language = new EnglishLanguage(); + return language; + } + } + + @Override + public String toString() { + if(this instanceof EnglishLanguage) { + return "ENG"; + } + if(this instanceof SpanishLanguage) { + return "SPA"; + } + return "ENG"; + } +} diff --git a/TamoStudy/src/model/language/SpanishLanguage.java b/TamoStudy/src/model/language/SpanishLanguage.java new file mode 100644 index 0000000..08a9a32 --- /dev/null +++ b/TamoStudy/src/model/language/SpanishLanguage.java @@ -0,0 +1,320 @@ +package model.language; + +/** + * + * @author narlock + * @translator tokisuno (modified by narlock) + * + */ +public class SpanishLanguage extends Language { + public SpanishLanguage() { + /* + * ################################## + * ################################## + * TEXTO DE BIENVENIDA EN LA GUI + * ################################## + * ################################## + */ + createdByText = "Creado por"; + localStudyText = "Estudio Local"; + onlineStudyText = "Estudio en línea"; + unableSearchUpdatesText = "No se puede buscar actualizaciones. No hay conexión a Internet."; + updateAvailableDownloadText = "Actualización disponsible. ¡Haz clic aquí para descargar!"; // VER ... {} + globalSettingsText = "Global Settings"; + + /* + * ################################## + * ################################## + * TEXTO PRINCIPAL EN LA GUI + * ################################## + * ################################## + */ + areYouSureYouWantToExitText = "Hiciste todo lo que querías?"; + dontShowThisMessageAgainText = "No mostrar este mensaje de nuevo"; + exitTamoStudyText = "¿Salir de TamoStudy?"; + deathText1 = "Por el descuido, lamento decir que tu Tamo ha fallecido :("; + deathText2 = "El progreso de este Tamo se guardará en el Historial de Tamo."; + newTamoNameText = "Nombre del nuevo Tamo"; + + /* + * ################################## + * ################################## + * TEXTO DE CREACIÓN / SELECCIÓN DE PERFIL + * ################################## + * ################################## + */ + noProfilesText = "No se encuentran perfiles locales en este computadora."; + welcomeBackText = "¡Bienvenido de vuelta a TamoStudy!"; + createNewProfileText = "Crear nuevo perfil"; + importProfileText = "Importar perfil de Beta 4.2"; + chooseProfileText = "Elegir perfil"; + loadProfileAutomaticallyText = "Cargar perfil automáticamente"; + loadProfileText = "Cargar perfil"; + deleteProfileText = "Eliminar perfil"; + invalidProfileFileText = "Perfil de Beta v4.2 no válido"; + confirmDeleteProfileText = "Confirmar eliminación del perfil"; + areYouSureText = "¿Estás seguro?"; + createProfileText = "Crear perfil de TamoStudy"; // <--- but there is createNewProfileText. -- de: tokisuno + usernameText = "Nombre de usuario"; + tamoNameText = "Nombre del Tamo"; + + + languageText = "Idioma"; + // Like the language... + englishText = "Inglés"; + spanishText = "Español"; + hindiText = "Hindi"; + portugueseText = "Portugués"; + japaneseText = "Japonés"; + germanText = "Alemán"; + frenchText = "Francés"; + turkishText = "Turco"; + mandarinChineseText = "Chino Mandarín"; + dutchText = "Holandés"; + koreanText = "Coreano"; + russianText = "Ruso"; + hungarianText = "Húngaro"; + romanianText = "Rumano"; + + difficultyText = "Niveles de Dificultad"; + peacefulText = "Pacífico"; + challengingText = "Desafiante"; + ironManText = "Extremo"; + + focusModeText = "Modo de concentración"; + pomodoroText = "Pomodoro"; + customCountdownText = "Temporizador Personalizado"; + fiveMinIntervalCountdownText = "Temporizador fijado en 5 minutos por intervalo"; + stopwatchText = "Modo Cronómetro"; + + resetDefaultProfileText = "Restablecer perfil predeterminado"; + updateNotificationsText = "Actualizar notificaiones"; + defaultProfileReset = "Restablecimiento del perfil predeterminado"; + + createText = "Crear"; + cancelText = "Cancelar"; + mustEnterValidNameText = "¡Debes ingresar un nombre válido!"; + settingsSavedText = "¡Ya está!"; + + /* + * ################################## + * ################################## + * TEXTO PRINCIPAL EN LA GUI + * ################################## + * ################################## + */ + menuButtonText = "Menú"; + dashboardStateButtonText = "Inicio"; + focusStateButtonText = "Centrar su atención"; + shopStateButtonText = "Tienda"; + inventoryStateButtonText = "Inventario"; + statisticsStateButtonText = "Estadísticas"; + achievementsStateButtonText = "Logros"; + settingsStateButtonText = "Configuración"; + tamoHistoryText = "Historia de Tamo"; + aboutStateButton = "Acerca de TamoStudy"; + + /* + * ################################## + * ################################## + * TEXTO DEL ESTADO DE TABLERO + * ################################## + * ################################## + */ + todaysFocusText = "Tiempo de estudio hoy"; + monthFocusText = "Tiempo de estudio mensual"; + totalFocusText = "Tiempo total de estudio"; + levelText = "Nivel"; + hoursText = "hrs"; + + /* + * ################################## + * ################################## + * TEXTO DEL ESTADO DE CENTRARSE + * ################################## + * ################################## + */ + pomoNumberOfSessionsText = "Cantidad de sesiones"; + pomoSessionLengthText = "Duración de Sesión"; + pomoBreakLengthText = "Duración de Descanso"; + minutesText = "Minutos"; + secondsText = "Segundos"; + durationText = "Duración"; + letsFocusText = "¡Concéntrate!"; + focusingText = "Concentrado"; + startFocusText = "Comenzar"; + breakFocusText = "Descansa"; + pauseFocusText = "Pausar temporizador"; + resumeFocusText = "Reanudar mantener concentración"; + youFocusedForText = "Te concentraste durante"; + minutesAndText = "minutos y"; + secondsPeriodText = "segundos."; + focusBrokeText = "Se interrumpió su concentración"; + focusText = "Concentración"; + breakText = "Descansa"; + focusCompleteText = "Sección completado"; + breakOverText = "¡El descanso ha terminado! ¡Concéntrate YA!"; + + /* + * ################################## + * ################################## + * TEXTO DE LOS ÍTEMS + * ################################## + * ################################## + */ + + + // i have 0 idea how to translate food descriptions in spanish. + // would be better if someone else did this + // de: tokisuno + onigiriText = "Onigiri"; + chickenPlateText = "Plato de Pollo"; + cheesecakeText = "Cheesecake"; + onigiriDescriptionText = "Un snack tradicional japonés
hecho de arroz sazonado
en forma de bola o triángulo,
a menudo con un relleno, y
envuelto en alga nori.

Restaura 1 punto de hambre."; + chickenPlateDescriptionText = "Un plato con pollo cocido
servido con una variedad de
acompañamientos y guarniciones.

Restaura 3 puntos de hambre."; + cheesecakeDescriptionText = "Un postre cremoso y rico
hecho con una base de
galletas trituradas o masa,
relleno con una mezcla suave
de queso crema y azúcar.

Restaura 8 puntos de hambre."; + + bedroomText = "Dormitorio"; + sofaText = "Sofá"; + sunriseText = "Amanecer"; + nightOutText = "Noche Fuera"; + enigmaText = "Misterio"; + cozyNightText = "Noche Acogedora"; + studyTimeText = "Tiempo de Estudio"; + pleasantBridgeText = "Puente Agradable"; + wisteriaText = "Glicina"; + moonText = "Luna"; + + bedroomDescriptionText = "Un fondo sereno de dormitorio
con una cama acogedora
ubicada debajo de una gran ventana,
invitando una amplia luz natural
y una vista del mundo exterior."; + sofaDescriptionText = "Una habitación relajada adornada
con un elegante sofá rojo,
creando un punto focal de
comodidad y elegancia dentro
de un ambiente agradable e invitador."; + sunriseDescriptionText = "Un fondo impresionante
que captura la belleza de un
amanecer mientras el sol emerge
graciosamente en el horizonte."; + nightOutDescriptionText = "Una atmósfera callejera
que emana una combinación
perfecta de calidez y
ambiente relajado en una
agradable noche fuera."; + enigmaDescriptionText = "Un fondo enigmático
envuelto en un aura de
misterio, pintado con tonos
profundos de rojo, granate y gris."; + cozyNightDescriptionText = "Un entorno sereno nocturno con una acogedora cama adornada con un tierno oso de peluche, irradiando calidez y una atmósfera reconfortante, perfecta para un sueño tranquilo."; + studyTimeDescriptionText = "Un refugio ideal para estudiar te espera con un gran escritorio de madera, una lámpara radiante iluminando filas de libros en una estantería amplia, creando un entorno propicio para el aprendizaje concentrado."; + pleasantBridgeDescriptionText = "Se despliega una serena escena de un bosque, mostrando un pintoresco puente japonés elegantemente arqueado sobre un río tranquilo, envuelto por la abrazadora belleza de la naturaleza."; + wisteriaDescriptionText = "En una escena onírica, florecen encantadores árboles de glicinas, sus cascadas de flores púrpuras ondeando suavemente mientras las hojas otoñales descienden graciosamente, pintando un momento pintoresco en la naturaleza."; + moonDescriptionText = "A medida que amanece, se despliega un espectáculo impresionante: una magnífica luna azul se alza en el cielo, sus brillantes rayos pintan el mundo en tonos de oro y azul, una armonía celestial de amanecer y magia lunar."; + + blackText = "Negro"; + goldText = "Dorado"; + redText = "Rojo"; + mintText = "Menta"; + purpleText = "Morado"; + blueText = "Azul"; + strawberryLemonadeText = "Limada de Fresa"; + sunsetText = "Puesta del sol"; + tealText = "Turquesa"; + codeText = "Código"; + + solidBackgroundText = "Fondo Sólido"; + gradientBackgroundText = "Fondo de Gradiente"; + rareBackgroundText = "Fondo Raro"; + themedBackgroundText = "Fondo Temático"; + + /* + * ################################## + * ################################## + * SHOP TEXT + * ################################## + * ################################## + */ + selectShopText = "Seleccionar Tienda"; + foodText = "Comida"; + backgroundsText = "Fondos"; + bordersText = "Fronteras"; + yourFoodInventoryIsFullText = "¡Tu inventario de comida está lleno!"; + confirmPurchaseOfText = "Confirmar pedido por completo"; + notEnoughTamoTokensText = "No tienes suficientes fichas de Tamo para completar esta compra."; + + /* + * ################################## + * ################################## + * INVENTORY TEXT + * ################################## + * ################################## + */ + inventoryText = "Inventario"; + feedTamoText = "Alimentar a Tamo"; + setBackgroundText = "Establecer Fondo"; + setBorderText = "Establecer Borde"; + welcomeToTheShopText = "Bienvenido/a a la tienda. ¿En qué puedo ayudarte?"; + hereAreOurFoodOptionsText = "¡Aquí tienes nuestras opciones de comida!"; + whatBackgroundsCanIHelpFindText = "¿En qué puedo ayudarte con los fondos?"; + whatBordersCanIHelpFindText = "¿En qué puedo ayudarte con los bordes?"; + letsCustomizeFocusTimerText = "¡Vamos a personalizar el temporizador de enfoque!"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + hoursOnText = "horas en"; + + /* + * ################################## + * ################################## + * ACHIEVEMENTS STATE TEXT + * ################################## + * ################################## + */ + theBeginningText = "El Comienzo"; + theBeginningDescText = "Logra 24 horas de concentración"; + nothingCanStopUsText = "¡Nada nos puede detener!"; + nothingCanStopUsDescText = "Logra 72 horas de concentración"; + neverGiveUpText = "¡Nunca te rindas!"; + neverGiveUpDescText = "Logra 240 horas de concentración"; + focusAscensionText = "Ascención mental."; + focusAscensionDescText = "Logra 1200 horas de concentración"; + cosmeticsText = "Cosméticos"; + cosmeticsDescText = "Compra y cambia la frontera de tu Tamo."; + sceneryChangeText = "Cambia el paisaje de fondo"; + sceneryChangeDescText = "Compra y cambia el paisaje de fondo de tu Tamo."; + fromTheBeginningText = "Desde el comienzo"; + fromTheBeginningDescText = "Perfil actualizado desde la versión anterior de TamoStudy."; + tamoFullText = "Tamo Completo"; + tamoFullDescText = "Alcanza el hambre máxima de tu Tamo."; + tamoLoveText = "Amor Tamo"; + tamoLoveDescText = "Alcanza la felicidad máxima de tu Tamo."; + dedicatedText = "Dedicado"; + dedicatedDescText = "Mantén concentración durante 1 hora o más durante 3 días consecutivos."; + buildingConsistencyText = "Construyendo consistencia"; + buildingConsistencyDescText = "Mantén concentración durante 1 hora o más durante 7 días consecutivos."; + tamoScholarText = "Tamo Erudito"; + tamoScholarDescText = "Mantén concentración durante 1 hora o más durante 30 días consecutivos."; + + /* + * ################################## + * ################################## + * SETTINGS STATE TEXT + * ################################## + * ################################## + */ + timerAlarmText = "Alarma del Temporizador"; + noTimerAlarmText = "Ninguna"; + softAlarmText = "Alarma pacífica"; + traditionalAlarmText = "Alarma tradicional"; + pacAlarmText = "Alarma pac"; + calmAlarmText = "Alarma tranquila"; + bellAlarmText = "Alarma de campana"; + guiSizeText = "Tamaño de la interfaz"; + notificationsText = "Notificaciones"; + discordRPCText = "Discord RPC"; + exitMessageText = "Mensaje de salida"; + onText = "ENCENDIDO"; + offText = "APAGADO"; + saveText = "Guardar"; + resetText = "Restablecer"; + + /* + * ################################## + * ################################## + * ABOUT STATE TEXT + * ################################## + * ################################## + */ + aboutTamoStudyText = "TamoStudy es un temporizador de trabajo y estudio diseñado
para mejorar la productivida al incorporar una mascota
virtual divertida para motivar a los usuarios a concentrarse
en sus tareas."; + } +} diff --git a/TamoStudy/src/model/profile/Profile.java b/TamoStudy/src/model/profile/Profile.java new file mode 100644 index 0000000..9b96665 --- /dev/null +++ b/TamoStudy/src/model/profile/Profile.java @@ -0,0 +1,289 @@ +package model.profile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +import io.ProfileJsonManager; +import model.language.Language; +import util.Utils; + +public class Profile { + + private long id; + + private String name; + + private String previousDateString; + + private long time; + + private long tokens; + + private ProfileSettings settings; + + private long backgroundIndicator; + + private long borderIndicator; + + private List achievementList; + + private List foodInventoryList; + + private List backgroundInventoryList; + + private List borderInventoryList; + + private Tamo tamo; + + private List tamoHistory; + + /** + * New Profile Constructor + * @param name + * @param language + * @param focusMode + * @param difficulty + * @param tamoName + */ + public Profile(String name, Language language, long focusMode, long difficulty, String tamoName) { + super(); + this.id = generateRandomProfileId(); + this.name = name; + this.previousDateString = Utils.todayAsString(); + this.time = 0; + this.tokens = 0; + this.settings = new ProfileSettings( + language, + focusMode, + difficulty + ); + this.backgroundIndicator = 0; + this.borderIndicator = 0; + this.achievementList = Collections.emptyList(); + this.foodInventoryList = Collections.emptyList(); + this.backgroundInventoryList = new ArrayList(); + this.backgroundInventoryList.add(0L); + this.borderInventoryList = new ArrayList(); + this.borderInventoryList.add(0L); + this.tamo = new Tamo( + tamoName + ); + this.tamoHistory = Collections.emptyList(); + } + + /** + * Load Profile Constructor + * @param id + * @param name + * @param previousDateString + * @param time + * @param tokens + * @param settings + * @param backgroundIndicator + * @param borderIndicator + * @param achievementList + * @param foodInventoryList + * @param backgroundInventoryList + * @param borderInventoryList + * @param tamo + * @param tamoHistory + */ + public Profile(long id, String name, String previousDateString, long time, long tokens, ProfileSettings settings, + long backgroundIndicator, long borderIndicator, List achievementList, List foodInventoryList, + List backgroundInventoryList, List borderInventoryList, Tamo tamo, List tamoHistory) { + super(); + this.id = id; + this.name = name; + this.previousDateString = previousDateString; + this.time = time; + this.tokens = tokens; + this.settings = settings; + this.backgroundIndicator = backgroundIndicator; + this.borderIndicator = borderIndicator; + this.achievementList = achievementList; + this.foodInventoryList = foodInventoryList; + this.backgroundInventoryList = backgroundInventoryList; + this.borderInventoryList = borderInventoryList; + this.tamo = tamo; + this.tamoHistory = tamoHistory; + } + + public Profile(String name, String joinDateString, String previousDateString, long time, long tokens, long backgroundIndicator, + long strikes, String tamoName, long tamoHappiness, long tamoHunger, long tamoId, long languageIndicator, + String ahmString, String invString, long focusMode, long sessionSoundIndicator, long difficulty, + boolean showAhmNotifications + ) { + this.id = generateRandomProfileId(); + this.name = name; + this.previousDateString = previousDateString; + this.time = time; + this.tokens = tokens; + this.settings = new ProfileSettings(languageIndicator, focusMode, sessionSoundIndicator, difficulty, showAhmNotifications); + this.backgroundIndicator = backgroundIndicator; + this.borderIndicator = 0; + this.achievementList = new ArrayList(); + this.achievementList.add(6L); + this.foodInventoryList = Collections.emptyList(); + this.backgroundInventoryList = convertInvStringToBackgroundInventoryList(invString); + this.borderInventoryList = new ArrayList(); + this.borderInventoryList.add(0L); + this.tamo = new Tamo(tamoName, time, tamoId, joinDateString, tamoHappiness, tamoHunger, strikes); + this.tamoHistory = Collections.emptyList(); + } + + private List convertInvStringToBackgroundInventoryList(String invString) { + List backgroundInventoryList = new ArrayList<>(); + String inventory[] = invString.split(""); + for(int i = 0; i < inventory.length; i++) { + backgroundInventoryList.add(Long.parseLong(inventory[i])); + } + return backgroundInventoryList; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPreviousDateString() { + return previousDateString; + } + + public void setPreviousDateString(String previousDateString) { + this.previousDateString = previousDateString; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public long getTokens() { + return tokens; + } + + public void setTokens(long tokens) { + this.tokens = tokens; + } + + public ProfileSettings getSettings() { + return settings; + } + + public void setSettings(ProfileSettings settings) { + this.settings = settings; + } + + public long getBackgroundIndicator() { + return backgroundIndicator; + } + + public void setBackgroundIndicator(long backgroundIndicator) { + this.backgroundIndicator = backgroundIndicator; + } + + public long getBorderIndicator() { + return borderIndicator; + } + + public void setBorderIndicator(long borderIndicator) { + this.borderIndicator = borderIndicator; + } + + public List getAchievementList() { + return achievementList; + } + + public void setAchievementList(List achievementList) { + this.achievementList = achievementList; + } + + public List getFoodInventoryList() { + return foodInventoryList; + } + + public void setFoodInventoryList(List foodInventoryList) { + this.foodInventoryList = foodInventoryList; + } + + public List getBackgroundInventoryList() { + return backgroundInventoryList; + } + + public void setBackgroundInventoryList(List backgroundInventoryList) { + this.backgroundInventoryList = backgroundInventoryList; + } + + public List getBorderInventoryList() { + return borderInventoryList; + } + + public void setBorderInventoryList(List borderInventoryList) { + this.borderInventoryList = borderInventoryList; + } + + public Tamo getTamo() { + return tamo; + } + + public void setTamo(Tamo tamo) { + this.tamo = tamo; + } + + public List getTamoHistory() { + return tamoHistory; + } + + public void setTamoHistory(List tamoHistory) { + this.tamoHistory = tamoHistory; + } + + @Override + public String toString() { + return "Profile [id=" + id + ", name=" + name + ", previousDateString=" + previousDateString + ", time=" + time + + ", tokens=" + tokens + ", settings=" + settings + ", backgroundIndicator=" + backgroundIndicator + + ", borderIndicator=" + borderIndicator + ", achievementList=" + achievementList + + ", foodInventoryList=" + foodInventoryList + ", backgroundInventoryList=" + backgroundInventoryList + + ", borderInventoryList=" + borderInventoryList + ", tamo=" + tamo + ", tamoHistory=" + tamoHistory + + "]"; + } + + private long generateRandomProfileId() { + Random random = new Random(); + int id = 0; + for (int i = 0; i < 5; i++) { + id = id * 10 + random.nextInt(10); + } + + boolean idAlreadyExists = false; + ProfileJsonManager profileJsonManager = new ProfileJsonManager(); + List profiles = profileJsonManager.readJson(); + for(Profile profile : profiles) { + if(profile.getId() == id) { + idAlreadyExists = true; + } + } + + if(idAlreadyExists) { + return generateRandomProfileId(); + } else { + return id; + } + } +} diff --git a/TamoStudy/src/model/profile/ProfileSettings.java b/TamoStudy/src/model/profile/ProfileSettings.java new file mode 100644 index 0000000..850b976 --- /dev/null +++ b/TamoStudy/src/model/profile/ProfileSettings.java @@ -0,0 +1,210 @@ +package model.profile; + +import model.language.Language; +import resources.Debug; +import resources.Theme; + +public class ProfileSettings { + + private Language language; + + /* + * 0 : Pomodoro + * 1 : Custom Countdown + * 2 : Five Min Interval Countdown + * 3 : Stopwatch + * 4 : Pomodoro with Long Breaks + */ + private long focusMode; + + private long difficulty; + + private long timerAlarm; + + private long guiSize; + + private Boolean receiveNotifications; + + private Boolean enableDiscordRPC; + + private Boolean showProgramCloseMessage; + + private Theme theme; + + /** + * New Profile Settings + * @param language + * @param focusMode + * @param difficulty + */ + public ProfileSettings(Language language, long focusMode, long difficulty) { + super(); + this.language = language; + this.focusMode = focusMode; + this.difficulty = difficulty; + this.timerAlarm = 0; + this.guiSize = 1; + this.receiveNotifications = true; + this.enableDiscordRPC = false; + this.showProgramCloseMessage = true; + this.theme = Theme.DARK; + } + + /** + * Load Profile Settings + * @param language + * @param focusMode + * @param difficulty + * @param timerAlarm + * @param guiSize + * @param receiveNotifications + * @param enableDiscordRPC + * @param showProgramCloseMessage + */ + public ProfileSettings(Language language, long focusMode, long difficulty, long timerAlarm, long guiSize, + Boolean receiveNotifications, Boolean enableDiscordRPC, Boolean showProgramCloseMessage, Theme theme) { + super(); + this.language = language; + this.focusMode = focusMode; + this.difficulty = difficulty; + this.timerAlarm = timerAlarm; + this.guiSize = guiSize; + this.receiveNotifications = receiveNotifications; + this.enableDiscordRPC = enableDiscordRPC; + this.showProgramCloseMessage = showProgramCloseMessage; + this.theme = theme; + } + + /** + * Convert Profile Settings + * @param languageIndicator + * @param focusMode + * @param sessionSoundIndicator + * @param difficulty + * @param showAhmNotifications + */ + public ProfileSettings(long languageIndicator, long focusMode, long sessionSoundIndicator, long difficulty, + boolean showAhmNotifications) { + this.language = Language.getLanguageFromBox((int) languageIndicator); + this.focusMode = convertNewFocusMode((int) focusMode); + this.difficulty = difficulty; + this.timerAlarm = sessionSoundIndicator; + this.guiSize = 1; + this.receiveNotifications = showAhmNotifications; + this.enableDiscordRPC = false; + this.showProgramCloseMessage = true; + this.theme = Theme.DARK; + } + + private long convertNewFocusMode(int oldFocusMode) { + switch(oldFocusMode) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 0; + default: + return 0; + } + } + + public Language getLanguage() { + return language; + } + + public void setLanguage(Language language) { + this.language = language; + } + + public long getFocusMode() { + return focusMode; + } + + public void setFocusMode(long focusMode) { + this.focusMode = focusMode; + } + + public long getDifficulty() { + return difficulty; + } + + public void setDifficulty(long difficulty) { + this.difficulty = difficulty; + } + + public long getTimerAlarm() { + return timerAlarm; + } + + public void setTimerAlarm(long timerAlarm) { + this.timerAlarm = timerAlarm; + } + + public long getGuiSize() { + return guiSize; + } + + public void setGuiSize(long guiSize) { + this.guiSize = guiSize; + } + + public Boolean getReceiveNotifications() { + return receiveNotifications; + } + + public void setReceiveNotifications(Boolean receiveNotifications) { + this.receiveNotifications = receiveNotifications; + } + + public Boolean getEnableDiscordRPC() { + return enableDiscordRPC; + } + + public void setEnableDiscordRPC(Boolean enableDiscordRPC) { + this.enableDiscordRPC = enableDiscordRPC; + } + + public Boolean getShowProgramCloseMessage() { + return showProgramCloseMessage; + } + + public void setShowProgramCloseMessage(Boolean showProgramCloseMessage) { + this.showProgramCloseMessage = showProgramCloseMessage; + } + + public Theme getTheme() { + return theme; + } + + public void setTheme(Theme theme) { + this.theme = theme; + } + + @Override + public String toString() { + return "ProfileSettings [language=" + language + ", focusMode=" + focusMode + ", difficulty=" + difficulty + + ", timerAlarm=" + timerAlarm + ", guiSize=" + guiSize + ", receiveNotifications=" + + receiveNotifications + ", enableDiscordRPC=" + enableDiscordRPC + ", showProgramCloseMessage=" + + showProgramCloseMessage + "]"; + } + + public String getSoundPath() { + switch((int) timerAlarm) { + case 1: + return "SOFT_ALARM.wav"; + case 2: + return "TRAD_ALARM.wav"; + case 3: + return "PAC_ALARM.wav"; + case 4: + return "CALM_ALARM.wav"; + case 5: + return "BELL_ALARM.wav"; + default: + Debug.error("ProfileSettings", "Error retrieving sound path: Unexpected value for timerAlarm = " + timerAlarm); + throw new RuntimeException("Unexpected error occurred"); + } + } + +} diff --git a/TamoStudy/src/model/profile/ProfileUpdateManager.java b/TamoStudy/src/model/profile/ProfileUpdateManager.java new file mode 100644 index 0000000..d3f034e --- /dev/null +++ b/TamoStudy/src/model/profile/ProfileUpdateManager.java @@ -0,0 +1,145 @@ +package model.profile; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; + +import javax.swing.Timer; + +import gui.TamoStudyGUI; +import resources.Debug; +import util.Utils; + +public class ProfileUpdateManager { + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private TamoStudyGUI tamoStudyGUI; + private Tamo tamo; + private Profile profile; + private Timer timer; + + public ProfileUpdateManager(TamoStudyGUI tamoStudyGUI) { + this.tamoStudyGUI = tamoStudyGUI; + this.profile = tamoStudyGUI.getProfile(); + this.tamo = tamoStudyGUI.getProfile().getTamo(); + + // Call update day on creation + updateHappyHungerOnDayChange(); + } + + public void updateHappyOnEvent(int subtraction) { + updateTamoHappy(tamo, subtraction); + + // Update JSON + tamoStudyGUI.getProfileJsonManager().writeJsonToFile(tamoStudyGUI.getProfiles()); + } + + public void updateHappyHungerOnDayChange() { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "Updating Happy Hunger for " + profile.getName() + ); + String todayAsString = Utils.todayAsString(); + if(!profile.getPreviousDateString().equals(todayAsString)) { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "New day - updating date string and applying happy/hunger changes." + ); + LocalDate todayLocalDate = LocalDate.parse(Utils.todayAsString()); + LocalDate previousLocalDate = LocalDate.parse(profile.getPreviousDateString()); + + profile.setPreviousDateString(todayAsString); + // Updating happiness and hunger based on time + + long daysBetween = ChronoUnit.DAYS.between(previousLocalDate, todayLocalDate); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "daysBetween = " + daysBetween); + + if(daysBetween < 3) { + updateTamoHunger(tamo, 2); + updateTamoHappy(tamo, 1); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween < 7 && daysBetween >= 3) { + updateTamoHunger(tamo, 3); + updateTamoHappy(tamo, 2); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween >= 7 && daysBetween < 30) { + updateTamoHunger(tamo, 10); + updateTamoHappy(tamo, 10); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween >= 30 && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(3); + Debug.info("ProfileUpdateManage.updateHappyHungerOnDayChange", "User did not login within 30 days. Tamo automatically passes."); + } + + + // Update JSON + tamoStudyGUI.getProfileJsonManager().writeJsonToFile(tamoStudyGUI.getProfiles()); + + /* + * TODO + * + * Under the condition that the state is display happy and hunger, notably, + * dashboard, focus, and statistics, the happiness and hunger should be updated, + * along with the tamo image. + */ + } else { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "Same day detected - applying no changes to profile." + ); + } + } + + public void updateHappyHungerBasedOnTime() { + timer = new Timer(900000, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + updateHappyHungerOnDayChange(); + } + }); + timer.start(); + } + + public void updateTamoHunger(Tamo tamo, int subtraction) { + // Calculate hunger + int hunger = (int) tamo.getHunger() - subtraction; + + // Validate hunger cannot be negative + if(hunger < 0) { + hunger = 0; + } + + // Set hunger + tamo.setHunger(hunger); + } + + public void updateTamoHappy(Tamo tamo, int subtraction) { + // Calculate hunger + int happy = (int) tamo.getHappy() - subtraction; + + // Validate hunger cannot be negative + if(happy < 0) { + happy = 0; + } + + // Set hunger + tamo.setHappy(happy); + } +} diff --git a/TamoStudy/src/model/profile/Tamo.java b/TamoStudy/src/model/profile/Tamo.java new file mode 100644 index 0000000..180c690 --- /dev/null +++ b/TamoStudy/src/model/profile/Tamo.java @@ -0,0 +1,212 @@ +package model.profile; + +import java.util.Random; + +import util.Utils; + +public class Tamo { + + private String name; + + private long time; + + private long type; + + private String birthDateString; + + private String passDateString; + + private long happy; + + private long hunger; + + private long strikes; + + private boolean focused; + + /** + * Tamo(name) + * @brief Constructor for new profile Tamo + */ + public Tamo(String name) { + super(); + this.time = 0; + this.name = name; + this.type = generateRandomTamoType(); + this.birthDateString = Utils.todayAsString(); + this.passDateString = null; + this.happy = 7; + this.hunger = 8; + this.setStrikes(0); + + focused = false; + } + + /** + * Tamo(name, type, birthDateString, passDateString) + * @brief Constructor for deceased Tamo + */ + public Tamo(String name, long time, long type, String birthDateString, String passDateString) { + super(); + this.name = name; + this.time = time; + this.type = type; + this.birthDateString = birthDateString; + this.passDateString = passDateString; + + focused = false; + } + + /** + * Tamo(name, type, birthDateString, happy, hunger) + * @brief Constructor for loading Tamo + */ + public Tamo(String name, long time, long type, String birthDateString, long happy, long hunger, long strikes) { + super(); + this.name = name; + this.time = time; + this.type = type; + this.birthDateString = birthDateString; + this.passDateString = null; + this.happy = happy; + this.hunger = hunger; + this.setStrikes(strikes); + + focused = false; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public long getType() { + return type; + } + + public void setType(long type) { + this.type = type; + } + + public String getBirthDateString() { + return birthDateString; + } + + public void setBirthDateString(String birthDateString) { + this.birthDateString = birthDateString; + } + + public String getPassDateString() { + return passDateString; + } + + public void setPassDateString(String passDateString) { + this.passDateString = passDateString; + } + + public long getHappy() { + return happy; + } + + public void setHappy(long happy) { + this.happy = happy; + } + + public long getHunger() { + return hunger; + } + + public void setHunger(long hunger) { + this.hunger = hunger; + } + + public long getStrikes() { + return strikes; + } + + public void setStrikes(long strikes) { + this.strikes = strikes; + } + + @Override + public String toString() { + return "Tamo [name=" + name + ", time=" + time + ", type=" + type + ", birthDateString=" + birthDateString + + ", passDateString=" + passDateString + ", happy=" + happy + ", hunger=" + hunger + ", strikes=" + + strikes + "]"; + } + + private long generateRandomTamoType() { + int max = 4; + int min = 1; + Random random = new Random(); + return random.nextInt(max - min + 1) + min; + } + + /** + * @return status + * @brief Based off of happy and hunger, the status of the + * Tamo will be determined. If focused, then will be in focus. + * + * If focused is true, return FOCUS + * If happy is 3 or below, return SAD + * If hunger is 3 or below, return HUNGRY + * If happy is 7 or above, return HAPPY + * Otherwise, return NORMAL + */ + public String getStatus(boolean focused) { + if(passDateString != null) { + return "NORMAL"; + } + + // Get Status String + if(focused) { + return "FOCUS"; + } + + else if(happy <= 3) { + return "SAD"; + } + + else if(hunger <= 3) { + return "HUNGRY"; + } + + else if(happy >= 7) { + return "HAPPY"; + } + + return "NORMAL"; + } + + public boolean isFocused() { + return focused; + } + + public void setFocused(boolean focused) { + this.focused = focused; + } + + // Every 24 hours studied, a new level is earned + public int getLevel() { + return (int) time / 86400; + } + + public int levelProgress() { + int level = getLevel(); + double secondsToNextLevel = (level + 1) * 86400 - time; + double progressToNextLevel = ((86400 - secondsToNextLevel) / 86400) * 100; + return (int) progressToNextLevel; + } + +} diff --git a/TamoStudy/src/model/time/DailyFocus.java b/TamoStudy/src/model/time/DailyFocus.java new file mode 100644 index 0000000..47b33a7 --- /dev/null +++ b/TamoStudy/src/model/time/DailyFocus.java @@ -0,0 +1,103 @@ +package model.time; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import gui.TamoStudyGUI; +import resources.Achievements; +import resources.Debug; +import util.Utils; + +public class DailyFocus { + + private Long profileId; + private List dailyFocusEntries; + + public DailyFocus(Long profileId, List dailyFocusEntry) { + super(); + this.profileId = profileId; + this.dailyFocusEntries = dailyFocusEntry; + } + + public Long getProfileId() { + return profileId; + } + + public void setProfileId(Long profileId) { + this.profileId = profileId; + } + + public List getDailyFocusEntries() { + return dailyFocusEntries; + } + + public void setDailyFocusEntries(List dailyFocusEntry) { + this.dailyFocusEntries = dailyFocusEntry; + } + + public void checkInRowDailyFocusAchievements(TamoStudyGUI gui, int length) { + List datesForAchievements = new ArrayList<>(); + Date todayDate = Utils.today(); + datesForAchievements.add(todayDate); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(todayDate); + + for(int i = 1; i < length; i++) { + calendar.add(Calendar.DAY_OF_YEAR, -1); + datesForAchievements.add(calendar.getTime()); + } + + boolean[] earnedDates = new boolean[length]; + for(int i = 0; i < length; i++) { + earnedDates[i] = false; + } + + for(int i = 0; i < length; i++) { + Calendar dateCalendar = Calendar.getInstance(); + dateCalendar.setTime(datesForAchievements.get(i)); + + long day = dateCalendar.get(Calendar.DAY_OF_MONTH); + long month = dateCalendar.get(Calendar.MONTH) + 1; + long year = dateCalendar.get(Calendar.YEAR); + +// Debug.info("DailyFocus.checkInRowDailyFocusAchievement(" + length + ")", "Checking " + month + "/" + day + "/" + year); + + for(DailyFocusEntry entry : this.dailyFocusEntries) { +// Debug.info("DailyFocus.checkInRowDailyFocusAchievement(" + length + ")", "Checking " + month + "/" + day + "/" + year + " is equal " + entry.getMonth() + "/" + entry.getDay() + "/" + entry.getYear() + " = " + (day == entry.getDay() && month == entry.getMonth() && year == entry.getYear())); + if(day == entry.getDay() && month == entry.getMonth() && year == entry.getYear() && entry.getTime() >= 3600) { + earnedDates[i] = true; + } + } + +// Debug.info("DailyFocus.checkInRowDailyFocusAchievement(" + length + ")", "Result: " + month + "/" + day + "/" + year + ". earnedDates[i] = " + earnedDates[i]); + } + + boolean earnedAchievement = true; + for(int i = 0; i < length; i++) { + if(earnedDates[i] == false) { + earnedAchievement = false; + } + } + + if(earnedAchievement) { + switch(length) { + case 3: + Debug.info("DailyFocus.checkInRowDailyFocusAchievement", "Profile earned " + length + " achievement."); + Achievements.earn(gui, 9); + break; + case 7: + Debug.info("DailyFocus.checkInRowDailyFocusAchievement", "Profile earned " + length + " achievement."); + Achievements.earn(gui, 10); + break; + case 30: + Debug.info("DailyFocus.checkInRowDailyFocusAchievement", "Profile earned " + length + " achievement."); + Achievements.earn(gui, 11); + break; + } + } else { + Debug.warn("DailyFocus.checkInRowDailyFocusAchievement", "Profile did not earn " + length + " achievement."); + } + } +} diff --git a/TamoStudy/src/model/time/DailyFocusEntry.java b/TamoStudy/src/model/time/DailyFocusEntry.java new file mode 100644 index 0000000..0712f5b --- /dev/null +++ b/TamoStudy/src/model/time/DailyFocusEntry.java @@ -0,0 +1,66 @@ +package model.time; + +/** + * DailyFocusEntry + * + * @author narlock + * + * Represents a singular month focus entry. + * Like an entry inside of a database, this entry + * has a 'primary key' so-to-say that is dependent + * on a day (Long, 22, like 22nd), + * on the month (Long, like 4 for April), and a + * year (like 2023, for 2023), and stores the + * time on the specific day. + */ +public class DailyFocusEntry { + + private Long day; + + private Long month; + + private Long year; + + private Long time; + + public DailyFocusEntry(Long day, Long month, Long year, Long time) { + super(); + this.day = day; + this.month = month; + this.year = year; + this.time = time; + } + + public Long getDay() { + return day; + } + + public void setDay(Long day) { + this.day = day; + } + + public Long getMonth() { + return month; + } + + public void setMonth(Long month) { + this.month = month; + } + + public Long getYear() { + return year; + } + + public void setYear(Long year) { + this.year = year; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + +} diff --git a/TamoStudy/src/model/time/MonthFocus.java b/TamoStudy/src/model/time/MonthFocus.java new file mode 100644 index 0000000..85e6b73 --- /dev/null +++ b/TamoStudy/src/model/time/MonthFocus.java @@ -0,0 +1,32 @@ +package model.time; + +import java.util.List; + +public class MonthFocus { + private Long profileId; + private List monthFocusEntries; + + public MonthFocus(Long profileId, List monthFocusEntries) { + super(); + this.profileId = profileId; + this.monthFocusEntries = monthFocusEntries; + } + + public Long getProfileId() { + return profileId; + } + + public void setProfileId(Long profileId) { + this.profileId = profileId; + } + + public List getMonthFocusEntries() { + return monthFocusEntries; + } + + public void setMonthFocusEntries(List monthFocusEntries) { + this.monthFocusEntries = monthFocusEntries; + } + + +} diff --git a/TamoStudy/src/model/time/MonthFocusEntry.java b/TamoStudy/src/model/time/MonthFocusEntry.java new file mode 100644 index 0000000..f6decd9 --- /dev/null +++ b/TamoStudy/src/model/time/MonthFocusEntry.java @@ -0,0 +1,55 @@ +package model.time; + +/** + * MonthFocusEntry + * + * @author narlock + * + * Represents a singular month focus entry. + * Like an entry inside of a database, this entry + * has a 'primary key' so-to-say that is dependent + * on the month (Long, like 4 for April), and a + * year (like 2023, for 2023), and stores the + * time on the specific day. + */ +public class MonthFocusEntry { + + private Long month; + + private Long year; + + private Long time; + + public MonthFocusEntry(Long month, Long year, Long time) { + super(); + this.month = month; + this.year = year; + this.time = time; + } + + public Long getMonth() { + return month; + } + + public void setMonth(Long month) { + this.month = month; + } + + public Long getYear() { + return year; + } + + public void setYear(Long year) { + this.year = year; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + +} diff --git a/TamoStudy/src/resources/Achievements.java b/TamoStudy/src/resources/Achievements.java new file mode 100644 index 0000000..de680d3 --- /dev/null +++ b/TamoStudy/src/resources/Achievements.java @@ -0,0 +1,155 @@ +package resources; + +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.GrayFilter; +import javax.swing.ImageIcon; +import javax.swing.JOptionPane; + +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; + +public class Achievements { + public static ImageIcon getAchievementIconByIndicator(boolean earned, int indicator, GuiSize guiSize) { + if(earned) { + return guiSize.scaleImageIcon(new ImageIcon(Achievements.class.getClassLoader().getResource("ACHIEVEMENT_" + indicator + ".png"))); + } + return toGrayscale(guiSize.scaleImageIcon(new ImageIcon(Achievements.class.getClassLoader().getResource("ACHIEVEMENT_" + indicator + ".png")))); + } + + public static ImageIcon toGrayscale(ImageIcon originalIcon) { + // Extract the Image from the ImageIcon + Image originalImage = originalIcon.getImage(); + + // Convert the Image to grayscale using GrayFilter + Image grayImage = GrayFilter.createDisabledImage(originalImage); + + // Create a new ImageIcon from the grayscale image + ImageIcon grayscaleIcon = new ImageIcon(grayImage); + + return grayscaleIcon; + } + + public static String getAchievementTitleByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.theBeginningText; + case 1: + return language.nothingCanStopUsText; + case 2: + return language.neverGiveUpText; + case 3: + return language.focusAscensionText; + case 4: + return language.cosmeticsText; + case 5: + return language.sceneryChangeText; + case 6: + return language.fromTheBeginningText; + case 7: + return language.tamoFullText; + case 8: + return language.tamoLoveText; + case 9: + return language.dedicatedText; + case 10: + return language.buildingConsistencyText; + case 11: + return language.tamoScholarText; + } + throw new RuntimeException("Invalid indicator provided"); + } + + public static String getAchievementDescriptionByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.theBeginningDescText; + case 1: + return language.nothingCanStopUsDescText; + case 2: + return language.neverGiveUpDescText; + case 3: + return language.focusAscensionDescText; + case 4: + return language.cosmeticsDescText; + case 5: + return language.sceneryChangeDescText; + case 6: + return language.fromTheBeginningDescText; + case 7: + return language.tamoFullDescText; + case 8: + return language.tamoLoveDescText; + case 9: + return language.dedicatedDescText; + case 10: + return language.buildingConsistencyDescText; + case 11: + return language.tamoScholarDescText; + } + throw new RuntimeException("Invalid indicator provided"); + } + + public static long getAchievementTokenEarningsByIndicator(int indicator) { + switch(indicator) { + case 0: + return 100; + case 1: + return 500; + case 2: + return 1000; + case 3: + return 2000; + case 4: + return 50; + case 5: + return 50; + case 6: + return 50; + case 7: + return 50; + case 8: + return 50; + case 9: + return 100; + case 10: + return 250; + case 11: + return 1000; + } + throw new RuntimeException("Invalid indicator provided"); + } + + public static void earn(TamoStudyGUI gui, long indicator) { + Profile profile = gui.getProfile(); + Language language = gui.getProfile().getSettings().getLanguage(); + List achievementList = new ArrayList<>(profile.getAchievementList()); + if(!achievementList.contains((Long) indicator)) { + // Add achievement to achievement list + Debug.info("Achievements.earn", "Profile " + profile.getName() + " has earned achievement " + indicator + "."); + achievementList.add(indicator); + profile.setAchievementList(achievementList); + + // Earn tokens for earning the achievement + Debug.info("Achievements.earn", "Profile tokens before achievement: " + profile.getTokens()); + long tokensEarned = getAchievementTokenEarningsByIndicator((int) indicator); + profile.setTokens(profile.getTokens() + tokensEarned); + Debug.info("Achievements.earn", "Profile tokens after achievement: " + profile.getTokens()); + + // Display achievement notification if setting is enabled + if(profile.getSettings().getReceiveNotifications()) { + JOptionPane.showMessageDialog(gui.getRootPane(), "Achievement Unlocked: " + getAchievementTitleByIndicator((int) indicator, language) + "
You have earned " + tokensEarned + " Tamo tokens!", "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(Achievements.class.getClassLoader().getResource("INFO.png"))); + } + + // Ensure Changes are earned + gui.updateTamoTokensLabel(); + gui.getProfileJsonManager().writeJsonToFile(gui.getProfiles()); + } else { + Debug.warn("Achievements.earn", "Profile " + profile.getName() + " already has achievement " + indicator + "."); + } + } +} diff --git a/TamoStudy/src/resources/CheckForUpdates.java b/TamoStudy/src/resources/CheckForUpdates.java new file mode 100644 index 0000000..d02db35 --- /dev/null +++ b/TamoStudy/src/resources/CheckForUpdates.java @@ -0,0 +1,72 @@ +package resources; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * CheckForUpdates + * @author antho + * + * This class implements a checkForUpdates object + * which contains a stored version list in which + * correspond to releases that are on the github repository + * + * the httpurl connection will identify all of the releases + * that the github contains + * + * if they are not equal, a new update will be signaled. + * + */ +public class CheckForUpdates { + + private ArrayList currentReleases; + + public CheckForUpdates() { + currentReleases = new ArrayList(); + currentReleases.add("\"b5.0\""); + currentReleases.add("\"b4.2\""); + currentReleases.add("\"b4.1\""); + currentReleases.add("\"b4.0\""); + currentReleases.add("\"b3.2\""); + currentReleases.add("\"b3.1\""); + currentReleases.add("\"b3.0\""); + currentReleases.add("\"b2.4\""); + currentReleases.add("\"b2.1\""); + currentReleases.add("\"b2.0\""); + currentReleases.add("\"b1.1\""); + currentReleases.add("\"a0.6.2\""); + currentReleases.add("\"a0.5.0\""); + currentReleases.add("\"a-0.4.1\""); + } + + public String checkForUpdates() throws Exception { +// ArrayList releases = new ArrayList(); +// +// //Create HttpURLConnection +// HttpURLConnection httpcon = (HttpURLConnection) new URL("https://api.github.com/repos/narlock/TamoStudy/releases").openConnection(); +// httpcon.addRequestProperty("User-Agent", "Mozilla/5.0"); +// BufferedReader in = new BufferedReader(new InputStreamReader(httpcon.getInputStream())); +// +// //Read line by line +// StringBuilder responseSB = new StringBuilder(); +// String line; +// while ( ( line = in.readLine() ) != null) { +// responseSB.append("\n" + line); +// } +// in.close(); +// +// Arrays.stream(responseSB.toString().split("\"tag_name\":")).skip(1).map(l -> l.split(",")[0]).forEach(l -> releases.add(l)); +// +// if(releases.equals(currentReleases)) { +// return null; +// } else { +// return releases.get(0); +// } + return null; + } +} diff --git a/TamoStudy/src/resources/Constants.java b/TamoStudy/src/resources/Constants.java new file mode 100644 index 0000000..b097cf8 --- /dev/null +++ b/TamoStudy/src/resources/Constants.java @@ -0,0 +1,148 @@ +package resources; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Image; + +import javax.swing.ImageIcon; + +import components.border.BubbleBorder; + +public class Constants { + + public static ImageResourceHandler imageResourceHandler = new ImageResourceHandler(); + + /* + * ################################## + * ################################## + * GENERAL CONSTANTS + * ################################## + * ################################## + */ + public static final String version = "v1.0-Final"; + public static final int ACHIEVEMENT_COUNT = 12; + + /* + * ################################## + * ################################## + * GUI CONSTANTS + * ################################## + * ################################## + */ + + public static final Dimension GUI_FRAME_SIZE = new Dimension(800, 600); + public static final Font SIDE_BUTTON_FONT = new Font("Arial", Font.BOLD, 16); + public static final Font TOP_MENU_FONT = SIDE_BUTTON_FONT; + public static final ImageIcon TOP_MENU_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("TOP_MENU.png")); // 32 x 32 + public static final ImageIcon TAMO_TOKEN_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("TAMO_TOKEN.png")); + public static final int BUTTON_BORDER_RADIUS = 15; + + /* + * ################################## + * ################################## + * DASHBOARD STATE CONSTANTS + * ################################## + * ################################## + */ + + public static final ImageIcon TAMOSTUDY_LOGO_IMAGE = new ImageIcon(Constants.class.getClassLoader().getResource("TAMOSTUDY_LOGO_IMAGE.gif")); + public static final Font STATISTICS_INFO_FONT = new Font("Arial", Font.PLAIN, 16); + public static final Font STATISTICS_INFO_FONT_BOLD = new Font("Arial", Font.BOLD, 16); + public static final Font VERSION_FONT = new Font("Arial", Font.BOLD, 10); + public static final Dimension TAMO_GRAPHICS_PANEL_DIMENSION = new Dimension(215, 315); + public static final Integer BACKGROUND_IMAGE_OFFSET = 8; + public static final ImageIcon HEART_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("HEART.png")); + public static final ImageIcon ONIGIRI_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("ONIGIRI.png")); + + /* + * ################################## + * ################################## + * FOCUS / TIMER STATE CONSTANTS + * ################################## + * ################################## + */ + public static final Font TIMER_FONT = new Font("Arial", Font.BOLD, 96); + public static final Font SUB_TEXT_FONT = new Font("Arial", Font.BOLD, 25); + public static final BubbleBorder TIMER_BORDER = new BubbleBorder(Color.WHITE, 6, 20, 10, true); + + /* + * ################################## + * ################################## + * SHOP CONSTANTS + * ################################## + * ################################## + */ + public static final Font KATH_MESSAGE_FONT = new Font("Arial", Font.PLAIN, 12); + public static final Dimension KATH_SHOP_DIMENSION = new Dimension(400, 267); + public static final Integer KATH_IMAGE_OFFSET = 40; + public static final Dimension KATH_MSG_DIMENSION = new Dimension(400, 130); + public static final ImageIcon LEFT_ARROW_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("ARROW_LEFT.png")); + public static final ImageIcon RIGHT_ARROW_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("ARROW_RIGHT.png")); + + /* + * ################################## + * ################################## + * INVENTORY CONSTANTS + * ################################## + * ################################## + */ + public static final Dimension ITEM_MENU_DIMENSION = new Dimension(32, 32); + + /* + * ################################## + * ################################## + * STATISTICS CONSTANTS + * ################################## + * ################################## + */ + public static final Dimension HOURS_IN_PAST_DIMENSION = new Dimension(540, 150); + public static final ImageIcon GRAY_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("GRAY.png")); + public static final ImageIcon GREEN_1_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("GREEN_1.png")); + public static final ImageIcon GREEN_2_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("GREEN_2.png")); + public static final ImageIcon GREEN_3_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("GREEN_3.png")); + public static final ImageIcon GREEN_4_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("GREEN_4.png")); + + /* + * ################################## + * ################################## + * ACHIEVEMENTS CONSTANTS + * ################################## + * ################################## + */ + public static final Font ACHIEVEMENT_TITLE_LABEL_FONT = new Font("Arial", Font.BOLD, 20); + public static final Font ACHIEVEMENT_DESCRIPTION_LABEL_FONT = new Font("Arial", Font.PLAIN, 12); + public static final Dimension ACHIEVEMENT_SCROLL_PANE_DIMENSION = new Dimension(400, 500); + + /* + * ################################## + * ################################## + * SETTINGS STATE CONSTANTS + * ################################## + * ################################## + */ + public static final ImageIcon DARK_MODE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("DARK_MODE.png")); + public static final ImageIcon LIGHT_MODE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("SUN_MODE.png")); + public static final Font SETTINGS_MESSAGE_LABEL_FONT = new Font("Arial", Font.BOLD, 24); + public static final Font SETTINGS_SETTING_LABEL_FONT = new Font("Arial", Font.BOLD, 16); + public static final Font SETTINGS_CHOICE_FONT = new Font("Arial", Font.PLAIN, 12); + public static final Font SETTINGS_CHOICE_FONT_BOLD = new Font("Arial", Font.BOLD, 12); + public static final int SETTINGS_HORIZONTAL_COMPONENT_DIFFERENCE = 20; + public static final int SETTINGS_VERTICAL_COMPONENT_DIFFERENCE = 10; + public static final ImageIcon MINUS_BUTTON_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("MINUS.png")); + public static final ImageIcon ADD_BUTTON_IMAGE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("ADD.png")); + + /* + * ################################## + * ################################## + * ABOUT STATE CONSTANTS + * ################################## + * ################################## + */ + public static final ImageIcon NARLOCK_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("NARLOCK_ICON.png")); + public static final ImageIcon TAMOSTUDY_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("TAMOSTUDY_ICON.png")); + public static final ImageIcon TWITTER_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("TWITTER_ICON.png")); + public static final ImageIcon YOUTUBE_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("YOUTUBE_ICON.png")); + public static final ImageIcon INSTAGRAM_ICON = new ImageIcon(Constants.class.getClassLoader().getResource("INSTAGRAM_ICON.png")); + +} diff --git a/TamoStudy/src/resources/Debug.java b/TamoStudy/src/resources/Debug.java new file mode 100644 index 0000000..15ae608 --- /dev/null +++ b/TamoStudy/src/resources/Debug.java @@ -0,0 +1,37 @@ +package resources; + +import java.text.SimpleDateFormat; +import java.util.Calendar; + +/** + * Debug + * + * @author narlock + * + * @brief Simple developer debug tool for printing logging messages. + */ +public class Debug { + + private static final boolean on = true; + + public static void info(String location, String message) { + if(on) { + String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); + System.out.println("\u001B[33m" + timeStamp + " [\u001B[37mINFO\u001B[33m] : \u001B[35m" + location + " \u001B[37m: " + message + "\u001B[0m"); + } + } + + public static void error(String location, String message) { + if(on) { + String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); + System.out.println("\u001B[33m" + timeStamp + " [\u001B[31mERROR\u001B[33m] : \u001B[35m" + location + " \u001B[37m: " + message + "\u001B[0m"); + } + } + + public static void warn(String location, String message) { + if(on) { + String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); + System.out.println("\u001B[33m" + timeStamp + " [\u001B[31mWARN\u001B[33m] : \u001B[35m" + location + " \u001B[37m: " + message + "\u001B[0m"); + } + } +} diff --git a/TamoStudy/src/resources/DiscordRP.java b/TamoStudy/src/resources/DiscordRP.java new file mode 100644 index 0000000..04b72c0 --- /dev/null +++ b/TamoStudy/src/resources/DiscordRP.java @@ -0,0 +1,102 @@ +package resources; + +import net.arikia.dev.drpc.DiscordEventHandlers; +import net.arikia.dev.drpc.DiscordRPC; +import net.arikia.dev.drpc.DiscordRichPresence; + +/** + * DiscordRP + * + * @author narlock + * + * @brief Utilizes Discord Rich Presence JAR + * to support Rich Presence for TamoStudy + */ +public class DiscordRP { + private boolean running = true; + private long created = 0; + private DiscordEventHandlers handlers; + + /** + * start + * @brief Initiates Rich Presence + */ + public void start() { + if(System.getProperty("os.name").contains("Windows")) { + Debug.info("DiscordRP.start","started"); + this.created = System.currentTimeMillis(); + + handlers = new DiscordEventHandlers.Builder().setReadyEventHandler((user) -> { + Debug.info("DiscordRP.start", "TamoStudy + Discord Rich Presence ready for " + user.username + "#" + user.discriminator + "!"); + update("Just opened TamoStudy!", ""); + }).build(); + + DiscordRPC.discordInitialize("1056586375484424263", handlers, true); + + new Thread("Discord Rich Presence") { + @Override + public void run() { + while(running) { + DiscordRPC.discordRunCallbacks(); + } + } + }.start(); + } + } + + /** + * start + * @param initialMessage + * @brief Initiates Rich Presence with set initialMessage + */ + public void start(String initialMessage) { + if(System.getProperty("os.name").contains("Windows")) { + Debug.info("DiscordRP.start","started"); + this.created = System.currentTimeMillis(); + + handlers = new DiscordEventHandlers.Builder().setReadyEventHandler((user) -> { + Debug.info("DiscordRP.start", "TamoStudy + Discord Rich Presence ready for " + user.username + "#" + user.discriminator + "!"); + update(initialMessage, ""); + }).build(); + + DiscordRPC.discordInitialize("1056586375484424263", handlers, true); + + new Thread("Discord Rich Presence") { + @Override + public void run() { + while(running) { + DiscordRPC.discordRunCallbacks(); + } + } + }.start(); + } + } + + /** + * shutdown + * @brief shuts down Rich Presence + */ + public void shutdown() { + if(System.getProperty("os.name").contains("Windows")) { + running = false; + DiscordRPC.discordShutdown(); + } + } + + /** + * update + * @brief Updates Rich Presence + * @param firstLine + * @param secondLine + */ + public void update(String firstLine, String secondLine) { + Debug.info("DiscordRP.start", "Updating presence"); + if(System.getProperty("os.name").contains("Windows")) { + DiscordRichPresence.Builder b = new DiscordRichPresence.Builder(secondLine); + b.setBigImage("large", ""); + b.setDetails(firstLine); + b.setStartTimestamps(created); + DiscordRPC.discordUpdatePresence(b.build()); + } + } +} diff --git a/TamoStudy/src/resources/ImageResourceHandler.java b/TamoStudy/src/resources/ImageResourceHandler.java new file mode 100644 index 0000000..2fa6bc6 --- /dev/null +++ b/TamoStudy/src/resources/ImageResourceHandler.java @@ -0,0 +1,31 @@ +package resources; + +import java.awt.Image; +import java.io.IOException; + +import javax.imageio.ImageIO; + +/** + * ImageResourceHandler + * @author narlock + * + */ +public class ImageResourceHandler { + + /** + * + * @param url + * @return + */ + public Image readImageFromUrl(String url) { + Image img; + try { + img = ImageIO.read(getClass().getClassLoader().getResource(url)); + return img; + } catch (IOException e) { + e.printStackTrace(); + } + throw new RuntimeException("Unexpected error occurred at runtime"); + } + +} diff --git a/TamoStudy/src/resources/Items.java b/TamoStudy/src/resources/Items.java new file mode 100644 index 0000000..d6b928c --- /dev/null +++ b/TamoStudy/src/resources/Items.java @@ -0,0 +1,274 @@ +package resources; + +import javax.swing.ImageIcon; + +import model.GuiSize; +import model.language.Language; + +public class Items { + public static String getFoodTitleByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.onigiriText; + case 1: + return language.chickenPlateText; + case 2: + return language.cheesecakeText; + } + throw new RuntimeException("Unknown indicator provided to getFoodTitleByIndicator"); + } + + public static int getFoodHungerByIndicator(int indicator) { + switch(indicator) { + case 0: + return 1; + case 1: + return 3; + case 2: + return 8; + } + throw new RuntimeException("Unknown indicator provided to getFoodHungerByIndicator"); + } + + public static ImageIcon getFoodIconByIndicator(int indicator, GuiSize guiSize) { + switch(indicator) { + case 0: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_1.png"))); + case 1: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_3.png"))); + case 2: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_10.png"))); + } + throw new RuntimeException("Unknown indicator provided to getFoodIconByIndicator"); + } + + public static ImageIcon getFoodInvIconByIndicator(int indicator, GuiSize guiSize) { + switch(indicator) { + case 0: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_1_INV.png"))); + case 1: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_3_INV.png"))); + case 2: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("FOOD_10_INV.png"))); + } + throw new RuntimeException("Unknown indicator provided to getFoodIconByIndicator"); + } + + public static int getFoodPriceByIndicator(int indicator) { + switch(indicator) { + case 0: + return 100; + case 1: + return 200; + case 2: + return 800; + } + throw new RuntimeException("Unknown indicator provided to getFoodPriceByIndicator"); + } + + public static String getFoodDescriptionByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.onigiriDescriptionText; + case 1: + return language.chickenPlateDescriptionText; + case 2: + return language.cheesecakeDescriptionText; + } + throw new RuntimeException("Unknown indicator provided to getFoodDescriptionByIndicator"); + } + + public static String getBackgroundTitleByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.bedroomText; + case 1: + return language.sofaText; + case 2: + return language.sunriseText; + case 3: + return language.nightOutText; + case 4: + return language.enigmaText; + case 5: + return language.cozyNightText; + case 6: + return language.studyTimeText; + case 7: + return language.pleasantBridgeText; + case 8: + return language.wisteriaText; + case 9: + return language.moonText; + } + throw new RuntimeException("Unknown indicator provided to getBackgroundTitleByIndicator"); + } + + public static ImageIcon getBackgroundIconByIndicator(int indicator, GuiSize guiSize) { + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BACKGROUND_" + indicator + "_SHOP.png"))); + } + + public static ImageIcon getBackgroundInvIconByIndicator(int indicator, GuiSize guiSize) { + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BACKGROUND_" + indicator + "_INV.png"))); + } + + public static int getBackgroundPriceByIndicator(int indicator) { + switch(indicator) { + case 0: + case 1: + case 2: + case 3: + case 4: + return 1000; + case 5: + case 6: + case 7: + case 8: + case 9: + return 5000; + } + throw new RuntimeException("Unknown indicator provided to getBackgroundPriceByIndicator"); + } + + public static String getBackgroundDescriptionByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.bedroomDescriptionText; + case 1: + return language.sofaDescriptionText; + case 2: + return language.sunriseDescriptionText; + case 3: + return language.nightOutDescriptionText; + case 4: + return language.enigmaDescriptionText; + case 5: + return language.cozyNightDescriptionText; + case 6: + return language.studyTimeDescriptionText; + case 7: + return language.pleasantBridgeDescriptionText; + case 8: + return language.wisteriaDescriptionText; + case 9: + return language.moonDescriptionText; + } + throw new RuntimeException("Unknown indicator provided to getBackgroundDescriptionByIndicator"); + } + + public static String getBorderTitleByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + return language.blackText; + case 1: + return language.goldText; + case 2: + return language.redText; + case 3: + return language.mintText; + case 4: + return language.purpleText; + case 5: + return language.blueText; + case 6: + return language.strawberryLemonadeText; + case 7: + return language.sunsetText; + case 8: + return language.tealText; + case 9: + return language.codeText; + } + throw new RuntimeException("Unknown indicator provided to getBorderTitleByIndicator"); + } + + public static ImageIcon getBorderIconByIndicator(int indicator, GuiSize guiSize) { + switch(indicator) { + case 0: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_BLACK_SHOP.png"))); + case 1: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_GOLD_SHOP.png"))); + case 2: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_RED_SHOP.png"))); + case 3: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_MINT_SHOP.png"))); + case 4: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_PURPLE_SHOP.png"))); + case 5: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_BLUE_SHOP.png"))); + case 6: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_STRAWLEMON_SHOP.png"))); + case 7: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_SUNSET_SHOP.png"))); + case 8: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_TEAL_SHOP.png"))); + case 9: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_CODE_SHOP.png"))); + } + throw new RuntimeException("Unknown indicator provided to getBorderIconByIndicator"); + } + + public static ImageIcon getBorderInvIconByIndicator(int indicator, GuiSize guiSize) { + switch(indicator) { + case 0: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_BLACK_INV.png"))); + case 1: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_GOLD_INV.png"))); + case 2: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_RED_INV.png"))); + case 3: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_MINT_INV.png"))); + case 4: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_PURPLE_INV.png"))); + case 5: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_BLUE_INV.png"))); + case 6: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_STRAWLEMON_INV.png"))); + case 7: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_SUNSET_INV.png"))); + case 8: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_TEAL_INV.png"))); + case 9: + return guiSize.scaleImageIcon(new ImageIcon(Items.class.getClassLoader().getResource("BORDER_CODE_INV.png"))); + } + throw new RuntimeException("Unknown indicator provided to getBorderIconByIndicator"); + } + + public static int getBorderPriceByIndicator(int indicator) { + switch(indicator) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + return 750; + case 6: + case 7: + case 8: + return 1250; + case 9: + return 800; + } + throw new RuntimeException("Unknown indicator provided to getBorderPriceByIndicator"); + } + + public static String getBorderDescriptionByIndicator(int indicator, Language language) { + switch(indicator) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + return language.solidBackgroundText; + case 6: + case 7: + case 8: + return language.gradientBackgroundText; + case 9: + return language.themedBackgroundText; + } + throw new RuntimeException("Unknown indicator provided to getBorderDescriptionByIndicator"); + } +} diff --git a/TamoStudy/src/resources/Theme.java b/TamoStudy/src/resources/Theme.java new file mode 100644 index 0000000..16d179d --- /dev/null +++ b/TamoStudy/src/resources/Theme.java @@ -0,0 +1,502 @@ +package resources; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JButton; + +import components.border.BubbleBorder; +import model.GuiSize; + +/** + * @author Anthony Narlock (narlock) + * @brief Theme, contains information about the Colors for current Theme + */ + +public class Theme { + + /** + * Theme attributes + */ + public Color mainColor; + public Color subColor; + public Color layerColor; + public Color textColor; + public Color layerTextColor; + public Color altTextColor; + public Color selectedTextColor; + + public Color timerColor; + + public final Font fontPlainReg = new Font("Arial", Font.PLAIN, 24); + public final Font fontBoldReg = new Font("Arial", Font.BOLD, 24); + public final Font fontBoldRegSmall = new Font("Arial", Font.BOLD, 18); + public final Font fontBoldRegLarge = new Font("Arial", Font.BOLD, 60); + + public String type; + + public Theme(int indicator) { + + //TODO need to add + // selectedTextColor + // altTextColor to other themes + + switch (indicator) { + case 0: + mainColor = new Color(64,64,64); + subColor = new Color(78,78,78); + layerColor = new Color(108, 108, 108); + textColor = Color.WHITE; + layerTextColor = new Color(153,153,153); + altTextColor = new Color(87, 87, 87); + selectedTextColor = new Color(244, 140, 6); + timerColor = Color.BLACK; + type = "Dark"; + break; + case 1: + mainColor = new Color(220,220,220); + subColor = new Color(240,240,240); + layerColor = Color.WHITE; + textColor = new Color(64,64,64); + layerTextColor = Color.BLACK; + altTextColor = new Color(87, 87, 87); + selectedTextColor = new Color(244, 140, 6); + timerColor = Color.WHITE; + type = "Light"; + break; + case 2: + mainColor = new Color(255,143,143); + subColor = new Color(255,161,161); + layerColor = new Color(255,120,120); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Red"; + break; + case 3: + mainColor = new Color(143,143,255); + subColor = new Color(161,161,255); + layerColor = new Color(120,120,255); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Blue"; + break; + case 4: + mainColor = new Color(143,255,143); + subColor = new Color(161,255,161); + layerColor = new Color(120,255,120); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Green"; + break; + case 5: + mainColor = new Color(255,225,143); + subColor = new Color(255,255,161); + layerColor = new Color(255,255,120); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Yellow"; + break; + case 6: + mainColor = new Color(255,219,143); + subColor = new Color(255,219,161); + layerColor = new Color(255,219,120); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Orange"; + break; + case 7: + mainColor = new Color(236,143,255); + subColor = new Color(236,161,255); + layerColor = new Color(236,120,255); + textColor = Color.BLACK; + layerTextColor = new Color(64,64,64); + type = "Purple"; + break; + default: + mainColor = new Color(64,64,64); + subColor = new Color(78,78,78); + layerColor = new Color(108, 108, 108); + textColor = Color.WHITE; + layerTextColor = new Color(153,153,153); + type = "Dark"; + break; + } + } + + public static final Theme DARK = new Theme(0); + public static final Theme LIGHT = new Theme(1); + + public static Theme getTheme(String themeString) { + if(themeString.equals("Dark")) { + return DARK; + } else if(themeString.equals("Light")) { + return LIGHT; + } else return DARK; + } + + public boolean checkEqualityWith(Theme other) { + return this.mainColor.equals(other.mainColor); + } + + public static final BubbleBorder SUB_BORDER = new BubbleBorder(Color.WHITE, 2, 15, 0); + + public static final Color PRIMARY = new Color(41, 128, 185); + public static final Color PRIMARY_ALT = new Color(29, 89, 130); + public static final BubbleBorder PRIMARY_BORDER = new BubbleBorder(PRIMARY, 0, 15, 0); + + public static final Color PRIMARY_DISABLED = new Color(164, 189, 206); + public static final BubbleBorder PRIMARY_DISABLED_BORDER = new BubbleBorder(PRIMARY_DISABLED, 0, 15, 0); + + public static final Color SECONDARY = new Color(128, 128, 128); + public static final Color SECONDARY_ALT = new Color(96, 96, 96); + public static final BubbleBorder SECONDARY_BORDER = new BubbleBorder(SECONDARY, 0, 15, 0); + + public static final Color SUCCESS = new Color(40, 167, 69); + public static final Color SUCCESS_ALT = new Color(24, 99, 42); + public static final BubbleBorder SUCCESS_BORDER = new BubbleBorder(SUCCESS, 0, 15, 0); + + public static final Color DANGER = new Color(220,53,69); + public static final Color DANGER_ALT = new Color(148, 35, 46); + public static final BubbleBorder DANGER_BORDER = new BubbleBorder(DANGER, 0, 15, 0); + + public static final BubbleBorder subBorder = new BubbleBorder(Color.WHITE, 3, 15, 0); + public static final BubbleBorder settingsBlackBorder = new BubbleBorder(Color.BLACK, 3, 15, 0); + + /** + * primaryVisualButton + * @param button + */ + public static void primaryVisualButton(JButton button) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(PRIMARY_BORDER); + button.setBackground(PRIMARY); + button.setForeground(Color.WHITE); + button.setFont(new Font("Arial", Font.BOLD, 18)); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.PRIMARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.PRIMARY); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * primaryVisualButton + * @param button + * @param font + */ + public static void primaryVisualButton(JButton button, GuiSize guiSize) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(new BubbleBorder(PRIMARY, 0, guiSize.buttonBorderRadius, 0)); + button.setBackground(PRIMARY); + button.setForeground(Color.WHITE); + button.setFont(guiSize.settingsChoiceBoldFont); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.PRIMARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.PRIMARY); + button.setForeground(Color.WHITE); + } + + }); + } + + public static void primaryDisabledVisualButton(JButton button) { + button.setEnabled(false); + button.setOpaque(true); + button.setBorder(PRIMARY_DISABLED_BORDER); + button.setBackground(PRIMARY_DISABLED); + button.setForeground(new Color(164, 189, 206)); + button.setFont(new Font("Arial", Font.BOLD, 18)); + } + + /** + * secondaryVisualButton + * @param button + */ + public static void secondaryVisualButton(JButton button) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(SECONDARY_BORDER); + button.setBackground(SECONDARY); + button.setForeground(Color.WHITE); + button.setFont(new Font("Arial", Font.BOLD, 18)); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.SECONDARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.SECONDARY); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * secondaryVisualButton + * @param button + * @param font + */ + public static void secondaryVisualButton(JButton button, GuiSize guiSize) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(new BubbleBorder(SECONDARY, 0, guiSize.buttonBorderRadius, 0)); + button.setBackground(SECONDARY); + button.setForeground(Color.WHITE); + button.setFont(guiSize.settingsChoiceBoldFont); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.SECONDARY_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.SECONDARY); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * successVisualButton + * @param button + */ + public static void successVisualButton(JButton button) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(SUCCESS_BORDER); + button.setBackground(SUCCESS); + button.setForeground(Color.WHITE); + button.setFont(new Font("Arial", Font.BOLD, 18)); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.SUCCESS_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.SUCCESS); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * successVisualButton + * @param button + * @param font + */ + public static void successVisualButton(JButton button, GuiSize guiSize) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(new BubbleBorder(SUCCESS, 0, guiSize.buttonBorderRadius, 0)); + button.setBackground(SUCCESS); + button.setForeground(Color.WHITE); + button.setFont(guiSize.settingsChoiceBoldFont); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.SUCCESS_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.SUCCESS); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * dangerVisualButton + * @param button + */ + public static void dangerVisualButton(JButton button) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(DANGER_BORDER); + button.setBackground(DANGER); + button.setForeground(Color.WHITE); + button.setFont(new Font("Arial", Font.BOLD, 18)); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.DANGER_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.DANGER); + button.setForeground(Color.WHITE); + } + + }); + } + + /** + * dangerVisualButton + * @param button + * @param font + */ + public static void dangerVisualButton(JButton button, Font font) { + button.setEnabled(true); + button.setOpaque(true); + button.setBorder(DANGER_BORDER); + button.setBackground(DANGER); + button.setForeground(Color.WHITE); + button.setFont(font); + + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + button.setBackground(Theme.DANGER_ALT); + button.setForeground(new Color(191, 191, 191)); + } + + @Override + public void mouseExited(MouseEvent e) { + button.setBackground(Theme.DANGER); + button.setForeground(Color.WHITE); + } + + }); + } + + public void buttonLayerEnterEffect(JButton button) { + button.addMouseListener(new MouseListener() { + + @Override + public void mouseClicked(MouseEvent e) {} + @Override + public void mousePressed(MouseEvent e) {} + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) { + if(button.isEnabled()) { + button.setForeground(layerTextColor); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if(button.isEnabled()) { + button.setForeground(textColor); + } + + } + + }); + } + + public static void labelButton(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setFocusPainted(false); + button.setBorderPainted(false); + } +} diff --git a/TamoStudy/src/state/AboutState.java b/TamoStudy/src/state/AboutState.java new file mode 100644 index 0000000..cf17107 --- /dev/null +++ b/TamoStudy/src/state/AboutState.java @@ -0,0 +1,192 @@ +package state; + +import java.awt.Desktop; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.URL; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import resources.Constants; +import resources.Theme; + +public class AboutState extends State { + + private static final long serialVersionUID = 353696047710911712L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GuiSize guiSize; + private Language language; + private Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JLabel tamoStudyImageLabel; + private JLabel versionLabel; + + private JPanel aboutTamoStudyPanel; + private JLabel aboutTamoStudyLabel; + + private JPanel socialMediaPanel; + private JButton narlockWebsiteButton; + private JButton tamoStudyWebsiteButton; + private JButton youtubeButton; + private JButton twitterButton; + private JButton instagramButton; + + public AboutState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + + } + + @Override + protected void initializeAttributes() { + this.guiSize = tsGui.getGuiSize(); + this.language = tsGui.getProfile().getSettings().getLanguage(); + this.theme = tsGui.getTheme(); + } + + @Override + protected void initializeComponents() { + tamoStudyImageLabel = new JLabel(guiSize.getTamoStudyLogoImage()); + versionLabel = new JLabel(Constants.version); + + aboutTamoStudyPanel = new JPanel(); + aboutTamoStudyLabel = new JLabel(language.aboutTamoStudyText); + + socialMediaPanel = new JPanel(); + narlockWebsiteButton = new JButton(guiSize.narlockIcon); + tamoStudyWebsiteButton = new JButton(guiSize.tamoStudyIcon); + youtubeButton = new JButton(guiSize.youtubeIcon); + twitterButton = new JButton(guiSize.twitterIcon); + instagramButton = new JButton(guiSize.instagramIcon); + } + + @Override + protected void initializeComponentVisuals() { + versionLabel.setFont(guiSize.achievementTitleLabelFont); + versionLabel.setForeground(theme.textColor); + + aboutTamoStudyPanel.add(aboutTamoStudyLabel); + aboutTamoStudyPanel.setBackground(theme.mainColor); + aboutTamoStudyPanel.setBorder(guiSize.messageBorder); + + aboutTamoStudyLabel.setForeground(theme.textColor); + + socialMediaPanel.setBackground(theme.subColor); + addButtonVisual(narlockWebsiteButton); + addButtonVisual(tamoStudyWebsiteButton); + addButtonVisual(youtubeButton); + addButtonVisual(twitterButton); + addButtonVisual(instagramButton); +// socialMediaPanel.add(narlockWebsiteButton); +// socialMediaPanel.add(tamoStudyWebsiteButton); + socialMediaPanel.add(youtubeButton); + socialMediaPanel.add(twitterButton); + socialMediaPanel.add(instagramButton); + } + + @Override + protected void initializeComponentActions() { + narlockWebsiteButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://narlock.github.io/narlock").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + + tamoStudyWebsiteButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://tamostudy.com/").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + + youtubeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://youtube.com/narlock").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + + twitterButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://twitter.com/narlockdev").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + + instagramButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { Desktop.getDesktop().browse(new URL("https://instagram.com/narlockdev").toURI()); } + catch (Exception e1) { e1.printStackTrace(); } + } + + }); + } + + @Override + protected void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + this.setLayout(new GridBagLayout()); + this.add(tamoStudyImageLabel, gbcv); + this.add(versionLabel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(aboutTamoStudyPanel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(socialMediaPanel, gbcv); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public void addButtonVisual(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setBorderPainted(false); + button.setFocusPainted(false); + } +} diff --git a/TamoStudy/src/state/AchievementsState.java b/TamoStudy/src/state/AchievementsState.java new file mode 100644 index 0000000..692cbbc --- /dev/null +++ b/TamoStudy/src/state/AchievementsState.java @@ -0,0 +1,106 @@ +package state; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; + +import components.panel.AchievementPanel; +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import resources.Constants; +import resources.Theme; + +public class AchievementsState extends State { + + private static final long serialVersionUID = -7353342192190711969L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GuiSize guiSize; + private Language language; + private Profile profile; + private Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JScrollPane scrollPane; + private JPanel achievementsPanel; + + public AchievementsState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + guiSize = tsGui.getGuiSize(); + profile = tsGui.getProfile(); + language = profile.getSettings().getLanguage(); + theme = profile.getSettings().getTheme(); + + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + + } + + @Override + protected void initializeComponents() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + gbcv.anchor = GridBagConstraints.WEST; + + achievementsPanel = new JPanel(new GridBagLayout()); + achievementsPanel.setBackground(theme.mainColor); + for(int i = 0; i < Constants.ACHIEVEMENT_COUNT; i++) { + boolean earned = false; + if(profile.getAchievementList().contains((long) i)) { + earned = true; + } + achievementsPanel.add(new AchievementPanel(theme, guiSize, language, i, earned), gbcv); + } + scrollPane = new JScrollPane(achievementsPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.getVerticalScrollBar().setUnitIncrement(16); + scrollPane.setPreferredSize(guiSize.achievementScrollPaneDimension); + scrollPane.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2)); + } + + @Override + protected void initializeComponentVisuals() { + // TODO Auto-generated method stub + + } + + @Override + protected void initializeComponentActions() { + // TODO Auto-generated method stub + + } + + @Override + protected void initializePanel() { + // TODO Auto-generated method stub + this.add(scrollPane); + } + +} diff --git a/TamoStudy/src/state/DashboardState.java b/TamoStudy/src/state/DashboardState.java new file mode 100644 index 0000000..cab939a --- /dev/null +++ b/TamoStudy/src/state/DashboardState.java @@ -0,0 +1,230 @@ +package state; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.plaf.basic.BasicProgressBarUI; + +import components.panel.TamoGraphicsPanel; +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import model.profile.Tamo; +import model.time.DailyFocusEntry; +import model.time.MonthFocusEntry; +import resources.Constants; +import resources.Theme; +import util.Utils; + +public class DashboardState extends State { + + private static final long serialVersionUID = -774794028854162351L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Profile profile; + private Language language; + private GuiSize guiSize; + private Tamo tamo; + private Theme theme; + private DailyFocusEntry dailyFocusEntry; + private MonthFocusEntry monthFocusEntry; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JLabel tamoStudyLogoImageLabel; + private JLabel versionLabel; + private JPanel tamoDashboardPanel; // Grid Panel + private TamoGraphicsPanel tamoGraphicsPanel; // LHS + private JPanel tamoInfoPanel; // RHS + private JLabel tamoNameLabel; + private JLabel tamoHappyLabel; + private JLabel tamoHungerLabel; + private JLabel tamoHoursTodayLabel; + private JLabel tamoHoursMonthLabel; + private JLabel tamoHoursAllLabel; + private JLabel tamoLevelLabel; + private JProgressBar levelProgressBar; + + public DashboardState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + profile = tsGui.getProfile(); + language = tsGui.getProfile().getSettings().getLanguage(); + guiSize = new GuiSize((int) profile.getSettings().getGuiSize()); + tamo = profile.getTamo(); + theme = profile.getSettings().getTheme(); + + this.dailyFocusEntry = Utils.searchTodayFocusEntryByProfile(tsGui.getDailyFocus().getDailyFocusEntries()); + // Create new daily focus entry if it does not exist + if(dailyFocusEntry == null) { + dailyFocusEntry = Utils.createDailyFocusEntry(); + tsGui.addNewDailyFocusEntryToDailyFocus(dailyFocusEntry); + tsGui.getDailyFocusJsonManager().writeJsonToFile(tsGui.getDailyFocusList()); + } + + this.monthFocusEntry = Utils.searchCurrentMonthEntryByProfile(tsGui.getMonthFocus().getMonthFocusEntries()); + // Create new month focus entry if it does not exist + if(monthFocusEntry == null) { + monthFocusEntry = Utils.createMonthFocusEntry(); + tsGui.addNewMonthFocusEntryToMonthFocus(monthFocusEntry); + tsGui.getMonthFocusJsonManager().writeJsonToFile(tsGui.getMonthFocusList()); + } + } + + @Override + protected void initializeComponents() { + tamoStudyLogoImageLabel = new JLabel(guiSize.getTamoStudyLogoImage()); + versionLabel = new JLabel(Constants.version); + + tamoDashboardPanel = new JPanel(); + tamoGraphicsPanel = new TamoGraphicsPanel(guiSize, tamo, profile.getBackgroundIndicator(), profile.getBorderIndicator()); + + tamoInfoPanel = new JPanel(new GridBagLayout()); + tamoNameLabel = new JLabel(tamo.getName()); + tamoHappyLabel = new JLabel("" + tamo.getHappy()); + tamoHungerLabel = new JLabel("" + tamo.getHunger()); + tamoHoursTodayLabel = new JLabel(language.todaysFocusText + ": " + Utils.convertSecondsToHours(dailyFocusEntry.getTime()) + " " + language.hoursText); + tamoHoursMonthLabel = new JLabel(language.monthFocusText + ": " + Utils.convertSecondsToHours(monthFocusEntry.getTime()) + " " + language.hoursText); + tamoHoursAllLabel = new JLabel(language.totalFocusText + ": " + Utils.convertSecondsToHours(profile.getTime()) + " " + language.hoursText); + tamoLevelLabel = new JLabel(language.levelText + " " + tamo.getLevel()); + levelProgressBar = new JProgressBar(0, 100); + + } + + @Override + protected void initializeComponentVisuals() { + versionLabel.setFont(guiSize.versionFont); + versionLabel.setForeground(theme.layerTextColor); + + tamoDashboardPanel.setBackground(theme.subColor); + tamoInfoPanel.setBackground(theme.subColor); + + tamoNameLabel.setFont(guiSize.messageLabelFont); + tamoNameLabel.setForeground(theme.textColor); + + tamoHappyLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHappyLabel.setForeground(theme.textColor); + tamoHappyLabel.setIcon(guiSize.heartImageIcon); + + tamoHungerLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHungerLabel.setForeground(theme.textColor); + tamoHungerLabel.setIcon(guiSize.onigiriImageIcon); + + tamoHoursAllLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursAllLabel.setForeground(theme.textColor); + tamoHoursMonthLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursMonthLabel.setForeground(theme.textColor); + tamoHoursTodayLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursTodayLabel.setForeground(theme.textColor); + + tamoLevelLabel.setFont(guiSize.statisticsInfoFontBold); + tamoLevelLabel.setForeground(theme.textColor); + + levelProgressBar.setOpaque(true); + levelProgressBar.setFont(guiSize.statisticsInfoFont); + levelProgressBar.setForeground(Theme.SUCCESS); + levelProgressBar.setBackground(theme.mainColor); + levelProgressBar.setBorder(BorderFactory.createLineBorder(theme.textColor, 1)); + levelProgressBar.setUI(new BasicProgressBarUI() { + protected Color getSelectionBackground() { + return Color.WHITE; // set the color of the progress bar + } + protected Color getSelectionForeground() { + return Color.BLACK; // set the color of the text on the progress bar + } + }); + levelProgressBar.setStringPainted(true); + levelProgressBar.setValue(tamo.levelProgress()); + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + tamoInfoPanel.add(tamoNameLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoHappyLabel, gbcv); + tamoInfoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoInfoPanel.add(tamoHungerLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoHoursTodayLabel, gbcv); + tamoInfoPanel.add(tamoHoursMonthLabel, gbcv); + tamoInfoPanel.add(tamoHoursAllLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoLevelLabel, gbcv); + tamoInfoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoInfoPanel.add(levelProgressBar, gbcv); + + + tamoDashboardPanel.add(tamoGraphicsPanel); + tamoDashboardPanel.add(tamoInfoPanel); + } + + @Override + protected void initializeComponentActions() { + // No actions in Dash board state + } + + @Override + protected void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + this.setLayout(new GridBagLayout()); + + // TODO Re-scale the image for small window and then get rid of this + if(guiSize.index != 0) { + this.add(tamoStudyLogoImageLabel, gbcv); + } + + this.add(tamoDashboardPanel, gbcv); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + + public JLabel createSpaceLabel() { + String DIVIDER = (System.getProperty("os.name").startsWith("Linux") || System.getProperty("os.name").startsWith("Windows")) + ? "────────────" : "━━━━━━━"; + + JLabel label = new JLabel(DIVIDER); + label.setFont(guiSize.topMenuFont); + label.setForeground(theme.altTextColor); + return label; + } + +} diff --git a/TamoStudy/src/state/FocusState.java b/TamoStudy/src/state/FocusState.java new file mode 100644 index 0000000..61dee25 --- /dev/null +++ b/TamoStudy/src/state/FocusState.java @@ -0,0 +1,818 @@ +package state; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.URL; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.FloatControl; +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.Timer; + +import components.panel.SetPanel; +import components.panel.TamoGraphicsPanel; +import components.panel.TimerPanel; +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import model.profile.Tamo; +import model.time.DailyFocusEntry; +import model.time.MonthFocusEntry; +import resources.Achievements; +import resources.Debug; +import resources.Theme; +import util.Utils; + +public class FocusState extends State { + + private static final long serialVersionUID = -3878552282431644324L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Profile profile; + private Language language; + private GuiSize guiSize; + private Tamo tamo; + private Theme theme; + private DailyFocusEntry dailyFocusEntry; + private MonthFocusEntry monthFocusEntry; + + private Timer timer; + private int sessionsRemaining; + private Timer pauseTimer; + private int timerPauseIndicator; + private int stopwatchCycleCount; + + /** + * Indicator for what time to use during pomodoro countdown timers. + * 0 : Pomodoro Session Length + * 1 : Pomodoro Break Length + * 2 : Pomodoro Long Break Length + */ + private int sessionTimeIndicator; + private int tempSec, tempMin, sec, min; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + + // Side 1 + private JPanel tamoPanel; + + private JLabel tamoNameLabel; + private TamoGraphicsPanel tamoGraphicsPanel; + private JPanel tamoHappyHungerPanel; + private JLabel tamoHappyLabel; + private JLabel tamoHungerLabel; + + // Side 2 + private JPanel timerSetPanel; + private TimerPanel timerPanel; + private SetPanel setPanel; + private JPanel buttonPanel; + private JButton startFocusButton, breakFocusButton, pauseFocusButton; + + public FocusState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + profile = tsGui.getProfile(); + language = tsGui.getProfile().getSettings().getLanguage(); + guiSize = new GuiSize((int) profile.getSettings().getGuiSize()); + tamo = profile.getTamo(); + theme = profile.getSettings().getTheme(); + + this.dailyFocusEntry = Utils.searchTodayFocusEntryByProfile(tsGui.getDailyFocus().getDailyFocusEntries()); + // Create new daily focus entry if it does not exist + if(dailyFocusEntry == null) { + dailyFocusEntry = Utils.createDailyFocusEntry(); + tsGui.addNewDailyFocusEntryToDailyFocus(dailyFocusEntry); + tsGui.getDailyFocusJsonManager().writeJsonToFile(tsGui.getDailyFocusList()); + } + + this.monthFocusEntry = Utils.searchCurrentMonthEntryByProfile(tsGui.getMonthFocus().getMonthFocusEntries()); + // Create new month focus entry if it does not exist + if(monthFocusEntry == null) { + monthFocusEntry = Utils.createMonthFocusEntry(); + tsGui.addNewMonthFocusEntryToMonthFocus(monthFocusEntry); + tsGui.getMonthFocusJsonManager().writeJsonToFile(tsGui.getMonthFocusList()); + } + } + + @Override + protected void initializeComponents() { + tamoPanel = new JPanel(new GridBagLayout()); + tamoNameLabel = new JLabel(tamo.getName()); + tamoGraphicsPanel = new TamoGraphicsPanel(guiSize, tamo, profile.getBackgroundIndicator(), profile.getBorderIndicator()); + tamoHappyHungerPanel = new JPanel(); + tamoHappyLabel = new JLabel("" + tamo.getHappy()); + tamoHungerLabel = new JLabel("" + tamo.getHunger()); + + timerSetPanel = new JPanel(new GridBagLayout()); + timerPanel = new TimerPanel(profile); + setPanel = new SetPanel(theme, timerPanel, profile.getSettings().getFocusMode(), language); + buttonPanel = new JPanel(); + startFocusButton = new JButton(language.startFocusText); + breakFocusButton = new JButton(language.breakFocusText); + pauseFocusButton = new JButton(language.pauseFocusText); + } + + @Override + protected void initializeComponentVisuals() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + // Tamo Panel + tamoPanel.setBackground(theme.subColor); + + tamoNameLabel.setFont(guiSize.messageLabelFont); + tamoNameLabel.setForeground(theme.textColor); + + tamoHappyHungerPanel.setBackground(theme.subColor); + + tamoHappyLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHappyLabel.setForeground(theme.textColor); + tamoHappyLabel.setIcon(guiSize.heartImageIcon); + + tamoHungerLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHungerLabel.setForeground(theme.textColor); + tamoHungerLabel.setIcon(guiSize.onigiriImageIcon); + + tamoHappyHungerPanel.add(tamoHappyLabel); + tamoHappyHungerPanel.add(tamoHungerLabel); + + tamoPanel.add(tamoNameLabel, gbcv); + tamoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoPanel.add(tamoGraphicsPanel, gbcv); + tamoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoPanel.add(tamoHappyHungerPanel, gbcv); + + // Timer Set Panel + startFocusButton.setBackground(Theme.SUCCESS); + startFocusButton.setFont(theme.fontBoldRegSmall); + startFocusButton = guiSize.scaleSuccessJButton(startFocusButton, guiSize.getScaleFromSize((int) profile.getSettings().getGuiSize())); + + breakFocusButton.setBackground(Theme.DANGER); + breakFocusButton.setFont(theme.fontBoldRegSmall); + breakFocusButton = guiSize.scaleDangerJButton(breakFocusButton, guiSize.getScaleFromSize((int) profile.getSettings().getGuiSize())); + breakFocusButton.setEnabled(false); + breakFocusButton.setBackground(Theme.DANGER_ALT); + breakFocusButton.setForeground(new Color(191, 191, 191)); + + pauseFocusButton.setBackground(Theme.PRIMARY); + pauseFocusButton.setFont(theme.fontBoldRegSmall); + pauseFocusButton = guiSize.scalePrimaryJButton(pauseFocusButton, guiSize.getScaleFromSize((int) profile.getSettings().getGuiSize())); + pauseFocusButton.setEnabled(false); + pauseFocusButton.setBackground(Theme.PRIMARY_ALT); + pauseFocusButton.setForeground(new Color(191, 191, 191)); + + buttonPanel.setBackground(theme.subColor); + buttonPanel.add(startFocusButton); + buttonPanel.add(breakFocusButton); + buttonPanel.add(pauseFocusButton); + + timerSetPanel.setBackground(theme.subColor); + timerSetPanel.add(timerPanel, gbcv); + + if(profile.getSettings().getFocusMode() != 3) { + timerSetPanel.add(setPanel, gbcv); + } + + timerSetPanel.add(buttonPanel, gbcv); + } + + @Override + protected void initializeComponentActions() { + startFocusButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + //Update Timer Information + updateTimerInformation(); + + //Set Information, TamoImage, study/Temp Min/Sec + setFocusInformation(); + + //Disable Buttons + toggleButtons(false); + + //Create Timer + if(profile.getSettings().getFocusMode() != 3) { + createTimer(); + } else { + createStopwatch(); + } + + } + + }); + + breakFocusButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(profile.getSettings().getFocusMode() != 3) { + // Lose 2 happiness points when focus is broken + tsGui.getProfileUpdateManager().updateHappyOnEvent(2); + + // Update happiness label + tamoHappyLabel.setText("" + tamo.getHappy()); + + // Update focus stats + updateFocusStatistics(); + + sessionsRemaining = 0; // Reset pomdoro - no sessions remaining + sessionTimeIndicator = 0; // Reset time indicator - will start on focus time + + String studyMessage = language.youFocusedForText + " " + tempMin + " " + language.minutesAndText + " " + tempSec + " " + language.secondsPeriodText; + + // Reset counting variables + tempMin = 0; + tempSec = 0; + + timer.stop(); + resetTimer(); + + JOptionPane.showMessageDialog(getRootPane(), studyMessage, language.focusBrokeText, JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } else { + String studyMessage = language.youFocusedForText + " " + tempMin + " " + language.minutesAndText + " " + tempSec + " " + language.secondsPeriodText; + + // Update focus statistics + updateFocusStatistics(); + + // Reset counting variables + tempMin = 0; + tempSec = 0; + + timer.stop(); + resetTimer(); + + JOptionPane.showMessageDialog(getRootPane(), studyMessage, language.focusBrokeText, JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } + + } + }); + + pauseFocusButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + pauseResumeTimer(); + } + }); + } + + @Override + protected void initializePanel() { + this.setLayout(new GridLayout(1, 2)); + this.setBackground(theme.subColor); + this.add(tamoPanel); + this.add(timerSetPanel); + } + + /* + * ################################## + * ################################## + * TIMER ACTIONS + * ################################## + * ################################## + */ + public void updateTimerInformation() { + switch((int) profile.getSettings().getFocusMode()) { + case 0: + // Set Timer based on Pomodoro setting + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(3)); + sessionsRemaining = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + break; + case 1: + // Custom Countdown + timerPanel.minuteTimeLabel.setText(((String) setPanel.customMinuteLengthBox.getSelectedItem())); + timerPanel.secondTimeLabel.setText(((String) setPanel.customSecondLengthBox.getSelectedItem())); + sessionsRemaining = 0; + break; + case 2: + // Five Min Interval Countdown + timerPanel.minuteTimeLabel.setText(((String) setPanel.fiveLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.fiveLengthBox.getSelectedItem()).substring(3)); + sessionsRemaining = 0; + break; + case 3: + // Stopwatch + timerPanel.minuteTimeLabel.setText("00"); + timerPanel.secondTimeLabel.setText("00"); + stopwatchCycleCount = 0; + break; + case 4: + // Pomodoro with Long Breaks + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(3)); + sessionsRemaining = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + break; + default: + // Pomodoro + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(3)); + sessionsRemaining = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + break; + } + pauseFocusButton.setText(language.pauseFocusText); + timerPanel.subTextLabel.setText(language.letsFocusText); + } + + public void setFocusInformation() { + // Set timer attributes + min = Integer.parseInt(timerPanel.minuteTimeLabel.getText()); + sec = Integer.parseInt(timerPanel.secondTimeLabel.getText()); + tempSec = 0; + tempMin = 0; + + // Set Tamo Image To Focus + tamoGraphicsPanel.getTamo().setFocused(true); + tamoGraphicsPanel.repaint(); + } + + public void createTimer() { + Debug.info("FocusState.createTimer", "Starting focus timer..."); + + sessionTimeIndicator = 0; // Ensure in focus mode + if(profile.getSettings().getFocusMode() == 0 || profile.getSettings().getFocusMode() == 4) { + int numOfSessions = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + timerPanel.subTextLabel.setText(language.focusText + " " + ((numOfSessions - sessionsRemaining) + 1) + "/" + numOfSessions); + } + + // Initialize Timer to subtract a second such that time focused is accurate + if(sec == 0 && min > 0) { + sec = 60; + min--; + } + + if(sec != 0) { + sec--; + if(sec < 10) { + timerPanel.secondTimeLabel.setText("0" + sec); + } + else { + timerPanel.secondTimeLabel.setText("" + sec); + } + if(min < 10) { + timerPanel.minuteTimeLabel.setText("0" + min); + } + else { + timerPanel.minuteTimeLabel.setText("" + min); + } + } + + // Begin the count down timer + timer = new Timer(1000, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + //Set how long studied for variables + tempSec = tempSec + 1; + + if(tempSec == 60) { + tempMin = tempMin + 1; + tempSec = 0; + } + + if(sec == 0) { + sec = 60; + min--; + } + + //Timer Completed + if(min < 0) { + + // Update statistics + updateFocusStatistics(); + + String studyMessage = language.youFocusedForText + " " + tempMin + " " + language.minutesAndText + " " + tempSec + " " + language.secondsPeriodText; + if(sessionTimeIndicator != 0) { + studyMessage = language.breakOverText; + } + + // Reset counting variables + tempMin = 0; + tempSec = 0; + + if(profile.getSettings().getTimerAlarm() >= 1) { // If user has a sound clip + + try { + //Get the url for the sound clip + String soundPath = profile.getSettings().getSoundPath(); + + URL url = this.getClass().getClassLoader().getResource(soundPath); + AudioInputStream audioIn = AudioSystem.getAudioInputStream(url); + + //get the clip from the url + Clip clip = AudioSystem.getClip(); + clip.open(audioIn); + + //volume control - make the sound quieter + FloatControl volume = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + volume.setValue(-1 * 20); + + //start and loop the clip + clip.start(); + clip.loop(Clip.LOOP_CONTINUOUSLY); + + //loop will end when user hits ok dialog + JOptionPane.showMessageDialog(getRootPane(), studyMessage, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + clip.stop(); + + } catch (Exception ex) { + /* + * Under the condition that the user has a set timer alarm, but an exception + * occurs, TamoStudy will proceed as if there was no alarm set. + */ + JOptionPane.showMessageDialog(getRootPane(), studyMessage, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } + + } else { + /* + * Under the condition that there is no timer alarm set + */ + JOptionPane.showMessageDialog(getRootPane(), studyMessage, "TamoStudy", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(getClass().getClassLoader().getResource("INFO.png"))); + } + + // Go to next session or break - POMODORO ONLY + if(sessionsRemaining > 1) { + // Currently finished focus session + if(sessionTimeIndicator == 0) { + int numOfSessions = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + Debug.info("FocusState.timer.actionPerformed", "Focus session " + ((numOfSessions - sessionsRemaining) + 1) + "/" + numOfSessions + " completed."); + sessionTimeIndicator = 1; // Break time + timerPanel.subTextLabel.setText(language.breakText + " " + ((numOfSessions - sessionsRemaining) + 1) + "/" + numOfSessions); + } + // Currently finished break session + else if(sessionTimeIndicator == 1) { + sessionsRemaining--; + int numOfSessions = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + Debug.info("FocusState.timer.actionPerformed", "Break session ended. Beginning focus session " + ((numOfSessions - sessionsRemaining) + 1) + "/" + numOfSessions); + sessionTimeIndicator = 0; // Focus time + timerPanel.subTextLabel.setText(language.focusText + " " + ((numOfSessions - sessionsRemaining) + 1) + "/" + numOfSessions); + } + + nextSession(); + } else { + // Timer is done! + timer.stop(); + resetTimer(); + } + + } + //Timer still running + else { + sec--; + if(sec < 10) { + timerPanel.secondTimeLabel.setText("0" + sec); + } + else { + timerPanel.secondTimeLabel.setText("" + sec); + } + if(min < 10) { + timerPanel.minuteTimeLabel.setText("0" + min); + } + else { + timerPanel.minuteTimeLabel.setText("" + min); + } + + if(sessionTimeIndicator == 0) { + // Focusing + if(profile.getSettings().getFocusMode() == 0 || profile.getSettings().getFocusMode() == 4) { + int numOfSessions = (Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem(); + int currentSession = ((numOfSessions - sessionsRemaining) + 1); + tsGui.updateDiscordRPC("Focusing - Session " + currentSession + "/" + numOfSessions, timerPanel.minuteTimeLabel.getText() + ":" + timerPanel.secondTimeLabel.getText() + " remaining"); + } else { + tsGui.updateDiscordRPC("Focusing", timerPanel.minuteTimeLabel.getText() + ":" + timerPanel.secondTimeLabel.getText() + " remaining"); + } + } else if(sessionTimeIndicator == 1) { + // Break + tsGui.updateDiscordRPC("Break", timerPanel.minuteTimeLabel.getText() + ":" + timerPanel.secondTimeLabel.getText() + " remaining"); + } + + + } + } + }); + + //Start timer + timer.start(); + } + + public void nextSession() { + switch(sessionTimeIndicator) { + case 1: + // Break Timer Set + int sessionNumber = (((Integer) setPanel.pomoNumberOfSessionsBox.getSelectedItem() - sessionsRemaining) + 1); + if(profile.getSettings().getFocusMode() == 4 && setPanel.sessions.get(sessionNumber) == 1) { + // Long Break + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoLongBreakLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoLongBreakLengthBox.getSelectedItem()).substring(3)); + } else { + // Short Break + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoBreakLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoBreakLengthBox.getSelectedItem()).substring(3)); + } + + // Set Tamo Image To Non-Focus + tamoGraphicsPanel.getTamo().setFocused(false); + tamoGraphicsPanel.repaint(); + break; + case 0: + default: + // Pomodoro Focus Timer Set + timerPanel.minuteTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(0, 2)); + timerPanel.secondTimeLabel.setText(((String) setPanel.pomoSessionLengthBox.getSelectedItem()).substring(3)); + + // Set Tamo Image To Focus + tamoGraphicsPanel.getTamo().setFocused(true); + tamoGraphicsPanel.repaint(); + break; + } + min = Integer.parseInt(timerPanel.minuteTimeLabel.getText()); + sec = Integer.parseInt(timerPanel.secondTimeLabel.getText()); + + // TODO Add logic to add a conditional if statement to start + // the next session. By default, this click will be done + // for the user. + startFocusButton.doClick(); + } + + public void createStopwatch() { + Debug.info("FocusState.createStopwatch", "Starting stopwatch..."); + stopwatchCycleCount = 0; + timerPanel.subTextLabel.setText("Cycles: " + stopwatchCycleCount); + + timer = new Timer(1000, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // Begin counting up starting from 00:00 + sec++; + tempSec = tempSec + 1; + + if(tempSec == 59) { + tempMin = tempMin + 1; + tempSec = 0; + } + + // Increment minute when sec = 60 + if(sec == 59) { + sec = 0; + min++; + } + + // Add cycle + if(min == 100) { + min = 0; + stopwatchCycleCount++; + timerPanel.subTextLabel.setText("Cycles: " + stopwatchCycleCount); + } + + if(sec < 10) { + timerPanel.secondTimeLabel.setText("0" + sec); + } + else { + timerPanel.secondTimeLabel.setText("" + sec); + } + if(min < 10) { + timerPanel.minuteTimeLabel.setText("0" + min); + } + else { + timerPanel.minuteTimeLabel.setText("" + min); + } + + tsGui.updateDiscordRPC("Focusing - Stopwatch", timerPanel.minuteTimeLabel.getText() + ":" + timerPanel.secondTimeLabel.getText() + ", cycles: " + stopwatchCycleCount); + } + + }); + timer.start(); + } + + /* + * ################################## + * ################################## + * STATISTIC METHODS + * ################################## + * ################################## + */ + + /** + * @brief tempMin and tempSec store the minutes + * and seconds that have been studied during the time + * that this method is called. + * This method calculates the total time (in seconds) + * the user has studied and adds to the total time. + * The user earns Tamo happiness based + * off of the amount of time studied. + * Finally, the user earns Tamo tokens based off of + * the amount of time studied. + */ + public void updateFocusStatistics() { + // Update Time + if(sessionTimeIndicator == 0) { // Only earn on focus sessions + int timeEarned = tempSec + (tempMin * 60); + Debug.info("FocusState.updateFocusStatistics", "Earned " + timeEarned + " tamo tokens"); + dailyFocusEntry.setTime(dailyFocusEntry.getTime() + timeEarned); // Daily Time + monthFocusEntry.setTime(monthFocusEntry.getTime() + timeEarned); // Month Time + profile.setTime(profile.getTime() + timeEarned); // Total Time + + // Update Tokens (72 seconds = 1 Tamo token) + profile.setTokens(profile.getTokens() + ((50 * timeEarned) / 3600)); + + // Update Tamo Happiness (30 minutes = 1 Happy) + int happinessEarned = timeEarned / 1800; + int newHappy = (int) tamo.getHappy() + happinessEarned; + tamo.setHappy(newHappy >= 10 ? 10 : newHappy); + + // Update Profile JSON + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + tsGui.updateTamoTokensLabel(); + } + } + + public void resetTimer() { + // Reset timer back to where user set it + updateTimerInformation(); + + // Set Tamo Image To Non-Focus + tamoGraphicsPanel.getTamo().setFocused(false); + tamoGraphicsPanel.resetTamoImage(); + tamoGraphicsPanel.repaint(); + + // Ensure that if paused was selected, that it is reset + if(pauseTimer != null && pauseTimer.isRunning()) { + pauseTimer.stop(); + + pauseFocusButton.setText("Pause Focus"); + timerPanel.minuteTimeLabel.setForeground(theme.textColor); + timerPanel.colonLabel.setForeground(theme.textColor); + timerPanel.secondTimeLabel.setForeground(theme.textColor); + } + + // Enable menu, options, and start buttons again + toggleButtons(true); + + // Check for focus time achievements + checkForFocusTimeAndHappyAchievements(); + + // Revert Discord RPC + tsGui.updateDiscordRPC("Ready to Focus!", ""); + } + + /** + * @brief Method that disables buttons from + * the TamoStudyGUI menu, the start focus button. + * Also disables the selection options for the timer. + * + * Enables the break focus button. + */ + public void toggleButtons(boolean enabled) { + // Disable menu buttons + tsGui.toggleMenuButtons(enabled); + + // Disable options + setPanel.toggleOptionButtons(enabled); + + // Disable Start focus + startFocusButton.setEnabled(enabled); + breakFocusButton.setEnabled(!enabled); + pauseFocusButton.setEnabled(!enabled); + + // Re-color start / break buttons + if(enabled) { + // Modify colors of start button + startFocusButton.setBackground(Theme.SUCCESS); + startFocusButton.setForeground(Color.WHITE); + if(profile.getSettings().getDifficulty() == 0) { + startFocusButton.setVisible(true); + } + + // Modify colors of break button + breakFocusButton.setBackground(Theme.DANGER_ALT); + breakFocusButton.setForeground(new Color(191, 191, 191)); + + // Modify colors of pause button + pauseFocusButton.setBackground(Theme.PRIMARY_ALT); + pauseFocusButton.setForeground(new Color(191, 191, 191)); + } else { + startFocusButton.setBackground(Theme.SUCCESS_ALT); + startFocusButton.setForeground(new Color(191, 191, 191)); + + if(profile.getSettings().getDifficulty() == 0) { + startFocusButton.setVisible(false); + } + + // Modify colors of break button + breakFocusButton.setBackground(Theme.DANGER); + breakFocusButton.setForeground(Color.WHITE); + + // Modify colors of pause button + pauseFocusButton.setBackground(Theme.PRIMARY); + pauseFocusButton.setForeground(Color.WHITE); + } + } + + public void pauseResumeTimer() { + if(timer.isRunning()) { + pauseFocusButton.setText(language.resumeFocusText); + timer.stop(); + + timerPauseIndicator = 0; + pauseTimer = new Timer(750, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(timerPauseIndicator == 0) { + // Color Normal + timerPanel.minuteTimeLabel.setForeground(theme.altTextColor); + timerPanel.colonLabel.setForeground(theme.altTextColor); + timerPanel.secondTimeLabel.setForeground(theme.altTextColor); + timerPauseIndicator = 1; + } else { + // Color Alt + timerPanel.minuteTimeLabel.setForeground(theme.textColor); + timerPanel.colonLabel.setForeground(theme.textColor); + timerPanel.secondTimeLabel.setForeground(theme.textColor); + timerPauseIndicator = 0; + } + } + + }); + pauseTimer.start(); + + } else { + pauseFocusButton.setText(language.pauseFocusText); + timer.start(); + + if(pauseTimer.isRunning()) { + pauseTimer.stop(); + // Set Color Normal + timerPanel.minuteTimeLabel.setForeground(theme.textColor); + timerPanel.colonLabel.setForeground(theme.textColor); + timerPanel.secondTimeLabel.setForeground(theme.textColor); + } + } + + } + + public void checkForFocusTimeAndHappyAchievements() { + // Happy + if(profile.getTamo().getHappy() >= 10) { + Achievements.earn(tsGui, 8); + } + + // Focus Time + if(profile.getTime() >= 86400) { + Debug.info("FocusState.checkForFocusTimeAnyHappyAchievements", "Earning Achievement 0"); + Achievements.earn(tsGui, 0); + } + if(profile.getTime() >= 259200) { + Debug.info("FocusState.checkForFocusTimeAnyHappyAchievements", "Earning Achievement 1"); + Achievements.earn(tsGui, 1); + } + if(profile.getTime() >= 864000) { + Debug.info("FocusState.checkForFocusTimeAnyHappyAchievements", "Earning Achievement 2"); + Achievements.earn(tsGui, 2); + } + if(profile.getTime() >= 4320000) { + Debug.info("FocusState.checkForFocusTimeAnyHappyAchievements", "Earning Achievement 3"); + Achievements.earn(tsGui, 3); + } + + // Daily Focus + tsGui.getDailyFocus().checkInRowDailyFocusAchievements(tsGui, 3); + tsGui.getDailyFocus().checkInRowDailyFocusAchievements(tsGui, 7); + tsGui.getDailyFocus().checkInRowDailyFocusAchievements(tsGui, 30); + } +} diff --git a/TamoStudy/src/state/InventoryState.java b/TamoStudy/src/state/InventoryState.java new file mode 100644 index 0000000..01a6a50 --- /dev/null +++ b/TamoStudy/src/state/InventoryState.java @@ -0,0 +1,314 @@ +package state; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import components.panel.InventoryItemPanel; +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import resources.Debug; +import resources.Items; +import resources.Theme; + +public class InventoryState extends State { + + private static final long serialVersionUID = -8665762242093633226L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private GuiSize guiSize; + private Profile profile; + private Theme theme; + private Language language; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JPanel inventorySelectionPanel; + private JLabel inventoryTitleLabel; + public JComboBox inventoryBox; + + private JPanel inventoryPanel; + private JPanel inventoryMenuPanel; + public InventoryItemPanel inventoryItemPanel; + + public InventoryState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + profile = tsGui.getProfile(); + guiSize = new GuiSize((int) tsGui.getProfile().getSettings().getGuiSize()); + theme = profile.getSettings().getTheme(); + language = tsGui.getProfile().getSettings().getLanguage(); + } + + @Override + protected void initializeComponents() { + inventorySelectionPanel = new JPanel(); + inventorySelectionPanel.setBackground(theme.subColor); + inventoryTitleLabel = new JLabel(language.inventoryText); + inventoryTitleLabel.setFont(guiSize.settingLabelFont); + inventoryTitleLabel.setForeground(theme.textColor); + inventoryBox = new JComboBox<>(); + inventoryBox.addItem(language.foodText); + inventoryBox.addItem(language.backgroundsText); + inventoryBox.addItem(language.bordersText); + + inventoryBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + changeInventory(); + } + }); + + inventorySelectionPanel.add(inventoryTitleLabel); + inventorySelectionPanel.add(inventoryBox); + } + + @Override + protected void initializeComponentVisuals() { + // TODO Auto-generated method stub + + } + + @Override + protected void initializeComponentActions() { + // TODO Auto-generated method stub + + } + + @Override + protected void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + this.setLayout(new GridBagLayout()); + this.add(inventorySelectionPanel, gbcv); + initializeItemsToInventoryMenuPanel(gbcv); + } + + public void initializeItemsToInventoryMenuPanel(GridBagConstraints gbcv) { + inventoryPanel = new JPanel(new GridLayout(1, 2)); + inventoryPanel.setBackground(theme.mainColor); + inventoryPanel.setBorder(guiSize.settingsPanelBorder); + inventoryMenuPanel = new JPanel(new GridLayout(7, 5)); + inventoryMenuPanel.setBackground(theme.mainColor); + + for(long foodIndicator : profile.getFoodInventoryList()) { + inventoryMenuPanel.add(createFoodMenuItemButton((int) foodIndicator)); + } + + int noItemCount = 35 - profile.getFoodInventoryList().size(); + if(noItemCount > 0) { + for(int i = 0; i < noItemCount; i++) { + inventoryMenuPanel.add(createEmptyMenuItem()); + } + } + + inventoryPanel.add(inventoryMenuPanel); + this.add(inventoryPanel, gbcv); + } + + public void changeInventory() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + this.remove(inventoryPanel); + this.repaint(); + + inventoryPanel = new JPanel(new GridBagLayout()); + inventoryPanel.setBackground(theme.mainColor); + inventoryPanel.setBorder(guiSize.settingsPanelBorder); + inventoryMenuPanel = new JPanel(new GridLayout(7, 5)); + inventoryMenuPanel.setBackground(theme.mainColor); + + if(inventoryBox.getSelectedIndex() == 0) { + for(long foodIndicator : profile.getFoodInventoryList()) { + inventoryMenuPanel.add(createFoodMenuItemButton((int) foodIndicator)); + } + + int noItemCount = 35 - profile.getFoodInventoryList().size(); + if(noItemCount > 0) { + for(int i = 0; i < noItemCount; i++) { + inventoryMenuPanel.add(createEmptyMenuItem()); + } + } + + } else if(inventoryBox.getSelectedIndex() == 1) { + for(long backgroundIndicator : profile.getBackgroundInventoryList()) { + inventoryMenuPanel.add(createBackgroundMenuItemButton((int) backgroundIndicator)); + } + + int noItemCount = 35 - profile.getBackgroundInventoryList().size(); + if(noItemCount > 0) { + for(int i = 0; i < noItemCount; i++) { + inventoryMenuPanel.add(createEmptyMenuItem()); + } + } + } else if(inventoryBox.getSelectedIndex() == 2) { + for(long borderIndicator : profile.getBorderInventoryList()) { + inventoryMenuPanel.add(createBorderMenuItemButton((int) borderIndicator)); + } + + int noItemCount = 35 - profile.getBorderInventoryList().size(); + if(noItemCount > 0) { + for(int i = 0; i < noItemCount; i++) { + inventoryMenuPanel.add(createEmptyMenuItem()); + } + } + } + inventoryPanel.add(inventoryMenuPanel, gbch); + this.add(inventoryPanel, gbcv); + this.revalidate(); + } + + public JButton createFoodMenuItemButton(int indicator) { + JButton foodMenuItemButton = new JButton(Items.getFoodInvIconByIndicator(indicator, guiSize)); + foodMenuItemButton.setPreferredSize(guiSize.itemMenuDimension); + foodMenuItemButton.setContentAreaFilled(false); + foodMenuItemButton.setOpaque(false); + foodMenuItemButton.setBorderPainted(false); + foodMenuItemButton.setFocusPainted(false); + foodMenuItemButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + selectFoodItem(indicator); + } + }); + return foodMenuItemButton; + } + + public JButton createBackgroundMenuItemButton(int indicator) { + JButton backgroundMenuItemButton = new JButton(Items.getBackgroundInvIconByIndicator(indicator, guiSize)); + backgroundMenuItemButton.setPreferredSize(guiSize.itemMenuDimension); + backgroundMenuItemButton.setContentAreaFilled(false); + backgroundMenuItemButton.setOpaque(false); + backgroundMenuItemButton.setBorderPainted(false); + backgroundMenuItemButton.setFocusPainted(false); + backgroundMenuItemButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + selectBackgroundItem(indicator); + } + }); + return backgroundMenuItemButton; + } + + public JButton createBorderMenuItemButton(int indicator) { + JButton borderMenuItemButton = new JButton(Items.getBorderInvIconByIndicator(indicator, guiSize)); + borderMenuItemButton.setPreferredSize(guiSize.itemMenuDimension); + borderMenuItemButton.setContentAreaFilled(false); + borderMenuItemButton.setOpaque(false); + borderMenuItemButton.setBorderPainted(false); + borderMenuItemButton.setFocusPainted(false); + borderMenuItemButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + selectBorderItem(indicator); + } + }); + return borderMenuItemButton; + } + + public JButton createEmptyMenuItem() { + JButton itemButton = new JButton(); + itemButton.setPreferredSize(new Dimension(32, 32)); + itemButton.setContentAreaFilled(false); + itemButton.setOpaque(false); + itemButton.setBorderPainted(false); + itemButton.setFocusPainted(false); + return itemButton; + } + + public void selectFoodItem(int indicator) { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + if(inventoryPanel.getComponentCount() == 1) { + // Need to add inventory item panel + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "FOOD", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } else { + // Remove inventory item panel, re-add + inventoryPanel.remove(inventoryItemPanel); + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "FOOD", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } + } + + public void selectBackgroundItem(int indicator) { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + if(inventoryPanel.getComponentCount() == 1) { + // Need to add inventory item panel + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "BACKGROUND", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } else { + // Remove inventory item panel, re-add + inventoryPanel.remove(inventoryItemPanel); + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "BACKGROUND", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } + } + + public void selectBorderItem(int indicator) { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + if(inventoryPanel.getComponentCount() == 1) { + // Need to add inventory item panel + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "BORDER", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } else { + // Remove inventory item panel, re-add + inventoryPanel.remove(inventoryItemPanel); + inventoryItemPanel = new InventoryItemPanel(tsGui, this, "BORDER", indicator); + inventoryPanel.add(inventoryItemPanel, gbch); + this.revalidate(); + } + } +} diff --git a/TamoStudy/src/state/SettingsState.java b/TamoStudy/src/state/SettingsState.java new file mode 100644 index 0000000..993bece --- /dev/null +++ b/TamoStudy/src/state/SettingsState.java @@ -0,0 +1,550 @@ +package state; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.Timer; + +import gui.TamoStudyGUI; +import io.ProfileJsonManager; +import model.GuiSize; +import model.language.Language; +import model.profile.ProfileSettings; +import resources.Debug; +import resources.Theme; + +/** + * SettingsState + * @author narlock + * @brief The settings state of TamoStudy + */ +public class SettingsState extends State { + + private static final long serialVersionUID = -8979954063946210819L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private ProfileJsonManager profileJsonManager; + private ProfileSettings settings; + private Language language; + private GuiSize guiSize; + private Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JPanel titlePanel; + private JLabel messageLabel; + private JButton themeButton; + + private JPanel settingsPanel; + private JPanel languagePanel; + private JLabel languageLabel; + private JComboBox languageBox; + private JPanel focusModePanel; + private JLabel focusModeLabel; + private JComboBox focusModeBox; + private JPanel difficultyPanel; + private JLabel difficultyLabel; + private JComboBox difficultyBox; + private JPanel timerAlarmPanel; + private JLabel timerAlarmLabel; + private JComboBox timerAlarmBox; + private JPanel guiSizePanel; + private JLabel guiSizeLabel; + private JButton decreaseGuiSizeButton; + private JButton increaseGuiSizeButton; + private JPanel receiveNotificationsPanel; + private JLabel receiveNotificationsLabel; + private JButton receiveNotificationsButton; + private JPanel enableDiscordRPCPanel; + private JLabel enableDiscordRPCLabel; + private JButton enableDiscordRPCButton; + private JPanel showProgramCloseMessagePanel; + private JLabel showProgramCloseMessageLabel; + private JButton showProgramCloseMessageButton; + + /** + * SettingsState + * @param tamoStudyGUI + */ + public SettingsState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + + } + + @Override + protected void initializeAttributes() { + profileJsonManager = tsGui.getProfileJsonManager(); + settings = tsGui.getProfile().getSettings(); + language = tsGui.getProfile().getSettings().getLanguage(); + guiSize = new GuiSize((int) tsGui.getProfile().getSettings().getGuiSize()); + theme = tsGui.getProfile().getSettings().getTheme(); + Debug.info("SettingsState.initializeAttributes", "Loaded settings=" + settings); + } + + @Override + protected void initializeComponents() { + titlePanel = new JPanel(); + messageLabel = new JLabel("Settings"); + + themeButton = new JButton(); + if(theme.type.equals("Dark")) { + themeButton.setIcon(guiSize.darkModeIcon); + } else { + themeButton.setIcon(guiSize.lightModeIcon); + } + addButtonVisual(themeButton); + + + settingsPanel = new JPanel(new GridBagLayout()); + + languagePanel = new JPanel(new GridBagLayout()); + languageLabel = new JLabel(language.languageText); + languageBox = new JComboBox<>(); + languageBox.addItem(language.englishText); + languageBox.addItem(language.spanishText); +// languageBox.addItem(language.hindiText); +// languageBox.addItem(language.portugueseText); +// languageBox.addItem(language.japaneseText); +// languageBox.addItem(language.germanText); +// languageBox.addItem(language.frenchText); +// languageBox.addItem(language.turkishText); +// languageBox.addItem(language.mandarinChineseText); +// languageBox.addItem(language.dutchText); +// languageBox.addItem(language.koreanText); +// languageBox.addItem(language.russianText); +// languageBox.addItem(language.hungarianText); +// languageBox.addItem(language.romanianText); + + focusModePanel = new JPanel(new GridBagLayout()); + focusModeLabel = new JLabel(language.focusModeText); + focusModeBox = new JComboBox<>(); + focusModeBox.addItem(language.pomodoroText); + focusModeBox.addItem(language.customCountdownText); + focusModeBox.addItem(language.fiveMinIntervalCountdownText); + focusModeBox.addItem(language.stopwatchText); + focusModeBox.addItem("Pomodoro with Long Breaks"); + + difficultyPanel = new JPanel(new GridBagLayout()); + difficultyLabel = new JLabel(language.difficultyText); + difficultyBox = new JComboBox<>(); + difficultyBox.addItem(language.peacefulText); + difficultyBox.addItem(language.challengingText); + difficultyBox.addItem(language.ironManText); + + timerAlarmPanel = new JPanel(new GridBagLayout()); + timerAlarmLabel = new JLabel(language.timerAlarmText); + timerAlarmBox = new JComboBox<>(); + timerAlarmBox.addItem(language.noTimerAlarmText); + timerAlarmBox.addItem(language.softAlarmText); + timerAlarmBox.addItem(language.traditionalAlarmText); + timerAlarmBox.addItem(language.pacAlarmText); +// timerAlarmBox.addItem(language.calmAlarmText); +// timerAlarmBox.addItem(language.bellAlarmText); + + guiSizePanel = new JPanel(new GridBagLayout()); + guiSizeLabel = new JLabel(language.guiSizeText); + decreaseGuiSizeButton = new JButton(guiSize.minusImageIcon); + increaseGuiSizeButton = new JButton(guiSize.addImageIcon); + + receiveNotificationsPanel = new JPanel(new GridBagLayout()); + receiveNotificationsLabel = new JLabel(language.notificationsText); + receiveNotificationsButton = new JButton(); + + enableDiscordRPCPanel = new JPanel(new GridBagLayout()); + enableDiscordRPCLabel = new JLabel(language.discordRPCText); + enableDiscordRPCButton = new JButton(); + + showProgramCloseMessagePanel = new JPanel(new GridBagLayout()); + showProgramCloseMessageLabel = new JLabel(language.exitMessageText); + showProgramCloseMessageButton = new JButton(); + } + + @Override + protected void initializeComponentVisuals() { + this.setLayout(new GridBagLayout()); + + titlePanel.setBackground(theme.subColor); + messageLabel.setFont(guiSize.messageLabelFont); + messageLabel.setForeground(theme.textColor); + + settingsPanel.setBackground(theme.mainColor); + settingsPanel.setBorder(guiSize.settingsPanelBorder); + + languagePanel.setBackground(theme.mainColor); + languageLabel.setFont(guiSize.settingLabelFont); + languageLabel.setForeground(theme.textColor); + languageBox.setSelectedIndex(Language.getIndexFromLanguage(language)); + languageBox.setFont(guiSize.settingsChoiceFont); + + focusModePanel.setBackground(theme.mainColor); + focusModeLabel.setFont(guiSize.settingLabelFont); + focusModeLabel.setForeground(theme.textColor); + focusModeBox.setSelectedIndex((int) settings.getFocusMode()); + focusModeBox.setFont(guiSize.settingsChoiceFont); + + difficultyPanel.setBackground(theme.mainColor); + difficultyLabel.setFont(guiSize.settingLabelFont); + difficultyLabel.setForeground(theme.textColor); + difficultyBox.setSelectedIndex((int) settings.getDifficulty()); + difficultyBox.setFont(guiSize.settingsChoiceFont); + + timerAlarmPanel.setBackground(theme.mainColor); + timerAlarmLabel.setFont(guiSize.settingLabelFont); + timerAlarmLabel.setForeground(theme.textColor); + timerAlarmBox.setSelectedIndex((int) settings.getTimerAlarm()); + timerAlarmBox.setFont(guiSize.settingsChoiceFont); + + guiSizePanel.setBackground(theme.mainColor); + guiSizeLabel.setFont(guiSize.settingLabelFont); + guiSizeLabel.setForeground(theme.textColor); + addButtonVisual(decreaseGuiSizeButton); + addButtonVisual(increaseGuiSizeButton); + + receiveNotificationsPanel.setBackground(theme.mainColor); + receiveNotificationsLabel.setFont(guiSize.settingLabelFont); + receiveNotificationsLabel.setForeground(theme.textColor); + if(settings.getReceiveNotifications()) { + receiveNotificationsButton.setText(language.onText); + Theme.primaryVisualButton(receiveNotificationsButton, guiSize); + } else { + receiveNotificationsButton.setText(language.offText); + Theme.secondaryVisualButton(receiveNotificationsButton, guiSize); + } + + enableDiscordRPCPanel.setBackground(theme.mainColor); + enableDiscordRPCLabel.setFont(guiSize.settingLabelFont); + enableDiscordRPCLabel.setForeground(theme.textColor); + if(settings.getEnableDiscordRPC()) { + enableDiscordRPCButton.setText(language.onText); + Theme.primaryVisualButton(enableDiscordRPCButton, guiSize); + } else { + enableDiscordRPCButton.setText(language.offText); + Theme.secondaryVisualButton(enableDiscordRPCButton, guiSize); + } + + showProgramCloseMessagePanel.setBackground(theme.mainColor); + showProgramCloseMessageLabel.setFont(guiSize.settingLabelFont); + showProgramCloseMessageLabel.setForeground(theme.textColor); + if(settings.getShowProgramCloseMessage()) { + showProgramCloseMessageButton.setText(language.onText); + Theme.primaryVisualButton(showProgramCloseMessageButton, guiSize); + } else { + showProgramCloseMessageButton.setText(language.offText); + Theme.secondaryVisualButton(showProgramCloseMessageButton, guiSize); + } + } + + @Override + protected void initializeComponentActions() { + + languageBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + settings.setLanguage(Language.getLanguageFromBox(languageBox.getSelectedIndex())); + + // Refresh tsGui + tsGui.resizeGui(); + + saveChanges(); + } + + }); + + focusModeBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + settings.setFocusMode(focusModeBox.getSelectedIndex()); + saveChanges(); + } + }); + + difficultyBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + settings.setDifficulty(difficultyBox.getSelectedIndex()); + saveChanges(); + } + }); + + timerAlarmBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + settings.setTimerAlarm(timerAlarmBox.getSelectedIndex()); + saveChanges(); + } + }); + + /* + * Upon click, the GUI's size will immediately be decreased. + * It will only be decreased if there is a size that is lower + * than the one it can be decreased to. The size will also + * be updated in the profile's settings. + */ + decreaseGuiSizeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int index = (int) tsGui.getProfile().getSettings().getGuiSize(); + Debug.info("deceaseGuiButton.actionPerformed", "Index is=" + index); + if(index > 0) { + Debug.info("decreaseGuiButton.actionPerformed", "Decreasing gui size"); + tsGui.getProfile().getSettings().setGuiSize(tsGui.getProfile().getSettings().getGuiSize() - 1); + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + tsGui.resizeGui(); + } + } + }); + + /* + * Upon click, the GUI's size will immediate be increased. + * It will only be increased if there is a size that is higher + * than the one it can be increased to. The size will also + * be updated in the profile's settings. + */ + increaseGuiSizeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + int index = (int) tsGui.getProfile().getSettings().getGuiSize(); + Debug.info("increaseGuiSizeButton.actionPerformed", "Index is=" + index); + if(index < 2) { + Debug.info("increaseGuiSizeButton.actionPerformed", "Increasing gui size"); + tsGui.getProfile().getSettings().setGuiSize(tsGui.getProfile().getSettings().getGuiSize() + 1); + tsGui.getProfileJsonManager().writeJsonToFile(tsGui.getProfiles()); + tsGui.resizeGui(); + } + } + }); + + /* + * Upon click, the button visual will change in accordance to ON/OFF. + * This will also set the value inside of the profile, but not + * immediately change it. + */ + receiveNotificationsButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(receiveNotificationsButton.getText().equals(language.onText)) { + receiveNotificationsButton.setText(language.offText); + Theme.secondaryVisualButton(receiveNotificationsButton, guiSize); + settings.setReceiveNotifications(false); + } else { + receiveNotificationsButton.setText(language.onText); + Theme.primaryVisualButton(receiveNotificationsButton, guiSize); + settings.setReceiveNotifications(true); + } + + saveChanges(); + } + }); + + /* + * Upon click, the button visual will change in accordance to ON/OFF. + * This will also set the value inside of the profile, but not + * immediately change it. + */ + enableDiscordRPCButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(enableDiscordRPCButton.getText().equals(language.onText)) { + enableDiscordRPCButton.setText(language.offText); + Theme.secondaryVisualButton(enableDiscordRPCButton, guiSize); + } else { + enableDiscordRPCButton.setText(language.onText); + Theme.primaryVisualButton(enableDiscordRPCButton, guiSize); + } + + if(!(System.getProperty("os.name").startsWith("Windows"))) { + settings.setEnableDiscordRPC(false); + } else if(enableDiscordRPCButton.getText().equals(language.onText)) { + settings.setEnableDiscordRPC(true); + } else { + settings.setEnableDiscordRPC(false); + } + + saveChanges(); + } + }); + + /* + * Upon click, the button visual will change in accordance to ON/OFF. + * This will also set the value inside of the profile, but not + * immediately change it. + */ + showProgramCloseMessageButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(showProgramCloseMessageButton.getText().equals(language.onText)) { + showProgramCloseMessageButton.setText(language.offText); + Theme.secondaryVisualButton(showProgramCloseMessageButton, guiSize); + settings.setShowProgramCloseMessage(false); + } else { + showProgramCloseMessageButton.setText(language.onText); + Theme.primaryVisualButton(showProgramCloseMessageButton, guiSize); + settings.setShowProgramCloseMessage(true); + } + + saveChanges(); + } + }); + + themeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(theme.type.equals("Light")) { + theme = Theme.DARK; + } else { + theme = Theme.LIGHT; + } + + // Overwrite JSON file + tsGui.getProfile().getSettings().setTheme(theme); + Debug.info("SettingsState.themeButton.actionPerformed", "Theme = " + theme.type); + profileJsonManager.writeJsonToFile(tsGui.getProfiles()); + + // Refresh tsGui + tsGui.resizeGui(); + } + }); + } + + @Override + protected void initializePanel() { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints innergbcv = new GridBagConstraints(); + innergbcv.gridwidth = GridBagConstraints.REMAINDER; + innergbcv.anchor = GridBagConstraints.WEST; + + languagePanel.add(languageLabel); + languagePanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference / 2), gbch); + languagePanel.add(languageBox); + + focusModePanel.add(focusModeLabel); + focusModePanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference / 2), gbch); + focusModePanel.add(focusModeBox); + + difficultyPanel.add(difficultyLabel); + difficultyPanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference / 2), gbch); + difficultyPanel.add(difficultyBox); + + timerAlarmPanel.add(timerAlarmLabel); + timerAlarmPanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference / 2), gbch); + timerAlarmPanel.add(timerAlarmBox); + + guiSizePanel.add(guiSizeLabel, gbch); + guiSizePanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference), gbch); + guiSizePanel.add(decreaseGuiSizeButton, gbch); + guiSizePanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference), gbch); + guiSizePanel.add(increaseGuiSizeButton, gbch); + + receiveNotificationsPanel.add(receiveNotificationsLabel, gbch); + receiveNotificationsPanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference), gbch); + receiveNotificationsPanel.add(receiveNotificationsButton, gbch); + + enableDiscordRPCPanel.add(enableDiscordRPCLabel, gbch); + enableDiscordRPCPanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference), gbch); + enableDiscordRPCPanel.add(enableDiscordRPCButton, gbch); + + showProgramCloseMessagePanel.add(showProgramCloseMessageLabel, gbch); + showProgramCloseMessagePanel.add(Box.createHorizontalStrut(guiSize.settingsHorizontalDifference), gbch); + showProgramCloseMessagePanel.add(showProgramCloseMessageButton, gbch); + + settingsPanel.add(languagePanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(focusModePanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(difficultyPanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(timerAlarmPanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(guiSizePanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(receiveNotificationsPanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(enableDiscordRPCPanel, innergbcv); + settingsPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), innergbcv); + settingsPanel.add(showProgramCloseMessagePanel, innergbcv); + + titlePanel.add(messageLabel); + titlePanel.add(themeButton); + + this.add(titlePanel, gbcv); + this.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + this.add(settingsPanel, gbcv); + + if(!(System.getProperty("os.name").startsWith("Windows"))) { + enableDiscordRPCPanel.setVisible(false); + } + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public void addButtonVisual(JButton button) { + button.setOpaque(false); + button.setContentAreaFilled(false); + button.setFocusPainted(false); + button.setBorderPainted(false); + } + + public void saveChanges() { + // Overwrite JSON file + profileJsonManager.writeJsonToFile(tsGui.getProfiles()); + Debug.info("SettingsState.saveChangesButton.actionPerformed", "Wrote profiles to file=" + tsGui.getProfiles()); + + // Change message label + messageLabel.setText(language.settingsSavedText); + messageLabel.setForeground(Theme.SUCCESS); + final Timer timer = new Timer(1000, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + messageLabel.setText("Settings"); + messageLabel.setForeground(theme.textColor); + ((Timer) e.getSource()).stop(); + } + }); + timer.start(); + + } +} diff --git a/TamoStudy/src/state/ShopState.java b/TamoStudy/src/state/ShopState.java new file mode 100644 index 0000000..fe37926 --- /dev/null +++ b/TamoStudy/src/state/ShopState.java @@ -0,0 +1,107 @@ +package state; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JComboBox; + +import components.panel.KathPanel; +import components.panel.ShopPanel; +import gui.TamoStudyGUI; +import model.language.Language; +import resources.Theme; + +public class ShopState extends State { + + private static final long serialVersionUID = 1930763097782384868L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Language language; + private Theme theme; + private int shopIndicator; // Which shop we are currently in + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private KathPanel kathPanel; + private ShopPanel shopPanel; + private JComboBox shopOptions; + + public ShopState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + language = tsGui.getProfile().getSettings().getLanguage(); + theme = tsGui.getProfile().getSettings().getTheme(); + } + + @Override + protected void initializeComponents() { + shopIndicator = 0; + kathPanel = new KathPanel(theme, tsGui.getGuiSize(), tsGui.getProfile().getSettings().getLanguage()); + shopPanel = new ShopPanel(tsGui, tsGui.getGuiSize(), tsGui.getProfile().getSettings().getLanguage()); + shopOptions = new JComboBox<>(); + shopOptions.addItem(language.selectShopText); + shopOptions.addItem(language.foodText); + shopOptions.addItem(language.backgroundsText); + shopOptions.addItem(language.bordersText); +// shopOptions.addItem("Timer Customization"); + } + + @Override + protected void initializeComponentVisuals() { + // TODO Auto-generated method stub + shopPanel.setBackground(theme.subColor); + } + + @Override + protected void initializeComponentActions() { + shopOptions.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + kathPanel.shopIndicator = shopOptions.getSelectedIndex(); + + // Validate Kath Panel + kathPanel.initializeAttributes(); + kathPanel.repaint(); + + // Validate Shop Panel + shopPanel.setShop(shopOptions.getSelectedIndex()); + repaint(); + } + + }); + } + + @Override + protected void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + this.setLayout(new GridBagLayout()); + this.add(kathPanel, gbcv); + this.add(shopPanel, gbcv); + this.add(shopOptions, gbcv); + } + +} diff --git a/TamoStudy/src/state/State.java b/TamoStudy/src/state/State.java new file mode 100644 index 0000000..29dd754 --- /dev/null +++ b/TamoStudy/src/state/State.java @@ -0,0 +1,21 @@ +package state; + +import javax.swing.JPanel; + +import gui.TamoStudyGUI; + +public abstract class State extends JPanel { + + public TamoStudyGUI tsGui; + + public State(TamoStudyGUI tamoStudyGUI) { + this.tsGui = tamoStudyGUI; + this.setBackground(tsGui.getTheme().subColor); + } + + protected abstract void initializeAttributes(); + protected abstract void initializeComponents(); + protected abstract void initializeComponentVisuals(); + protected abstract void initializeComponentActions(); + protected abstract void initializePanel(); +} diff --git a/TamoStudy/src/state/StatisticsState.java b/TamoStudy/src/state/StatisticsState.java new file mode 100644 index 0000000..d513d16 --- /dev/null +++ b/TamoStudy/src/state/StatisticsState.java @@ -0,0 +1,228 @@ +package state; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.plaf.basic.BasicProgressBarUI; + +import components.panel.HoursInPastPanel; +import components.panel.TamoGraphicsPanel; +import gui.TamoStudyGUI; +import io.DailyFocusJsonManager; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import model.profile.Tamo; +import model.time.DailyFocus; +import model.time.DailyFocusEntry; +import model.time.MonthFocusEntry; +import resources.Theme; +import util.Utils; + +public class StatisticsState extends State { + + private static final long serialVersionUID = 1058419726546781724L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Profile profile; + private Language language; + private GuiSize guiSize; + private Tamo tamo; + private Theme theme; + private DailyFocusEntry dailyFocusEntry; + private MonthFocusEntry monthFocusEntry; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JPanel statisticsPanel; + private TamoGraphicsPanel tamoGraphicsPanel; // LHS + private JPanel tamoInfoPanel; // RHS + private JLabel tamoNameLabel; + private JLabel tamoHappyLabel; + private JLabel tamoHungerLabel; + private JLabel tamoHoursTodayLabel; + private JLabel tamoHoursMonthLabel; + private JLabel tamoHoursAllLabel; + private JLabel tamoLevelLabel; + private JProgressBar levelProgressBar; + + private DailyFocus profileDailyFocus; + private HoursInPastPanel hoursInPastPanel; + + public StatisticsState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + profile = tsGui.getProfile(); + language = tsGui.getProfile().getSettings().getLanguage(); + guiSize = new GuiSize((int) profile.getSettings().getGuiSize()); + tamo = profile.getTamo(); + theme = profile.getSettings().getTheme(); + + this.dailyFocusEntry = Utils.searchTodayFocusEntryByProfile(tsGui.getDailyFocus().getDailyFocusEntries()); + // Create new daily focus entry if it does not exist + if(dailyFocusEntry == null) { + dailyFocusEntry = Utils.createDailyFocusEntry(); + tsGui.addNewDailyFocusEntryToDailyFocus(dailyFocusEntry); + tsGui.getDailyFocusJsonManager().writeJsonToFile(tsGui.getDailyFocusList()); + } + + this.monthFocusEntry = Utils.searchCurrentMonthEntryByProfile(tsGui.getMonthFocus().getMonthFocusEntries()); + // Create new month focus entry if it does not exist + if(monthFocusEntry == null) { + monthFocusEntry = Utils.createMonthFocusEntry(); + tsGui.addNewMonthFocusEntryToMonthFocus(monthFocusEntry); + tsGui.getMonthFocusJsonManager().writeJsonToFile(tsGui.getMonthFocusList()); + } + + DailyFocusJsonManager dailyFocusJsonManager = new DailyFocusJsonManager(); + List dailyFocusList = dailyFocusJsonManager.readJson(); + for(DailyFocus dailyFocus : dailyFocusList) { + if(dailyFocus.getProfileId() == profile.getId()) { + profileDailyFocus = dailyFocus; + } + } + } + + @Override + protected void initializeComponents() { + statisticsPanel = new JPanel(); + tamoGraphicsPanel = new TamoGraphicsPanel(guiSize, tamo, profile.getBackgroundIndicator(), profile.getBorderIndicator()); + tamoInfoPanel = new JPanel(new GridBagLayout()); + tamoNameLabel = new JLabel(tamo.getName()); + tamoHappyLabel = new JLabel("" + tamo.getHappy()); + tamoHungerLabel = new JLabel("" + tamo.getHunger()); + tamoHoursTodayLabel = new JLabel(language.todaysFocusText + ": " + Utils.convertSecondsToHours(dailyFocusEntry.getTime()) + " " + language.hoursText); + tamoHoursMonthLabel = new JLabel(language.monthFocusText + ": " + Utils.convertSecondsToHours(monthFocusEntry.getTime()) + " " + language.hoursText); + tamoHoursAllLabel = new JLabel(language.totalFocusText + ": " + Utils.convertSecondsToHours(profile.getTime()) + " " + language.hoursText); + tamoLevelLabel = new JLabel(language.levelText + " " + tamo.getLevel()); + levelProgressBar = new JProgressBar(0, 100); + + hoursInPastPanel = new HoursInPastPanel(language, theme, profileDailyFocus.getDailyFocusEntries(), guiSize); + } + + @Override + protected void initializeComponentVisuals() { + statisticsPanel.setBackground(theme.subColor); + tamoInfoPanel.setBackground(theme.subColor); + + tamoNameLabel.setFont(guiSize.messageLabelFont); + tamoNameLabel.setForeground(theme.textColor); + + tamoHappyLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHappyLabel.setForeground(theme.textColor); + tamoHappyLabel.setIcon(guiSize.heartImageIcon); + + tamoHungerLabel.setFont(guiSize.statisticsInfoFontBold); + tamoHungerLabel.setForeground(theme.textColor); + tamoHungerLabel.setIcon(guiSize.onigiriImageIcon); + + tamoHoursAllLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursAllLabel.setForeground(theme.textColor); + tamoHoursMonthLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursMonthLabel.setForeground(theme.textColor); + tamoHoursTodayLabel.setFont(guiSize.statisticsInfoFont); + tamoHoursTodayLabel.setForeground(theme.textColor); + + tamoLevelLabel.setFont(guiSize.statisticsInfoFontBold); + tamoLevelLabel.setForeground(theme.textColor); + + levelProgressBar.setOpaque(true); + levelProgressBar.setFont(guiSize.statisticsInfoFont); + levelProgressBar.setForeground(Theme.SUCCESS); + levelProgressBar.setBackground(theme.mainColor); + levelProgressBar.setBorder(BorderFactory.createLineBorder(theme.textColor, 1)); + levelProgressBar.setUI(new BasicProgressBarUI() { + protected Color getSelectionBackground() { + return Color.WHITE; // set the color of the progress bar + } + protected Color getSelectionForeground() { + return Color.BLACK; // set the color of the text on the progress bar + } + }); + levelProgressBar.setStringPainted(true); + levelProgressBar.setValue(tamo.levelProgress()); + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + tamoInfoPanel.add(tamoNameLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoHappyLabel, gbcv); + tamoInfoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoInfoPanel.add(tamoHungerLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoHoursTodayLabel, gbcv); + tamoInfoPanel.add(tamoHoursMonthLabel, gbcv); + tamoInfoPanel.add(tamoHoursAllLabel, gbcv); + tamoInfoPanel.add(createSpaceLabel(), gbcv); + tamoInfoPanel.add(tamoLevelLabel, gbcv); + tamoInfoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoInfoPanel.add(levelProgressBar, gbcv); + + statisticsPanel.add(tamoGraphicsPanel); + statisticsPanel.add(tamoInfoPanel); + } + + @Override + protected void initializeComponentActions() { + // TODO Auto-generated method stub + + } + + @Override + protected void initializePanel() { + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + this.setLayout(new GridBagLayout()); + this.add(statisticsPanel, gbcv); + // TODO Add Github-like contribution calendar + this.add(hoursInPastPanel, gbcv); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + + public JLabel createSpaceLabel() { + String DIVIDER = (System.getProperty("os.name").startsWith("Linux") || System.getProperty("os.name").startsWith("Windows")) + ? "────────────" : "━━━━━━━"; + + JLabel label = new JLabel(DIVIDER); + label.setFont(guiSize.topMenuFont); + label.setForeground(theme.altTextColor); + return label; + } +} diff --git a/TamoStudy/src/state/TamoHistoryState.java b/TamoStudy/src/state/TamoHistoryState.java new file mode 100644 index 0000000..def9186 --- /dev/null +++ b/TamoStudy/src/state/TamoHistoryState.java @@ -0,0 +1,239 @@ +package state; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.plaf.basic.BasicProgressBarUI; + +import components.panel.TamoGraphicsPanel; +import gui.TamoStudyGUI; +import model.GuiSize; +import model.language.Language; +import model.profile.Profile; +import model.profile.Tamo; +import resources.Debug; +import resources.Theme; +import util.Utils; + +public class TamoHistoryState extends State { + + private static final long serialVersionUID = -8715178495100570733L; + + /* + * ################################## + * ################################## + * ATTRIBUTES + * ################################## + * ################################## + */ + private Profile profile; + private List tamoHistory; + private Tamo tamo; + private GuiSize guiSize; + private int tamoPage; + private Language language; + private Theme theme; + + /* + * ################################## + * ################################## + * COMPONENTS + * ################################## + * ################################## + */ + private JButton previousButton; + private JButton nextButton; + + private JPanel tamoPanel; + private JLabel tamoNameLabel; + private JLabel tamoLevelLabel; + private JProgressBar levelProgressBar; + private JLabel tamoHeadstoneLabel; + private JPanel tamoGraphicsPanelPanel; + private TamoGraphicsPanel tamoGraphicsPanel; + + public TamoHistoryState(TamoStudyGUI tamoStudyGUI) { + super(tamoStudyGUI); + initializeAttributes(); + initializeComponents(); + initializeComponentVisuals(); + initializeComponentActions(); + initializePanel(); + } + + @Override + protected void initializeAttributes() { + profile = tsGui.getProfile(); + tamoHistory = tsGui.getProfile().getTamoHistory(); + guiSize = tsGui.getGuiSize(); + tamoPage = 0; + theme = profile.getSettings().getTheme(); + language = profile.getSettings().getLanguage(); + } + + @Override + protected void initializeComponents() { + nextButton = new JButton(guiSize.rightArrowIcon); + previousButton = new JButton(guiSize.leftArrowIcon); + + tamoPanel = new JPanel(new GridBagLayout()); + tamo = tamoHistory.get(0); + tamoGraphicsPanelPanel = new JPanel(); + tamoGraphicsPanel = new TamoGraphicsPanel(guiSize, tamo, profile.getBackgroundIndicator(), profile.getBorderIndicator()); + + tamoNameLabel = new JLabel(tamo.getName()); + tamoLevelLabel = new JLabel(language.levelText + " : " + tamo.getLevel()); + levelProgressBar = new JProgressBar(0, 100); + tamoHeadstoneLabel = new JLabel(tamo.getBirthDateString() + " - " + tamo.getPassDateString()); + } + + @Override + protected void initializeComponentVisuals() { + addButtonVisual(nextButton); + addButtonVisual(previousButton); + + tamoPanel.setBackground(theme.subColor); + + tamoNameLabel.setFont(guiSize.messageLabelFont); + tamoNameLabel.setForeground(theme.textColor); + + tamoLevelLabel.setFont(guiSize.statisticsInfoFont); + tamoLevelLabel.setForeground(theme.textColor); + + levelProgressBar.setOpaque(true); + levelProgressBar.setFont(guiSize.statisticsInfoFont); + levelProgressBar.setForeground(Theme.SUCCESS); + levelProgressBar.setBackground(theme.mainColor); + levelProgressBar.setBorder(BorderFactory.createLineBorder(theme.textColor, 1)); + levelProgressBar.setUI(new BasicProgressBarUI() { + protected Color getSelectionBackground() { + return Color.WHITE; // set the color of the progress bar + } + protected Color getSelectionForeground() { + return Color.BLACK; // set the color of the text on the progress bar + } + }); + levelProgressBar.setStringPainted(true); + levelProgressBar.setValue(tamo.levelProgress()); + + tamoHeadstoneLabel.setFont(guiSize.messageLabelFont); + tamoHeadstoneLabel.setForeground(theme.textColor); + } + + @Override + protected void initializeComponentActions() { + nextButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + nextPreviousPage(true); + + } + }); + + previousButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + nextPreviousPage(false); + + } + }); + } + + @Override + protected void initializePanel() { + GridBagConstraints gbch = new GridBagConstraints(); + gbch.gridheight = GridBagConstraints.REMAINDER; + + GridBagConstraints gbcv = new GridBagConstraints(); + gbcv.gridwidth = GridBagConstraints.REMAINDER; + + tamoPanel.add(tamoNameLabel, gbcv); + tamoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + + tamoGraphicsPanelPanel.add(tamoGraphicsPanel); + + tamoPanel.add(tamoGraphicsPanelPanel, gbcv); + tamoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoPanel.add(tamoHeadstoneLabel, gbcv); + tamoPanel.add(Box.createVerticalStrut(guiSize.settingsVerticalDifference), gbcv); + tamoPanel.add(tamoLevelLabel, gbcv); + tamoPanel.add(levelProgressBar, gbcv); + + this.setLayout(new GridBagLayout()); + this.add(previousButton, gbch); + this.add(tamoPanel, gbch); + this.add(nextButton, gbch); + } + + public void nextPreviousPage(boolean next) { + if(next) { + try { + tamoHistory.get(tamoPage + 1); + + // Changing page + tamoPage++; + tamo = tamoHistory.get(tamoPage); + repaintTamoPanel(); + } catch (IndexOutOfBoundsException e) { + // No Tamo for index + System.out.println("Cannot move forward"); + } + } else { + try { + tamoHistory.get(tamoPage - 1); + + // Changing page + tamoPage--; + tamo = tamoHistory.get(tamoPage); + repaintTamoPanel(); + } catch (IndexOutOfBoundsException e) { + // No Tamo for index + System.out.println("Cannot move backwards"); + } + } + + Debug.info("TamoHistoryState.nextPreviousPage", "tamoPage = " + tamoPage); + } + + public void repaintTamoPanel() { + tamoGraphicsPanelPanel.remove(tamoGraphicsPanel); + tamoGraphicsPanel = new TamoGraphicsPanel(guiSize, tamo, profile.getBackgroundIndicator(), profile.getBorderIndicator()); + tamoGraphicsPanelPanel.add(tamoGraphicsPanel); + + tamoNameLabel.setText(tamo.getName()); + tamoLevelLabel.setText(language.levelText + " : " + tamo.getLevel()); + levelProgressBar.setValue(tamo.levelProgress()); + tamoHeadstoneLabel.setText(tamo.getBirthDateString() + " - " + tamo.getPassDateString()); + + tamoGraphicsPanel.revalidate(); + tamoGraphicsPanel.repaint(); + this.revalidate(); + this.repaint(); + } + + /* + * ################################## + * ################################## + * HELPER METHODS + * ################################## + * ################################## + */ + public void addButtonVisual(JButton button) { + button.setContentAreaFilled(false); + button.setOpaque(false); + button.setBorderPainted(false); + button.setFocusPainted(false); + } +} diff --git a/TamoStudy/src/test/model/profile/ProfileUpdateManagerTests.java b/TamoStudy/src/test/model/profile/ProfileUpdateManagerTests.java new file mode 100644 index 0000000..77ba6a9 --- /dev/null +++ b/TamoStudy/src/test/model/profile/ProfileUpdateManagerTests.java @@ -0,0 +1,229 @@ +package test.model.profile; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import model.language.EnglishLanguage; +import model.profile.Profile; +import model.profile.ProfileSettings; +import model.profile.ProfileUpdateManager; +import model.profile.Tamo; +import resources.Debug; +import util.Utils; + +class ProfileUpdateManagerTests { + + void updateHappyHungerOnDayChange(Profile profile) { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "Updating Happy Hunger for " + profile.getName() + ); + String todayAsString = Utils.todayAsString(); + if(!profile.getPreviousDateString().equals(todayAsString)) { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "New day - updating date string and applying happy/hunger changes." + ); + LocalDate todayLocalDate = LocalDate.parse(Utils.todayAsString()); + LocalDate previousLocalDate = LocalDate.parse(profile.getPreviousDateString()); + + profile.setPreviousDateString(todayAsString); + // Updating happiness and hunger based on time + + long daysBetween = ChronoUnit.DAYS.between(previousLocalDate, todayLocalDate); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "daysBetween = " + daysBetween); + + if(daysBetween < 3) { + updateTamoHunger(profile.getTamo(), 2); + updateTamoHappy(profile.getTamo(), 1); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween < 7 && daysBetween >= 3) { + updateTamoHunger(profile.getTamo(), 3); + updateTamoHappy(profile.getTamo(), 2); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween >= 7 && daysBetween < 30) { + updateTamoHunger(profile.getTamo(), 10); + updateTamoHappy(profile.getTamo(), 10); + + if((profile.getTamo().getHunger() < 2 || profile.getTamo().getHappy() < 2) && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(profile.getTamo().getStrikes() + 1); + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", "Strike added to tamo " + profile.getTamo().getName() + ", now has " + profile.getTamo().getStrikes() + "."); + } + } else if(daysBetween >= 30 && profile.getSettings().getDifficulty() != 0) { + profile.getTamo().setStrikes(3); + Debug.info("ProfileUpdateManage.updateHappyHungerOnDayChange", "User did not login within 30 days. Tamo automatically passes."); + } + + /* + * TODO + * + * Under the condition that the state is display happy and hunger, notably, + * dashboard, focus, and statistics, the happiness and hunger should be updated, + * along with the tamo image. + */ + } else { + Debug.info("ProfileUpdateManager.updateHappyHungerOnDayChange", + "Same day detected - applying no changes to profile." + ); + } + } + + public void updateTamoHunger(Tamo tamo, int subtraction) { + // Calculate hunger + int hunger = (int) tamo.getHunger() - subtraction; + + // Validate hunger cannot be negative + if(hunger < 0) { + hunger = 0; + } + + // Set hunger + tamo.setHunger(hunger); + } + + public void updateTamoHappy(Tamo tamo, int subtraction) { + // Calculate hunger + int happy = (int) tamo.getHappy() - subtraction; + + // Validate hunger cannot be negative + if(happy < 0) { + happy = 0; + } + + // Set hunger + tamo.setHappy(happy); + } + + public Profile createTestProfile() { + return new Profile( + 123, + "TestName", + Utils.todayAsString(), + 1000, + 100, + new ProfileSettings(new EnglishLanguage(), 0, 1), + 0, + 0, + new ArrayList(), + new ArrayList(), + new ArrayList(), + new ArrayList(), + new Tamo("Lisa"), + new ArrayList() + ); + } + + @Test + void testUpdateHappyHungerOnChangeSameDay() { + Profile profile = createTestProfile(); + + updateHappyHungerOnDayChange(profile); + + assertEquals(profile.getTamo().getStrikes(), 0); + assertEquals(profile.getTamo().getHappy(), 7); + assertEquals(profile.getTamo().getHunger(), 8); + } + + @Test + void testUpdateHappyHungerOnChangeDaysBetween3NoStrikes() { + // Get the current date + LocalDate currentDate = Utils.today().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate previousDate = currentDate.minusDays(1); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String previousDateString = previousDate.format(formatter); + + // Test today - 1 + Profile profile = createTestProfile(); + profile.setPreviousDateString(previousDateString); + updateHappyHungerOnDayChange(profile); + + assertEquals(profile.getTamo().getStrikes(), 0); + assertEquals(profile.getTamo().getHappy(), 6); + assertEquals(profile.getTamo().getHunger(), 6); + + // Test today - 2 + previousDate.minusDays(1); + previousDateString = previousDate.format(formatter); + Profile profile2 = createTestProfile(); + profile2.setPreviousDateString(previousDateString); + updateHappyHungerOnDayChange(profile2); + + assertEquals(profile2.getTamo().getStrikes(), 0); + assertEquals(profile2.getTamo().getHappy(), 6); + assertEquals(profile2.getTamo().getHunger(), 6); + } + + @Test + void testUpdateHappyHungerOnChangeDaysBetween3Strikes() { + // Get the current date + LocalDate currentDate = Utils.today().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate previousDate = currentDate.minusDays(1); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String previousDateString = previousDate.format(formatter); + + // Test today - 1 + Profile profile = createTestProfile(); + profile.getTamo().setHappy(2); + profile.getTamo().setHunger(2); + profile.setPreviousDateString(previousDateString); + updateHappyHungerOnDayChange(profile); + + assertEquals(profile.getTamo().getStrikes(), 1); + assertEquals(profile.getTamo().getHappy(), 1); + assertEquals(profile.getTamo().getHunger(), 0); + } + + + @Test + void testUpdateHappyHungerOnChangeDaysBetween3and7NoStrikes() { + // Get the current date + LocalDate currentDate = Utils.today().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate previousDate = currentDate.minusDays(3); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String previousDateString = previousDate.format(formatter); + + // Test today - 1 + Profile profile = createTestProfile(); + profile.setPreviousDateString(previousDateString); + updateHappyHungerOnDayChange(profile); + + assertEquals(0, profile.getTamo().getStrikes()); + assertEquals(5, profile.getTamo().getHappy()); + assertEquals(5, profile.getTamo().getHunger()); + } + + @Test + void testUpdateHappyHungerOnChangeDaysBetween3and7Strikes() { + // Get the current date + LocalDate currentDate = Utils.today().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate previousDate = currentDate.minusDays(3); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String previousDateString = previousDate.format(formatter); + + // Test today - 1 + Profile profile = createTestProfile(); + profile.getTamo().setHappy(4); + profile.getTamo().setHunger(4); + profile.setPreviousDateString(previousDateString); + updateHappyHungerOnDayChange(profile); + + assertEquals(1, profile.getTamo().getStrikes()); + assertEquals(2, profile.getTamo().getHappy()); + assertEquals(1, profile.getTamo().getHunger()); + } +} diff --git a/TamoStudy/src/util/Utils.java b/TamoStudy/src/util/Utils.java new file mode 100644 index 0000000..7f36a85 --- /dev/null +++ b/TamoStudy/src/util/Utils.java @@ -0,0 +1,197 @@ +package util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.temporal.ChronoUnit; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; + +import model.profile.Profile; +import model.time.DailyFocus; +import model.time.DailyFocusEntry; +import model.time.MonthFocus; +import model.time.MonthFocusEntry; +import resources.Debug; + +public class Utils { + public static Date today() { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date date = new Date(); + String formattedDateString = formatter.format(date); + try { + return formatter.parse(formattedDateString); + } catch (ParseException e) { + e.printStackTrace(); + } + throw new RuntimeException("Unexpected error occurred"); + } + + public static Date yesterday(Date today) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date date = Date.from(today.toInstant().minus(1, ChronoUnit.DAYS)); + String formattedDateString = formatter.format(date); + try { + return formatter.parse(formattedDateString); + } catch (ParseException e) { + e.printStackTrace(); + } + throw new RuntimeException("Unexpected error occurred"); + } + + public static String todayAsString() { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date date = new Date(); + return formatter.format(date); + } + + public static Date stringToDate(String dateString) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + try { + return formatter.parse(dateString); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } + + public static String dateAsString(Date date) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.format(date); + } + + public static String prettyDateAsString(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM d, yyyy"); + return sdf.format(date); + } + + public static boolean validateDateString(String dateString) { + String regex = "^\\d{4}\\-(0[1-9]|1[012])\\-(0[1-9]|[12][0-9]|3[01])$"; + return Pattern.matches(regex, dateString); + } + + public static String decrypt(String message) { + char[] chars = message.toCharArray(); + for(int i = 0; i < message.length(); i++) { + chars[i] -= 6; + } + + String encryptedMessage = new String(chars); + return encryptedMessage; + } + + public static String readFile(File file) { + StringBuilder fileContents = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + fileContents.append(line); + fileContents.append(System.lineSeparator()); + } + } catch (IOException e) { + e.printStackTrace(); + } + return fileContents.toString(); + } + + public static long getCurrentDay() { + Calendar calendar = Calendar.getInstance(); + return calendar.get(Calendar.DAY_OF_MONTH); + } + + public static long getCurrentMonth() { + Calendar calendar = Calendar.getInstance(); + return calendar.get(Calendar.MONTH) + 1; // Month is zero-based, so add 1 + } + + public static long getCurrentYear() { + Calendar calendar = Calendar.getInstance(); + return calendar.get(Calendar.YEAR); + } + + public static DailyFocus createDailyFocus(Profile profile) { + return new DailyFocus( + profile.getId(), + Collections.emptyList() + ); + } + + public static MonthFocus createMonthFocus(Profile profile) { + return new MonthFocus( + profile.getId(), + Collections.emptyList() + ); + } + + public static DailyFocusEntry createDailyFocusEntry() { + return new DailyFocusEntry( + getCurrentDay(), + getCurrentMonth(), + getCurrentYear(), + (long) 0 + ); + } + + public static MonthFocusEntry createMonthFocusEntry() { + return new MonthFocusEntry(getCurrentMonth(), getCurrentYear(), (long) 0); + } + + public static DailyFocus searchDailyFocusByProfile(List dailyFocusList, Profile profile) { + for(DailyFocus dailyFocus : dailyFocusList) { + if(dailyFocus.getProfileId() == profile.getId()) { + return dailyFocus; + } + } + Debug.warn("Utils.searchDailyFocusByProfileId", "No daily focus object found for profile. Returning null to signal does not exist"); + return null; + } + + public static DailyFocusEntry searchTodayFocusEntryByProfile(List dailyFocusEntries) { + for(DailyFocusEntry dailyFocusEntry : dailyFocusEntries) { + if(dailyFocusEntry.getDay() == getCurrentDay() + && dailyFocusEntry.getMonth() == getCurrentMonth() + && dailyFocusEntry.getYear() == getCurrentYear()) { + return dailyFocusEntry; + } + } + + Debug.warn("Utils.searchTodayFocusEntryByProfile", "No daily focus entry found for today. Returning null to signal entry does not exist"); + return null; + } + + public static MonthFocus searchMonthFocusByProfile(List monthFocusList, Profile profile) { + for(MonthFocus monthFocus : monthFocusList) { + if(monthFocus.getProfileId() == profile.getId()) { + return monthFocus; + } + } + + Debug.warn("Utils.searchMonthFocusByProfile", "No month focus object found for profile. Returning null to signal does not exist"); + return null; + } + + public static MonthFocusEntry searchCurrentMonthEntryByProfile(List monthFocusEntries) { + for(MonthFocusEntry monthFocusEntry : monthFocusEntries) { + if(monthFocusEntry.getMonth() == getCurrentMonth() + && monthFocusEntry.getYear() == getCurrentYear()) { + return monthFocusEntry; + } + } + + Debug.warn("Utils.searchCurrentMonthEntryByProfile", "No month focus entry found for this month. Returning null to signal entry does not exist"); + return null; + } + + public static double convertSecondsToHours(long seconds) { + double hours = (double) seconds / 3600; // 1 hour = 3600 seconds + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + return Double.parseDouble(decimalFormat.format(hours)); + } +}