mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 02:07:00 +08:00
feat: add initial dashbot package implementation
- Created a new Dashbot package with core functionalities. - Implemented Dashbot window model and notifier for state management. - Added UI components including Dashbot default page and home page. - Integrated routing for Dashbot with initial routes defined. - Included assets for Dashbot icons and set up pubspec.yaml. - Added tests for Dashbot window notifier to ensure functionality. - Established a basic README and CHANGELOG for the package.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||
import 'package:dashbot/dashbot.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/dashbot/dashbot.dart';
|
||||
import 'common_widgets/common_widgets.dart';
|
||||
import 'envvar/environment_page.dart';
|
||||
import 'home_page/home_page.dart';
|
||||
@@ -129,15 +129,15 @@ class Dashboard extends ConsumerWidget {
|
||||
),
|
||||
floatingActionButton: isDashBotEnabled
|
||||
? FloatingActionButton(
|
||||
onPressed: () => showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: DashBotWidget(),
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
||||
onPressed: () => showDashbotWindow(context, ref),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 6.0,
|
||||
horizontal: 10,
|
||||
),
|
||||
child: DashbotIcons.getDashbotIcon1(),
|
||||
),
|
||||
child: const Icon(Icons.help_outline),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
|
||||
31
packages/dashbot/.gitignore
vendored
Normal file
31
packages/dashbot/.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
build/
|
||||
3
packages/dashbot/CHANGELOG.md
Normal file
3
packages/dashbot/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
||||
1
packages/dashbot/LICENSE
Normal file
1
packages/dashbot/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
39
packages/dashbot/README.md
Normal file
39
packages/dashbot/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
This README describes the package. If you publish this package to pub.dev,
|
||||
this README's contents appear on the landing page for your package.
|
||||
|
||||
For information about how to write a good package README, see the guide for
|
||||
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
|
||||
|
||||
For general information about developing packages, see the Dart guide for
|
||||
[creating packages](https://dart.dev/guides/libraries/create-packages)
|
||||
and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/to/develop-packages).
|
||||
-->
|
||||
|
||||
TODO: Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.
|
||||
|
||||
## Features
|
||||
|
||||
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||
|
||||
## Getting started
|
||||
|
||||
TODO: List prerequisites and provide or point to information on how to
|
||||
start using the package.
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
4
packages/dashbot/analysis_options.yaml
Normal file
4
packages/dashbot/analysis_options.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
BIN
packages/dashbot/assets/dashbot_icon_1.png
Normal file
BIN
packages/dashbot/assets/dashbot_icon_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
packages/dashbot/assets/dashbot_icon_2.png
Normal file
BIN
packages/dashbot/assets/dashbot_icon_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,40 @@
|
||||
import 'package:apidash_design_system/apidash_design_system.dart'
|
||||
show kVSpacer20, kVSpacer16, kVSpacer10;
|
||||
import 'package:dashbot/core/utils/dashbot_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DashbotDefaultPage extends StatelessWidget {
|
||||
const DashbotDefaultPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
kVSpacer16,
|
||||
DashbotIcons.getDashbotIcon1(width: 60),
|
||||
|
||||
kVSpacer20,
|
||||
Text(
|
||||
'Hello there!',
|
||||
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w800),
|
||||
),
|
||||
kVSpacer10,
|
||||
Text(
|
||||
'Request not made yet',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Why not go ahead and make one?",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w200),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
31
packages/dashbot/lib/core/model/dashbot_window_model.dart
Normal file
31
packages/dashbot/lib/core/model/dashbot_window_model.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
class DashbotWindowModel {
|
||||
final double width;
|
||||
final double height;
|
||||
final double right;
|
||||
final double bottom;
|
||||
final bool isActive;
|
||||
|
||||
const DashbotWindowModel({
|
||||
this.width = 350,
|
||||
this.height = 450,
|
||||
this.right = 50,
|
||||
this.bottom = 100,
|
||||
this.isActive = false,
|
||||
});
|
||||
|
||||
DashbotWindowModel copyWith({
|
||||
double? width,
|
||||
double? height,
|
||||
double? right,
|
||||
double? bottom,
|
||||
bool? isActive,
|
||||
}) {
|
||||
return DashbotWindowModel(
|
||||
width: width ?? this.width,
|
||||
height: height ?? this.height,
|
||||
right: right ?? this.right,
|
||||
bottom: bottom ?? this.bottom,
|
||||
isActive: isActive ?? this.isActive,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import '../model/dashbot_window_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'dashbot_window_notifier.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class DashbotWindowNotifier extends _$DashbotWindowNotifier {
|
||||
@override
|
||||
DashbotWindowModel build() {
|
||||
return const DashbotWindowModel();
|
||||
}
|
||||
|
||||
void updatePosition(double dx, double dy, Size screenSize) {
|
||||
state = state.copyWith(
|
||||
right: (state.right - dx).clamp(0, screenSize.width - state.width),
|
||||
bottom: (state.bottom - dy).clamp(0, screenSize.height - state.height),
|
||||
);
|
||||
}
|
||||
|
||||
void updateSize(double dx, double dy, Size screenSize) {
|
||||
final newWidth =
|
||||
(state.width - dx).clamp(300, screenSize.width - state.right);
|
||||
final newHeight =
|
||||
(state.height - dy).clamp(350, screenSize.height - state.bottom);
|
||||
|
||||
state = state.copyWith(
|
||||
width: newWidth.toDouble(),
|
||||
height: newHeight.toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
void toggleActive() {
|
||||
state = state.copyWith(isActive: !state.isActive);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'dashbot_window_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$dashbotWindowNotifierHash() =>
|
||||
r'239915bec100bc33e5533291ff10233ea197d556';
|
||||
|
||||
/// See also [DashbotWindowNotifier].
|
||||
@ProviderFor(DashbotWindowNotifier)
|
||||
final dashbotWindowNotifierProvider =
|
||||
NotifierProvider<DashbotWindowNotifier, DashbotWindowModel>.internal(
|
||||
DashbotWindowNotifier.new,
|
||||
name: r'dashbotWindowNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$dashbotWindowNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$DashbotWindowNotifier = Notifier<DashbotWindowModel>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
31
packages/dashbot/lib/core/routes/dashbot_router.dart
Normal file
31
packages/dashbot/lib/core/routes/dashbot_router.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'dashbot_routes.dart';
|
||||
import '../common/pages/dashbot_default_page.dart';
|
||||
import '../../features/home/view/pages/home_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Route<dynamic>? generateRoute(
|
||||
RouteSettings settings,
|
||||
) {
|
||||
switch (settings.name) {
|
||||
case (DashbotRoutes.dashbotHome):
|
||||
return MaterialPageRoute(
|
||||
builder: (context) => DashbotHomePage(),
|
||||
);
|
||||
case (DashbotRoutes.dashbotDefault):
|
||||
return MaterialPageRoute(
|
||||
builder: (context) => DashbotDefaultPage(),
|
||||
);
|
||||
// case (DashbotRoutes.dashbotChat):
|
||||
// final args = settings.arguments as Map<String, dynamic>?;
|
||||
// final initialPrompt = args?['initialPrompt'] as String;
|
||||
// return MaterialPageRoute(
|
||||
// builder: (context) => ChatScreen(
|
||||
// initialPrompt: initialPrompt,
|
||||
// ),
|
||||
// );
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (context) => DashbotDefaultPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
6
packages/dashbot/lib/core/routes/dashbot_routes.dart
Normal file
6
packages/dashbot/lib/core/routes/dashbot_routes.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
class DashbotRoutes {
|
||||
static const String dashbotHome = '/dashbothome';
|
||||
static const String dashbotDefault = '/dashbotdefault';
|
||||
static const String dashbotChat = '/dashbotchat';
|
||||
static const String dashbotUnknown = '/dashbotunknown';
|
||||
}
|
||||
17
packages/dashbot/lib/core/utils/dashbot_icons.dart
Normal file
17
packages/dashbot/lib/core/utils/dashbot_icons.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class DashbotIcons {
|
||||
DashbotIcons._();
|
||||
static String get dashbotIcon1 =>
|
||||
'packages/dashbot/assets/dashbot_icon_1.png';
|
||||
static String get dashbotIcon2 =>
|
||||
'packages/dashbot/assets/dashbot_icon_2.png';
|
||||
|
||||
static Image getDashbotIcon1({double? width, double? height, BoxFit? fit}) {
|
||||
return Image.asset(dashbotIcon1, width: width, height: height, fit: fit);
|
||||
}
|
||||
|
||||
static Image getDashbotIcon2({double? width, double? height, BoxFit? fit}) {
|
||||
return Image.asset(dashbotIcon2, width: width, height: height, fit: fit);
|
||||
}
|
||||
}
|
||||
25
packages/dashbot/lib/core/utils/show_dashbot.dart
Normal file
25
packages/dashbot/lib/core/utils/show_dashbot.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../dashbot_dashboard.dart';
|
||||
import '../providers/dashbot_window_notifier.dart';
|
||||
|
||||
void showDashbotWindow(BuildContext context, WidgetRef ref) {
|
||||
final isDashbotActive = ref.read(dashbotWindowNotifierProvider).isActive;
|
||||
final windowNotifier = ref.read(dashbotWindowNotifierProvider.notifier);
|
||||
if (isDashbotActive) return;
|
||||
final overlay = Overlay.of(context);
|
||||
OverlayEntry? entry;
|
||||
|
||||
entry = OverlayEntry(
|
||||
builder:
|
||||
(context) => DashbotWindow(
|
||||
onClose: () {
|
||||
entry?.remove();
|
||||
windowNotifier.toggleActive();
|
||||
},
|
||||
),
|
||||
);
|
||||
windowNotifier.toggleActive();
|
||||
overlay.insert(entry);
|
||||
}
|
||||
2
packages/dashbot/lib/core/utils/utils.dart
Normal file
2
packages/dashbot/lib/core/utils/utils.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'show_dashbot.dart';
|
||||
export 'dashbot_icons.dart';
|
||||
3
packages/dashbot/lib/dashbot.dart
Normal file
3
packages/dashbot/lib/dashbot.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'dashbot_dashboard.dart';
|
||||
export 'core/providers/dashbot_window_notifier.dart';
|
||||
export 'core/utils/utils.dart';
|
||||
147
packages/dashbot/lib/dashbot_dashboard.dart
Normal file
147
packages/dashbot/lib/dashbot_dashboard.dart
Normal file
@@ -0,0 +1,147 @@
|
||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||
import 'package:dashbot/core/utils/dashbot_icons.dart';
|
||||
|
||||
import 'core/providers/dashbot_window_notifier.dart';
|
||||
import 'core/routes/dashbot_router.dart';
|
||||
import 'core/routes/dashbot_routes.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class DashbotWindow extends ConsumerWidget {
|
||||
final VoidCallback onClose;
|
||||
|
||||
const DashbotWindow({super.key, required this.onClose});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final windowState = ref.watch(dashbotWindowNotifierProvider);
|
||||
final windowNotifier = ref.read(dashbotWindowNotifierProvider.notifier);
|
||||
// final RequestModel? currentRequest = ref.watch(
|
||||
// selectedRequestModelProvider,
|
||||
// );
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
right: windowState.right,
|
||||
bottom: windowState.bottom,
|
||||
child: Material(
|
||||
elevation: 8,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
width: windowState.width,
|
||||
height: windowState.height,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
// This is to update position
|
||||
GestureDetector(
|
||||
onPanUpdate: (details) {
|
||||
windowNotifier.updatePosition(
|
||||
details.delta.dx,
|
||||
details.delta.dy,
|
||||
MediaQuery.of(context).size,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).colorScheme.primaryContainer,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
kHSpacer20,
|
||||
DashbotIcons.getDashbotIcon1(width: 38),
|
||||
|
||||
kHSpacer12,
|
||||
Text(
|
||||
'DashBot',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color:
|
||||
Theme.of(context).colorScheme.surface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color:
|
||||
Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
onPressed: onClose,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Navigator(
|
||||
initialRoute: DashbotRoutes.dashbotHome,
|
||||
// currentRequest?.responseStatus == null
|
||||
// ? DashbotRoutes.dashbotDefault
|
||||
// : DashbotRoutes.dashbotHome,
|
||||
onGenerateRoute: generateRoute,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// This is to update size
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
child: GestureDetector(
|
||||
onPanUpdate: (details) {
|
||||
windowNotifier.updateSize(
|
||||
details.delta.dx,
|
||||
details.delta.dy,
|
||||
MediaQuery.of(context).size,
|
||||
);
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeUpLeft,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 6, left: 1),
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer
|
||||
.withValues(alpha: 0.7),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.drag_indicator_rounded,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
135
packages/dashbot/lib/features/home/view/pages/home_page.dart
Normal file
135
packages/dashbot/lib/features/home/view/pages/home_page.dart
Normal file
@@ -0,0 +1,135 @@
|
||||
import 'package:dashbot/core/utils/dashbot_icons.dart';
|
||||
|
||||
import '../../../../core/routes/dashbot_routes.dart';
|
||||
import 'package:apidash_design_system/tokens/measurements.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class DashbotHomePage extends ConsumerStatefulWidget {
|
||||
const DashbotHomePage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<DashbotHomePage> createState() => _DashbotHomePageState();
|
||||
}
|
||||
|
||||
class _DashbotHomePageState extends ConsumerState<DashbotHomePage> {
|
||||
void navigateToChat(String prompt) {
|
||||
Navigator.of(context).pushNamed(
|
||||
DashbotRoutes.dashbotChat,
|
||||
arguments: {'initialPrompt': prompt},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
kVSpacer16,
|
||||
DashbotIcons.getDashbotIcon1(width: 60),
|
||||
|
||||
kVSpacer16,
|
||||
Text(
|
||||
'Hello there,',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w800),
|
||||
),
|
||||
Text('How can I help you today?'),
|
||||
kVSpacer16,
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pushNamed(
|
||||
// DashbotRoutes.dashbotChat,
|
||||
// );
|
||||
// },
|
||||
// style: TextButton.styleFrom(
|
||||
// side: BorderSide(
|
||||
// color: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 0,
|
||||
// horizontal: 16,
|
||||
// ),
|
||||
// ),
|
||||
// child: const Text("🤖 Chat with Dashbot"),
|
||||
// ),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
style: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 0,
|
||||
horizontal: 16,
|
||||
),
|
||||
),
|
||||
child: const Text("🔎 Explain me this response"),
|
||||
),
|
||||
// TextButton(
|
||||
// onPressed: () {},
|
||||
// style: TextButton.styleFrom(
|
||||
// side: BorderSide(
|
||||
// color: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 0,
|
||||
// horizontal: 16,
|
||||
// ),
|
||||
// ),
|
||||
// child: const Text("🐞 Help me debug this error"),
|
||||
// ),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
style: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 0,
|
||||
horizontal: 16,
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
"📄 Generate documentation",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
style: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 0,
|
||||
horizontal: 16,
|
||||
),
|
||||
),
|
||||
child: const Text("📝 Generate Tests"),
|
||||
),
|
||||
// TextButton(
|
||||
// onPressed: () {},
|
||||
// style: TextButton.styleFrom(
|
||||
// side: BorderSide(
|
||||
// color: Theme.of(context).colorScheme.primary,
|
||||
// ),
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// vertical: 0,
|
||||
// horizontal: 16,
|
||||
// ),
|
||||
// ),
|
||||
// child: const Text("📊 Generate Visualizations"),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
63
packages/dashbot/pubspec.yaml
Normal file
63
packages/dashbot/pubspec.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
name: dashbot
|
||||
description: "A new Flutter package project."
|
||||
version: 0.0.1
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.2
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
http: ^1.3.0
|
||||
apidash_design_system:
|
||||
path: ../apidash_design_system
|
||||
apidash_core:
|
||||
path: ../apidash_core
|
||||
flutter_riverpod: ^2.5.1
|
||||
riverpod_annotation: ^2.5.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^5.0.0
|
||||
riverpod_lint: ^2.5.1
|
||||
riverpod_generator: ^2.5.1
|
||||
custom_lint: ^0.7.3
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
# To add assets to your package, add an assets section, like this:
|
||||
assets:
|
||||
- assets/dashbot_icon_1.png
|
||||
- assets/dashbot_icon_2.png
|
||||
#
|
||||
# For details regarding assets in packages, see
|
||||
# https://flutter.dev/to/asset-from-package
|
||||
#
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/to/resolution-aware-images
|
||||
|
||||
# To add custom fonts to your package, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
# "family" key with the font family name, and a "fonts" key with a
|
||||
# list giving the asset and other descriptors for the font. For
|
||||
# example:
|
||||
# fonts:
|
||||
# - family: Schyler
|
||||
# fonts:
|
||||
# - asset: fonts/Schyler-Regular.ttf
|
||||
# - asset: fonts/Schyler-Italic.ttf
|
||||
# style: italic
|
||||
# - family: Trajan Pro
|
||||
# fonts:
|
||||
# - asset: fonts/TrajanPro.ttf
|
||||
# - asset: fonts/TrajanPro_Bold.ttf
|
||||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts in packages, see
|
||||
# https://flutter.dev/to/font-from-package
|
||||
5
packages/dashbot/test/dashbot_test.dart
Normal file
5
packages/dashbot/test/dashbot_test.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('adds one to input values', () {});
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import 'dart:ui';
|
||||
import 'package:dashbot/core/model/dashbot_window_model.dart';
|
||||
import 'package:dashbot/core/providers/dashbot_window_notifier.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../../../../test/providers/helpers.dart';
|
||||
|
||||
void main() {
|
||||
const testScreenSize = Size(1200, 800);
|
||||
|
||||
group("DashbotWindowNotifier - ", () {
|
||||
test(
|
||||
'given dashbot window model when instatiated then initial values must match the default values',
|
||||
() {
|
||||
final container = createContainer();
|
||||
|
||||
final initialState = container.read(dashbotWindowNotifierProvider);
|
||||
|
||||
expect(initialState, const DashbotWindowModel());
|
||||
expect(initialState.width, 350);
|
||||
expect(initialState.height, 450);
|
||||
expect(initialState.right, 50);
|
||||
expect(initialState.bottom, 100);
|
||||
expect(initialState.isActive, false);
|
||||
});
|
||||
|
||||
test('Toggle active state', () {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Initial state is false
|
||||
expect(container.read(dashbotWindowNotifierProvider).isActive, false);
|
||||
|
||||
// First toggle
|
||||
notifier.toggleActive();
|
||||
expect(container.read(dashbotWindowNotifierProvider).isActive, true);
|
||||
|
||||
// Second toggle
|
||||
notifier.toggleActive();
|
||||
expect(container.read(dashbotWindowNotifierProvider).isActive, false);
|
||||
});
|
||||
|
||||
group('Position updates', () {
|
||||
test(
|
||||
'given dashbot window notifier when position is updated 100px to the left and 50px down then then values must be 150 and 50',
|
||||
() {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Drag 100px left and 50px down
|
||||
notifier.updatePosition(-100, 50, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
expect(state.right, 50 - (-100)); // 50 - (-100) = 150
|
||||
expect(state.bottom, 100 - 50); // 100 - 50 = 50
|
||||
});
|
||||
|
||||
test(
|
||||
'given dashbot window notifier when position is updated beyond the left boundary then the value must be clamped to the upper boundary',
|
||||
() {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Try to drag 1200px left (dx positive when moving right in coordinates)
|
||||
notifier.updatePosition(-1200, 0, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
expect(state.right,
|
||||
850); // 50 - (-1200) = 1250 → not within bounds, max is screen width(1200) - width(350) = 850
|
||||
});
|
||||
|
||||
test(
|
||||
'given dashbot window notifier when position is updated beyond bottom boundary then the value must be clamped to the upper boundary',
|
||||
() {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Move to bottom edge
|
||||
notifier.updatePosition(0, -700, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
// 100 - (-700) = 800 → but max is screenHeight(800) - height(450) = 350
|
||||
expect(state.bottom, 350);
|
||||
});
|
||||
});
|
||||
|
||||
group('Size updates', () {
|
||||
test('Normal resize within bounds', () {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Increase width by 100px, height by 50px
|
||||
notifier.updateSize(-100, -50, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
expect(state.width, 350 - (-100)); // = 450
|
||||
expect(state.height, 450 - (-50)); // = 500
|
||||
});
|
||||
|
||||
test(
|
||||
'given dashbot window notifier when tried to resize below the minimum limit then the value must be clamped to the lower boundary',
|
||||
() {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Try to shrink too much
|
||||
notifier.updateSize(100, 100, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
expect(state.width, 300); // Clamped to minimum
|
||||
expect(state.height, 350); // Clamped to minimum
|
||||
});
|
||||
|
||||
test(
|
||||
'given dashbot window notifier when tried to resize above the maximum limit then the value must be clamped to the upper boundary',
|
||||
() {
|
||||
final container = createContainer();
|
||||
final notifier = container.read(dashbotWindowNotifierProvider.notifier);
|
||||
|
||||
// Try to expand beyond screen
|
||||
notifier.updateSize(-1200, -900, testScreenSize);
|
||||
|
||||
final state = container.read(dashbotWindowNotifierProvider);
|
||||
// Max width = screenWidth(1200) - right(50) = 1150
|
||||
expect(state.width, 1150);
|
||||
// Max height = screenHeight(800) - bottom(100) = 700
|
||||
expect(state.height, 700);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
15
pubspec.lock
15
pubspec.lock
@@ -381,6 +381,13 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
dashbot:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/dashbot"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
data_table_2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1388,6 +1395,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
riverpod_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -14,6 +14,8 @@ dependencies:
|
||||
path: packages/apidash_core
|
||||
apidash_design_system:
|
||||
path: packages/apidash_design_system
|
||||
dashbot:
|
||||
path: packages/dashbot
|
||||
carousel_slider: ^5.0.0
|
||||
code_builder: ^4.10.0
|
||||
csv: ^6.0.0
|
||||
|
||||
Reference in New Issue
Block a user