initState method
Called when this object is inserted into the tree.
The framework will call this method exactly once for each State object it creates.
Override this method to perform initialization that depends on the location at which this object was inserted into the tree (i.e., context) or on the widget used to configure this object (i.e., widget).
If a State's build method depends on an object that can itself change state, for example a ChangeNotifier or Stream, or some other object to which one can subscribe to receive notifications, then be sure to subscribe and unsubscribe properly in initState, didUpdateWidget, and dispose:
- In initState, subscribe to the object.
- In didUpdateWidget unsubscribe from the old object and subscribe to the new one if the updated widget configuration requires replacing the object.
- In dispose, unsubscribe from the object.
You should not use BuildContext.dependOnInheritedWidgetOfExactType from this method. However, didChangeDependencies will be called immediately following this method, and BuildContext.dependOnInheritedWidgetOfExactType can be used there.
Implementations of this method should start with a call to the inherited
method, as in super.initState().
Implementation
@override
void initState() {
super.initState();
// TODO 20240613 gjw IS THIS REQUIRED?
deleteFileIfExists();
// Get the app name and version.
_loadAppInfo();
// Create the [tabController] to manage what happens on leaving/entering
// tabs.
_tabController = TabController(length: homeTabs.length, vsync: this);
// Initialize the tab widgets once in order to use IndexedStack
// later. 20250115 gjw Note that the order here must be the same as in
// [homeTabs]. There should be a better way to do this without having this
// implicit order requirement.
_tabWidgets = [
const DatasetPanel(),
const ExploreTabs(),
const TransformTabs(),
const ModelTabs(),
const EvaluatePanel(),
const RConsole(),
const ScriptTab(),
const DebugTab(),
];
// Add a listener to the TabController to perform an action when we leave
// the tab.
_tabController.addListener(() {
// Check if we are leaving the tab, not entering it.
if (!_tabController.indexIsChanging) {
// Index 0 is the DATABASE tab.
// Index 2 is the TRANSFORM tab.
if (_tabController.previousIndex == 0 ||
_tabController.previousIndex == 2) {
if (ref.read(datatypeProvider) == 'table') {
// 20250210 gjw On leaving the DATASET tab or the TRANSFORM tab,
// where we can change the dataset `ds` in either of these tabs, we
// run the R scripted data template, but only if there the dataset
// type is a table. We need to run the template here after we have
// loaded and setup the variable roles or transformed the
// dataset. Trying to run the dataset template before leaving the
// DATASET tab, for example, results in TARGET and RISK being set to
// NULL.
//
// Note that variable roles are set up in
// `features/dataset/display.dart` after the dataset is loaded and
// we need to wait until the roles are set before we run the
// template.
rSource(context, ref, ['dataset_template']);
// 20241211 gjw In `features/dataset/display.dart` we use a
// hueristic for datasets with only two columns to assume they are
// for basket analysis in ASSOCIATIONS. In such a case, withonly two
// columns, we want to set the default for ASSOCIATIONS to be
// Basket. We do that here on moving from the DATASET tab, rather
// than in `display.dart` as there it throws an exception: "Tried to
// modify a provider while the widget tree was building." It works
// here!
ref.read(basketsAssociationProvider.notifier).state =
ref.read(metaDataProvider).length == 2;
}
}
// You can also perform other actions here, such as showing a snackbar,
// calling a function, etc.
}
});
// TODO 20250131 gjw Why should we do this here on every Rattle startup? It
// might be better on a tap of the PACAKGE button in the DATASET popup.
//
// 20250205 gjw On starting up Rattle and loading a dataset the dataset load
// failed, perhaps due to the unfinished query for the package list.
// rSource(context, ref, ['dataset_list_packages']);
}