Compare commits

...

19 Commits

Author SHA1 Message Date
751f878a32 Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 9s
2025-12-22 08:48:39 -06:00
3d1d98ee7b Add src/main/java/dev/sillyangel/calc/CalculatorHistory.java
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-22 08:44:41 -06:00
bf126de5b9 Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 10:01:53 -06:00
485dccdf3b Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 09:57:41 -06:00
5b9568013d Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 7s
2025-12-17 09:54:05 -06:00
48c2e0abd9 Update .gitea/workflows/build.yml
All checks were successful
Build the Jar / build (push) Successful in 8s
2025-12-17 09:25:28 -06:00
ebdf464c31 Upload files to "lib"
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 09:02:06 -06:00
b812535366 Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 09:00:15 -06:00
a52fe8dc78 Update src/main/java/dev/sillyangel/calc/Calculator.java
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 08:59:30 -06:00
cc2a625fc1 update something?
Some checks failed
Build the Jar / build (push) Failing after 6s
2025-12-17 08:53:50 -06:00
c7659bb44e Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 9s
2025-12-17 08:47:08 -06:00
16e85a3fe3 delete now deletes 😭
Some checks failed
Build the Jar / build (push) Failing after 7s
2025-12-17 08:44:40 -06:00
c8aa7a9648 Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 7s
2025-12-16 14:01:08 -06:00
cdc05c9b67 Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 8s
2025-12-16 13:45:03 -06:00
250384e738 Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 8s
2025-12-16 13:39:29 -06:00
1c749e1098 Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 8s
2025-12-16 13:08:36 -06:00
c3756e1982 Update src/main/java/dev/sillyangel/calc/Calculator.java
All checks were successful
Build the Jar / build (push) Successful in 9s
2025-12-16 12:13:27 -06:00
97777f1046 Upload files to "lib"
All checks were successful
Build the Jar / build (push) Successful in 8s
2025-12-15 14:15:58 -06:00
c59fdc4430 Delete CalcShortforCalculator.jar
All checks were successful
Build the Jar / build (push) Successful in 7s
2025-12-15 14:12:05 -06:00
8 changed files with 357 additions and 35 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- name: Compile Java files
run: |
javac -encoding UTF-8 -cp "lib/flatlaf-3.7.jar" -d out/production/Calc \
javac -encoding UTF-8 -cp "lib/flatlaf-3.7.jar:lib/flatlaf-extras-3.7.jar" -d out/production/Calc \
$(find src/main/java -name "*.java")
- name: Copy resources

Binary file not shown.

BIN
lib/flatlaf-3.7-sources.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/flatlaf-extras-3.7.jar Normal file

Binary file not shown.

View File

