# Com / Github / Blaxk3 / Ui

## Overview

`com.github.blaxk3.ui` contains the Swing-based user interface for the currency converter application. The module builds the main window, wires the amount input and currency selectors, and connects the UI to the exchange-rate API so users can convert values, swap currencies, and clear the form.

This module also contains two small inner utility classes that keep the UI responsive and constrain input. `NumericFilter` restricts text entry to numeric values, while `CurrencyCode` loads the available currency codes in the background so the window can appear without blocking on network work.

## Key Classes and Interfaces

### [UI](src/main/java/com/github/blaxk3/ui/UI.java:30)

`UI` is the main application window. It extends `javax.swing.JFrame` and assembles all visible components for the converter: the amount field, the source and target currency combo boxes, the output label, and the action buttons.

The constructor sets up the frame immediately. It loads an application icon from `/icon/image/icon.png`, creates and adds the main panel, configures the title, size, layout, close behavior, and visibility, and centers the window on screen. In other words, instantiating `UI` is enough to launch the app.

Important responsibilities and methods:

- `getComboBox1()` and `getComboBox2()` expose the two currency selectors so the button handlers can read and update the selected currencies.
- `getTextField()` exposes the amount input field for validation and conversion logic.
- `setTextField(String msg)` and `setLabel(String textField)` are simple setters used by event handlers to update the form state and result display.
- `panel()` builds the container hierarchy for the window.
- `comboBox1()` and `comboBox2()` create the currency dropdowns and start asynchronous loading of currency codes.
- `button()` creates the Convert, Swap, and Clear buttons and binds their actions.
- `textField()` creates the amount input field and installs numeric-only filtering.
- `label()` creates the output label that displays the converted amount.

The class depends on `com.github.blaxk3.api.CurrencyRateAPI` for all currency data and conversion logic. The UI itself does not compute exchange rates; it delegates that work to the API layer.

### [UI.NumericFilter](src/main/java/com/github/blaxk3/ui/UI.java:167)

`NumericFilter` is a `DocumentFilter` implementation that constrains the amount field to numeric input with at most one decimal point. It exists to prevent invalid values from reaching the conversion logic.

Key methods:

- `insertString(FilterBypass fb, int offset, String string, AttributeSet attr)` simulates the edit against the current document text, then allows the insert only if the resulting string is valid.
- `replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)` applies the same validation when the user replaces selected text.
- `isValid(String text)` checks whether the string is empty, all digits, or digits with a single decimal point.

This class is intentionally strict. It allows blank input, digits, and one decimal separator, but rejects anything else. That keeps the conversion path simple and avoids parsing surprises later.

### [UI.CurrencyCode](src/main/java/com/github/blaxk3/ui/UI.java:214)

`CurrencyCode` is a `SwingWorker<String[], Void>` that loads available currency codes off the event dispatch thread. The worker takes a target `JComboBox<String>` in its constructor and populates it when the background task completes.

Key methods:

- `doInBackground()` calls `new CurrencyRateAPI().getCurrencyCode()` and returns the raw code list.
- `done()` retrieves the result with `get()`, sorts the codes, and adds them to the combo box. If loading fails, it logs an error with SLF4J.

This design keeps the UI responsive while currency codes are fetched. It also centralizes the population logic so both combo boxes are filled consistently.

## How It Works

### Window construction

1. `new UI()` loads the window icon and builds the main panel.
2. `panel()` creates a vertical container with two horizontal rows.
3. The first row contains the amount field and the left currency selector.
4. The second row contains the result label, the right currency selector, and the three action buttons.

### Loading currency lists

Both combo boxes are created empty in `comboBox1()` and `comboBox2()`. Each one immediately starts a `CurrencyCode` worker. When the worker finishes, `done()` sorts the returned codes and adds them to the combo box.

This means the window can render before the currency data arrives, instead of waiting for the API call to finish.

### Converting a value

The Convert button handler in `button()` performs the main business flow:

