feat(app): add evaluation history, bot control panel, simulation visualizer, and vendored signalr_core
This commit is contained in:
@@ -26,12 +26,14 @@ extension SwitchMapExtension<T> on Stream<T> {
|
||||
onError: controller?.addError,
|
||||
);
|
||||
}, onDone: () {
|
||||
// Wait for last sub to finish or close
|
||||
outputSub?.cancel();
|
||||
controller?.close();
|
||||
});
|
||||
},
|
||||
onCancel: () {
|
||||
outputSub?.cancel();
|
||||
inputSub?.cancel();
|
||||
controller?.close();
|
||||
},
|
||||
);
|
||||
return controller.stream;
|
||||
|
||||
@@ -10,12 +10,19 @@ import '../bloc/search_bloc.dart';
|
||||
import '../repositories/search_repository.dart';
|
||||
|
||||
/// Focused Spotlight Asset Search Dialog with reactive Favorite Star Button, Hero transitions, and Shimmer loading states.
|
||||
///
|
||||
/// By default, tapping a result navigates straight to [AssetDetailScreen] (the main search-feature use case).
|
||||
/// Pass [onAssetSelected] to repurpose this as a reusable asset PICKER instead - e.g. the simulation screen's
|
||||
/// ISIN input - in which case a tap pops the dialog and invokes the callback with the picked ISIN/name instead
|
||||
/// of navigating anywhere.
|
||||
class AssetSearchDialog extends StatelessWidget {
|
||||
final ApiClient apiClient;
|
||||
final void Function(String isin, String name)? onAssetSelected;
|
||||
|
||||
const AssetSearchDialog({
|
||||
super.key,
|
||||
required this.apiClient,
|
||||
this.onAssetSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -24,15 +31,16 @@ class AssetSearchDialog extends StatelessWidget {
|
||||
create: (context) => SearchBloc(
|
||||
repository: SearchRepository(apiClient: apiClient),
|
||||
)..add(const SearchQueryChanged('')),
|
||||
child: _AssetSearchDialogContent(apiClient: apiClient),
|
||||
child: _AssetSearchDialogContent(apiClient: apiClient, onAssetSelected: onAssetSelected),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AssetSearchDialogContent extends StatefulWidget {
|
||||
final ApiClient apiClient;
|
||||
final void Function(String isin, String name)? onAssetSelected;
|
||||
|
||||
const _AssetSearchDialogContent({required this.apiClient});
|
||||
const _AssetSearchDialogContent({required this.apiClient, this.onAssetSelected});
|
||||
|
||||
@override
|
||||
State<_AssetSearchDialogContent> createState() => _AssetSearchDialogContentState();
|
||||
@@ -162,6 +170,10 @@ class _AssetSearchDialogContentState extends State<_AssetSearchDialogContent> {
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
if (widget.onAssetSelected != null) {
|
||||
widget.onAssetSelected!(isin, assetName);
|
||||
return;
|
||||
}
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
||||
Reference in New Issue
Block a user