Flutter Stopwatch/Timer使用Firebase在不同屏幕上获得相同时间的最佳方式



我正在创建记分牌,我创建了一个秒表,但现在我遇到了一个问题,即我启动秒表的位置显示的时间必须在另一个屏幕/计算机上启动。因此,当我启动计时器时,它也应该为其他用户更新时间。

所以我的问题是,最好的方法是什么

我试着做了一些事情,但效果不太好。

time.dart -这里只有我看到发生了什么(你可以说是私人的(

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

final CollectionReference time=FirebaseFirestore.instance.collection('game'(;

class Time extends StatefulWidget {
@override
State<Time> createState() => TimeState();
}
class TimeState extends State<Time> {
Duration duration = Duration();
Timer? timer;
final myController = TextEditingController();

@override
void initState() {
super.initState();
reset();
}
void reset() {
setState(() => duration = Duration());
}
void addTime() {
const addSeconds = 1;
setState(() {
final seconds = duration.inSeconds + addSeconds;
duration = Duration(seconds: seconds);
});
}
void startTimer({bool resets = true}) {
if (resets) {
reset();
}
timer = Timer.periodic(Duration(seconds: 1), (_) => addTime());
}
void stopTimer({bool resets = true}) {
if (resets) {
reset();
}
setState(() {
timer?.cancel();
});
}
void firstHalfEnd() {
setState(() => duration = Duration(minutes: 45, seconds: 00));
stopTimer(resets: false);
}

void secondHalfEnd() {
setState(() => duration = Duration(minutes: 90, seconds: 00));
stopTimer(resets: false);
}
void addMinute (){
setState(() {
duration = duration + const Duration(minutes: 1);
});
}
void subtractMinute (){
setState(() {
duration = duration - const Duration(minutes: 1);
});
}
@override
Widget build(BuildContext context) => Scaffold(
backgroundColor:
Colors.green, 
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buiildTime(),
SizedBox(
height: 20,
), 
buildButtons()
],
)),
);
Widget buiildTime() {
String twoDigits(int n) => n.toString().padLeft(
2, '0'); // pretvara jednoznamenkaste brojeve u "dvoznamenkaste" 9 -> 09
final minutes = twoDigits(duration.inMinutes.remainder(100));
final seconds = twoDigits(duration.inSeconds.remainder(60));
setState(() {
time.doc('Time').collection('minutes').doc('minutes').set({'minutes': '$minutes'});
time.doc('Time').update({'seconds': '$seconds'});
});
return Text(
'$minutes:$seconds',
style: TextStyle(fontSize: 20),

);
}
Widget buildButtons() {
bool time_going = timer == null ? false : timer!.isActive;
bool time_stops = duration.inSeconds == 0;

return time_going || !time_stops
? Column(
mainAxisAlignment: MainAxisAlignment.center,

children: [
Row(
children: [
TextButton(
child:Text(time_going ? 'PAUSE' : 'RESUME'),


onPressed: () {
if (time_going) {
stopTimer(resets: false);
} else {
startTimer(resets: false);
}
}),
SizedBox(
width: 12,
),
TextButton( child: Text( "RESET"), onPressed:  reset,),
],
),
SizedBox(

height: 10,
),
Row(

crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: firstHalfEnd,
child: Text('1. Half END'),
style: ButtonStyle(backgroundColor: MaterialStateProperty.all<Color>(Colors.blue) , foregroundColor:MaterialStateProperty.all<Color> (Colors.white) ,),
),
SizedBox(width: 10,),
SizedBox(

child:TextButton(
onPressed: secondHalfEnd,
child: Text('2. Half END'),
style: ButtonStyle(backgroundColor: MaterialStateProperty.all<Color>(Colors.blue) , foregroundColor:MaterialStateProperty.all<Color> (Colors.white) ,),

)),
],
),
Row(
children: [

ElevatedButton(onPressed: addMinute, child: Text('+1 minute')),
SizedBox(width: 10,),
ElevatedButton(onPressed: subtractMinute, child: Text('-1 minute'))

],
)
],
)
: TextButton(
onPressed: startTimer,
child: Text('Start Timer!'),
style: ButtonStyle(backgroundColor: MaterialStateProperty.all<Color>(Colors.black) , foregroundColor:MaterialStateProperty.all<Color> (Colors.white) ,));
}
}

记分牌上的代码。dart-其他用户会看到(或公开(

Container(
height: 100,
width: 100,
child: StreamBuilder(
stream: clubData.doc('Time').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
} else {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text(
":${data['seconds']}",
style:
TextStyle(color: Colors.white, fontSize: 20),
);
}
}))

我不确定你所采用的方法是否是最好的,因为它广泛依赖于对Firestore的读写,一些客户在网络上的延迟使他们无法按时完成任务,或者给人一秒钟在应用程序上花费多少时间的不同感觉。

这里有一个更好的选择,你将如何设计这个。

