Scenario lifecycle methods
- Add ScenarioContext which knows about View and start/stop runnable methods. - Change Catalog to rely on ScenarioContext and call start/stop on an appropriate moment. - Still keep Scenario.build() around so that we have time to refactor in favour of ScenarioContext.buildContext() or whatever build() method in it should be. - Fixes #1004
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023 the original author or authors.
|
* Copyright 2023-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -43,7 +43,6 @@ import org.springframework.shell.component.view.control.MenuView.MenuItem;
|
|||||||
import org.springframework.shell.component.view.control.MenuView.MenuItemCheckStyle;
|
import org.springframework.shell.component.view.control.MenuView.MenuItemCheckStyle;
|
||||||
import org.springframework.shell.component.view.control.StatusBarView;
|
import org.springframework.shell.component.view.control.StatusBarView;
|
||||||
import org.springframework.shell.component.view.control.StatusBarView.StatusItem;
|
import org.springframework.shell.component.view.control.StatusBarView.StatusItem;
|
||||||
import org.springframework.shell.component.view.control.View;
|
|
||||||
import org.springframework.shell.component.view.control.cell.AbstractListCell;
|
import org.springframework.shell.component.view.control.cell.AbstractListCell;
|
||||||
import org.springframework.shell.component.view.event.EventLoop;
|
import org.springframework.shell.component.view.event.EventLoop;
|
||||||
import org.springframework.shell.component.view.event.KeyEvent;
|
import org.springframework.shell.component.view.event.KeyEvent;
|
||||||
@@ -56,6 +55,7 @@ import org.springframework.shell.geom.HorizontalAlign;
|
|||||||
import org.springframework.shell.geom.Rectangle;
|
import org.springframework.shell.geom.Rectangle;
|
||||||
import org.springframework.shell.geom.VerticalAlign;
|
import org.springframework.shell.geom.VerticalAlign;
|
||||||
import org.springframework.shell.samples.catalog.scenario.Scenario;
|
import org.springframework.shell.samples.catalog.scenario.Scenario;
|
||||||
|
import org.springframework.shell.samples.catalog.scenario.Scenario.ScenarioContext;
|
||||||
import org.springframework.shell.samples.catalog.scenario.ScenarioComponent;
|
import org.springframework.shell.samples.catalog.scenario.ScenarioComponent;
|
||||||
import org.springframework.shell.style.ThemeResolver;
|
import org.springframework.shell.style.ThemeResolver;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
@@ -78,7 +78,7 @@ public class Catalog {
|
|||||||
|
|
||||||
// mapping from category name to scenarios(can belong to multiple categories)
|
// mapping from category name to scenarios(can belong to multiple categories)
|
||||||
private final Map<String, List<ScenarioData>> categoryMap = new TreeMap<>();
|
private final Map<String, List<ScenarioData>> categoryMap = new TreeMap<>();
|
||||||
private View currentScenarioView = null;
|
private ScenarioContext currentScenarioContext = null;
|
||||||
private TerminalUI ui;
|
private TerminalUI ui;
|
||||||
private ListView<String> categories;
|
private ListView<String> categories;
|
||||||
private ListView<ScenarioData> scenarios;
|
private ListView<ScenarioData> scenarios;
|
||||||
@@ -130,8 +130,9 @@ public class Catalog {
|
|||||||
eventLoop.onDestroy(eventLoop.keyEvents()
|
eventLoop.onDestroy(eventLoop.keyEvents()
|
||||||
.doOnNext(m -> {
|
.doOnNext(m -> {
|
||||||
if (m.getPlainKey() == Key.q && m.hasCtrl()) {
|
if (m.getPlainKey() == Key.q && m.hasCtrl()) {
|
||||||
if (currentScenarioView != null) {
|
if (currentScenarioContext != null) {
|
||||||
currentScenarioView = null;
|
currentScenarioContext.stop();
|
||||||
|
currentScenarioContext = null;
|
||||||
ui.setRoot(app, true);
|
ui.setRoot(app, true);
|
||||||
ui.setFocus(categories);
|
ui.setFocus(categories);
|
||||||
}
|
}
|
||||||
@@ -172,13 +173,11 @@ public class Catalog {
|
|||||||
// handle event when scenario is chosen
|
// handle event when scenario is chosen
|
||||||
eventLoop.onDestroy(eventLoop.viewEvents(LISTVIEW_SCENARIO_TYPEREF, scenarios)
|
eventLoop.onDestroy(eventLoop.viewEvents(LISTVIEW_SCENARIO_TYPEREF, scenarios)
|
||||||
.subscribe(event -> {
|
.subscribe(event -> {
|
||||||
View view = event.args().item().scenario().configure(ui).build();
|
ScenarioContext context = event.args().item().scenario().configure(ui).buildContext();
|
||||||
ui.configure(view);
|
ui.configure(context.view());
|
||||||
// View view = event.args().item().scenario()
|
component.setRoot(context.view(), true);
|
||||||
// .configure(ui, eventLoop, themeResolver, activeThemeName)
|
context.start();
|
||||||
// .build();
|
currentScenarioContext = context;
|
||||||
component.setRoot(view, true);
|
|
||||||
currentScenarioView = view;
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023 the original author or authors.
|
* Copyright 2023-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -54,6 +54,11 @@ public abstract class AbstractScenario implements Scenario {
|
|||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View build() {
|
||||||
|
throw new UnsupportedOperationException("Need to implement via 'buildContext'");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Scenario configure(TerminalUI ui) {
|
public Scenario configure(TerminalUI ui) {
|
||||||
this.ui = ui;
|
this.ui = ui;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2023 the original author or authors.
|
* Copyright 2023-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.shell.samples.catalog.scenario;
|
package org.springframework.shell.samples.catalog.scenario;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.shell.component.view.TerminalUI;
|
import org.springframework.shell.component.view.TerminalUI;
|
||||||
import org.springframework.shell.component.view.control.View;
|
import org.springframework.shell.component.view.control.View;
|
||||||
|
import org.springframework.shell.samples.catalog.Catalog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Scenario} participates in a catalog showcase.
|
* {@link Scenario} participates in a catalog showcase.
|
||||||
@@ -28,17 +30,29 @@ public interface Scenario {
|
|||||||
// Common category names
|
// Common category names
|
||||||
public static final String CATEGORY_ALL = "All Scenarios";
|
public static final String CATEGORY_ALL = "All Scenarios";
|
||||||
public static final String CATEGORY_LISTVIEW = "ListView";
|
public static final String CATEGORY_LISTVIEW = "ListView";
|
||||||
|
public static final String CATEGORY_PROGRESSVIEW = "ProgressView";
|
||||||
public static final String CATEGORY_BOXVIEW = "BoxView";
|
public static final String CATEGORY_BOXVIEW = "BoxView";
|
||||||
public static final String CATEGORY_LAYOUT = "Layout";
|
public static final String CATEGORY_LAYOUT = "Layout";
|
||||||
public static final String CATEGORY_OTHER = "Other";
|
public static final String CATEGORY_OTHER = "Other";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a {@link View} to be shown with a scenario.
|
* Build a {@link View} to be shown with a scenario. Prefer {@link #buildContext()}
|
||||||
|
* as this method will be deprecated and renamed.
|
||||||
*
|
*
|
||||||
* @return view of a scenario
|
* @return view of a scenario
|
||||||
|
* @see #buildContext()
|
||||||
*/
|
*/
|
||||||
View build();
|
View build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link ScenarioContext} wrapping needed view and lifecycle methods.
|
||||||
|
*
|
||||||
|
* @return a scenario context
|
||||||
|
*/
|
||||||
|
default ScenarioContext buildContext() {
|
||||||
|
return ScenarioContext.of(build());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure scenario.
|
* Configure scenario.
|
||||||
*
|
*
|
||||||
@@ -47,4 +61,78 @@ public interface Scenario {
|
|||||||
*/
|
*/
|
||||||
Scenario configure(TerminalUI ui);
|
Scenario configure(TerminalUI ui);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context represents a build {@code View} and lifecycle methods called by a
|
||||||
|
* catalog app.
|
||||||
|
*
|
||||||
|
* For simple {@link View} without any need for lifecycle methods, just call
|
||||||
|
* {@link #of(View)}.
|
||||||
|
*/
|
||||||
|
public interface ScenarioContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a view represented by a {@link Scenario}.
|
||||||
|
*
|
||||||
|
* @return a scenario view
|
||||||
|
*/
|
||||||
|
View view();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a {@link Catalog} when its ready to show a {@link View} build from
|
||||||
|
* a {@link Scenario}.
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a {@link Catalog} when its ready to discard a {@link View} build from
|
||||||
|
* a {@link Scenario}.
|
||||||
|
*/
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to build a {@code ScenarioContext} of {@link View} without
|
||||||
|
* lifecycle callbacks.
|
||||||
|
*
|
||||||
|
* @param view the main view
|
||||||
|
* @return a scenario context
|
||||||
|
*/
|
||||||
|
public static ScenarioContext of(View view) {
|
||||||
|
return of(view, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to build a {@code ScenarioContext}.
|
||||||
|
*
|
||||||
|
* @param view the main view
|
||||||
|
* @param start the start callback
|
||||||
|
* @param stop the stop callback
|
||||||
|
* @return a scenario context
|
||||||
|
*/
|
||||||
|
public static ScenarioContext of(View view, @Nullable Runnable start, @Nullable Runnable stop) {
|
||||||
|
return new ScenarioContext() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View view() {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
if (start != null) {
|
||||||
|
start.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (stop != null) {
|
||||||
|
stop.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user