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");
|
||||
* 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.StatusBarView;
|
||||
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.event.EventLoop;
|
||||
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.VerticalAlign;
|
||||
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.style.ThemeResolver;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -78,7 +78,7 @@ public class Catalog {
|
||||
|
||||
// mapping from category name to scenarios(can belong to multiple categories)
|
||||
private final Map<String, List<ScenarioData>> categoryMap = new TreeMap<>();
|
||||
private View currentScenarioView = null;
|
||||
private ScenarioContext currentScenarioContext = null;
|
||||
private TerminalUI ui;
|
||||
private ListView<String> categories;
|
||||
private ListView<ScenarioData> scenarios;
|
||||
@@ -130,8 +130,9 @@ public class Catalog {
|
||||
eventLoop.onDestroy(eventLoop.keyEvents()
|
||||
.doOnNext(m -> {
|
||||
if (m.getPlainKey() == Key.q && m.hasCtrl()) {
|
||||
if (currentScenarioView != null) {
|
||||
currentScenarioView = null;
|
||||
if (currentScenarioContext != null) {
|
||||
currentScenarioContext.stop();
|
||||
currentScenarioContext = null;
|
||||
ui.setRoot(app, true);
|
||||
ui.setFocus(categories);
|
||||
}
|
||||
@@ -172,13 +173,11 @@ public class Catalog {
|
||||
// handle event when scenario is chosen
|
||||
eventLoop.onDestroy(eventLoop.viewEvents(LISTVIEW_SCENARIO_TYPEREF, scenarios)
|
||||
.subscribe(event -> {
|
||||
View view = event.args().item().scenario().configure(ui).build();
|
||||
ui.configure(view);
|
||||
// View view = event.args().item().scenario()
|
||||
// .configure(ui, eventLoop, themeResolver, activeThemeName)
|
||||
// .build();
|
||||
component.setRoot(view, true);
|
||||
currentScenarioView = view;
|
||||
ScenarioContext context = event.args().item().scenario().configure(ui).buildContext();
|
||||
ui.configure(context.view());
|
||||
component.setRoot(context.view(), true);
|
||||
context.start();
|
||||
currentScenarioContext = context;
|
||||
}));
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,6 +54,11 @@ public abstract class AbstractScenario implements Scenario {
|
||||
return ui;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View build() {
|
||||
throw new UnsupportedOperationException("Need to implement via 'buildContext'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scenario configure(TerminalUI 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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
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.control.View;
|
||||
import org.springframework.shell.samples.catalog.Catalog;
|
||||
|
||||
/**
|
||||
* {@link Scenario} participates in a catalog showcase.
|
||||
@@ -28,17 +30,29 @@ public interface Scenario {
|
||||
// Common category names
|
||||
public static final String CATEGORY_ALL = "All Scenarios";
|
||||
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_LAYOUT = "Layout";
|
||||
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
|
||||
* @see #buildContext()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -47,4 +61,78 @@ public interface Scenario {
|
||||
*/
|
||||
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