Added help pages, styled text implementation, and improved splash screen.
This commit is contained in:
parent
2a79afe1b5
commit
ce78df559e
|
@ -26,9 +26,9 @@
|
||||||
inkscape:pagecheckerboard="1"
|
inkscape:pagecheckerboard="1"
|
||||||
inkscape:deskcolor="#505050"
|
inkscape:deskcolor="#505050"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:zoom="2.0863221"
|
inkscape:zoom="1.4752525"
|
||||||
inkscape:cx="143.55406"
|
inkscape:cx="125.40226"
|
||||||
inkscape:cy="122.22466"
|
inkscape:cy="94.899008"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1025"
|
inkscape:window-height="1025"
|
||||||
inkscape:window-x="1080"
|
inkscape:window-x="1080"
|
||||||
|
@ -36,6 +36,11 @@
|
||||||
inkscape:window-maximized="1"
|
inkscape:window-maximized="1"
|
||||||
inkscape:current-layer="layer1" /><defs
|
inkscape:current-layer="layer1" /><defs
|
||||||
id="defs1"><rect
|
id="defs1"><rect
|
||||||
|
x="317.65446"
|
||||||
|
y="235.76737"
|
||||||
|
width="216.44269"
|
||||||
|
height="83.027779"
|
||||||
|
id="rect4" /><rect
|
||||||
x="23.509132"
|
x="23.509132"
|
||||||
y="17.511823"
|
y="17.511823"
|
||||||
width="25.696689"
|
width="25.696689"
|
||||||
|
@ -45,7 +50,12 @@
|
||||||
y="17.511823"
|
y="17.511823"
|
||||||
width="25.696689"
|
width="25.696689"
|
||||||
height="28.301114"
|
height="28.301114"
|
||||||
id="rect3" /></defs><g
|
id="rect3" /><rect
|
||||||
|
x="317.65446"
|
||||||
|
y="235.76737"
|
||||||
|
width="216.44269"
|
||||||
|
height="83.027779"
|
||||||
|
id="rect5" /></defs><g
|
||||||
inkscape:label="Layer 1"
|
inkscape:label="Layer 1"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"><rect
|
id="layer1"><rect
|
||||||
|
@ -54,9 +64,26 @@
|
||||||
width="105.83333"
|
width="105.83333"
|
||||||
height="52.916664"
|
height="52.916664"
|
||||||
x="0"
|
x="0"
|
||||||
y="0" /><g
|
y="0" /><path
|
||||||
|
style="display:inline;fill:#397526;fill-opacity:1;stroke:none;stroke-width:35.921;stroke-linecap:round"
|
||||||
|
d="M -51.278833,56.497593 160.38037,45.238259 159.49177,-7.633004 c 0,0 -24.42624,1.512546 -47.38917,9.245796 -22.962932,7.733249 -18.862832,17.268118 -51.065942,24.86209 -32.20311,7.593969 -45.158576,4.517345 -74.188418,14.395906 -29.029843,9.87856 -38.127073,15.626805 -38.127073,15.626805 z"
|
||||||
|
id="path5"
|
||||||
|
sodipodi:nodetypes="ccczzzc" /><path
|
||||||
|
style="display:inline;fill:#e7b300;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
||||||
|
d="M -1.3473491,68.51775 104.48598,33.263506 v -52.916667 c 0,0 -12.21534,4.282234 -23.751883,14.636677 C 69.197554,5.3379594 71.165788,14.434953 55.014288,25.695895 38.862788,36.956837 32.416445,35.338519 17.831036,48.531087 3.2456269,61.723654 -1.3473491,68.51775 -1.3473491,68.51775 Z"
|
||||||
|
id="path3"
|
||||||
|
sodipodi:nodetypes="ccczzzc" /><path
|
||||||
|
style="display:inline;fill:#ba8e00;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
||||||
|
d="M 1.2353516e-7,65.117916 105.83333,40.715416 V -12.20125 c 0,0 -12.215341,3.0297196 -23.751884,12.20125 C 70.544903,9.1715303 72.513137,18.470338 56.361637,28.075167 40.210137,37.679996 33.763794,35.400695 19.178385,47.097731 4.5929761,58.794766 1.2353516e-7,65.117916 1.2353516e-7,65.117916 Z"
|
||||||
|
id="path2"
|
||||||
|
sodipodi:nodetypes="ccczzzc" /><path
|
||||||
|
style="display:inline;fill:#ca9c00;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
||||||
|
d="M 0,52.916666 H 105.83333 V 0 c 0,0 -12.215341,0.21316952 -23.751884,6.7246636 C 70.544903,13.236158 72.513137,22.988791 56.361637,28.869491 40.210137,34.750191 33.763794,30.984525 19.178385,39.318533 4.592976,47.65254 0,52.916666 0,52.916666 Z"
|
||||||
|
id="path1"
|
||||||
|
sodipodi:nodetypes="ccczzzc" /><g
|
||||||
id="logo-group"
|
id="logo-group"
|
||||||
transform="translate(-30.013895,12.599684)"><path
|
transform="translate(41.550528,32.475407)"
|
||||||
|
style="display:inline"><path
|
||||||
id="top-right-background"
|
id="top-right-background"
|
||||||
style="fill:#346b23;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-linecap:round"
|
style="fill:#346b23;fill-opacity:1;stroke:none;stroke-width:0.79375;stroke-linecap:round"
|
||||||
d="M 4.2333332,0 C 1.8880691,0 0,1.8880691 0,4.2333332 V 12.7 c 0,2.345264 1.8880691,4.233333 4.2333332,4.233333 H 12.7 c 2.345264,0 4.233333,-1.888069 4.233333,-4.233333 V 4.2333332 C 16.933333,1.8880691 15.045264,0 12.7,0 Z" /><path
|
d="M 4.2333332,0 C 1.8880691,0 0,1.8880691 0,4.2333332 V 12.7 c 0,2.345264 1.8880691,4.233333 4.2333332,4.233333 H 12.7 c 2.345264,0 4.233333,-1.888069 4.233333,-4.233333 V 4.2333332 C 16.933333,1.8880691 15.045264,0 12.7,0 Z" /><path
|
||||||
|
@ -71,16 +98,22 @@
|
||||||
style="font-size:8px;line-height:8.64px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3);display:inline;fill:#ca9c00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round"
|
style="font-size:8px;line-height:8.64px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3);display:inline;fill:#ca9c00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round"
|
||||||
d="m 25.689419,18.184344 v 0.507817 c -0.54427,0.01823 -0.959661,0.136597 -1.246119,0.355347 -0.283854,0.216146 -0.425622,0.518229 -0.425622,0.90625 0,0.244791 0.0468,0.455806 0.14055,0.632889 0.09635,0.177084 0.24613,0.32939 0.449255,0.456994 0.205729,0.125 0.527312,0.240838 0.964812,0.347609 l 0.117124,0.03137 v 0.115242 l 0.628916,-0.628916 c -0.04352,-0.0111 -0.08269,-0.02199 -0.128837,-0.03325 v -1.664003 c 0.283854,0.01823 0.509099,0.0976 0.675766,0.238223 0.158491,0.133727 0.2669,0.329437 0.326484,0.585622 l 0.527896,-0.527896 c -0.107669,-0.217411 -0.243902,-0.385244 -0.409099,-0.503008 -0.26302,-0.190104 -0.636672,-0.294241 -1.121047,-0.312471 v -0.507817 z m 0,1.0194 v 1.613387 c -0.309896,-0.08073 -0.523441,-0.153667 -0.640628,-0.218771 -0.117188,-0.06771 -0.207095,-0.150977 -0.269595,-0.249935 -0.0599,-0.101562 -0.08973,-0.22657 -0.08973,-0.375007 0,-0.236979 0.08464,-0.420695 0.253909,-0.550903 0.16927,-0.132812 0.417915,-0.20575 0.74604,-0.218771 z"
|
d="m 25.689419,18.184344 v 0.507817 c -0.54427,0.01823 -0.959661,0.136597 -1.246119,0.355347 -0.283854,0.216146 -0.425622,0.518229 -0.425622,0.90625 0,0.244791 0.0468,0.455806 0.14055,0.632889 0.09635,0.177084 0.24613,0.32939 0.449255,0.456994 0.205729,0.125 0.527312,0.240838 0.964812,0.347609 l 0.117124,0.03137 v 0.115242 l 0.628916,-0.628916 c -0.04352,-0.0111 -0.08269,-0.02199 -0.128837,-0.03325 v -1.664003 c 0.283854,0.01823 0.509099,0.0976 0.675766,0.238223 0.158491,0.133727 0.2669,0.329437 0.326484,0.585622 l 0.527896,-0.527896 c -0.107669,-0.217411 -0.243902,-0.385244 -0.409099,-0.503008 -0.26302,-0.190104 -0.636672,-0.294241 -1.121047,-0.312471 v -0.507817 z m 0,1.0194 v 1.613387 c -0.309896,-0.08073 -0.523441,-0.153667 -0.640628,-0.218771 -0.117188,-0.06771 -0.207095,-0.150977 -0.269595,-0.249935 -0.0599,-0.101562 -0.08973,-0.22657 -0.08973,-0.375007 0,-0.236979 0.08464,-0.420695 0.253909,-0.550903 0.16927,-0.132812 0.417915,-0.20575 0.74604,-0.218771 z"
|
||||||
transform="matrix(2.4707763,0,0,2.4707763,-55.488799,-44.26592)"
|
transform="matrix(2.4707763,0,0,2.4707763,-55.488799,-44.26592)"
|
||||||
sodipodi:nodetypes="cccscccccccccccccccccccscsc" /></g><path
|
sodipodi:nodetypes="cccscccccccccccccccccccscsc" /></g><text
|
||||||
style="display:inline;fill:#e7b300;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
xml:space="preserve"
|
||||||
d="M -1.3473491,68.51775 104.48598,33.263506 v -52.916667 c 0,0 -12.21534,4.282234 -23.751883,14.636677 C 69.197554,5.3379594 71.165788,14.434953 55.014288,25.695895 38.862788,36.956837 32.416445,35.338519 17.831036,48.531087 3.2456269,61.723654 -1.3473491,68.51775 -1.3473491,68.51775 Z"
|
transform="matrix(0.26458333,0,0,0.26458333,-25.033368,-34.700052)"
|
||||||
id="path3"
|
id="text4"
|
||||||
sodipodi:nodetypes="ccczzzc" /><path
|
style="font-weight:bold;font-size:64px;line-height:69.12px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect4);display:inline;fill:#346b23;fill-opacity:1;stroke-width:96;stroke-linecap:round"><tspan
|
||||||
style="display:inline;fill:#a78000;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
x="317.6543"
|
||||||
d="M 1.2353516e-7,65.117916 105.83333,40.715416 V -12.20125 c 0,0 -12.215341,3.0297196 -23.751884,12.20125 C 70.544903,9.1715303 72.513137,18.470338 56.361637,28.075167 40.210137,37.679996 33.763794,35.400695 19.178385,47.097731 4.5929761,58.794766 1.2353516e-7,65.117916 1.2353516e-7,65.117916 Z"
|
y="289.52758"
|
||||||
id="path2"
|
id="tspan5"><tspan
|
||||||
sodipodi:nodetypes="ccczzzc" /><path
|
style="font-weight:normal;font-family:FreeSerif;-inkscape-font-specification:FreeSerif"
|
||||||
style="display:inline;fill:#ca9c00;fill-opacity:1;stroke:none;stroke-width:25.4;stroke-linecap:round"
|
id="tspan3">PerFin</tspan></tspan></text><text
|
||||||
d="M 0,52.916666 H 105.83333 V 0 c 0,0 -12.215341,0.21316952 -23.751884,6.7246636 C 70.544903,13.236158 72.513137,22.988791 56.361637,28.869491 40.210137,34.750191 33.763794,30.984525 19.178385,39.318533 4.592976,47.65254 0,52.916666 0,52.916666 Z"
|
xml:space="preserve"
|
||||||
id="path1"
|
transform="matrix(0.26458333,0,0,0.26458333,-24.420403,-19.32274)"
|
||||||
sodipodi:nodetypes="ccczzzc" /></g></svg>
|
id="text5"
|
||||||
|
style="font-weight:bold;font-size:24px;line-height:25.92px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono Bold';letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect5);display:inline;fill:#346b23;fill-opacity:1;stroke-width:96;stroke-linecap:round"><tspan
|
||||||
|
x="317.6543"
|
||||||
|
y="255.92758"
|
||||||
|
id="tspan7"><tspan
|
||||||
|
style="font-weight:normal;font-family:FreeSerif;-inkscape-font-specification:FreeSerif"
|
||||||
|
id="tspan6">Personal Finance</tspan></tspan></text></g></svg>
|
||||||
|
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 8.5 KiB |
|
@ -7,6 +7,7 @@ import com.andrewlalis.perfin.model.Profile;
|
||||||
import com.andrewlalis.perfin.view.ImageCache;
|
import com.andrewlalis.perfin.view.ImageCache;
|
||||||
import com.andrewlalis.perfin.view.SceneUtil;
|
import com.andrewlalis.perfin.view.SceneUtil;
|
||||||
import com.andrewlalis.perfin.view.StartupSplashScreen;
|
import com.andrewlalis.perfin.view.StartupSplashScreen;
|
||||||
|
import com.andrewlalis.perfin.view.component.ScrollPaneRouterView;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
@ -38,7 +39,7 @@ public class PerfinApp extends Application {
|
||||||
* A router that controls which help page is being viewed in the side-pane.
|
* A router that controls which help page is being viewed in the side-pane.
|
||||||
* Certain user actions may cause this router to navigate to certain pages.
|
* Certain user actions may cause this router to navigate to certain pages.
|
||||||
*/
|
*/
|
||||||
public static final SceneRouter helpRouter = new SceneRouter(new AnchorPaneRouterView(true));
|
public static final SceneRouter helpRouter = new SceneRouter(new ScrollPaneRouterView());
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
|
@ -75,23 +76,24 @@ public class PerfinApp extends Application {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void mapResourceRoute(String route, String resource) {
|
|
||||||
router.map(route, PerfinApp.class.getResource(resource));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void defineRoutes(Consumer<String> msgConsumer) {
|
private static void defineRoutes(Consumer<String> msgConsumer) {
|
||||||
msgConsumer.accept("Initializing application views.");
|
msgConsumer.accept("Initializing application views.");
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
mapResourceRoute("accounts", "/accounts-view.fxml");
|
// App pages.
|
||||||
mapResourceRoute("account", "/account-view.fxml");
|
router.map("accounts", PerfinApp.class.getResource("/accounts-view.fxml"));
|
||||||
mapResourceRoute("edit-account", "/edit-account.fxml");
|
router.map("account", PerfinApp.class.getResource("/account-view.fxml"));
|
||||||
mapResourceRoute("transactions", "/transactions-view.fxml");
|
router.map("edit-account", PerfinApp.class.getResource("/edit-account.fxml"));
|
||||||
mapResourceRoute("create-transaction", "/create-transaction.fxml");
|
router.map("transactions", PerfinApp.class.getResource("/transactions-view.fxml"));
|
||||||
mapResourceRoute("create-balance-record", "/create-balance-record.fxml");
|
router.map("create-transaction", PerfinApp.class.getResource("/create-transaction.fxml"));
|
||||||
|
router.map("create-balance-record", PerfinApp.class.getResource("/create-balance-record.fxml"));
|
||||||
|
|
||||||
// Map help pages.
|
// Help pages.
|
||||||
helpRouter.map("help-test", PerfinApp.class.getResource("/help-pages/help-test.fxml"));
|
|
||||||
helpRouter.map("home", PerfinApp.class.getResource("/help-pages/home.fxml"));
|
helpRouter.map("home", PerfinApp.class.getResource("/help-pages/home.fxml"));
|
||||||
|
helpRouter.map("accounts", PerfinApp.class.getResource("/help-pages/accounts-view.fxml"));
|
||||||
|
helpRouter.map("adding-an-account", PerfinApp.class.getResource("/help-pages/adding-an-account.fxml"));
|
||||||
|
helpRouter.map("transactions", PerfinApp.class.getResource("/help-pages/transactions-view.fxml"));
|
||||||
|
helpRouter.map("adding-a-transaction", PerfinApp.class.getResource("/help-pages/adding-a-transaction.fxml"));
|
||||||
|
helpRouter.map("profiles", PerfinApp.class.getResource("/help-pages/profiles.fxml"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,13 @@ package com.andrewlalis.perfin.control;
|
||||||
import com.andrewlalis.javafx_scene_router.AnchorPaneRouterView;
|
import com.andrewlalis.javafx_scene_router.AnchorPaneRouterView;
|
||||||
import com.andrewlalis.perfin.view.BindingUtil;
|
import com.andrewlalis.perfin.view.BindingUtil;
|
||||||
import com.andrewlalis.perfin.view.ProfilesStage;
|
import com.andrewlalis.perfin.view.ProfilesStage;
|
||||||
|
import com.andrewlalis.perfin.view.component.ScrollPaneRouterView;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
import static com.andrewlalis.perfin.PerfinApp.helpRouter;
|
import static com.andrewlalis.perfin.PerfinApp.helpRouter;
|
||||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||||
|
@ -19,7 +20,8 @@ public class MainViewController {
|
||||||
|
|
||||||
@FXML public Button showManualButton;
|
@FXML public Button showManualButton;
|
||||||
@FXML public Button hideManualButton;
|
@FXML public Button hideManualButton;
|
||||||
@FXML public VBox manualVBox;
|
@FXML public BorderPane helpPane;
|
||||||
|
@FXML public Button helpBackButton;
|
||||||
|
|
||||||
@FXML public void initialize() {
|
@FXML public void initialize() {
|
||||||
AnchorPaneRouterView routerView = (AnchorPaneRouterView) router.getView();
|
AnchorPaneRouterView routerView = (AnchorPaneRouterView) router.getView();
|
||||||
|
@ -41,15 +43,26 @@ public class MainViewController {
|
||||||
router.navigate("accounts");
|
router.navigate("accounts");
|
||||||
|
|
||||||
// Initialize the help manual components.
|
// Initialize the help manual components.
|
||||||
manualVBox.managedProperty().bind(manualVBox.visibleProperty());
|
helpPane.managedProperty().bind(helpPane.visibleProperty());
|
||||||
manualVBox.setVisible(false);
|
helpPane.setVisible(false);
|
||||||
showManualButton.managedProperty().bind(showManualButton.visibleProperty());
|
showManualButton.managedProperty().bind(showManualButton.visibleProperty());
|
||||||
showManualButton.visibleProperty().bind(manualVBox.visibleProperty().not());
|
showManualButton.visibleProperty().bind(helpPane.visibleProperty().not());
|
||||||
hideManualButton.managedProperty().bind(hideManualButton.visibleProperty());
|
hideManualButton.managedProperty().bind(hideManualButton.visibleProperty());
|
||||||
hideManualButton.visibleProperty().bind(manualVBox.visibleProperty());
|
hideManualButton.visibleProperty().bind(helpPane.visibleProperty());
|
||||||
|
|
||||||
AnchorPaneRouterView helpRouterView = (AnchorPaneRouterView) helpRouter.getView();
|
helpBackButton.managedProperty().bind(helpBackButton.visibleProperty());
|
||||||
manualVBox.getChildren().add(helpRouterView.getAnchorPane());
|
helpRouter.currentRouteProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
helpBackButton.setVisible(helpRouter.getHistory().canGoBack());
|
||||||
|
});
|
||||||
|
helpBackButton.setOnAction(event -> helpRouter.navigateBack());
|
||||||
|
|
||||||
|
ScrollPaneRouterView helpRouterView = (ScrollPaneRouterView) helpRouter.getView();
|
||||||
|
ScrollPane helpRouterScrollPane = helpRouterView.getScrollPane();
|
||||||
|
helpRouterScrollPane.setMinWidth(200.0);
|
||||||
|
helpRouterScrollPane.setMaxWidth(400.0);
|
||||||
|
helpRouterScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
|
||||||
|
helpRouterScrollPane.getStyleClass().addAll("padding-extra");
|
||||||
|
helpPane.setCenter(helpRouterScrollPane);
|
||||||
|
|
||||||
helpRouter.navigate("home");
|
helpRouter.navigate("home");
|
||||||
}
|
}
|
||||||
|
@ -77,10 +90,25 @@ public class MainViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML public void showManual() {
|
@FXML public void showManual() {
|
||||||
manualVBox.setVisible(true);
|
helpPane.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML public void hideManual() {
|
@FXML public void hideManual() {
|
||||||
manualVBox.setVisible(false);
|
helpPane.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML public void helpViewHome() {
|
||||||
|
helpRouter.getHistory().clear();
|
||||||
|
helpRouter.navigate("home");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML public void helpViewAccounts() {
|
||||||
|
helpRouter.getHistory().clear();
|
||||||
|
helpRouter.navigate("accounts");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML public void helpViewTransactions() {
|
||||||
|
helpRouter.getHistory().clear();
|
||||||
|
helpRouter.navigate("transactions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import com.andrewlalis.perfin.data.ProfileLoadException;
|
||||||
import com.andrewlalis.perfin.data.util.FileUtil;
|
import com.andrewlalis.perfin.data.util.FileUtil;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
import com.andrewlalis.perfin.view.ProfilesStage;
|
import com.andrewlalis.perfin.view.ProfilesStage;
|
||||||
import javafx.beans.binding.BooleanExpression;
|
import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import com.andrewlalis.perfin.view.component.validation.validators.PredicateValidator;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
@ -16,6 +16,8 @@ import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.scene.text.TextFlow;
|
import javafx.scene.text.TextFlow;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -24,22 +26,16 @@ import java.util.List;
|
||||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||||
|
|
||||||
public class ProfilesViewController {
|
public class ProfilesViewController {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ProfilesViewController.class);
|
||||||
|
|
||||||
@FXML public VBox profilesVBox;
|
@FXML public VBox profilesVBox;
|
||||||
@FXML public TextField newProfileNameField;
|
@FXML public TextField newProfileNameField;
|
||||||
@FXML public Text newProfileNameErrorLabel;
|
|
||||||
@FXML public Button addProfileButton;
|
@FXML public Button addProfileButton;
|
||||||
|
|
||||||
@FXML public void initialize() {
|
@FXML public void initialize() {
|
||||||
BooleanExpression newProfileNameValid = BooleanProperty.booleanExpression(newProfileNameField.textProperty()
|
var newProfileNameValid = new ValidationApplier<>(new PredicateValidator<String>()
|
||||||
.map(text -> (
|
.addPredicate(s -> s == null || s.isBlank() || Profile.validateName(s), "Profile name should consist of only lowercase numbers.")
|
||||||
text != null &&
|
).attachToTextField(newProfileNameField);
|
||||||
!text.isBlank() &&
|
|
||||||
Profile.validateName(text) &&
|
|
||||||
!Profile.getAvailableProfiles().contains(text)
|
|
||||||
)));
|
|
||||||
newProfileNameErrorLabel.managedProperty().bind(newProfileNameErrorLabel.visibleProperty());
|
|
||||||
newProfileNameErrorLabel.visibleProperty().bind(newProfileNameValid.not().and(newProfileNameField.textProperty().isNotEmpty()));
|
|
||||||
newProfileNameErrorLabel.wrappingWidthProperty().bind(newProfileNameField.widthProperty());
|
|
||||||
addProfileButton.disableProperty().bind(newProfileNameValid.not());
|
addProfileButton.disableProperty().bind(newProfileNameValid.not());
|
||||||
|
|
||||||
refreshAvailableProfiles();
|
refreshAvailableProfiles();
|
||||||
|
@ -106,7 +102,7 @@ public class ProfilesViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean openProfile(String name, boolean showPopup) {
|
private boolean openProfile(String name, boolean showPopup) {
|
||||||
System.out.println("Opening profile: " + name);
|
log.info("Opening profile \"{}\".", name);
|
||||||
try {
|
try {
|
||||||
Profile.load(name);
|
Profile.load(name);
|
||||||
ProfilesStage.closeView();
|
ProfilesStage.closeView();
|
||||||
|
|
|
@ -62,10 +62,15 @@ public class StartupSplashScreen extends Stage implements Consumer<String> {
|
||||||
|
|
||||||
private void runTasks() {
|
private void runTasks() {
|
||||||
Thread.ofVirtual().start(() -> {
|
Thread.ofVirtual().start(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
for (var task : tasks) {
|
for (var task : tasks) {
|
||||||
try {
|
try {
|
||||||
task.accept(this);
|
task.accept(this);
|
||||||
Thread.sleep(100);
|
Thread.sleep(500);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
accept("Startup failed: " + e.getMessage());
|
accept("Startup failed: " + e.getMessage());
|
||||||
e.printStackTrace(System.err);
|
e.printStackTrace(System.err);
|
||||||
|
@ -80,7 +85,7 @@ public class StartupSplashScreen extends Stage implements Consumer<String> {
|
||||||
}
|
}
|
||||||
accept("Startup successful!");
|
accept("Startup successful!");
|
||||||
try {
|
try {
|
||||||
Thread.sleep(500);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.andrewlalis.perfin.view.component;
|
||||||
|
|
||||||
|
import com.andrewlalis.javafx_scene_router.RouterView;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
|
||||||
|
public class ScrollPaneRouterView implements RouterView {
|
||||||
|
private final ScrollPane scrollPane = new ScrollPane();
|
||||||
|
|
||||||
|
public ScrollPaneRouterView() {
|
||||||
|
scrollPane.setFitToHeight(true);
|
||||||
|
scrollPane.setFitToWidth(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showRouteNode(Parent node) {
|
||||||
|
scrollPane.setContent(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScrollPane getScrollPane() {
|
||||||
|
return scrollPane;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
package com.andrewlalis.perfin.view.component;
|
||||||
|
|
||||||
|
import com.andrewlalis.perfin.PerfinApp;
|
||||||
|
import javafx.beans.DefaultProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.beans.property.StringPropertyBase;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.AccessibleAttribute;
|
||||||
|
import javafx.scene.control.Hyperlink;
|
||||||
|
import javafx.scene.layout.Border;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.text.TextFlow;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.andrewlalis.perfin.PerfinApp.helpRouter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component that renders markdown-ish text as a series of TextFlow elements,
|
||||||
|
* styled according to some basic styles.
|
||||||
|
*/
|
||||||
|
@DefaultProperty("text")
|
||||||
|
public class StyledText extends VBox {
|
||||||
|
private StringProperty text;
|
||||||
|
private boolean initialized = false;
|
||||||
|
|
||||||
|
public final void setText(String value) {
|
||||||
|
if (value == null) value = "";
|
||||||
|
textProperty().set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getText() {
|
||||||
|
return text == null ? "" : text.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final StringProperty textProperty() {
|
||||||
|
if (text == null) {
|
||||||
|
text = new StringPropertyBase("") {
|
||||||
|
@Override public Object getBean() { return StyledText.this; }
|
||||||
|
@Override public String getName() { return "text"; }
|
||||||
|
@Override public void invalidated() {
|
||||||
|
notifyAccessibleAttributeChanged(AccessibleAttribute.TEXT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void layoutChildren() {
|
||||||
|
if (!initialized) {
|
||||||
|
String s = getText();
|
||||||
|
getChildren().clear();
|
||||||
|
getChildren().addAll(renderText(s));
|
||||||
|
getStyleClass().add("spacing-extra");
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
super.layoutChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TextFlow> renderText(String text) {
|
||||||
|
return new TextFlowBuilder().build(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TextFlowBuilder {
|
||||||
|
private final List<TextFlow> flows = new ArrayList<>();
|
||||||
|
private int idx = 0;
|
||||||
|
private final StringBuilder currentRun = new StringBuilder();
|
||||||
|
private TextFlow currentParagraph;
|
||||||
|
|
||||||
|
public List<TextFlow> build(String text) {
|
||||||
|
flows.clear();
|
||||||
|
idx = 0;
|
||||||
|
currentRun.setLength(0);
|
||||||
|
currentParagraph = new TextFlow();
|
||||||
|
|
||||||
|
while (idx < text.length()) {
|
||||||
|
if (text.startsWith("**", idx)) {
|
||||||
|
parseStyledText(text, "**", "bold-text");
|
||||||
|
} else if (text.startsWith("*", idx)) {
|
||||||
|
parseStyledText(text, "*", "italic-text");
|
||||||
|
} else if (text.startsWith("`", idx)) {
|
||||||
|
parseStyledText(text, "`", "mono-font");
|
||||||
|
} else if (text.startsWith(" -- ", idx)) {
|
||||||
|
parsePageBreak(text);
|
||||||
|
} else if (text.startsWith("[", idx)) {
|
||||||
|
parseLink(text);
|
||||||
|
} else if (text.startsWith("#", idx) && (idx == 0 || (idx > 0 && text.charAt(idx - 1) == ' '))) {
|
||||||
|
parseHeader(text);
|
||||||
|
} else {
|
||||||
|
currentRun.append(text.charAt(idx));
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendTextIfPresent();
|
||||||
|
appendParagraphIfPresent();
|
||||||
|
return flows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parsePageBreak(String text) {
|
||||||
|
appendTextIfPresent();
|
||||||
|
appendParagraphIfPresent();
|
||||||
|
while (text.charAt(idx) == ' ') idx++;
|
||||||
|
while (text.charAt(idx) == '-') idx++;
|
||||||
|
while (text.charAt(idx) == ' ') idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseStyledText(String text, String marker, String styleClass) {
|
||||||
|
appendTextIfPresent();
|
||||||
|
int endIdx = text.indexOf(marker, idx + marker.length());
|
||||||
|
Text textItem = new Text(text.substring(idx + marker.length(), endIdx));
|
||||||
|
textItem.getStyleClass().add(styleClass);
|
||||||
|
currentParagraph.getChildren().add(textItem);
|
||||||
|
idx = endIdx + marker.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseLink(String text) {
|
||||||
|
appendTextIfPresent();
|
||||||
|
int labelEndIdx = text.indexOf(']', idx);
|
||||||
|
String label = text.substring(idx + 1, labelEndIdx);
|
||||||
|
idx = labelEndIdx + 1;
|
||||||
|
final String link;
|
||||||
|
if (text.charAt(labelEndIdx + 1) == '(') {
|
||||||
|
int linkEndIdx = text.indexOf(')', labelEndIdx + 2);
|
||||||
|
link = text.substring(labelEndIdx + 2, linkEndIdx);
|
||||||
|
idx = linkEndIdx + 1;
|
||||||
|
} else {
|
||||||
|
link = null;
|
||||||
|
}
|
||||||
|
Hyperlink hyperlink = new Hyperlink(label);
|
||||||
|
if (link != null) {
|
||||||
|
if (link.startsWith("http")) {
|
||||||
|
hyperlink.setOnAction(event -> PerfinApp.instance.getHostServices().showDocument(link));
|
||||||
|
} else if (link.startsWith("help:")) {
|
||||||
|
hyperlink.setOnAction(event -> helpRouter.navigate(link.substring(5).strip()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hyperlink.setBorder(Border.EMPTY);
|
||||||
|
hyperlink.setPadding(new Insets(0, 0, 0, 0));
|
||||||
|
currentParagraph.getChildren().add(hyperlink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseHeader(String text) {
|
||||||
|
appendTextIfPresent();
|
||||||
|
appendParagraphIfPresent();
|
||||||
|
int size = 0;
|
||||||
|
while (text.charAt(idx) == '#') {
|
||||||
|
idx++;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
int endIdx = text.indexOf("#".repeat(size), idx);
|
||||||
|
Text header = new Text(text.substring(idx, endIdx).strip());
|
||||||
|
idx = endIdx + size;
|
||||||
|
while (text.charAt(idx) == ' ') idx++;
|
||||||
|
String styleClass = switch(size) {
|
||||||
|
case 1 -> "large-font";
|
||||||
|
case 2 -> "largest-font";
|
||||||
|
default -> "largest-font";
|
||||||
|
};
|
||||||
|
header.getStyleClass().addAll(styleClass, "bold-text");
|
||||||
|
currentParagraph.getChildren().add(header);
|
||||||
|
appendParagraphIfPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendTextIfPresent() {
|
||||||
|
if (!currentRun.isEmpty()) {
|
||||||
|
currentParagraph.getChildren().add(new Text(currentRun.toString()));
|
||||||
|
currentRun.setLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendParagraphIfPresent() {
|
||||||
|
if (!currentParagraph.getChildren().isEmpty()) {
|
||||||
|
flows.add(currentParagraph);
|
||||||
|
currentParagraph = new TextFlow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
styleClass="std-spacing"
|
||||||
|
>
|
||||||
|
<StyledText>
|
||||||
|
## The Accounts View ##
|
||||||
|
In the *Accounts view*, you'll see an overview of all the active
|
||||||
|
accounts in your *Perfin* profile.
|
||||||
|
--
|
||||||
|
To add a new account, simply click on **Add an Account** from the menu
|
||||||
|
at the top. [Read about how to add an account here.](help:adding-an-account)
|
||||||
|
--
|
||||||
|
Additionally, the top menu also shows an overview of the derived total
|
||||||
|
balance for each currency you own. This adds up the balances of all
|
||||||
|
accounts of like currency, and gives you a total of each.
|
||||||
|
--
|
||||||
|
Accounts are, by default, ordered according to the most recent activity.
|
||||||
|
That means that your most active accounts will appear *first* in this
|
||||||
|
page, and your least active accounts will appear *last*.
|
||||||
|
|
||||||
|
# Account Tiles #
|
||||||
|
Each account's tile displays some basic information about the account
|
||||||
|
up-front, like its name, number, balance, and type. Click on a tile to
|
||||||
|
navigate to that account's page for more detailed information, and to
|
||||||
|
make changes to the account.
|
||||||
|
--
|
||||||
|
The *current balance* shown in each account tile is derived from the
|
||||||
|
account's last-known **balance record**, and all transactions that have
|
||||||
|
happened between then and now.
|
||||||
|
</StyledText>
|
||||||
|
</VBox>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
>
|
||||||
|
<StyledText>
|
||||||
|
## Adding a Transaction ##
|
||||||
|
When you're adding a new transaction to your *Perfin* profile, there are
|
||||||
|
some details that you should be aware of.
|
||||||
|
|
||||||
|
# Timestamp #
|
||||||
|
The timestamp is the date and time at which the transaction took place,
|
||||||
|
in your local time zone. Generally, it's encouraged to set this as the
|
||||||
|
real timestamp at which the transaction took place (the time shown on a
|
||||||
|
receipt or invoice, for example), rather than the timestamp provided by
|
||||||
|
your financial institution once the payment has been processed.
|
||||||
|
--
|
||||||
|
It's formatted as `yyyy-mm-dd HH:MM:SS`, so for example, November 14th,
|
||||||
|
2015 at 4:15pm would be written as `2015-11-14 16:15:00`. You can omit
|
||||||
|
the seconds if you like, however.
|
||||||
|
--
|
||||||
|
Also note that you may not enter timestamps from the future; it just
|
||||||
|
doesn't make sense to do so.
|
||||||
|
|
||||||
|
# Amount #
|
||||||
|
The total amount of the transaction, as a positive decimal value. This
|
||||||
|
is the final amount which you've paid or received, including any tax,
|
||||||
|
tips, or transaction fees.
|
||||||
|
|
||||||
|
# Currency #
|
||||||
|
The currency of the transaction. This should be the same currency as the
|
||||||
|
account(s) that the transaction is linked to.
|
||||||
|
|
||||||
|
# Linked Debit and Credit Accounts #
|
||||||
|
Every transaction, for it to mean something, needs to be linked to one
|
||||||
|
(or sometimes two) of your accounts. A transaction's impact on an
|
||||||
|
account depends on whether the transaction is being treated as a **Debit**
|
||||||
|
or a **Credit** on the account.
|
||||||
|
--
|
||||||
|
The account linked as **Debit** is the one whose assets will
|
||||||
|
**increase** as a result of the transaction. Some common examples of
|
||||||
|
transactions with debit-linked accounts include deposits to checking
|
||||||
|
or savings accounts, or refunds to credit cards.
|
||||||
|
--
|
||||||
|
The account linked as **Credit** is the one whose assets will
|
||||||
|
**decrease** as a result of the transaction. Some common examples of
|
||||||
|
transactions with credit-linked accounts include payments or purchases
|
||||||
|
with a checking or savings account, or a credit card.
|
||||||
|
--
|
||||||
|
In short, if your account is *gaining money*, link it under **debit**.
|
||||||
|
If your account is *losing money*, link it under **credit**.
|
||||||
|
--
|
||||||
|
For transfers between two accounts that are both tracked in *Perfin*,
|
||||||
|
the *sending* account should be linked under **credit**, and the
|
||||||
|
*receiving* account under **debit**.
|
||||||
|
|
||||||
|
# Attachments #
|
||||||
|
Often, you'll have a receipt, invoice, bank statement, or some other
|
||||||
|
document which acts as proof of a transaction. You can attach files to
|
||||||
|
a transaction to save those files with it, as a reference. The files
|
||||||
|
will be copied to your *Perfin* profile.
|
||||||
|
</StyledText>
|
||||||
|
</VBox>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
>
|
||||||
|
<StyledText>
|
||||||
|
## Adding an Account ##
|
||||||
|
When adding an account, you'll need to provide some basic information
|
||||||
|
about the account so that Perfin can integrate it with its automatic
|
||||||
|
balance calculations and other functions.
|
||||||
|
|
||||||
|
# Name #
|
||||||
|
The name of the account is just a bit of text that you can use to
|
||||||
|
identify the account from the rest of yours. Make sure it's unique, and
|
||||||
|
to-the-point, since the account's name is used elsewhere in the app to
|
||||||
|
refer to the account.
|
||||||
|
|
||||||
|
# Number #
|
||||||
|
The number of the account is the unique account number provided by your
|
||||||
|
financial institution. For checking and savings accounts, it'll be the
|
||||||
|
account number provided by your bank, and for credit cards, it'll be the
|
||||||
|
credit card's number.
|
||||||
|
|
||||||
|
# Currency #
|
||||||
|
The currency is pretty self-explanatory; simply select the currency that
|
||||||
|
your account uses. Perfin uses 3-character *currency codes* quite often,
|
||||||
|
and you can read about them [here](https://en.wikipedia.org/wiki/ISO_4217#List_of_currency_codes).
|
||||||
|
|
||||||
|
# Account Type #
|
||||||
|
The account's type determines how certain balance calculations and
|
||||||
|
properties of the account work. For instance, a **Credit Card**
|
||||||
|
account's balance is interpreted to be the amount you owe to the card's
|
||||||
|
provider (the amount you need to pay off), while a **Checking**
|
||||||
|
account's balance is naturally the amount of money in your account.
|
||||||
|
|
||||||
|
# Initial Balance #
|
||||||
|
In order to accurately compute your account's balance (without needing
|
||||||
|
to check back every hour with your financial institution), Perfin needs
|
||||||
|
to know what your account's starting balance is. This way, it can use
|
||||||
|
that balance, combined with any transactions you add, to tell you your
|
||||||
|
balance at any moment in time.
|
||||||
|
</StyledText>
|
||||||
|
</VBox>
|
|
@ -1,15 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<?import javafx.scene.text.Text?>
|
|
||||||
<?import javafx.scene.text.TextFlow?>
|
|
||||||
<VBox xmlns="http://javafx.com/javafx"
|
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
|
||||||
>
|
|
||||||
<TextFlow>
|
|
||||||
<Text>
|
|
||||||
This is a testing help page, which is meant to be shown only for
|
|
||||||
testing the help system and navigation.
|
|
||||||
</Text>
|
|
||||||
</TextFlow>
|
|
||||||
</VBox>
|
|
|
@ -1,29 +1,35 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import javafx.scene.control.Label?>
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
<?import javafx.scene.control.TextField?>
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Text?>
|
|
||||||
<?import javafx.scene.text.TextFlow?>
|
|
||||||
<VBox xmlns="http://javafx.com/javafx"
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
styleClass="std-spacing"
|
||||||
>
|
>
|
||||||
<Label styleClass="large-font,bold-text" text="Perfin Help Pages"/>
|
<StyledText>
|
||||||
<TextFlow>
|
## Homepage ##
|
||||||
<Text>
|
This is the homepage for Perfin's help pages: a manual for how to use
|
||||||
This is the homepage for Perfin's help pages: a manual for how to
|
Perfin safely and effectively to manage your personal finances.
|
||||||
use Perfin safely and effectively to manage your personal finances.
|
--
|
||||||
</Text>
|
Search for a topic below, or follow one of the index links.
|
||||||
</TextFlow>
|
</StyledText>
|
||||||
<TextFlow>
|
|
||||||
<Text>
|
|
||||||
Search for a topic below, or click on the help icon beside some
|
|
||||||
component to navigate to its page.
|
|
||||||
</Text>
|
|
||||||
</TextFlow>
|
|
||||||
<HBox>
|
<HBox>
|
||||||
<Label text="Search!"/>
|
<TextField disable="true" text="Searching is WIP" HBox.hgrow="ALWAYS"/>
|
||||||
<TextField/>
|
|
||||||
</HBox>
|
</HBox>
|
||||||
|
<StyledText>
|
||||||
|
# Help Pages Index #
|
||||||
|
The following is a list of all help pages.
|
||||||
|
--
|
||||||
|
[Accounts View](help:accounts)
|
||||||
|
--
|
||||||
|
[Adding an Account](help:adding-an-account)
|
||||||
|
--
|
||||||
|
[Transactions View](help:transactions)
|
||||||
|
--
|
||||||
|
[Adding a Transaction](help:adding-a-transaction)
|
||||||
|
--
|
||||||
|
[Profiles](help:profiles)
|
||||||
|
</StyledText>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
>
|
||||||
|
<StyledText>
|
||||||
|
## Profiles ##
|
||||||
|
In *Perfin*, all the accounts, transactions, attachments, bank
|
||||||
|
statements, and other financial data, are stored in a *profile*. You can
|
||||||
|
think of it as a save file. It's a single folder that encapsulates all
|
||||||
|
your data.
|
||||||
|
--
|
||||||
|
Perfin uses profiles to make it easy to work with multiple financial
|
||||||
|
portfolios, export and import bulk data, and to let *you*, the user,
|
||||||
|
access your data directly, as opposed to hiding it in some proprietary
|
||||||
|
file format.
|
||||||
|
--
|
||||||
|
A running Perfin program always has one profile open at a time. You can
|
||||||
|
change the active profile by clicking **Profiles** from the app's top
|
||||||
|
menu, and then clicking **Open** next to the profile you'd like to use.
|
||||||
|
--
|
||||||
|
By default, when you first start Perfin, a profile named *default* is
|
||||||
|
created for you to use. Most of the time, you won't need to worry about
|
||||||
|
using other profiles, but if you do, now you know how.
|
||||||
|
</StyledText>
|
||||||
|
</VBox>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import com.andrewlalis.perfin.view.component.StyledText?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<VBox xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
styleClass="std-spacing"
|
||||||
|
>
|
||||||
|
<StyledText>
|
||||||
|
## The Transactions View ##
|
||||||
|
In the *Transactions view*, you're shown a list of all transactions that
|
||||||
|
have been added to your *Perfin* profile, along with some controls for
|
||||||
|
navigating this list.
|
||||||
|
--
|
||||||
|
The transactions are ordered, by default, according to their timestamp,
|
||||||
|
with recent transactions appearing before older ones.
|
||||||
|
--
|
||||||
|
Simply click on a transaction to view its details or make changes.
|
||||||
|
--
|
||||||
|
To add a new transaction, click **Add Transaction** in the top menu. You
|
||||||
|
can read more about adding a transaction [here](help:adding-a-transaction).
|
||||||
|
</StyledText>
|
||||||
|
</VBox>
|
Binary file not shown.
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 15 KiB |
|
@ -5,9 +5,11 @@
|
||||||
<BorderPane
|
<BorderPane
|
||||||
xmlns="http://javafx.com/javafx"
|
xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
fx:id="mainContainer"
|
|
||||||
fx:controller="com.andrewlalis.perfin.control.MainViewController"
|
fx:controller="com.andrewlalis.perfin.control.MainViewController"
|
||||||
>
|
>
|
||||||
|
<center>
|
||||||
|
<BorderPane fx:id="mainContainer">
|
||||||
|
<!-- Top bar for the app -->
|
||||||
<top>
|
<top>
|
||||||
<VBox>
|
<VBox>
|
||||||
<HBox styleClass="std-padding,std-spacing">
|
<HBox styleClass="std-padding,std-spacing">
|
||||||
|
@ -17,18 +19,38 @@
|
||||||
<Button text="Transactions" onAction="#goToTransactions"/>
|
<Button text="Transactions" onAction="#goToTransactions"/>
|
||||||
<Button text="Profiles" onAction="#viewProfiles"/>
|
<Button text="Profiles" onAction="#viewProfiles"/>
|
||||||
|
|
||||||
<Button text="View Manual" fx:id="showManualButton" onAction="#showManual"/>
|
<Button text="View Help" fx:id="showManualButton" onAction="#showManual"/>
|
||||||
<Button text="Hide Manual" fx:id="hideManualButton" onAction="#hideManual"/>
|
<Button text="Hide Help" fx:id="hideManualButton" onAction="#hideManual"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
<HBox fx:id="breadcrumbHBox" styleClass="std-spacing,small-font"/>
|
<HBox fx:id="breadcrumbHBox" styleClass="std-spacing,small-font"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
</top>
|
</top>
|
||||||
|
<!-- App footer -->
|
||||||
<bottom>
|
<bottom>
|
||||||
<HBox styleClass="std-padding,std-spacing">
|
<HBox styleClass="std-padding,std-spacing">
|
||||||
<Label text="Perfin Version 1.2.0"/>
|
<Label text="Perfin Version 1.2.0"/>
|
||||||
|
<AnchorPane>
|
||||||
|
<Label text="© 2024 Andrew Lalis" styleClass="small-font,secondary-color-text-fill" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0"/>
|
||||||
|
</AnchorPane>
|
||||||
</HBox>
|
</HBox>
|
||||||
</bottom>
|
</bottom>
|
||||||
|
</BorderPane>
|
||||||
|
</center>
|
||||||
|
|
||||||
|
<!-- Right-side panel to show help info, at the top level of the whole app. -->
|
||||||
<right>
|
<right>
|
||||||
<VBox fx:id="manualVBox" style="-fx-min-width: 400px;" styleClass="padding-extra-1"/>
|
<BorderPane fx:id="helpPane">
|
||||||
|
<top>
|
||||||
|
<VBox styleClass="padding-extra-1">
|
||||||
|
<Label text="Perfin Help" styleClass="largest-font,bold-text"/>
|
||||||
|
<HBox styleClass="std-spacing">
|
||||||
|
<Hyperlink onAction="#helpViewHome">Home</Hyperlink>
|
||||||
|
<Hyperlink onAction="#helpViewAccounts">Accounts</Hyperlink>
|
||||||
|
<Hyperlink onAction="#helpViewTransactions">Transactions</Hyperlink>
|
||||||
|
</HBox>
|
||||||
|
<Button fx:id="helpBackButton" text="Back"/>
|
||||||
|
</VBox>
|
||||||
|
</top>
|
||||||
|
</BorderPane>
|
||||||
</right>
|
</right>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
|
|
@ -39,19 +39,13 @@
|
||||||
<bottom>
|
<bottom>
|
||||||
<BorderPane>
|
<BorderPane>
|
||||||
<left>
|
<left>
|
||||||
<VBox styleClass="std-padding">
|
<AnchorPane styleClass="std-padding">
|
||||||
<Label text="Add New Profile"/>
|
<Label text="Add New Profile" styleClass="bold-text" AnchorPane.leftAnchor="0" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0"/>
|
||||||
</VBox>
|
</AnchorPane>
|
||||||
</left>
|
</left>
|
||||||
<center>
|
<center>
|
||||||
<VBox styleClass="std-padding">
|
<VBox styleClass="std-padding">
|
||||||
<TextField fx:id="newProfileNameField" style="-fx-min-width: 50px; -fx-pref-width: 50px;"/>
|
<TextField fx:id="newProfileNameField" style="-fx-min-width: 50px; -fx-pref-width: 50px;"/>
|
||||||
<Text
|
|
||||||
fx:id="newProfileNameErrorLabel"
|
|
||||||
styleClass="error-text"
|
|
||||||
style="-fx-fill: red;"
|
|
||||||
text="Invalid profile name. Profile names must only contain lowercase text."
|
|
||||||
/>
|
|
||||||
</VBox>
|
</VBox>
|
||||||
</center>
|
</center>
|
||||||
<right>
|
<right>
|
||||||
|
|
Loading…
Reference in New Issue