Add command files and enhance session management features
This commit is contained in:
@@ -10,6 +10,7 @@ import "../../widgets/chat/chat_box.dart";
|
||||
import "../../widgets/chat/chat_view.dart";
|
||||
import "../../widgets/common/footer_bar.dart";
|
||||
import "../../widgets/common/app_header.dart";
|
||||
import "../../widgets/common/button.dart";
|
||||
import "../../widgets/sidebar/sidebar.dart";
|
||||
import "../../widgets/sidebar/sidebar_v2.dart";
|
||||
|
||||
@@ -137,19 +138,38 @@ class _ChatArea extends StatelessWidget {
|
||||
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.all(16),
|
||||
// padding: const EdgeInsets.all(16),
|
||||
padding: EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16
|
||||
),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 600),
|
||||
constraints: const BoxConstraints(maxWidth: 700),
|
||||
child: Column(
|
||||
children: [
|
||||
|
||||
Expanded(
|
||||
child: chatProvider.messages.isEmpty
|
||||
? _EmptyChatState()
|
||||
: ChatView(scrollController: scrollController),
|
||||
),
|
||||
if (chatProvider.messages.isEmpty)...[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_EmptyChatState(),
|
||||
|
||||
ChatBox(),
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
] else ...[
|
||||
Expanded(child: ChatView(scrollController: scrollController)),
|
||||
|
||||
ChatBox(),
|
||||
|
||||
Gap(12),
|
||||
],
|
||||
|
||||
|
||||
ChatBox(),
|
||||
|
||||
],
|
||||
),
|
||||
@@ -177,58 +197,15 @@ class _EmptyChatState extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
||||
const Icon(LucideIcons.messagesSquare, size: 28),
|
||||
const Gap(16),
|
||||
Text(
|
||||
"Ask the agency anything",
|
||||
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w700),
|
||||
"Lets burn some braincells",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const Gap(8),
|
||||
).x4Large.extraBold,
|
||||
Text(
|
||||
"Select a project and thread from the sidebar, or start a new chat.",
|
||||
textAlign: TextAlign.center,
|
||||
).textSmall.muted,
|
||||
|
||||
const Gap(24),
|
||||
|
||||
Select<ProjectRecord>(
|
||||
itemBuilder: (context, item) => Text(item.name),
|
||||
popup: SelectPopup.builder(
|
||||
searchPlaceholder: const Text("Search projects"),
|
||||
builder: (context, searchQuery) {
|
||||
final filtered = searchQuery == null || searchQuery.isEmpty
|
||||
? projects
|
||||
: projects.where((p) =>
|
||||
p.name.toLowerCase().contains(searchQuery.toLowerCase()) ||
|
||||
p.workingDirectory.toLowerCase().contains(searchQuery.toLowerCase())
|
||||
).toList();
|
||||
|
||||
return SelectItemList(
|
||||
children: [
|
||||
for (final project in filtered)
|
||||
SelectItemButton(
|
||||
value: project,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(project.name),
|
||||
Text(project.workingDirectory).textSmall.muted,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
onChanged: (project) {
|
||||
if (project != null) coordinator.selectProject(project);
|
||||
},
|
||||
constraints: const BoxConstraints(minWidth: 240),
|
||||
value: selected,
|
||||
placeholder: const Text("Select a project"),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -272,24 +249,69 @@ class _InsetShadowPainter extends CustomPainter {
|
||||
}
|
||||
|
||||
|
||||
class _SidebarPane extends StatelessWidget {
|
||||
class _SidebarPane extends StatefulWidget {
|
||||
|
||||
const _SidebarPane();
|
||||
|
||||
@override
|
||||
State<_SidebarPane> createState() => _SidebarPaneState();
|
||||
}
|
||||
|
||||
class _SidebarPaneState extends State<_SidebarPane> {
|
||||
|
||||
bool _open = true;
|
||||
|
||||
static const _dur = Duration(milliseconds: 220);
|
||||
static const _curve = Curves.easeInOut;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return OutlinedContainer(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.15),
|
||||
blurRadius: 16,
|
||||
spreadRadius: 2,
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
|
||||
AnimatedSlide(
|
||||
offset: _open ? Offset.zero : const Offset(-1.1, 0),
|
||||
duration: _dur,
|
||||
curve: _curve,
|
||||
child: AnimatedOpacity(
|
||||
opacity: _open ? 1.0 : 0.0,
|
||||
duration: _dur,
|
||||
curve: _curve,
|
||||
child: OutlinedContainer(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.15),
|
||||
blurRadius: 16,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
],
|
||||
child: SidebarV2(onClose: () => setState(() => _open = false)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
AnimatedOpacity(
|
||||
opacity: _open ? 0.0 : 1.0,
|
||||
duration: _dur,
|
||||
curve: _curve,
|
||||
child: IgnorePointer(
|
||||
ignoring: _open,
|
||||
child: IconButton.ghost(
|
||||
onPressed: () => setState(() => _open = true),
|
||||
icon: Icon(
|
||||
LucideIcons.panelLeftOpen,
|
||||
size: 16,
|
||||
color: theme.colorScheme.mutedForeground,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
child: SidebarV2(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user