Initial commit: NANAHUI CRM - Flutter Firebase CRM assistant
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../models/task_model.dart';
|
||||
|
||||
class AIService {
|
||||
final String? openaiApiKey;
|
||||
final String? anthropicApiKey;
|
||||
final String? googleAiApiKey;
|
||||
|
||||
AIService({
|
||||
this.openaiApiKey,
|
||||
this.anthropicApiKey,
|
||||
this.googleAiApiKey,
|
||||
});
|
||||
|
||||
// Генерация подзадач из основной задачи
|
||||
Future<List<Map<String, dynamic>>> generateSubtasks({
|
||||
required String title,
|
||||
required String description,
|
||||
}) async {
|
||||
if (openaiApiKey == null) {
|
||||
return _mockGenerateSubtasks(title, description);
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://api.openai.com/v1/chat/completions'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $openaiApiKey',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'model': 'gpt-4o-mini',
|
||||
'messages': [
|
||||
{
|
||||
'role': 'system',
|
||||
'content': 'You are a task planning assistant. Break down tasks into logical subtasks.',
|
||||
},
|
||||
{
|
||||
'role': 'user',
|
||||
'content': 'Break down this task into 3-7 subtasks:\n\nTitle: $title\nDescription: $description\n\nReturn ONLY a JSON array of subtasks with format: [{"title": "...", "estimatedHours": 0}]',
|
||||
},
|
||||
],
|
||||
'temperature': 0.7,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
final content = data['choices'][0]['message']['content'];
|
||||
final List<dynamic> subtasks = jsonDecode(content);
|
||||
return subtasks.cast<Map<String, dynamic>>();
|
||||
}
|
||||
} catch (e) {
|
||||
print('AI Service Error: $e');
|
||||
}
|
||||
|
||||
return _mockGenerateSubtasks(title, description);
|
||||
}
|
||||
|
||||
// AI приоритизация задач
|
||||
Future<TaskPriority> prioritizeTask({
|
||||
required String title,
|
||||
required String description,
|
||||
DateTime? dueDate,
|
||||
}) async {
|
||||
if (openaiApiKey == null) {
|
||||
return _mockPrioritizeTask(dueDate);
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://api.openai.com/v1/chat/completions'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $openaiApiKey',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'model': 'gpt-4o-mini',
|
||||
'messages': [
|
||||
{
|
||||
'role': 'system',
|
||||
'content': 'You are a task prioritization assistant. Determine task priority: low, medium, high, or urgent.',
|
||||
},
|
||||
{
|
||||
'role': 'user',
|
||||
'content': 'What priority should this task have?\n\nTitle: $title\nDescription: $description\nDue: ${dueDate ?? "Not specified"}\n\nReply with ONE word: low, medium, high, or urgent',
|
||||
},
|
||||
],
|
||||
'temperature': 0.3,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
final content = data['choices'][0]['message']['content'].trim().toLowerCase();
|
||||
|
||||
switch (content) {
|
||||
case 'urgent': return TaskPriority.urgent;
|
||||
case 'high': return TaskPriority.high;
|
||||
case 'low': return TaskPriority.low;
|
||||
default: return TaskPriority.medium;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('AI Service Error: $e');
|
||||
}
|
||||
|
||||
return _mockPrioritizeTask(dueDate);
|
||||
}
|
||||
|
||||
// Умное планирование - распределение задач по времени
|
||||
Future<List<Map<String, dynamic>>> smartSchedule({
|
||||
required List<TaskModel> tasks,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
required int availableHoursPerDay,
|
||||
}) async {
|
||||
// Mock implementation для начала
|
||||
final schedule = <Map<String, dynamic>>[];
|
||||
var currentDate = startDate;
|
||||
var remainingHours = availableHoursPerDay;
|
||||
|
||||
for (final task in tasks) {
|
||||
if (currentDate.isAfter(endDate)) break;
|
||||
|
||||
if (task.estimatedHours <= remainingHours) {
|
||||
schedule.add({
|
||||
'taskId': task.id,
|
||||
'date': currentDate,
|
||||
'hours': task.estimatedHours,
|
||||
});
|
||||
remainingHours -= task.estimatedHours;
|
||||
} else {
|
||||
// Переходим на следующий день
|
||||
currentDate = currentDate.add(const Duration(days: 1));
|
||||
remainingHours = availableHoursPerDay;
|
||||
|
||||
if (currentDate.isAfter(endDate)) break;
|
||||
|
||||
schedule.add({
|
||||
'taskId': task.id,
|
||||
'date': currentDate,
|
||||
'hours': task.estimatedHours > remainingHours
|
||||
? remainingHours
|
||||
: task.estimatedHours,
|
||||
});
|
||||
remainingHours -= task.estimatedHours > remainingHours
|
||||
? remainingHours
|
||||
: task.estimatedHours;
|
||||
}
|
||||
}
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
// Генерация описания задачи
|
||||
Future<String> generateTaskDescription({
|
||||
required String title,
|
||||
String? context,
|
||||
}) async {
|
||||
if (openaiApiKey == null) {
|
||||
return 'Описание для задачи: $title';
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse('https://api.openai.com/v1/chat/completions'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $openaiApiKey',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'model': 'gpt-4o-mini',
|
||||
'messages': [
|
||||
{
|
||||
'role': 'system',
|
||||
'content': 'You are a task description writer. Write clear, concise task descriptions.',
|
||||
},
|
||||
{
|
||||
'role': 'user',
|
||||
'content': 'Write a brief description for this task:\n\nTitle: $title\nContext: ${context ?? "No additional context"}\n\nKeep it under 100 words.',
|
||||
},
|
||||
],
|
||||
'temperature': 0.5,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
return data['choices'][0]['message']['content'];
|
||||
}
|
||||
} catch (e) {
|
||||
print('AI Service Error: $e');
|
||||
}
|
||||
|
||||
return 'Описание для задачи: $title';
|
||||
}
|
||||
|
||||
// Mock данные для тестирования
|
||||
List<Map<String, dynamic>> _mockGenerateSubtasks(String title, String description) {
|
||||
return [
|
||||
{'title': 'Анализ требований', 'estimatedHours': 2},
|
||||
{'title': 'Проектирование', 'estimatedHours': 3},
|
||||
{'title': 'Реализация', 'estimatedHours': 8},
|
||||
{'title': 'Тестирование', 'estimatedHours': 3},
|
||||
{'title': 'Документирование', 'estimatedHours': 2},
|
||||
];
|
||||
}
|
||||
|
||||
TaskPriority _mockPrioritizeTask(DateTime? dueDate) {
|
||||
if (dueDate == null) return TaskPriority.medium;
|
||||
|
||||
final daysUntilDue = dueDate.difference(DateTime.now()).inDays;
|
||||
|
||||
if (daysUntilDue <= 1) return TaskPriority.urgent;
|
||||
if (daysUntilDue <= 3) return TaskPriority.high;
|
||||
if (daysUntilDue <= 7) return TaskPriority.medium;
|
||||
return TaskPriority.low;
|
||||
}
|
||||
}
|
||||
|
||||
final aiService = AIService(
|
||||
// API ключи лучше хранить в .env файле или Firebase Remote Config
|
||||
openaiApiKey: null, // Добавить ключ здесь или через env
|
||||
anthropicApiKey: null,
|
||||
googleAiApiKey: null,
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class FirebaseConfig {
|
||||
static Future<void> initialize() async {
|
||||
await Firebase.initializeApp();
|
||||
debugPrint('Firebase initialized successfully');
|
||||
}
|
||||
|
||||
static Future<void> setupFirestore() async {
|
||||
// Настройки Firestore для лучшей производительности
|
||||
// Будут применены после инициализации
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import '../models/task_model.dart';
|
||||
import '../models/project_model.dart';
|
||||
import '../models/mind_map_model.dart';
|
||||
import '../models/calendar_event_model.dart';
|
||||
import '../models/alarm_model.dart';
|
||||
import '../models/user_model.dart';
|
||||
|
||||
class FirestoreService {
|
||||
final FirebaseFirestore _db = FirebaseFirestore.instance;
|
||||
|
||||
// === USERS ===
|
||||
Future<void> createUser(UserModel user) async {
|
||||
await _db.collection('users').doc(user.id).set(user.toFirestore());
|
||||
}
|
||||
|
||||
Future<UserModel?> getUser(String userId) async {
|
||||
final doc = await _db.collection('users').doc(userId).get();
|
||||
return doc.exists ? UserModel.fromFirestore(doc) : null;
|
||||
}
|
||||
|
||||
Future<void> updateUser(UserModel user) async {
|
||||
await _db.collection('users').doc(user.id).update(user.toFirestore());
|
||||
}
|
||||
|
||||
// === PROJECTS ===
|
||||
Future<void> createProject(ProjectModel project) async {
|
||||
await _db.collection('projects').doc(project.id).set(project.toFirestore());
|
||||
}
|
||||
|
||||
Future<List<ProjectModel>> getProjectsByTeam(String teamId) async {
|
||||
final snapshot = await _db
|
||||
.collection('projects')
|
||||
.where('teamId', isEqualTo: teamId)
|
||||
.orderBy('createdAt', descending: true)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => ProjectModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<List<ProjectModel>> getProjectsByUser(String userId) async {
|
||||
final snapshot = await _db
|
||||
.collection('projects')
|
||||
.where('memberIds', arrayContains: userId)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => ProjectModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
// === TASKS ===
|
||||
Future<void> createTask(TaskModel task) async {
|
||||
await _db.collection('tasks').doc(task.id).set(task.toFirestore());
|
||||
}
|
||||
|
||||
Future<List<TaskModel>> getTasksByProject(String projectId) async {
|
||||
final snapshot = await _db
|
||||
.collection('tasks')
|
||||
.where('projectId', isEqualTo: projectId)
|
||||
.orderBy('createdAt', descending: true)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => TaskModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<List<TaskModel>> getTasksByAssignee(String assigneeId) async {
|
||||
final snapshot = await _db
|
||||
.collection('tasks')
|
||||
.where('assigneeId', isEqualTo: assigneeId)
|
||||
.where('status', whereIn: ['todo', 'inProgress', 'review'])
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => TaskModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<void> updateTask(TaskModel task) async {
|
||||
await _db.collection('tasks').doc(task.id).update(task.toFirestore());
|
||||
}
|
||||
|
||||
Future<void> deleteTask(String taskId) async {
|
||||
await _db.collection('tasks').doc(taskId).delete();
|
||||
}
|
||||
|
||||
// Задачи с поддержкой иерархии (для mind-map)
|
||||
Future<List<TaskModel>> getTaskHierarchy(String projectId) async {
|
||||
final snapshot = await _db
|
||||
.collection('tasks')
|
||||
.where('projectId', isEqualTo: projectId)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => TaskModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
// === MIND MAPS ===
|
||||
Future<void> createMindMapNode(MindMapNode node) async {
|
||||
await _db.collection('mindmaps').doc(node.projectId).collection('nodes').doc(node.id).set(node.toFirestore());
|
||||
}
|
||||
|
||||
Future<List<MindMapNode>> getMindMapNodes(String projectId) async {
|
||||
final snapshot = await _db
|
||||
.collection('mindmaps')
|
||||
.doc(projectId)
|
||||
.collection('nodes')
|
||||
.orderBy('level')
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => MindMapNode.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<void> updateMindMapNode(MindMapNode node) async {
|
||||
await _db
|
||||
.collection('mindmaps')
|
||||
.doc(node.projectId)
|
||||
.collection('nodes')
|
||||
.doc(node.id)
|
||||
.update(node.toFirestore());
|
||||
}
|
||||
|
||||
// === CALENDAR EVENTS ===
|
||||
Future<void> createEvent(CalendarEventModel event) async {
|
||||
await _db.collection('events').doc(event.id).set(event.toFirestore());
|
||||
}
|
||||
|
||||
Future<List<CalendarEventModel>> getEventsByDateRange({
|
||||
required DateTime start,
|
||||
required DateTime end,
|
||||
String? userId,
|
||||
}) async {
|
||||
Query query = _db
|
||||
.collection('events')
|
||||
.where('startTime', isLessThanOrEqualTo: Timestamp.fromDate(end))
|
||||
.where('endTime', isGreaterThanOrEqualTo: Timestamp.fromDate(start));
|
||||
|
||||
if (userId != null) {
|
||||
query = query.where('attendeeIds', arrayContains: userId);
|
||||
}
|
||||
|
||||
final snapshot = await query.get();
|
||||
return snapshot.docs.map((doc) => CalendarEventModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<void> updateEvent(CalendarEventModel event) async {
|
||||
await _db.collection('events').doc(event.id).update(event.toFirestore());
|
||||
}
|
||||
|
||||
Future<void> deleteEvent(String eventId) async {
|
||||
await _db.collection('events').doc(eventId).delete();
|
||||
}
|
||||
|
||||
// === ALARMS ===
|
||||
Future<void> createAlarm(AlarmModel alarm) async {
|
||||
await _db.collection('alarms').doc(alarm.id).set(alarm.toFirestore());
|
||||
}
|
||||
|
||||
Future<List<AlarmModel>> getAlarmsByUser(String userId) async {
|
||||
final snapshot = await _db
|
||||
.collection('alarms')
|
||||
.where('isEnabled', isEqualTo: true)
|
||||
.orderBy('dateTime')
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => AlarmModel.fromFirestore(doc)).toList();
|
||||
}
|
||||
|
||||
Future<void> updateAlarm(AlarmModel alarm) async {
|
||||
await _db.collection('alarms').doc(alarm.id).update(alarm.toFirestore());
|
||||
}
|
||||
|
||||
Future<void> deleteAlarm(String alarmId) async {
|
||||
await _db.collection('alarms').doc(alarmId).delete();
|
||||
}
|
||||
|
||||
// === BATCH OPERATIONS ===
|
||||
Future<void> syncTasks(List<TaskModel> tasks) async {
|
||||
final batch = _db.batch();
|
||||
|
||||
for (final task in tasks) {
|
||||
batch.set(_db.collection('tasks').doc(task.id), task.toFirestore());
|
||||
}
|
||||
|
||||
await batch.commit();
|
||||
}
|
||||
|
||||
// === STREAMS (для реального времени) ===
|
||||
Stream<List<TaskModel>> watchTasks(String projectId) {
|
||||
return _db
|
||||
.collection('tasks')
|
||||
.where('projectId', isEqualTo: projectId)
|
||||
.snapshots()
|
||||
.map((snapshot) => snapshot.docs.map((doc) => TaskModel.fromFirestore(doc)).toList());
|
||||
}
|
||||
|
||||
Stream<List<CalendarEventModel>> watchEvents(String userId) {
|
||||
return _db
|
||||
.collection('events')
|
||||
.where('attendeeIds', arrayContains: userId)
|
||||
.snapshots()
|
||||
.map((snapshot) => snapshot.docs.map((doc) => CalendarEventModel.fromFirestore(doc)).toList());
|
||||
}
|
||||
}
|
||||
|
||||
final firestoreService = FirestoreService();
|
||||
@@ -0,0 +1,138 @@
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../models/task_model.dart';
|
||||
import '../models/alarm_model.dart';
|
||||
import '../models/mind_map_model.dart';
|
||||
import '../models/calendar_event_model.dart';
|
||||
|
||||
class LocalStorageService {
|
||||
static const String _tasksBoxName = 'tasks';
|
||||
static const String _alarmsBoxName = 'alarms';
|
||||
static const String _mindMapsBoxName = 'mindMaps';
|
||||
static const String _eventsBoxName = 'events';
|
||||
static const String _settingsBoxName = 'settings';
|
||||
|
||||
late Box<Map> _tasksBox;
|
||||
late Box<Map> _alarmsBox;
|
||||
late Box<Map> _mindMapsBox;
|
||||
late Box<Map> _eventsBox;
|
||||
late Box<Object?> _settingsBox;
|
||||
|
||||
Future<void> initialize() async {
|
||||
await Hive.initFlutter();
|
||||
|
||||
_tasksBox = await Hive.openBox<Map>(_tasksBoxName);
|
||||
_alarmsBox = await Hive.openBox<Map>(_alarmsBoxName);
|
||||
_mindMapsBox = await Hive.openBox<Map>(_mindMapsBoxName);
|
||||
_eventsBox = await Hive.openBox<Map>(_eventsBoxName);
|
||||
_settingsBox = await Hive.openBox<Object?>(_settingsBoxName);
|
||||
}
|
||||
|
||||
// Tasks
|
||||
Future<void> saveTask(TaskModel task) async {
|
||||
await _tasksBox.put(task.id, task.toFirestore());
|
||||
}
|
||||
|
||||
Future<void> saveTasks(List<TaskModel> tasks) async {
|
||||
for (final task in tasks) {
|
||||
await _tasksBox.put(task.id, task.toFirestore());
|
||||
}
|
||||
}
|
||||
|
||||
List<TaskModel> getTasks() {
|
||||
return _tasksBox.values.map((data) {
|
||||
return TaskModel.fromFirestore(
|
||||
_createMockDocument(data as Map<String, dynamic>),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Future<void> deleteTask(String taskId) async {
|
||||
await _tasksBox.delete(taskId);
|
||||
}
|
||||
|
||||
// Alarms
|
||||
Future<void> saveAlarm(AlarmModel alarm) async {
|
||||
await _alarmsBox.put(alarm.id, alarm.toFirestore());
|
||||
}
|
||||
|
||||
List<AlarmModel> getAlarms() {
|
||||
return _alarmsBox.values.map((data) {
|
||||
return AlarmModel.fromFirestore(
|
||||
_createMockDocument(data as Map<String, dynamic>),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Future<void> deleteAlarm(String alarmId) async {
|
||||
await _alarmsBox.delete(alarmId);
|
||||
}
|
||||
|
||||
// Mind Maps
|
||||
Future<void> saveMindMapNodes(List<MindMapNode> nodes) async {
|
||||
for (final node in nodes) {
|
||||
await _mindMapsBox.put(node.id, node.toFirestore());
|
||||
}
|
||||
}
|
||||
|
||||
List<MindMapNode> getMindMapNodes() {
|
||||
return _mindMapsBox.values.map((data) {
|
||||
return MindMapNode.fromFirestore(
|
||||
_createMockDocument(data as Map<String, dynamic>),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Events
|
||||
Future<void> saveEvent(CalendarEventModel event) async {
|
||||
await _eventsBox.put(event.id, event.toFirestore());
|
||||
}
|
||||
|
||||
List<CalendarEventModel> getEvents() {
|
||||
return _eventsBox.values.map((data) {
|
||||
return CalendarEventModel.fromFirestore(
|
||||
_createMockDocument(data as Map<String, dynamic>),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Settings
|
||||
Future<void> saveSetting(String key, Object? value) async {
|
||||
await _settingsBox.put(key, value);
|
||||
}
|
||||
|
||||
T? getSetting<T>(String key, {T? defaultValue}) {
|
||||
return _settingsBox.get(key, defaultValue: defaultValue) as T?;
|
||||
}
|
||||
|
||||
// Clear all local data
|
||||
Future<void> clearAll() async {
|
||||
await _tasksBox.clear();
|
||||
await _alarmsBox.clear();
|
||||
await _mindMapsBox.clear();
|
||||
await _eventsBox.clear();
|
||||
await _settingsBox.clear();
|
||||
}
|
||||
|
||||
// Sync with Firebase (merge remote and local)
|
||||
Future<void> syncWithRemote(List<TaskModel> remoteTasks) async {
|
||||
final localTasks = getTasks();
|
||||
final localMap = {for (var t in localTasks) t.id: t};
|
||||
final remoteMap = {for (var t in remoteTasks) t.id: t};
|
||||
|
||||
// Merge: remote takes precedence
|
||||
final merged = {...localMap, ...remoteMap};
|
||||
|
||||
await _tasksBox.clear();
|
||||
for (final task in merged.values) {
|
||||
await _tasksBox.put(task.id, task.toFirestore());
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to create mock DocumentSnapshot
|
||||
dynamic _createMockDocument(Map<String, dynamic> data) {
|
||||
// Простая эмуляция для конвертации
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
final localStorageService = LocalStorageService();
|
||||
@@ -0,0 +1,47 @@
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../screens/auth_screen.dart';
|
||||
import '../screens/home_screen.dart';
|
||||
import '../screens/tasks_screen.dart';
|
||||
import '../screens/mind_map_screen.dart';
|
||||
import '../screens/calendar_screen.dart';
|
||||
import '../screens/alarms_screen.dart';
|
||||
|
||||
class AppRouter {
|
||||
static final GoRouter router = GoRouter(
|
||||
initialLocation: '/auth',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/auth',
|
||||
name: 'auth',
|
||||
builder: (context, state) => const AuthScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/home',
|
||||
name: 'home',
|
||||
builder: (context, state) => const HomeScreen(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'tasks',
|
||||
name: 'tasks',
|
||||
builder: (context, state) => const TasksScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'mindmap',
|
||||
name: 'mindmap',
|
||||
builder: (context, state) => const MindMapScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'calendar',
|
||||
name: 'calendar',
|
||||
builder: (context, state) => const CalendarScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: 'alarms',
|
||||
name: 'alarms',
|
||||
builder: (context, state) => const AlarmsScreen(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppTheme {
|
||||
static ThemeData get lightTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
floatingActionButtonTheme: const FloatingActionButtonThemeData(
|
||||
elevation: 4,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static ThemeData get darkTheme {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
),
|
||||
cardTheme: CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
floatingActionButtonTheme: const FloatingActionButtonThemeData(
|
||||
elevation: 4,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user