Files

164 lines
5.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_animate/flutter_animate.dart';
import '../../providers/ideas_provider.dart';
import '../../providers/workspace_provider.dart';
import '../../core/theme/app_theme.dart';
import '../../widgets/loading_indicator.dart';
import '../../widgets/error_display.dart';
import '../../widgets/empty_state.dart';
import '../../widgets/funnel_status_badge.dart';
import '../../models/idea.dart';
import '../../core/constants/app_constants.dart';
import '../ideas/widgets/funnel_kanban.dart';
class DashboardScreen extends ConsumerWidget {
const DashboardScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final ideasState = ref.watch(ideasProvider);
final wsState = ref.watch(workspaceProvider);
final ideasNotifier = ref.read(ideasProvider.notifier);
return Scaffold(
appBar: AppBar(
title: Text(wsState.selectedWorkspace?.name ?? 'VoIdea'),
actions: [
IconButton(
icon: Icon(ideasState.viewMode == 'list'
? Icons.view_kanban
: Icons.view_list),
onPressed: () {
ideasNotifier.setViewMode(
ideasState.viewMode == 'list' ? 'kanban' : 'list');
},
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () => context.push('/ideas/create'),
),
],
),
body: RefreshIndicator(
onRefresh: () => ideasNotifier.loadIdeas(),
child: _buildBody(context, ref, ideasState),
),
);
}
Widget _buildBody(BuildContext context, WidgetRef ref, IdeasState state) {
if (state.isLoading && state.ideas.isEmpty) {
return const ShimmerList();
}
if (state.error != null && state.ideas.isEmpty) {
return ErrorDisplay(
message: state.error!,
onRetry: () => ref.read(ideasProvider.notifier).loadIdeas(),
);
}
if (state.ideas.isEmpty) {
return EmptyState(
icon: Icons.lightbulb_outline,
title: 'Пока нет идей',
subtitle: 'Создайте первую идею',
actionLabel: 'Создать идею',
onAction: () => context.push('/ideas/create'),
);
}
if (state.viewMode == 'kanban') {
return IdeaFunnelKanban(ideas: state.ideas);
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: state.ideas.length,
itemBuilder: (context, index) {
final idea = state.ideas[index];
return _IdeaCard(idea: idea).animate().fadeIn(
duration: 300.ms,
delay: (index * 50).ms,
);
},
);
}
}
class _IdeaCard extends StatelessWidget {
final Idea idea;
const _IdeaCard({required this.idea});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () => context.push('/ideas/${idea.id}'),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
idea.title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
if (idea.funnelStatus != null)
FunnelStatusBadge(status: idea.funnelStatus),
],
),
const SizedBox(height: 8),
if (idea.description.isNotEmpty)
Text(
idea.description,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: VoIdeaColors.muted,
),
),
const SizedBox(height: 12),
Row(
children: [
Icon(Icons.thumb_up_outlined,
size: 14, color: VoIdeaColors.muted),
const SizedBox(width: 4),
Text(idea.upvotes.toString(),
style: const TextStyle(
color: VoIdeaColors.muted, fontSize: 12)),
const SizedBox(width: 16),
Icon(Icons.thumb_down_outlined,
size: 14, color: VoIdeaColors.muted),
const SizedBox(width: 4),
Text(idea.downvotes.toString(),
style: const TextStyle(
color: VoIdeaColors.muted, fontSize: 12)),
const SizedBox(width: 16),
Icon(Icons.comment_outlined,
size: 14, color: VoIdeaColors.muted),
const SizedBox(width: 4),
Text(idea.commentCount.toString(),
style: const TextStyle(
color: VoIdeaColors.muted, fontSize: 12)),
],
),
],
),
),
),
);
}
}