Firestore文档将包含服务器时间戳和计数器的持续时间(小时、分钟和秒等(。递减计时器将在自定义Time小部件中从服务器时间戳开始实现。

为了让你感觉到这种方法在Firestore的使用上会有多大的不同,只需假设你有20个人在大约6分钟内设置相同的倒计时。您的方法将需要7200读取操作(20个客户端(*(6分钟(*(60秒(。它还需要360写入操作(6分钟(*(60秒(。另一方面,上述建议将需要20读取操作和2写入操作(第一次写入用于将文档存储在firestore中,第二次写入用于firestore发布时间戳(。

所以我找到了一种方法来做我想做的事。@rashidom给了我一个提示。所以我会发布我的代码,这样它就可以帮助其他人。

带有时间控件的文件。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:semafor/colors.dart';
int liveTime = 0, normalTime = 0;
int onPressedTime = 0;
int timeControlls = 0;
final CollectionReference saljemVrijeme =
FirebaseFirestore.instance.collection('game');
class ClockControlls extends StatefulWidget {
const ClockControlls({Key? key}) : super(key: key);
@override
State<ClockControlls> createState() => _ClockControllsState();
}
class _ClockControllsState extends State<ClockControlls> {

@override
build(BuildContext context) {
return Container(
height: 200,
width: 580,
decoration: BoxDecoration(
color: kOpenScoreboardGreyDark,
shape: BoxShape.rectangle,
border: Border.all(
color: kOpenScoreboardBlue,
width: 3,
),
borderRadius: BorderRadius.circular(20.0),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
const Text(
"Scoreboard",
style: TextStyle(
fontSize: 30,
color: Colors.white,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:  kOpenScoreboardGreyDarker,
foregroundColor: Colors.white
),
onPressed: () {
setState(() {
if (timeControlls == 0) {
onPressedTime =
DateTime.now().millisecondsSinceEpoch;
timeControlls = 1;
} else if (timeControlls == 2) {
onPressedTime = DateTime.now().millisecondsSinceEpoch - 2700000;
timeControlls = 1;
}
saljemVrijeme.doc('Time').update({'index': 1, });
saljemVrijeme.doc('Time').update({'onClick': onPressedTime, });

});
},
child: const Text('Start'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:  kOpenScoreboardGreyDarker,
foregroundColor: Colors.white,
),
onPressed: () {
setState(() {
timeControlls = 0;
saljemVrijeme.doc('Time').update({'index': 0, });

});
},
child: const Text('Reset Game Clock'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:  kOpenScoreboardGreyDarker,
foregroundColor: Colors.white,
),
onPressed: () {
setState(() {
timeControlls = 2;
saljemVrijeme.doc('Time').update({'index': 2, });
});
},
child: const Text('End of FIRST HALF'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:  kOpenScoreboardGreyDarker,
foregroundColor: Colors.white,
),
onPressed: () {
setState(() {
timeControlls = 3;
saljemVrijeme.doc('Time').update({'index': 3, });
});
},
child: const Text('End of GAME'),
),
]
),
],
),
)
);
}
}

用于在其他屏幕上显示时间的文件。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
final CollectionReference primamVrijeme =
FirebaseFirestore.instance.collection('game');

int liveTime = 0, normalTime = 0;
int onPressedTime = 0;
int timeControlls = 0;
class ShowTime extends StatefulWidget {
const ShowTime({Key? key}) : super(key: key);
@override
State<ShowTime> createState() => _ShowTimeState();
}
class _ShowTimeState extends State<ShowTime> {

Future<int?> getTime() async {
var a = await primamVrijeme.doc('Time').get();
setState(() {
onPressedTime = a['onClick'];
timeControlls= a['index'];
});
return liveTime;
}


String _stringTime() {
liveTime = DateTime.now().millisecondsSinceEpoch - onPressedTime;
var minutesString =
_getMinutes(liveTime).remainder(100).toString().padLeft(2, '0');
var secondsString = _getSeconds(liveTime).toString().padLeft(2, '0');
return "$minutesString:$secondsString";
}
@override
Widget build(BuildContext context) {
getTime();
return Scaffold(
body: StreamBuilder(
stream: Stream.periodic(const Duration(seconds: 1)),
builder: (context, snapshot) {
return Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
IndexedStack(index: timeControlls, children: <Widget>[
Container(
width: 100,
height: 100,
color: Colors.black,
child: Center(
child: Text(
'00:00',
style: TextStyle(
fontSize: 25, color: Colors.white),
),
)),
Container(
width: 100,
height: 100,
color: Colors.black,
child: Center(
child: Text(
_stringTime(),
style: TextStyle(
fontSize: 25, color: Colors.white),
),
)),
Container(
width: 100,
height: 100,
color: Colors.black,
child: Center(
child: Text(
'45:00',
style: TextStyle(
fontSize: 25, color: Colors.white),
),
)),
Container(
width: 100,
height: 100,
color: Colors.black,
child: Center(
child: Text(
'KRAJ',
style:
TextStyle(fontSize: 25, color: Colors.white),
),
)),
Text(
_stringTime(),
style: TextStyle(fontSize: 25, color: Colors.white),
)
]),

],
),

],
),
],
);
},
),
);
}
int _getMinutes(int milliseconds) {
return (milliseconds ~/ (60 * 1000));
}
int _getSeconds(int milliseconds) {
return (milliseconds - (_getMinutes(milliseconds) * 60 * 1000)) ~/ 1000;
}
}

相关内容

最新更新