1. It checks that the text field is not empty and is not just `.`.
2. It reads the selected source and target currency codes from the combo boxes.
3. It parses the amount as a `double`, wraps it in `BigDecimal`, and passes it to `CurrencyRateAPI.convert(...)`.
4. It formats the returned numeric result with `DecimalFormat("#,###.###")` and writes it to the result label.
5. If the input is missing, it shows an error dialog asking for an amount.
6. If the API call fails with `MalformedURLException` or `URISyntaxException`, the handler rethrows the error as a runtime exception.

### Swapping currencies

The Swap button simply exchanges the selected items in the two combo boxes. It reads the current left selection, assigns the right selection to the left, and then assigns the saved value back to the right.

### Clearing the form

The Clear button resets both the amount field and the result label to empty strings.

### Input validation

The amount field uses `NumericFilter` through the underlying `PlainDocument`. Every insert or replacement is checked before it is applied. This prevents letters, symbols, and multiple decimal points from ever entering the field.

## Mermaid Diagram

```mermaid
flowchart TD
UIClass["UI"] --> Panel["panel()"]
UIClass --> ButtonGroup["button()"]
UIClass --> TextFieldComp["textField()"]
UIClass --> LabelComp["label()"]
UIClass --> ComboBoxLeft["comboBox1()"]
UIClass --> ComboBoxRight["comboBox2()"]
ComboBoxLeft --> CurrencyCodeWorker["CurrencyCode"]
ComboBoxRight --> CurrencyCodeWorker
ButtonGroup --> CurrencyRateAPI["CurrencyRateAPI"]
TextFieldComp --> NumericFilter["NumericFilter"]
CurrencyCodeWorker --> CurrencyRateAPI
```

## Data Model

This module does not define business entities or DTOs of its own. Its main runtime data structures are UI components and a few standard Java types:

- `JTextField` holds the amount entered by the user.
- Two `JComboBox<String>` instances hold the source and target currency codes.
- `JLabel` displays the conversion result.
- `BigDecimal` is used when passing the amount to the API layer.
- `String[]` is the temporary result format returned by `CurrencyCode`.

The currency codes themselves come from `CurrencyRateAPI.getCurrencyCode()` and are displayed directly in the combo boxes.

## Dependencies and Integration

### External API integration

The module depends on `com.github.blaxk3.api.CurrencyRateAPI` in two places:

- `CurrencyCode.doInBackground()` fetches the list of supported currency codes.
- The Convert button handler calls `CurrencyRateAPI.convert(...)` to compute the exchange result.

This makes `com.github.blaxk3.ui` the presentation layer for the API module. The UI owns user interaction and formatting, while the API layer owns currency data and conversion behavior.

### Swing and AWT

The implementation uses standard Swing and AWT components:

- `JFrame`, `JPanel`, `JButton`, `JComboBox`, `JLabel`, `JTextField`
- `SwingWorker` for background loading
- `DocumentFilter` for input validation
- layout and styling classes such as `FlowLayout`, `BoxLayout`, `GridLayout`, `Font`, `Color`, and `Dimension`

### Logging

`CurrencyCode.done()` logs failures through SLF4J with a module-level logger. That is the only explicit logging in the file.

## Notes for Developers

- The constructor shows the window immediately. If you add initialization logic, be aware that it will run during frame creation.
- `button()` calls `new CurrencyRateAPI()` inside the method and again in the `CurrencyCode` worker. If you extend the module, consider whether this repeated construction is acceptable for your use case.
- `NumericFilter` allows only one decimal point and no sign character. That means negative amounts are not currently supported.
- The Convert handler checks for empty input and for a lone `.` only. Other malformed values are largely prevented by the document filter rather than by the button logic.
- `CurrencyCode.done()` sorts the codes before populating the combo boxes, so the display order is alphabetical rather than whatever order the API returns.
- The combo boxes are populated asynchronously. Any code that depends on their contents should account for the fact that the lists may be empty immediately after the UI is constructed.
- `setTextField(...)` and `setLabel(...)` are straightforward mutators, but they assume the corresponding Swing components have already been created by the constructor.
