2222import com .owlplug .core .components .TaskRunner ;
2323import com .owlplug .core .tasks .AbstractTask ;
2424import java .util .ArrayList ;
25+ import javafx .animation .Interpolator ;
26+ import javafx .animation .KeyFrame ;
27+ import javafx .animation .KeyValue ;
28+ import javafx .animation .Timeline ;
29+ import javafx .application .Platform ;
30+ import javafx .beans .property .DoubleProperty ;
31+ import javafx .beans .property .SimpleDoubleProperty ;
32+ import javafx .beans .property .SimpleStringProperty ;
33+ import javafx .beans .property .StringProperty ;
2534import javafx .concurrent .Worker .State ;
2635import javafx .fxml .FXML ;
2736import javafx .scene .control .Button ;
3443import javafx .scene .image .ImageView ;
3544import javafx .scene .layout .Region ;
3645import javafx .util .Callback ;
46+ import javafx .util .Duration ;
3747import org .springframework .beans .factory .annotation .Autowired ;
3848import org .springframework .stereotype .Controller ;
3949
@@ -44,14 +54,21 @@ public class TaskBarController extends BaseController {
4454 private TaskRunner taskRunner ;
4555
4656 @ FXML
47- public Label taskLabel ;
57+ private Label taskLabel ;
4858 @ FXML
49- public ProgressBar taskProgressBar ;
59+ private ProgressBar taskProgressBar ;
5060 @ FXML
5161 private Button taskHistoryButton ;
5262 @ FXML
5363 private Button logsButton ;
5464
65+ private final DoubleProperty progressProperty = new SimpleDoubleProperty ();
66+
67+ private final StringProperty taskNameProperty = new SimpleStringProperty ();
68+
69+ private Timeline progressTimeline ;
70+
71+
5572 /**
5673 * FXML initialize.
5774 */
@@ -60,25 +77,10 @@ public void initialize() {
6077 taskHistoryButton .setOnAction (e -> openTaskHistory ());
6178 resetErrorLog ();
6279
63- }
64-
65- public void setErrorLog (AbstractTask task , String title , String content ) {
66-
67- this .getTelemetryService ().event ("/Error/TaskExecution" , p -> {
68- p .put ("taskName" , task .getName ());
69- p .put ("error" , title );
70- p .put ("content" , content );
71- });
72- logsButton .setVisible (true );
73- logsButton .setManaged (true );
74- logsButton .setOnAction (e -> {
75- showErrorDialog (title , content );
80+ progressProperty .addListener ((obs , oldVal , newVal ) -> {
81+ updateProgress (newVal .doubleValue ());
7682 });
77- }
78-
79- public void resetErrorLog () {
80- logsButton .setManaged (false );
81- logsButton .setVisible (false );
83+ taskLabel .textProperty ().bind (taskNameProperty );
8284 }
8385
8486 private void openTaskHistory () {
@@ -128,8 +130,83 @@ public void updateItem(AbstractTask item, boolean empty) {
128130
129131 private void showErrorDialog (String title , String content ) {
130132 this .getDialogManager ().newSimpleInfoDialog (
131- new Label (title ), new TextArea (content )
133+ new Label (title ), new TextArea (content )
132134 ).show ();
133135 }
134136
137+ public void setErrorLog (AbstractTask task , String title , String content ) {
138+
139+ this .getTelemetryService ().event ("/Error/TaskExecution" , p -> {
140+ p .put ("taskName" , task .getName ());
141+ p .put ("error" , title );
142+ p .put ("content" , content );
143+ });
144+ taskProgressBar .getStyleClass ().add ("progress-bar-error" );
145+ logsButton .setVisible (true );
146+ logsButton .setManaged (true );
147+ logsButton .setOnAction (e -> {
148+ showErrorDialog (title , content );
149+ });
150+ }
151+
152+ public void resetErrorLog () {
153+ taskProgressBar .getStyleClass ().remove ("progress-bar-error" );
154+ logsButton .setManaged (false );
155+ logsButton .setVisible (false );
156+ }
157+
158+
159+ public StringProperty taskNameProperty () {
160+ return taskNameProperty ;
161+ }
162+
163+ public DoubleProperty progressProperty () {
164+ return progressProperty ;
165+ }
166+
167+ private void updateProgress (double target ) {
168+ double current = taskProgressBar .getProgress ();
169+ if (Double .isNaN (current )) {
170+ current = 0.0 ;
171+ }
172+ // Non-running task can report negative progress to indicate indeterminate state
173+ // Clamp to 0.0 for display animation purposes
174+ if (target < 0.0 ) {
175+ target = 0.0 ;
176+ }
177+
178+ // Apply immediately if decreasing or equa
179+ if (target <= current ) {
180+ if (progressTimeline != null ) {
181+ progressTimeline .stop ();
182+ progressTimeline = null ;
183+ }
184+ taskProgressBar .setProgress (target );
185+ return ;
186+ }
187+
188+ // If a timeline is already running, stop it
189+ if (progressTimeline != null ) {
190+ progressTimeline .stop ();
191+ }
192+
193+ // | Delta | Step-by-step | millis result |
194+ // | :---- | :------------------------------ | :----------------------- |
195+ // | 0.5 | `delta/0.5 = 1 → (1−1)=0` | `1000 + 0×4000 = 1000` |
196+ // | 0.25 | `delta/0.5 = 0.5 → (1−0.5)=0.5` | `1000 + 0.5×4000 = 3000` |
197+ // | 0.1 | `delta/0.5 = 0.2 → (1−0.2)=0.8` | `1000 + 0.8×4000 = 4200` |
198+ // | 0.05 | `delta/0.5 = 0.1 → (1−0.1)=0.9` | `1000 + 0.9×4000 = 4600` |
199+ // | 0.0 | (edge) | `1000 + 1×4000 = 5000` |
200+ // Increasing progress animation duration from 1s to 5s depending on delta
201+ // Small increments takes longer to reach target
202+ double delta = target - current ;
203+ double millis = 1000 + (1 - Math .min (1 , delta / 0.5 )) * 4000 ;
204+ KeyValue kv = new KeyValue (taskProgressBar .progressProperty (), target , Interpolator .EASE_BOTH );
205+ KeyFrame kf = new KeyFrame (Duration .millis (millis ), kv );
206+
207+ progressTimeline = new Timeline (kf );
208+ progressTimeline .setOnFinished (ev -> progressTimeline = null );
209+ progressTimeline .play ();
210+
211+ }
135212}
0 commit comments