feat:增加数据存储
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import 'package:fitnote/modesl/menu.dart';
|
import 'package:fitnote/models/menu.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AppNavbar extends StatefulWidget {
|
class AppNavbar extends StatefulWidget {
|
||||||
|
|||||||
@@ -1,12 +1,31 @@
|
|||||||
|
import 'package:fitnote/models/health.dart';
|
||||||
import 'package:fitnote/pages/home_page.dart';
|
import 'package:fitnote/pages/home_page.dart';
|
||||||
|
import 'package:fitnote/provider/health_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async{
|
||||||
runApp(const HealthLogApp());
|
// 初始化Hive
|
||||||
|
await Hive.initFlutter();
|
||||||
|
|
||||||
|
// 注册适配器
|
||||||
|
Hive.registerAdapter(HealthRecordAdapter());
|
||||||
|
|
||||||
|
final healthsBox = await Hive.openBox<HealthRecord>('healths');
|
||||||
|
|
||||||
|
runApp(
|
||||||
|
MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider(create: (_) => HealthProvider())
|
||||||
|
],
|
||||||
|
child: MyApp(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class HealthLogApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const HealthLogApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
82
lib/models/health.dart
Normal file
82
lib/models/health.dart
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
// flutter packages pub run build_runner build
|
||||||
|
part 'health.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: 0)
|
||||||
|
class HealthRecord extends HiveObject {
|
||||||
|
@HiveField(0)
|
||||||
|
int id;
|
||||||
|
|
||||||
|
@HiveField(1)
|
||||||
|
String sportProject;
|
||||||
|
|
||||||
|
@HiveField(2)
|
||||||
|
num sportDuration;
|
||||||
|
|
||||||
|
@HiveField(3)
|
||||||
|
num weight;
|
||||||
|
|
||||||
|
@HiveField(4)
|
||||||
|
String sleepStartTime;
|
||||||
|
|
||||||
|
@HiveField(5)
|
||||||
|
String sleepEndTime;
|
||||||
|
|
||||||
|
@HiveField(6)
|
||||||
|
num sleepDuration;
|
||||||
|
|
||||||
|
@HiveField(7)
|
||||||
|
String date;
|
||||||
|
|
||||||
|
HealthRecord({
|
||||||
|
required this.id,
|
||||||
|
required this.sportProject,
|
||||||
|
required this.sportDuration,
|
||||||
|
required this.weight,
|
||||||
|
required this.sleepStartTime,
|
||||||
|
required this.sleepEndTime,
|
||||||
|
required this.sleepDuration,
|
||||||
|
required this.date,
|
||||||
|
});
|
||||||
|
|
||||||
|
static HealthRecord getEmpty() {
|
||||||
|
return HealthRecord(
|
||||||
|
id: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
sportProject: '',
|
||||||
|
sportDuration: 0,
|
||||||
|
weight: 0,
|
||||||
|
sleepStartTime: '',
|
||||||
|
sleepEndTime: '',
|
||||||
|
sleepDuration: 0,
|
||||||
|
date: '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HealthRecord getDefault() {
|
||||||
|
return HealthRecord(
|
||||||
|
id: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
sportProject: '跑步',
|
||||||
|
sportDuration: 30,
|
||||||
|
weight: 70,
|
||||||
|
sleepStartTime: '',
|
||||||
|
sleepEndTime: '',
|
||||||
|
sleepDuration: 0,
|
||||||
|
date: '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RecordType {
|
||||||
|
weight('体重', FontAwesomeIcons.weightScale, Color(0xFFF59E0B)),
|
||||||
|
sport('运动', FontAwesomeIcons.personRunning, Color(0xFF38BDF8)),
|
||||||
|
sleep('睡眠', FontAwesomeIcons.moon, Color(0xFF10B981));
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final IconData icon;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const RecordType(this.title, this.icon, this.color);
|
||||||
|
}
|
||||||
62
lib/models/health.g.dart
Normal file
62
lib/models/health.g.dart
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'health.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class HealthRecordAdapter extends TypeAdapter<HealthRecord> {
|
||||||
|
@override
|
||||||
|
final int typeId = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
HealthRecord read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return HealthRecord(
|
||||||
|
id: fields[0] as int,
|
||||||
|
sportProject: fields[1] as String,
|
||||||
|
sportDuration: fields[2] as num,
|
||||||
|
weight: fields[3] as num,
|
||||||
|
sleepStartTime: fields[4] as String,
|
||||||
|
sleepEndTime: fields[5] as String,
|
||||||
|
sleepDuration: fields[6] as num,
|
||||||
|
date: fields[7] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, HealthRecord obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(8)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.id)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.sportProject)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.sportDuration)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.weight)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.sleepStartTime)
|
||||||
|
..writeByte(5)
|
||||||
|
..write(obj.sleepEndTime)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.sleepDuration)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is HealthRecordAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class HealthRecord {
|
|
||||||
@JsonKey(name: 'id')
|
|
||||||
int? id;
|
|
||||||
|
|
||||||
@JsonKey(name: 'sportProject')
|
|
||||||
String? sportProject;
|
|
||||||
|
|
||||||
@JsonKey(name: 'sportDuration')
|
|
||||||
num? sportDuration;
|
|
||||||
|
|
||||||
@JsonKey(name: 'weight')
|
|
||||||
num? weight;
|
|
||||||
|
|
||||||
@JsonKey(name: 'sleepStartTime')
|
|
||||||
String? sleepStartTime;
|
|
||||||
|
|
||||||
@JsonKey(name: 'sleepEndTime')
|
|
||||||
String? sleepEndTime;
|
|
||||||
|
|
||||||
@JsonKey(name: 'sleepDuration')
|
|
||||||
num? sleepDuration;
|
|
||||||
|
|
||||||
@JsonKey(name: 'date')
|
|
||||||
String date;
|
|
||||||
|
|
||||||
HealthRecord({
|
|
||||||
this.id,
|
|
||||||
this.sportProject,
|
|
||||||
this.sportDuration,
|
|
||||||
this.weight,
|
|
||||||
this.sleepStartTime,
|
|
||||||
this.sleepEndTime,
|
|
||||||
this.sleepDuration,
|
|
||||||
required this.date,
|
|
||||||
});
|
|
||||||
|
|
||||||
// factory Health.fromJson(Map<String, dynamic> json) => _$HealthFromJson(json);
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> toJson() => _$HealthToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum RecordType {
|
|
||||||
weight('体重', FontAwesomeIcons.weightScale, Color(0xFFF59E0B)),
|
|
||||||
sport('运动', FontAwesomeIcons.personRunning, Color(0xFF38BDF8)),
|
|
||||||
sleep('睡眠', FontAwesomeIcons.moon, Color(0xFF10B981));
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
final IconData icon;
|
|
||||||
final Color color;
|
|
||||||
|
|
||||||
const RecordType(this.title, this.icon, this.color);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:fitnote/layout/app_navbar.dart';
|
import 'package:fitnote/layout/app_navbar.dart';
|
||||||
import 'package:fitnote/modesl/menu.dart';
|
import 'package:fitnote/models/menu.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:fitnote/widget/record/goal_progress.dart';
|
import 'package:fitnote/widget/record/goal_progress.dart';
|
||||||
import 'package:fitnote/widget/record/today_record.dart';
|
import 'package:fitnote/widget/record/record_daily.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@@ -25,11 +25,12 @@ class _RecordPageState extends State<RecordPage> {
|
|||||||
return weekdays[weekday - 1];
|
return weekdays[weekday - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [GoalProgress(), const SizedBox(height: 24), TodayRecord()],
|
children: [GoalProgress(), const SizedBox(height: 24), RecordDaily()],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
43
lib/provider/health_provider.dart
Normal file
43
lib/provider/health_provider.dart
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import 'package:fitnote/models/health.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HealthProvider with ChangeNotifier {
|
||||||
|
late HealthRecord _formItem;
|
||||||
|
|
||||||
|
HealthRecord get formItem => _formItem;
|
||||||
|
|
||||||
|
void resetForm() {
|
||||||
|
_formItem = HealthRecord.getEmpty();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initForm(HealthRecord record) {
|
||||||
|
_formItem = record;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateWeight(num weight) {
|
||||||
|
_formItem.weight = weight;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSportProject(String sportProject) {
|
||||||
|
_formItem.sportProject = sportProject;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSportDuration(num sportDuration) {
|
||||||
|
_formItem.sportDuration = sportDuration;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSleepStartTime(String sleepStartTime) {
|
||||||
|
_formItem.sleepStartTime = sleepStartTime;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSleepEndTime(String sleepEndTime) {
|
||||||
|
_formItem.sleepEndTime = sleepEndTime;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
46
lib/service/health_service.dart
Normal file
46
lib/service/health_service.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:fitnote/models/health.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
|
||||||
|
class HealthService {
|
||||||
|
static const String boxName = 'healths';
|
||||||
|
|
||||||
|
Box<HealthRecord> get box => Hive.box<HealthRecord>(boxName);
|
||||||
|
|
||||||
|
Future<bool> addRecord(HealthRecord record) async {
|
||||||
|
try {
|
||||||
|
await box.add(record);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<HealthRecord> getAllRecords() {
|
||||||
|
return box.values.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
HealthRecord getAllRecordByDate(String date) {
|
||||||
|
return box.values.toList().firstWhere(
|
||||||
|
(item) => item.date == date,
|
||||||
|
orElse: () => HealthRecord.getEmpty(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> updateRecord(HealthRecord record) async {
|
||||||
|
try {
|
||||||
|
await record.save();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> deleteRecord(HealthRecord record) async {
|
||||||
|
try {
|
||||||
|
await record.delete();
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:fitnote/modesl/health.dart';
|
import 'package:fitnote/models/health.dart';
|
||||||
import 'package:fitnote/widget/record/common.dart';
|
import 'package:fitnote/widget/record/common.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_common/widget/common_widget.dart';
|
import 'package:flutter_common/widget/common_widget.dart';
|
||||||
|
|||||||
211
lib/widget/record/record_daily.dart
Normal file
211
lib/widget/record/record_daily.dart
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
import 'package:fitnote/models/health.dart';
|
||||||
|
import 'package:fitnote/provider/health_provider.dart';
|
||||||
|
import 'package:fitnote/service/health_service.dart';
|
||||||
|
import 'package:fitnote/widget/record/common.dart';
|
||||||
|
import 'package:fitnote/widget/record/record_form.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_common/widget/common_widget.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class RecordDaily extends StatefulWidget {
|
||||||
|
const RecordDaily({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RecordDaily> createState() => _RecordDailyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RecordDailyState extends State<RecordDaily> {
|
||||||
|
final HealthService service = HealthService();
|
||||||
|
|
||||||
|
late HealthRecord _record;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_record = service.getAllRecordByDate('2025-12-01');
|
||||||
|
}
|
||||||
|
|
||||||
|
final recordForm = HealthRecord(
|
||||||
|
id: 1,
|
||||||
|
sportProject: '羽毛球',
|
||||||
|
sportDuration: 20,
|
||||||
|
sleepStartTime: '23:00',
|
||||||
|
sleepEndTime: '24:00',
|
||||||
|
sleepDuration: 60,
|
||||||
|
weight: 70,
|
||||||
|
date: '2025-11-28',
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CommonCard(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
buildCardTitle(
|
||||||
|
context: context,
|
||||||
|
title: '今日记录',
|
||||||
|
icon: FontAwesomeIcons.calendarCheck,
|
||||||
|
),
|
||||||
|
_buildTodayTag(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
ListView.separated(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: RecordType.values.length,
|
||||||
|
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final recordType = RecordType.values[index];
|
||||||
|
return _buildRecordListTile(recordType);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTodayTag() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF1F5F9),
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
DateFormat('MM月dd日').format(DateTime.now()),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Color(0xFF64748B),
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRecordListTile(RecordType type) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [type.color.withAlpha(10), Colors.white.withAlpha(200)],
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(10),
|
||||||
|
blurRadius: 12,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
leading: Container(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: type.color.withAlpha(30),
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
),
|
||||||
|
child: Icon(type.icon, color: type.color, size: 22),
|
||||||
|
),
|
||||||
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
type.title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: type.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
_buildRecordContent(type),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
trailing: GestureDetector(
|
||||||
|
onTap: () => onTapRecord(type),
|
||||||
|
child: Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: type.color.withAlpha(30),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
_checkHasRecordValue(type)
|
||||||
|
? FontAwesomeIcons.pencil
|
||||||
|
: FontAwesomeIcons.plus,
|
||||||
|
color: type.color,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _checkHasRecordValue(RecordType type) {
|
||||||
|
switch (type) {
|
||||||
|
case RecordType.weight:
|
||||||
|
return _record.weight != 0;
|
||||||
|
case RecordType.sport:
|
||||||
|
return _record.sportProject != '';
|
||||||
|
case RecordType.sleep:
|
||||||
|
return _record.sleepStartTime != '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTapRecord(RecordType type) {
|
||||||
|
final provider = context.read<HealthProvider>();
|
||||||
|
provider.initForm(HealthRecord.getDefault());
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => Dialog(child: RecordForm(type: type)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRecordContent(RecordType type) {
|
||||||
|
if (!_checkHasRecordValue(type)) {
|
||||||
|
return Text(
|
||||||
|
"尚未记录今日数据,点击添加",
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late String title;
|
||||||
|
switch (type) {
|
||||||
|
case RecordType.weight:
|
||||||
|
title = "${_record.weight} kg";
|
||||||
|
case RecordType.sport:
|
||||||
|
title = "${_record.sportProject} · ${_record.sportDuration}分钟";
|
||||||
|
case RecordType.sleep:
|
||||||
|
title =
|
||||||
|
"入睡 ${_record.sleepStartTime} · 起床 ${_record.sleepEndTime} · ${_record.sleepDuration}分钟";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.grey[800],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
156
lib/widget/record/record_form.dart
Normal file
156
lib/widget/record/record_form.dart
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import 'package:fitnote/models/health.dart';
|
||||||
|
import 'package:fitnote/provider/health_provider.dart';
|
||||||
|
import 'package:fitnote/service/health_service.dart';
|
||||||
|
import 'package:fitnote/widget/dropdown_select.dart';
|
||||||
|
import 'package:fitnote/widget/number_input.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:getwidget/getwidget.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class RecordForm extends StatefulWidget {
|
||||||
|
final RecordType type;
|
||||||
|
|
||||||
|
const RecordForm({super.key, required this.type});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RecordForm> createState() => _RecordFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RecordFormState extends State<RecordForm> {
|
||||||
|
final HealthService service = HealthService();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(padding: EdgeInsets.all(20), child: _buildFormContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFormButton() {
|
||||||
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: GFButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
color: colors.secondary,
|
||||||
|
text: "取消",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: GFButton(
|
||||||
|
onPressed: () {
|
||||||
|
_saveRecord();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
color: colors.primary,
|
||||||
|
text: "确定",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _saveRecord() {
|
||||||
|
final provider = context.read<HealthProvider>();
|
||||||
|
|
||||||
|
// service.updateRecord(provider.formItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFormTitle(String title) {
|
||||||
|
return Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFiledTitle(String title) {
|
||||||
|
return Text(title, style: TextStyle(fontSize: 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFormContent() {
|
||||||
|
final provider = context.watch<HealthProvider>();
|
||||||
|
|
||||||
|
switch (widget.type) {
|
||||||
|
case RecordType.weight:
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
_buildFormTitle('记录体重'),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildFiledTitle('体重:'),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
NumberInput(
|
||||||
|
value: provider.formItem.weight,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 0.1,
|
||||||
|
unit: 'Kg',
|
||||||
|
onChanged: (value) => provider.updateWeight(value!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
_buildFormButton(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
case RecordType.sport:
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
_buildFormTitle('记录运动'),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildFiledTitle('运动类型:'),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
DropdownSelect(
|
||||||
|
value: provider.formItem.sportProject,
|
||||||
|
items: ['羽毛球', '乒乓球', '篮球', '跑步'],
|
||||||
|
onChanged: (value) => provider.updateSportProject(value!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildFiledTitle('运动时长:'),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
NumberInput(
|
||||||
|
value: provider.formItem.sportDuration,
|
||||||
|
min: 5,
|
||||||
|
max: 240,
|
||||||
|
step: 5,
|
||||||
|
unit: '分钟',
|
||||||
|
onChanged: (value) => provider.updateSportDuration(value!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
_buildFormButton(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
case RecordType.sleep:
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
_buildFiledTitle('记录睡眠'),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
// 这里添加睡眠相关的输入控件
|
||||||
|
SizedBox(height: 20),
|
||||||
|
_buildFormButton(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
import 'package:fitnote/modesl/health.dart';
|
|
||||||
import 'package:fitnote/widget/dropdown_select.dart';
|
|
||||||
import 'package:fitnote/widget/number_input.dart';
|
|
||||||
import 'package:fitnote/widget/record/common.dart';
|
|
||||||
import 'package:fitnote/widget/select_input.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_common/widget/common_widget.dart';
|
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:getwidget/getwidget.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:numberpicker/numberpicker.dart';
|
|
||||||
|
|
||||||
class TodayRecord extends StatefulWidget {
|
|
||||||
const TodayRecord({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<TodayRecord> createState() => _TodayRecordState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TodayRecordState extends State<TodayRecord> {
|
|
||||||
final record = HealthRecord(
|
|
||||||
id: 1,
|
|
||||||
sportProject: '羽毛球',
|
|
||||||
sportDuration: 20,
|
|
||||||
sleepStartTime: '23:00',
|
|
||||||
sleepEndTime: '24:00',
|
|
||||||
sleepDuration: 60,
|
|
||||||
weight: 0,
|
|
||||||
date: '2025-11-28',
|
|
||||||
);
|
|
||||||
|
|
||||||
final recordForm = HealthRecord(
|
|
||||||
id: 1,
|
|
||||||
sportProject: '羽毛球',
|
|
||||||
sportDuration: 20,
|
|
||||||
sleepStartTime: '23:00',
|
|
||||||
sleepEndTime: '24:00',
|
|
||||||
sleepDuration: 60,
|
|
||||||
weight: 70,
|
|
||||||
date: '2025-11-28',
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CommonCard(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
buildCardTitle(
|
|
||||||
context: context,
|
|
||||||
title: '今日记录',
|
|
||||||
icon: FontAwesomeIcons.calendarCheck,
|
|
||||||
),
|
|
||||||
_buildTodayTag(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
ListView.separated(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: RecordType.values.length,
|
|
||||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final recordType = RecordType.values[index];
|
|
||||||
return _buildRecordListTile(recordType);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTodayTag() {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFFF1F5F9),
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
DateFormat('MM月dd日').format(DateTime.now()),
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Color(0xFF64748B),
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRecordListTile(RecordType type) {
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: [type.color.withAlpha(10), Colors.white.withAlpha(200)],
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withAlpha(10),
|
|
||||||
blurRadius: 12,
|
|
||||||
offset: const Offset(0, 4),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ListTile(
|
|
||||||
leading: Container(
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: type.color.withAlpha(30),
|
|
||||||
borderRadius: BorderRadius.circular(24),
|
|
||||||
),
|
|
||||||
child: Icon(type.icon, color: type.color, size: 22),
|
|
||||||
),
|
|
||||||
title: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
type.title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: type.color,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
_buildRecordContent(type),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
trailing: GestureDetector(
|
|
||||||
onTap: () => onTapRecord(type),
|
|
||||||
child: Container(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: type.color.withAlpha(30),
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
_checkHasRecordValue(type)
|
|
||||||
? FontAwesomeIcons.pencil
|
|
||||||
: FontAwesomeIcons.plus,
|
|
||||||
color: type.color,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
splashColor: Colors.transparent,
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _checkHasRecordValue(RecordType type) {
|
|
||||||
switch (type) {
|
|
||||||
case RecordType.weight:
|
|
||||||
return record.weight != null;
|
|
||||||
case RecordType.sport:
|
|
||||||
return record.sportProject != null;
|
|
||||||
case RecordType.sleep:
|
|
||||||
return record.sleepStartTime != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDialogButton(RecordType type) {
|
|
||||||
final colors = Theme.of(context).colorScheme;
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: GFButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
color: colors.secondary.withAlpha(100),
|
|
||||||
text: "取消",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: GFButton(onPressed: () {}, color: colors.primary, text: "确定"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// void _saveRecordData(RecordType type) {
|
|
||||||
// setState(() {
|
|
||||||
// switch (type) {
|
|
||||||
// case RecordType.weight:
|
|
||||||
// record.weight = _dialogWeight;
|
|
||||||
// break;
|
|
||||||
// case RecordType.sport:
|
|
||||||
// record.sportProject = _dialogSportProject;
|
|
||||||
// record.sportDuration = _dialogSportDuration.toInt();
|
|
||||||
// break;
|
|
||||||
// case RecordType.sleep:
|
|
||||||
// // 处理睡眠数据
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
Widget _buildDialogTitle(String title) {
|
|
||||||
return Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildFiledTitle(String title) {
|
|
||||||
return Text(title, style: TextStyle(fontSize: 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDialogContent(RecordType type) {
|
|
||||||
final colors = Theme.of(context).colorScheme;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case RecordType.weight:
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
_buildDialogTitle('记录体重'),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
_buildFiledTitle('体重:'),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
NumberInput(
|
|
||||||
value: recordForm.weight!,
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
step: 0.1,
|
|
||||||
unit: 'Kg',
|
|
||||||
onChanged:
|
|
||||||
(value) => setState(() => recordForm.weight = value!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
_buildDialogButton(type),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
case RecordType.sport:
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
_buildDialogTitle('记录运动'),
|
|
||||||
SizedBox(height: 24),
|
|
||||||
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
_buildFiledTitle('运动类型:'),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
DropdownSelect(
|
|
||||||
value: recordForm.sportProject!,
|
|
||||||
items: ['羽毛球', '乒乓球', '篮球', '跑步'],
|
|
||||||
onChanged: (newValue) {
|
|
||||||
setState(() {
|
|
||||||
recordForm.sportProject = newValue!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
// 运动时长
|
|
||||||
_buildFiledTitle('运动时长:'),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
NumberInput(
|
|
||||||
value: recordForm.sportDuration,
|
|
||||||
min: 5,
|
|
||||||
max: 240,
|
|
||||||
step: 5,
|
|
||||||
unit: '分钟',
|
|
||||||
onChanged:
|
|
||||||
(value) =>
|
|
||||||
setState(() => recordForm.sportDuration = value!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 24),
|
|
||||||
_buildDialogButton(type),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
case RecordType.sleep:
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
_buildFiledTitle('记录睡眠'),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
// 这里添加睡眠相关的输入控件
|
|
||||||
SizedBox(height: 20),
|
|
||||||
_buildDialogButton(type),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onTapRecord(RecordType type) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder:
|
|
||||||
(context) => Dialog(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(20),
|
|
||||||
child: _buildDialogContent(type),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRecordContent(RecordType type) {
|
|
||||||
if (!_checkHasRecordValue(type)) {
|
|
||||||
return Text(
|
|
||||||
"尚未记录今日数据,点击添加",
|
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
late String title;
|
|
||||||
switch (type) {
|
|
||||||
case RecordType.weight:
|
|
||||||
title = "${record.weight} kg";
|
|
||||||
case RecordType.sport:
|
|
||||||
title = "${record.sportProject} · ${record.sportDuration}分钟";
|
|
||||||
case RecordType.sleep:
|
|
||||||
title =
|
|
||||||
"入睡 ${record.sleepStartTime} · 起床 ${record.sleepEndTime} · ${record.sleepDuration}分钟";
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Colors.grey[800],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
69
pubspec.lock
69
pubspec.lock
@@ -5,18 +5,23 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
|
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "85.0.0"
|
version: "76.0.0"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.3"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d"
|
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.7.1"
|
version: "6.11.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -197,10 +202,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb"
|
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "2.3.8"
|
||||||
dbus:
|
dbus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -399,6 +404,30 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.2"
|
||||||
|
hive:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: hive
|
||||||
|
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
|
hive_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: hive_flutter
|
||||||
|
sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
hive_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: hive_generator
|
||||||
|
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -456,21 +485,13 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.7.2"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.9.0"
|
version: "4.9.0"
|
||||||
json_serializable:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: json_serializable
|
|
||||||
sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c
|
|
||||||
url: "https://pub.flutter-io.cn"
|
|
||||||
source: hosted
|
|
||||||
version: "6.9.5"
|
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -519,6 +540,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3-main.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -672,7 +701,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "1.5.2"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
|
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
|
||||||
@@ -792,18 +821,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "1.5.0"
|
||||||
source_helper:
|
source_helper:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_helper
|
name: source_helper
|
||||||
sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca
|
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.7"
|
version: "1.3.5"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
name: fitnote
|
name: fitnote
|
||||||
Reference in New Issue
Block a user