fix: 修复日历事件详情页布局问题并添加底部输入框
- 修复 Row 中 Flexible 在无界宽度约束下的布局崩溃问题 - 用 Expanded 包裹内层 Row 提供有界宽度约束 - 添加底部输入框组件(+按钮、输入框、麦克风图标) - 实现事件详情页动态数据展示 - 添加编辑和删除事件功能 - 添加事件不存在时的错误页面
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ScheduleSourceType { manual, imported, agentGenerated }
|
||||
|
||||
enum ScheduleStatus { active, completed, canceled, archived }
|
||||
|
||||
class ScheduleItemModel {
|
||||
final String id;
|
||||
final String title;
|
||||
final String? description;
|
||||
final DateTime startAt;
|
||||
final DateTime? endAt;
|
||||
final String timezone;
|
||||
final ScheduleMetadata? metadata;
|
||||
final ScheduleSourceType sourceType;
|
||||
final ScheduleStatus status;
|
||||
final DateTime createdAt;
|
||||
|
||||
ScheduleItemModel({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.description,
|
||||
required this.startAt,
|
||||
this.endAt,
|
||||
this.timezone = 'Asia/Shanghai',
|
||||
this.metadata,
|
||||
this.sourceType = ScheduleSourceType.manual,
|
||||
this.status = ScheduleStatus.active,
|
||||
DateTime? createdAt,
|
||||
}) : createdAt = createdAt ?? DateTime.now();
|
||||
|
||||
ScheduleItemModel copyWith({
|
||||
String? id,
|
||||
String? title,
|
||||
String? description,
|
||||
DateTime? startAt,
|
||||
DateTime? endAt,
|
||||
String? timezone,
|
||||
ScheduleMetadata? metadata,
|
||||
ScheduleSourceType? sourceType,
|
||||
ScheduleStatus? status,
|
||||
DateTime? createdAt,
|
||||
}) {
|
||||
return ScheduleItemModel(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
description: description ?? this.description,
|
||||
startAt: startAt ?? this.startAt,
|
||||
endAt: endAt ?? this.endAt,
|
||||
timezone: timezone ?? this.timezone,
|
||||
metadata: metadata ?? this.metadata,
|
||||
sourceType: sourceType ?? this.sourceType,
|
||||
status: status ?? this.status,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduleMetadata {
|
||||
final String? color;
|
||||
final String? location;
|
||||
final String? notes;
|
||||
final List<Attachment>? attachments;
|
||||
|
||||
ScheduleMetadata({this.color, this.location, this.notes, this.attachments});
|
||||
|
||||
ScheduleMetadata copyWith({
|
||||
String? color,
|
||||
String? location,
|
||||
String? notes,
|
||||
List<Attachment>? attachments,
|
||||
}) {
|
||||
return ScheduleMetadata(
|
||||
color: color ?? this.color,
|
||||
location: location ?? this.location,
|
||||
notes: notes ?? this.notes,
|
||||
attachments: attachments ?? this.attachments,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Attachment {
|
||||
final String name;
|
||||
final String? url;
|
||||
final String? content;
|
||||
final String type;
|
||||
|
||||
Attachment({
|
||||
required this.name,
|
||||
this.url,
|
||||
this.content,
|
||||
this.type = 'document',
|
||||
});
|
||||
}
|
||||
|
||||
const defaultColors = [
|
||||
Color(0xFF3B82F6),
|
||||
Color(0xFF8B5CF6),
|
||||
Color(0xFF10B981),
|
||||
Color(0xFFF59E0B),
|
||||
Color(0xFFEF4444),
|
||||
];
|
||||
@@ -0,0 +1,109 @@
|
||||
import 'package:social_app/core/config/env.dart';
|
||||
import '../models/schedule_item_model.dart';
|
||||
|
||||
class MockCalendarService {
|
||||
static final MockCalendarService _instance = MockCalendarService._internal();
|
||||
factory MockCalendarService() => _instance;
|
||||
|
||||
final List<ScheduleItemModel> _events = [];
|
||||
|
||||
MockCalendarService._internal();
|
||||
|
||||
List<ScheduleItemModel> get events => List.unmodifiable(_events);
|
||||
|
||||
List<ScheduleItemModel> getEventsForDay(DateTime date) {
|
||||
final dateOnly = DateTime(date.year, date.month, date.day);
|
||||
return _events.where((event) {
|
||||
final eventDate = DateTime(
|
||||
event.startAt.year,
|
||||
event.startAt.month,
|
||||
event.startAt.day,
|
||||
);
|
||||
return eventDate == dateOnly && event.status == ScheduleStatus.active;
|
||||
}).toList()..sort((a, b) => a.startAt.compareTo(b.startAt));
|
||||
}
|
||||
|
||||
List<ScheduleItemModel> getEventsForRange(DateTime start, DateTime end) {
|
||||
return _events.where((event) {
|
||||
return event.startAt.isAfter(start.subtract(const Duration(days: 1))) &&
|
||||
event.startAt.isBefore(end.add(const Duration(days: 1))) &&
|
||||
event.status == ScheduleStatus.active;
|
||||
}).toList()..sort((a, b) => a.startAt.compareTo(b.startAt));
|
||||
}
|
||||
|
||||
ScheduleItemModel? getEventById(String id) {
|
||||
try {
|
||||
return _events.firstWhere((e) => e.id == id);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void addEvent(ScheduleItemModel event) {
|
||||
_events.add(event);
|
||||
}
|
||||
|
||||
void updateEvent(ScheduleItemModel event) {
|
||||
final index = _events.indexWhere((e) => e.id == event.id);
|
||||
if (index >= 0) {
|
||||
_events[index] = event;
|
||||
}
|
||||
}
|
||||
|
||||
void deleteEvent(String id) {
|
||||
_events.removeWhere((e) => e.id == id);
|
||||
}
|
||||
}
|
||||
|
||||
class CalendarService {
|
||||
static final CalendarService _instance = CalendarService._internal();
|
||||
factory CalendarService() => _instance;
|
||||
CalendarService._internal();
|
||||
|
||||
MockCalendarService get _mock => MockCalendarService();
|
||||
|
||||
List<ScheduleItemModel> getEventsForDay(DateTime date) {
|
||||
if (Env.isMockApi) {
|
||||
return _mock.getEventsForDay(date);
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
|
||||
List<ScheduleItemModel> getEventsForRange(DateTime start, DateTime end) {
|
||||
if (Env.isMockApi) {
|
||||
return _mock.getEventsForRange(start, end);
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
|
||||
ScheduleItemModel? getEventById(String id) {
|
||||
if (Env.isMockApi) {
|
||||
return _mock.getEventById(id);
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
|
||||
void addEvent(ScheduleItemModel event) {
|
||||
if (Env.isMockApi) {
|
||||
_mock.addEvent(event);
|
||||
return;
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
|
||||
void updateEvent(ScheduleItemModel event) {
|
||||
if (Env.isMockApi) {
|
||||
_mock.updateEvent(event);
|
||||
return;
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
|
||||
void deleteEvent(String id) {
|
||||
if (Env.isMockApi) {
|
||||
_mock.deleteEvent(id);
|
||||
return;
|
||||
}
|
||||
throw UnimplementedError('Real API not implemented');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user