@@ -15,13 +15,22 @@ import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.*;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import java.util.prefs.Preferences;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.SystemInfo;
import dev.sillyangel.calc.themes.*;
import dev.sillyangel.calc.CalculatorModes;
public class Calculator extends JFrame implements KeyListener {
private static final String PREF_NODE_NAME = "dev/sillyangel/calc";
private static boolean
private static int
public static final Preferences prefs = Preferences.userRoot().node(PREF_NODE_NAME);
public static String APPILCATION_VERSION = "1.0.0pre";
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField display;
@@ -36,15 +45,31 @@ public class Calculator extends JFrame implements KeyListener {
protected double result;
private String[] Modes = new String[] {"Standard", "Scientific", "Data calculation"};
private JComboBox<String> modeselect;
private final CalculatorHistory history;
public static final String getVersion() {
return APPILCATION_VERSION;
}
public static void main(String[] args) {
// IntelliJTheme.setup(Calculator.class.getResourceAsStream("/DarkPurple.theme.json"));
// FlatMacDarkLaf.setup();
// MacDarkRed.setup();
MacDarkBlue.setup();
MacDarkBlue.setup();
System.out.println("\nangel's awesome calculator (acc) " + Calculator.getVersion());
System.out.println("created by angel");
System.out.println("---------------------------------");
if( SystemInfo.isMacOS ) {
System.setProperty( "apple.laf.useScreenMenuBar", "true" );
System.setProperty( "apple.awt.application.name", "Calculator" );
System.setProperty( "apple.awt.application.appearance", "system" );
}
if( SystemInfo.isLinux ) { // why is linux different
JFrame.setDefaultLookAndFeelDecorated(true);
}
try {
// UIManager.setLookAndFeel("com.formdev.flatlaf.themes.FlatMacDarkLaf");
UIManager.put("defaultFont", new Font("Segoe UI", Font.PLAIN, 29));
} catch (Throwable e) {
e.printStackTrace();
}
@@ -59,11 +84,12 @@ public class Calculator extends JFrame implements KeyListener {
}
});
}
public Calculator() {
history = new CalculatorHistory();
setBackground(new Color(32, 32, 32));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// setIconImage(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon.png")));
//setIconImage(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon.png")));
List<Image> icons = new ArrayList<>();
icons.add(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon16.png")));
icons.add(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon32.png")));
@@ -72,7 +98,7 @@ public class Calculator extends JFrame implements KeyListener {
icons.add(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon512.png")));
icons.add(Toolkit.getDefaultToolkit().getImage(Calculator.class.getResource("/images/appIcon1024.png")));
setIconImages(icons);
setTitle("AAC");
setBounds(100, 100, 368, 556);
setFocusable(true);
@@ -96,7 +122,8 @@ public class Calculator extends JFrame implements KeyListener {
}
});
JPanel panel = new JPanel();
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
GroupLayout gl_contentPane = new GroupLayout(contentPane);
gl_contentPane.setHorizontalGroup(
gl_contentPane.createParallelGroup(Alignment.LEADING)
@@ -125,14 +152,55 @@ public class Calculator extends JFrame implements KeyListener {
JMenuBar menubar = new JMenuBar();
JMenu help = new JMenu("Help");
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
/*
* Edit Will have
* Undo
* Redo
* Cut
* Copy
* Paste
* Delete which is just Backspace or Clear all a
* Settings
* */
JMenuItem Exit = new JMenuItem("Exit");
Exit.addActionListener(e -> System.exit(1));
Exit.setMnemonic('E');
JMenuItem about = new JMenuItem("About");
about.setMnemonic('A');
about.addActionListener(e -> aboutActionPerformed());
JMenuItem undo = new JMenuItem("Undo");
JMenuItem redo = new JMenuItem("Redo");
JMenuItem cut = new JMenuItem("Cut");
JMenuItem copy = new JMenuItem("Copy");
JMenuItem paste = new JMenuItem("Paste");
JMenuItem delete = new JMenuItem("Delete");
delete.addActionListener(e -> clearEntry());
JMenuItem preferencesm = new JMenuItem("Preferences");
preferencesm.setMnemonic('P');
preferencesm.addActionListener(e -> PreferencesAction());
edit.add(undo);
edit.add(redo);
edit.add(cut);
edit.add(copy);
edit.add(paste);
edit.add(delete);
edit.add(preferencesm);
file.add(Exit);
file.setMnemonic('F');
help.add(about);
help.setMnemonic('H');
edit.setMnemonic('E');
menubar.add(file);
menubar.add(edit);
menubar.add(help);
setJMenuBar(menubar);
@@ -345,30 +413,30 @@ public class Calculator extends JFrame implements KeyListener {
btnBackspace.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnClear.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnClearEntry.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnPlusMin.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnEq.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnDot.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn0.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn1.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn2.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn3.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn4.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn5.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn6.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn7.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn8.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btn9.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnMul.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnMin.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnDiv.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnPlus.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnPercent.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnReciprocal.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnSquare.setFont(new Font("Segoe UI", Font.PLAIN, 29));
btnSquareRoot.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnBackspace.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnClear.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnClearEntry.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnPlusMin.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnEq.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnDot.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn0.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn1.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn2.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn3.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn4.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn5.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn6.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn7.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn8.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btn9.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnMul.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnMin.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnDiv.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnPlus.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnPercent.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnReciprocal.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnSquare.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// btnSquareRoot.setFont(new Font("Segoe UI", Font.PLAIN, 29));
// Make all buttons non-focusable so keyboard input always goes to the frame because if we don't it breaks
btnBackspace.setFocusable(false);
@@ -424,7 +492,86 @@ public class Calculator extends JFrame implements KeyListener {
contentPane.setLayout(gl_contentPane);
}
private void PreferencesAction() {
JDialog dialog = new JDialog(this, "Preferences", true);
dialog.setSize(320, 220);
dialog.setLocationRelativeTo(this);
dialog.setLayout(new BorderLayout(10, 10));
JPanel panel = new JPanel();
panel.setBorder(new EmptyBorder(10, 10, 10, 10));
panel.setLayout(new GridLayout(0, 2, 8, 8));
// Theme selector
JComboBox<String> themeBox = new JComboBox<>(new String[]{"Dark", "Light"});
themeBox.setSelectedItem(prefs.get(PREF_THEME, "Dark"));
// Font size
JSpinner fontSizeSpinner = new JSpinner(
new SpinnerNumberModel(
prefs.getInt(PREF_FONT_SIZE, 22),
12, 48, 1
)
);
// Always on top
JCheckBox alwaysOnTopBox = new JCheckBox(
"Always on top",
prefs.getBoolean(PREF_ALWAYS_ON_TOP, false)
);
panel.add(new JLabel("Theme"));
panel.add(themeBox);
panel.add(new JLabel("Font size"));
panel.add(fontSizeSpinner);
panel.add(new JLabel(""));
panel.add(alwaysOnTopBox);
JButton apply = new JButton("Apply");
JButton close = new JButton("Close");
apply.addActionListener(e -> {
String theme = (String) themeBox.getSelectedItem();
int fontSize = (int) fontSizeSpinner.getValue();
boolean alwaysOnTop = alwaysOnTopBox.isSelected();
prefs.put(PREF_THEME, theme);
prefs.putInt(PREF_FONT_SIZE, fontSize);
prefs.putBoolean(PREF_ALWAYS_ON_TOP, alwaysOnTop);
applyPreferences(theme, fontSize, alwaysOnTop);
});
close.addActionListener(e -> dialog.dispose());
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttons.add(apply);
buttons.add(close);
dialog.add(panel, BorderLayout.CENTER);
dialog.add(buttons, BorderLayout.SOUTH);
dialog.setVisible(true);
}
private void applyPreferences(String theme, int fontSize, boolean alwaysOnTop) {
display.setFont(new Font("Segoe UI", Font.PLAIN, fontSize));
setAlwaysOnTop(alwaysOnTop);
try {
FlatAnimatedLafChange.showSnapshot();
if ("Light".equals(theme)) {
FlatIntelliJLaf.setup();
} else {
FlatDarculaLaf.setup();
}
FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void aboutActionPerformed() {
JLabel titleLabel = new JLabel( "Angel's Awesome Calculator" );
titleLabel.putClientProperty( FlatClientProperties.STYLE_CLASS, "h1" );
@@ -451,6 +598,7 @@ public class Calculator extends JFrame implements KeyListener {
titleLabel,
"a very okay calculator app created in java (uses flatlaf)",
" ",
"Version " + Calculator.getVersion(),
"Copyright " + Year.now() + " angel",
linkLabel,
},
@@ -567,6 +715,42 @@ public class Calculator extends JFrame implements KeyListener {
display.setText(""+result);
}
private void loadPreferences() {
int fontSize = prefs.getInt(PREF_FONT_SIZE, 22);
boolean alwaysOnTop = prefs.getBoolean(PREF_ALWAYS_ON_TOP, false);
display.setFont(new Font("Segoe UI", Font.PLAIN, fontSize));
setAlwaysOnTop(alwaysOnTop);
}
private void changeThemes(String theme) {
boolean dark = switch (theme.toLowerCase()) {
case "dark", "darcula", "macdarkblue", "macdarkred" -> true;
default -> false;
};
// Only switch if needed
if (FlatLaf.isLafDark() != dark || isCustomMacTheme(theme)) {
EventQueue.invokeLater(() -> {
FlatAnimatedLafChange.showSnapshot();
try {
switch (theme.toLowerCase()) {
case "light" -> FlatIntelliJLaf.setup();
case "dark", "darcula" -> FlatDarculaLaf.setup();
case "macdarkblue" -> MacDarkBlue.setup();
case "macdarkred" -> MacDarkRed.setup();
default -> FlatDarculaLaf.setup();
}
FlatLaf.updateUI();
} finally {
FlatAnimatedLafChange.hideSnapshotWithAnimation();
}
});
}
}
// Implement the keyPressed method
@Override
public void keyPressed(KeyEvent e) {

View File

@@ -0,0 +1,138 @@
package dev.sillyangel.calc;
import java.io.*;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* Manages calculation history for the calculator application.
* Stores calculations in a file and provides methods to retrieve and manage history.
*/
public class CalculatorHistory {
private final List<String> calculationHistory = new ArrayList<>();
private final Path historyFilePath;
private static final String HISTORY_DIR = System.getProperty("user.home") + File.separator + ".calculator";
private static final String HISTORY_FILE = "calc_history.txt";
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public CalculatorHistory() {
historyFilePath = Paths.get(HISTORY_DIR, HISTORY_FILE);
initializeHistoryFile();
}
/**
* Initializes the history file and directory structure.
* Creates the directory and file if they don't exist, and loads existing history.
*/
private void initializeHistoryFile() {
try {
// Create directory if it doesn't exist
Path dir = Paths.get(HISTORY_DIR);
if (!Files.exists(dir)) {
Files.createDirectories(dir);
System.out.println("Created history directory: " + HISTORY_DIR);
}
// Create file if it doesn't exist
if (!Files.exists(historyFilePath)) {
Files.createFile(historyFilePath);
System.out.println("Created history file: " + historyFilePath);
}
// Load existing history
loadHistory();
} catch (IOException e) {
System.err.println("Error initializing history file: " + e.getMessage());
}
}
/**
* Saves a calculation to the history file.
* @param calculation The calculation string to save (e.g., "5 + 3 = 8")
*/
public void saveToHistory(String calculation) {
try {
String timestamp = LocalDateTime.now().format(formatter);
String entry = "[" + timestamp + "] " + calculation;
// Add to memory list
calculationHistory.add(entry);
// Append to file
Files.write(historyFilePath,
(entry + System.lineSeparator()).getBytes(),
StandardOpenOption.APPEND);
System.out.println("Saved to history: " + entry);
} catch (IOException e) {
System.err.println("Error saving to history: " + e.getMessage());
}
}
/**
* Loads history from the file into memory.
*/
private void loadHistory() {
try {
if (Files.exists(historyFilePath)) {
List<String> lines = Files.readAllLines(historyFilePath);
calculationHistory.addAll(lines);
System.out.println("Loaded " + lines.size() + " history entries");
}
} catch (IOException e) {
System.err.println("Error loading history: " + e.getMessage());
}
}
/**
* Returns a copy of all calculation history entries.
* @return A list of history entries with timestamps
*/
public List<String> getCalculationHistory() {
return new ArrayList<>(calculationHistory);
}
/**
* Returns the most recent N history entries.
* @param count The number of entries to return
* @return A list of the most recent history entries
*/
public List<String> getRecentHistory(int count) {
int size = calculationHistory.size();
int fromIndex = Math.max(0, size - count);
return new ArrayList<>(calculationHistory.subList(fromIndex, size));
}
/**
* Clears all history entries from memory and file.
*/
public void clearHistory() {
try {
calculationHistory.clear();
Files.write(historyFilePath, new byte[0], StandardOpenOption.TRUNCATE_EXISTING);
System.out.println("History cleared");
} catch (IOException e) {
System.err.println("Error clearing history: " + e.getMessage());
}
}
/**
* Returns the number of history entries.
* @return The count of history entries
*/
public int getHistoryCount() {
return calculationHistory.size();
}
/**
* Returns the path to the history file.
* @return The file path as a string
*/
public String getHistoryFilePath() {
return historyFilePath.toString();
}
}