feat:增加TDesign组件库
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
class AppConfig {
|
||||
static const int initWeight = 73;
|
||||
static const int goalWeight = 72;
|
||||
static const int goalTotalSpot = 400;
|
||||
static const double initWeight = 73;
|
||||
static const double minWeight = 70;
|
||||
static const double maxWeight = 75;
|
||||
static const double goalWeight = 72;
|
||||
|
||||
static const double initSpot = 30;
|
||||
static const double minSpot = 10;
|
||||
static const double maxSpot = 120;
|
||||
static const double goalTotalSpot = 400;
|
||||
|
||||
static const int goalAvgSleep = 8;
|
||||
|
||||
static const List<String> sportProjectList = ['羽毛球', '乒乓球', '跑步'];
|
||||
|
||||
@@ -48,9 +48,9 @@ class HealthRecord extends HiveObject {
|
||||
|
||||
HealthRecord copyWith({
|
||||
int? id,
|
||||
num? weight,
|
||||
double? weight,
|
||||
String? sportProject,
|
||||
num? sportDuration,
|
||||
double? sportDuration,
|
||||
String? sleepStartTime,
|
||||
String? sleepEndTime,
|
||||
String? date,
|
||||
|
||||
@@ -8,8 +8,8 @@ class HealthProvider with ChangeNotifier {
|
||||
RecordType type = RecordType.weight;
|
||||
bool isEditing = false;
|
||||
|
||||
num latestWeight = 0;
|
||||
num totalSpot = 0;
|
||||
double latestWeight = 0;
|
||||
double totalSpot = 0;
|
||||
num avgSleep = 0;
|
||||
|
||||
void initForm(HealthRecord record) {
|
||||
@@ -52,12 +52,12 @@ class HealthProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void updateLatestWeight(num weight) {
|
||||
void updateLatestWeight(double weight) {
|
||||
latestWeight = weight;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void updateTotalSpot(num duration) {
|
||||
void updateTotalSpot(double duration) {
|
||||
totalSpot = duration;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ class HealthService {
|
||||
}
|
||||
|
||||
// 获取总运动时长
|
||||
num getTotalSport() {
|
||||
double getTotalSport() {
|
||||
int year = DateTime.now().year;
|
||||
int month = DateTime.now().month;
|
||||
num totalDuration = 0;
|
||||
double totalDuration = 0;
|
||||
|
||||
for (final record in getAllRecords()) {
|
||||
if (record.sportDuration != 0) {
|
||||
@@ -88,12 +88,12 @@ class HealthService {
|
||||
}
|
||||
|
||||
// 获取最新体重
|
||||
num getLatestWeight() {
|
||||
double getLatestWeight() {
|
||||
final records = getAllRecordsOrderByDate();
|
||||
|
||||
for (final record in records) {
|
||||
if (record.weight != 0) {
|
||||
return record.weight;
|
||||
return record.weight.toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ String formatContent(HealthRecord record, RecordType type) {
|
||||
late String title;
|
||||
switch (type) {
|
||||
case RecordType.weight:
|
||||
title = "${record.weight} ${type.unit}";
|
||||
title = "${record.weight.toStringAsFixed(1)} ${type.unit}";
|
||||
case RecordType.sport:
|
||||
title = "${record.sportProject} · ${record.sportDuration} ${type.unit}";
|
||||
case RecordType.sleep:
|
||||
@@ -131,3 +131,10 @@ String formatContent(HealthRecord record, RecordType type) {
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
String getTimeFromSelectDate(Map<String, int> selected) {
|
||||
final String hour = selected['hour'].toString().padLeft(2, '0');
|
||||
final String minute = selected['minute'].toString().padLeft(2, '0');
|
||||
|
||||
return '${hour}:${minute}';
|
||||
}
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
TextStyle _titleStyle() {
|
||||
return TextStyle(fontSize: 16, fontWeight: FontWeight.w600);
|
||||
}
|
||||
|
||||
TextStyle _contentStyle() {
|
||||
return TextStyle(fontSize: 16, fontWeight: FontWeight.w500);
|
||||
}
|
||||
|
||||
OutlineInputBorder _border(ColorScheme colors) {
|
||||
return OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colors.onSurface.withAlpha(100), width: 1.5),
|
||||
);
|
||||
}
|
||||
|
||||
OutlineInputBorder _enabledBorder(ColorScheme colors) {
|
||||
return OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colors.onSurface.withAlpha(100), width: 1.5),
|
||||
);
|
||||
}
|
||||
|
||||
OutlineInputBorder _focusedBorder(ColorScheme colors) {
|
||||
return OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colors.primary, width: 2),
|
||||
);
|
||||
}
|
||||
|
||||
EdgeInsetsGeometry _containerPadding() {
|
||||
return EdgeInsets.symmetric(horizontal: 16, vertical: 10);
|
||||
}
|
||||
|
||||
Widget buildFormTime({
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
required String title,
|
||||
required DateTime? initialValue,
|
||||
required ValueChanged<DateTime?> onChanged,
|
||||
double width = 100,
|
||||
String hintText = '请选择时间',
|
||||
}) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final alphaColor = colors.onSurface.withAlpha(100);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Container(width: width, child: Text(title, style: _titleStyle())),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FormBuilderDateTimePicker(
|
||||
name: name,
|
||||
inputType: InputType.time,
|
||||
initialTime: TimeOfDay.now(),
|
||||
initialValue: initialValue,
|
||||
format: DateFormat.Hm(),
|
||||
onChanged: (value) => onChanged(value),
|
||||
style: _contentStyle(),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(color: alphaColor),
|
||||
prefixIcon: Icon(Icons.schedule_rounded, size: 24),
|
||||
border: _border(colors),
|
||||
enabledBorder: _enabledBorder(colors),
|
||||
focusedBorder: _focusedBorder(colors),
|
||||
filled: true,
|
||||
fillColor: colors.surfaceContainer,
|
||||
contentPadding: _containerPadding(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildFormSlider({
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
required String title,
|
||||
required String label,
|
||||
required double min,
|
||||
required double max,
|
||||
required double initialValue,
|
||||
required int divisions,
|
||||
required ValueChanged<double?> onChanged,
|
||||
double width = 100,
|
||||
}) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final alphaColor = colors.onSurface.withAlpha(100);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Container(width: width, child: Text(title, style: _titleStyle())),
|
||||
const SizedBox(width: 8),
|
||||
|
||||
Expanded(
|
||||
child: FormBuilderSlider(
|
||||
name: name,
|
||||
min: min,
|
||||
max: max,
|
||||
initialValue: initialValue,
|
||||
divisions: divisions,
|
||||
onChanged: (value) => onChanged(value),
|
||||
label: label,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildFormRadioGroup({
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
required String title,
|
||||
required String initialValue,
|
||||
required List<String> items,
|
||||
required ValueChanged<String?> onChanged,
|
||||
double width = 100,
|
||||
}) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final alphaColor = colors.onSurface.withAlpha(100);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Container(width: width, child: Text(title, style: _titleStyle())),
|
||||
const SizedBox(width: 8),
|
||||
|
||||
Expanded(
|
||||
child: FormBuilderRadioGroup<String>(
|
||||
name: name,
|
||||
options:
|
||||
items
|
||||
.map(
|
||||
(item) =>
|
||||
FormBuilderFieldOption(value: item, child: Text(item)),
|
||||
)
|
||||
.toList(),
|
||||
initialValue: initialValue,
|
||||
activeColor: colors.primary,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
onChanged: (value) => onChanged(value),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:fitnote/utils/record_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:getwidget/getwidget.dart';
|
||||
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
||||
|
||||
Widget buildCardTitle({
|
||||
required BuildContext context,
|
||||
@@ -70,17 +69,14 @@ Widget buildProgressItem({
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GFProgressBar(
|
||||
animation: true,
|
||||
lineHeight: 20,
|
||||
percentage: progress,
|
||||
progressBarColor: color,
|
||||
child: Text(
|
||||
'${roundNum(progress * 100)}%',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
TDProgress(
|
||||
type: TDProgressType.linear,
|
||||
progressStatus: TDProgressStatus.primary,
|
||||
value: progress,
|
||||
color: color,
|
||||
strokeWidth: 20,
|
||||
progressLabelPosition: TDProgressLabelPosition.inside,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class _GoalProgressState extends State<GoalProgress> {
|
||||
const SizedBox(height: 28),
|
||||
buildProgressItem(
|
||||
title: '目标体重',
|
||||
current: provider.latestWeight.toString(),
|
||||
current: provider.latestWeight.toStringAsFixed(1),
|
||||
target: AppConfig.goalWeight.toString(),
|
||||
unit: RecordType.weight.unit,
|
||||
progress: calWeightProgress(
|
||||
|
||||
@@ -9,9 +9,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_common/flutter_common.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:provider/provider.dart';
|
||||
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
||||
|
||||
class RecordDaily extends StatefulWidget {
|
||||
const RecordDaily({super.key});
|
||||
@@ -172,7 +172,7 @@ class _RecordDailyState extends State<RecordDaily> {
|
||||
break;
|
||||
case RecordType.sport:
|
||||
provider.updateSportProject(AppConfig.sportProjectList[0]);
|
||||
provider.updateSportDuration(30);
|
||||
provider.updateSportDuration(AppConfig.initSpot);
|
||||
break;
|
||||
case RecordType.sleep:
|
||||
provider.updateSleepStartTime('');
|
||||
@@ -202,64 +202,44 @@ class _RecordDailyState extends State<RecordDaily> {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GFButton(
|
||||
onPressed: () {
|
||||
child: TDButton(
|
||||
text: '取消',
|
||||
theme: TDButtonTheme.light,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
_resetRecord();
|
||||
},
|
||||
color: Colors.grey,
|
||||
text: "取消",
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: GFButton(
|
||||
onPressed: () {
|
||||
child: TDButton(
|
||||
text: '删除',
|
||||
theme: TDButtonTheme.danger,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
_deleteRecord(type);
|
||||
},
|
||||
color: Colors.red,
|
||||
text: "删除",
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: GFButton(
|
||||
onPressed: () {
|
||||
child: TDButton(
|
||||
text: '确定',
|
||||
theme: TDButtonTheme.primary,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
_saveRecord();
|
||||
},
|
||||
color: colors.primary,
|
||||
text: "确定",
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _resetRecord() {
|
||||
final provider = context.read<HealthProvider>();
|
||||
if (!provider.isEditing) {
|
||||
switch (provider.type) {
|
||||
case RecordType.weight:
|
||||
provider.updateWeight(0);
|
||||
break;
|
||||
case RecordType.sport:
|
||||
provider.updateSportProject('跑步');
|
||||
provider.updateSportDuration(0);
|
||||
break;
|
||||
case RecordType.sleep:
|
||||
provider.updateSleepStartTime('');
|
||||
provider.updateSleepEndTime('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteRecord(RecordType type) async{
|
||||
void _deleteRecord(RecordType type) async {
|
||||
final provider = context.read<HealthProvider>();
|
||||
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case RecordType.weight:
|
||||
provider.updateWeight(0);
|
||||
break;
|
||||
@@ -351,7 +331,9 @@ class _RecordDailyState extends State<RecordDaily> {
|
||||
String startTime = record.sleepStartTime;
|
||||
String endTime = record.sleepEndTime;
|
||||
num difference = calSleepMinDuration(startTime, endTime) - lastValue;
|
||||
String formattedDiff = NumberFormat('+0.00;-0.00').format(difference / 60);
|
||||
String formattedDiff = NumberFormat(
|
||||
'+0.00;-0.00',
|
||||
).format(difference / 60);
|
||||
change = '较上次 $formattedDiff ${type.unit}';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import 'package:fitnote/models/health.dart';
|
||||
import 'package:fitnote/provider/health_provider.dart';
|
||||
import 'package:fitnote/service/health_service.dart';
|
||||
import 'package:fitnote/utils/record_utils.dart';
|
||||
import 'package:fitnote/widget/form.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
||||
|
||||
class RecordForm extends StatefulWidget {
|
||||
final RecordType type;
|
||||
@@ -63,6 +63,88 @@ class _RecordFormState extends State<RecordForm> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFormSleepContent(HealthProvider provider) {
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
|
||||
return TDCellGroup(
|
||||
theme: TDCellGroupTheme.cardTheme,
|
||||
cells: [
|
||||
TDCell(
|
||||
title: '入睡时间',
|
||||
note: startTime,
|
||||
arrow: true,
|
||||
leftIcon: Icons.access_alarm,
|
||||
onClick: (click) {
|
||||
TDPicker.showDatePicker(
|
||||
context,
|
||||
title: '选择时间',
|
||||
onConfirm: (selected) {
|
||||
provider.updateSleepStartTime(getTimeFromSelectDate(selected));
|
||||
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
calSleepDuration(startTime, endTime);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
useYear: false,
|
||||
useMonth: false,
|
||||
useDay: false,
|
||||
useHour: true,
|
||||
useMinute: true,
|
||||
useSecond: false,
|
||||
dateStart: [1999, 01, 01],
|
||||
dateEnd: [2099, 12, 31],
|
||||
initialDate: [
|
||||
DateTime.now().year,
|
||||
DateTime.now().month,
|
||||
DateTime.now().day,
|
||||
DateTime.now().hour,
|
||||
DateTime.now().minute,
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
TDCell(
|
||||
title: '起床时间',
|
||||
note: endTime,
|
||||
arrow: true,
|
||||
leftIcon: Icons.access_alarm,
|
||||
onClick: (click) {
|
||||
TDPicker.showDatePicker(
|
||||
context,
|
||||
title: '选择时间',
|
||||
onConfirm: (selected) {
|
||||
provider.updateSleepEndTime(getTimeFromSelectDate(selected));
|
||||
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
calSleepDuration(startTime, endTime);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
useYear: false,
|
||||
useMonth: false,
|
||||
useDay: false,
|
||||
useHour: true,
|
||||
useMinute: true,
|
||||
useSecond: false,
|
||||
dateStart: [1999, 01, 01],
|
||||
dateEnd: [2099, 12, 31],
|
||||
initialDate: [
|
||||
DateTime.now().year,
|
||||
DateTime.now().month,
|
||||
DateTime.now().day,
|
||||
DateTime.now().hour,
|
||||
DateTime.now().minute,
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFormContent() {
|
||||
final provider = context.watch<HealthProvider>();
|
||||
|
||||
@@ -73,16 +155,24 @@ class _RecordFormState extends State<RecordForm> {
|
||||
children: [
|
||||
_buildFormTitle('记录体重'),
|
||||
SizedBox(height: 20),
|
||||
buildFormSlider(
|
||||
context: context,
|
||||
name: 'slider',
|
||||
title: '体重(Kg)',
|
||||
label: provider.formItem.weight.toString(),
|
||||
min: 70,
|
||||
max: 75,
|
||||
initialValue: 72,
|
||||
divisions: 50,
|
||||
onChanged: (value) => provider.updateWeight(value!),
|
||||
TDSlider(
|
||||
boxDecoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
sliderThemeData: TDSliderThemeData.capsule(
|
||||
context: context,
|
||||
scaleFormatter: (double value) {
|
||||
return '${value.toStringAsFixed(1)} Kg';
|
||||
},
|
||||
showThumbValue: true,
|
||||
min: AppConfig.minWeight,
|
||||
max: AppConfig.maxWeight,
|
||||
),
|
||||
value: provider.formItem.weight.toDouble(),
|
||||
leftLabel: AppConfig.minWeight.toString(),
|
||||
rightLabel: AppConfig.maxWeight.toString(),
|
||||
onChanged: (value) => provider.updateWeight(value),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
],
|
||||
@@ -93,63 +183,62 @@ class _RecordFormState extends State<RecordForm> {
|
||||
children: [
|
||||
_buildFormTitle('记录运动'),
|
||||
SizedBox(height: 24),
|
||||
buildFormRadioGroup(
|
||||
context: context,
|
||||
title: '运动类型',
|
||||
name: 'sport',
|
||||
initialValue: provider.formItem.sportProject,
|
||||
items: AppConfig.sportProjectList,
|
||||
onChanged: (value) => provider.updateSportProject(value!),
|
||||
TDRadioGroup(
|
||||
selectId:
|
||||
AppConfig.sportProjectList
|
||||
.indexOf(provider.formItem.sportProject)
|
||||
.toString(),
|
||||
passThrough: true,
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.all(0),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return TDRadio(
|
||||
id: index.toString(),
|
||||
title: AppConfig.sportProjectList[index],
|
||||
);
|
||||
},
|
||||
itemCount: AppConfig.sportProjectList.length,
|
||||
),
|
||||
onRadioGroupChange:
|
||||
(value) => {
|
||||
provider.updateSportProject(
|
||||
AppConfig.sportProjectList[int.parse(value!)],
|
||||
),
|
||||
},
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
buildFormSlider(
|
||||
context: context,
|
||||
name: 'slider',
|
||||
title: '时长(分钟)',
|
||||
label: provider.formItem.sportDuration.toString(),
|
||||
min: 0,
|
||||
max: 120,
|
||||
initialValue: 30,
|
||||
divisions: 12,
|
||||
onChanged: (value) => provider.updateSportDuration(value!),
|
||||
TDSlider(
|
||||
boxDecoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
sliderThemeData: TDSliderThemeData.capsule(
|
||||
context: context,
|
||||
scaleFormatter: (double value) {
|
||||
return '${value.toStringAsFixed(0)} 分钟';
|
||||
},
|
||||
showThumbValue: true,
|
||||
divisions: 11,
|
||||
min: AppConfig.minSpot,
|
||||
max: AppConfig.maxSpot,
|
||||
),
|
||||
value: provider.formItem.sportDuration.toDouble(),
|
||||
leftLabel: AppConfig.minSpot.toString(),
|
||||
rightLabel: AppConfig.maxSpot.toString(),
|
||||
onChanged: (value) => provider.updateSportDuration(value),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
],
|
||||
);
|
||||
case RecordType.sleep:
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildFormTitle('记录睡眠'),
|
||||
SizedBox(height: 24),
|
||||
buildFormTime(
|
||||
context: context,
|
||||
name: 'startTime',
|
||||
title: '入睡时间',
|
||||
initialValue: timeOfDayToDateTime(parseTime(startTime)),
|
||||
onChanged: (time) {
|
||||
provider.updateSleepStartTime(formatTime(time!));
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
calSleepDuration(startTime, endTime);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
buildFormTime(
|
||||
context: context,
|
||||
name: 'endTime',
|
||||
title: '起床时间',
|
||||
initialValue: timeOfDayToDateTime(parseTime(endTime)),
|
||||
onChanged: (time) {
|
||||
provider.updateSleepEndTime(formatTime(time!));
|
||||
final startTime = provider.formItem.sleepStartTime;
|
||||
final endTime = provider.formItem.sleepEndTime;
|
||||
calSleepDuration(startTime, endTime);
|
||||
},
|
||||
),
|
||||
_buildFormSleepContent(provider),
|
||||
SizedBox(height: 10),
|
||||
_buildSleepDuration(provider.formItem),
|
||||
SizedBox(height: 10),
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import 'package:fitnote/provider/health_provider.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 Welcome extends StatefulWidget {
|
||||
const Welcome({super.key});
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <rive_native/rive_native_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) rive_native_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin");
|
||||
rive_native_plugin_register_with_registrar(rive_native_registrar);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
rive_native
|
||||
)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import file_picker
|
||||
import file_selector_macos
|
||||
import flutter_image_compress_macos
|
||||
import path_provider_foundation
|
||||
import rive_native
|
||||
@@ -13,6 +14,7 @@ import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin"))
|
||||
|
||||
172
pubspec.lock
172
pubspec.lock
@@ -191,7 +191,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cupertino_icons
|
||||
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||
@@ -230,6 +230,14 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
easy_refresh:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: easy_refresh
|
||||
sha256: "486e30abfcaae66c0f2c2798a10de2298eb9dc5e0bb7e1dba9328308968cae0c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -262,6 +270,38 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "10.3.7"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_linux
|
||||
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.9.3+2"
|
||||
file_selector_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_macos
|
||||
sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.9.4+4"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
file_selector_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_windows
|
||||
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.9.3+4"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -359,6 +399,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.0.31"
|
||||
flutter_slidable:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_slidable
|
||||
sha256: a857de7ea701f276fd6a6c4c67ae885b60729a3449e42766bb0e655171042801
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
flutter_swiper_null_safety:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_swiper_null_safety
|
||||
sha256: "5a855e0080d035c08e82f8b7fd2f106344943a30c9ab483b2584860a2f22eaaf"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -401,14 +457,6 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
getwidget:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: getwidget
|
||||
sha256: ab0201d6c1d27b508f05fa571e0e5038d60a603fd80303002b882f18b1c77231
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -473,14 +521,70 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
infinite_listview:
|
||||
dependency: transitive
|
||||
image_picker:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: infinite_listview
|
||||
sha256: f6062c1720eb59be553dfa6b89813d3e8dd2f054538445aaa5edaddfa5195ce6
|
||||
name: image_picker
|
||||
sha256: "1f498d086203360cca099d20ffea2963f48c39ce91bdd8a3b6d4a045786b02c8"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.0.8"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.8.12+23"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.8.13"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.11.1"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -617,14 +721,6 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
numberpicker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: numberpicker
|
||||
sha256: "4c129154944b0f6b133e693f8749c3f8bfb67c4d07ef9dcab48b595c22d1f156"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -641,6 +737,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_drawing
|
||||
sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -926,6 +1038,22 @@ packages:
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
tdesign_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: tdesign_flutter
|
||||
sha256: cf166a5fdbbfd9129305d2c2906633c8d0151bbb2d0a6fbcf901bdd76726a555
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.2.6"
|
||||
tdesign_flutter_adaptation:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: tdesign_flutter_adaptation
|
||||
sha256: "8c5ba936abd2651472495b19dd23c525f04fb2eac6ba23de55a8b63a7c226deb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.16.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1 +1 @@
|
||||
name: fitnote
|
||||
name: fitnote
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <rive_native/rive_native_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
RiveNativePluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("RiveNativePlugin"));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
rive_native
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user