rollback to material + app usage init

This commit is contained in:
2023-01-27 18:50:44 +05:30
parent fd60fca746
commit ecb59d8b52
8 changed files with 1915 additions and 992 deletions

View File

@@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<application <application
android:label="Task Tracker" android:label="Task Tracker"
android:name="${applicationName}" android:name="${applicationName}"

View File

@@ -8,8 +8,8 @@ import 'package:uuid/uuid.dart';
import 'theme_provider.dart'; import 'theme_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'User.dart' as User; import 'User.dart' as User;
class Category{
class Category {
Category(this.category_id, this.name, this.color, this.productive); Category(this.category_id, this.name, this.color, this.productive);
String category_id; String category_id;
@@ -23,9 +23,8 @@ class Category{
static String colProductive = "productive"; static String colProductive = "productive";
} }
class TaskType{ class TaskType {
TaskType(this.id, this.name, this.category, {this.relatedProject, this.cat});
TaskType(this.id, this.name, this.category,{this.relatedProject, this.cat});
String id; String id;
String name; String name;
@@ -34,18 +33,21 @@ class TaskType{
Project? relatedProject; Project? relatedProject;
static String colId = "id"; static String colId = "id";
static String colName="name"; static String colName = "name";
static String colCategory = "category_id"; static String colCategory = "category_id";
static String colRelatedProject = "related_project"; static String colRelatedProject = "related_project";
static String getDisplayName(TaskType taskType){ static String getDisplayName(TaskType taskType) {
return (taskType.name + ((taskType.relatedProject != null) ? ' [${taskType.relatedProject!.name}]' : '')); return (taskType.name +
((taskType.relatedProject != null)
? ' [${taskType.relatedProject!.name}]'
: ''));
} }
} }
class Activity{ class Activity {
Activity(this.taskType, this.startTime, this.endTime,
Activity(this.taskType, this.startTime, this.endTime, {this.metadata,DateTime? tEndTime,DateTime? tStartTime}){ {this.metadata, DateTime? tEndTime, DateTime? tStartTime}) {
trueStartTime = tStartTime ?? startTime; trueStartTime = tStartTime ?? startTime;
trueEndTime = tEndTime ?? endTime; trueEndTime = tEndTime ?? endTime;
} }
@@ -56,65 +58,66 @@ class Activity{
DateTime endTime; DateTime endTime;
String? metadata; String? metadata;
Activity.fromJson(Map<String,dynamic> json): taskType=json['taskType'], startTime=json['sTime'], endTime=json['eTime']; Activity.fromJson(Map<String, dynamic> json)
: taskType = json['taskType'],
startTime = json['sTime'],
endTime = json['eTime'];
Map<String, dynamic> toJson()=>{ Map<String, dynamic> toJson() =>
'taskType': taskType, {'taskType': taskType, 'sTime': startTime, 'eTime': endTime};
'sTime':startTime,
'eTime':endTime
};
static String colType = "type"; static String colType = "type";
static String colStartTime = "s_time"; static String colStartTime = "s_time";
static String colEndTime = "e_time"; static String colEndTime = "e_time";
static String colMetadata= "metadata"; static String colMetadata = "metadata";
} }
class InitialData{ class InitialData {
static List<TaskType> getTaskTypes(String username){ static List<TaskType> getTaskTypes(String username) {
List<TaskType> tasks =[ List<TaskType> tasks = [
TaskType(username + 'Sleep','Sleep', 'Relax'), TaskType(username + 'Sleep', 'Sleep', 'Relax'),
TaskType(username + 'Physics','Physics', 'Study'), TaskType(username + 'Physics', 'Physics', 'Study'),
TaskType(username + 'History','History','Study'), TaskType(username + 'History', 'History', 'Study'),
TaskType(username + 'Football','Football', 'Play'), TaskType(username + 'Football', 'Football', 'Play'),
TaskType(username + 'At work','At work', 'Work'), TaskType(username + 'At work', 'At work', 'Work'),
TaskType(username + 'Chores','Chores', 'Daily Activities'), TaskType(username + 'Chores', 'Chores', 'Daily Activities'),
TaskType(username + 'Eat','Eat','Daily Activities'), TaskType(username + 'Eat', 'Eat', 'Daily Activities'),
TaskType(username + 'Hang out','Hang out', 'Social') TaskType(username + 'Hang out', 'Hang out', 'Social')
]; ];
return tasks; return tasks;
} }
static List<Category> getCategories(String username){ static List<Category> getCategories(String username) {
List<Category> cats = [ List<Category> cats = [
Category(username+'Relax','Relax', '#555555', false), Category(username + 'Relax', 'Relax', '#555555', false),
Category(username+'Daily Activities','Daily Activities', '#009955',false), Category(
Category(username+'Study','Study', '#00FF00', true), username + 'Daily Activities', 'Daily Activities', '#009955', false),
Category(username+'Play','Play', '#FF0000', false), Category(username + 'Study', 'Study', '#00FF00', true),
Category(username+'Work','Work', '#00AAFF', true), Category(username + 'Play', 'Play', '#FF0000', false),
Category(username+'Social','Social', '#00AAAA', false) Category(username + 'Work', 'Work', '#00AAFF', true),
Category(username + 'Social', 'Social', '#00AAAA', false)
]; ];
return cats; return cats;
} }
} }
class Queries {
class Queries{ Queries(this.link, this.data);
Queries(this.link,this.data);
String link; String link;
String data; String data;
static String colLink= "file"; static String colLink = "file";
static String colData = "data"; static String colData = "data";
} }
class Project{ class Project {
Project(this.name, this.category, this.steps,this.eta, this.deadline,{this.cat}); Project(this.name, this.category, this.steps, this.eta, this.deadline,
{this.cat});
String name; String name;
String getName()=> name.replaceAll(User.username, ""); String getName() => name.replaceAll(User.username, "");
String category; String category;
Category? cat; Category? cat;
List<ProjectStep> steps; List<ProjectStep> steps;
@@ -122,23 +125,29 @@ class Project{
DateTime deadline; DateTime deadline;
static String colName = "name"; static String colName = "name";
static String colCat="category_id"; static String colCat = "category_id";
static String colSteps = "steps"; static String colSteps = "steps";
static String colDeadline = "deadline"; static String colDeadline = "deadline";
static String colEta = "eta"; static String colEta = "eta";
} }
class ProjectStep{ class ProjectStep {
ProjectStep(this.stepName,this.eta,this.progress); ProjectStep(this.stepName, this.eta, this.progress);
ProjectStep.fromJson(Map<String,dynamic> json): stepName=json['name'], eta=json['eta'], progress=json['progress'], finishedDate=(json['finishedDate']!=null) ? DateTime.parse(json['finishedDate']) : null; ProjectStep.fromJson(Map<String, dynamic> json)
: stepName = json['name'],
eta = json['eta'],
progress = json['progress'],
finishedDate = (json['finishedDate'] != null)
? DateTime.parse(json['finishedDate'])
: null;
Map<String, dynamic> toJson()=>{ Map<String, dynamic> toJson() => {
'name': stepName, 'name': stepName,
'eta':eta, 'eta': eta,
'progress':progress, 'progress': progress,
if(finishedDate!=null) 'finishedDate':finishedDate.toString() if (finishedDate != null) 'finishedDate': finishedDate.toString()
}; };
String stepName; String stepName;
int eta; int eta;
@@ -146,8 +155,7 @@ class ProjectStep{
DateTime? finishedDate; DateTime? finishedDate;
} }
class Journal{ class Journal {
Journal(this.id, this.day, {this.title, this.description}); Journal(this.id, this.day, {this.title, this.description});
String id; String id;
@@ -159,8 +167,9 @@ class Journal{
static String colDescription = 'Desc'; static String colDescription = 'Desc';
} }
class Todo{ class Todo {
Todo(this.id, this.category,this.metadata, this.dueDate, {this.notificationTime, this.task}); Todo(this.id, this.category, this.metadata, this.dueDate,
{this.notificationTime, this.task});
String id; String id;
String category; String category;
@@ -175,101 +184,128 @@ class Todo{
static String colNotificationTime = 'notification_time'; static String colNotificationTime = 'notification_time';
} }
class Settings {
class Settings{ static Future<String> UUID() async {
static Future<String> UUID() async{
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('uuid')){ if (prefs.containsKey('uuid')) {
return await Future.value(prefs.getString('uuid')); return await Future.value(prefs.getString('uuid'));
}else{ } else {
var uuid = Uuid(); var uuid = Uuid();
String _uuid = uuid.v4(); String _uuid = uuid.v4();
// if(Platform.isAndroid){ // if(Platform.isAndroid){
// //
// } // }
await prefs.setString('uuid',_uuid); await prefs.setString('uuid', _uuid);
return Future.value(_uuid); return Future.value(_uuid);
} }
} }
static Future<void> setTheme(int value) async{ static Future<void> setTheme(int value) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setInt("theme", value); await prefs.setInt("theme", value);
} }
static String notification_key= "notification_interval"; static String notification_key = "notification_interval";
static String adaptive_notification_key = "adaptive_notification"; static String adaptive_notification_key = "adaptive_notification";
static String untracked_unprod_key = "untracked_unproductive"; static String untracked_unprod_key = "untracked_unproductive";
static String auto_log_key = "auto_log";
static Future<int> getNotificationInterval() async{ static Future<int> getNotificationInterval() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
int _value = 1; int _value = 1;
if(prefs.containsKey(notification_key)){ if (prefs.containsKey(notification_key)) {
_value = await prefs.getInt(notification_key) ?? 1; _value = await prefs.getInt(notification_key) ?? 1;
}else{ } else {
prefs.setInt(notification_key,_value); prefs.setInt(notification_key, _value);
} }
return _value; return _value;
} }
static Future<void> setNotificationInterval(int value) async{ static Future<void> setNotificationInterval(int value) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setInt(notification_key, value); prefs.setInt(notification_key, value);
} }
static List<String> notificationOptions = <String>['Off','1 hour', '2 hour', '3 hour', '4 hour', '5 hour', '6 hour']; static List<String> notificationOptions = <String>[
'Off',
'1 hour',
'2 hour',
'3 hour',
'4 hour',
'5 hour',
'6 hour'
];
static bool adaptiveNotificationAvailable() { static bool adaptiveNotificationAvailable() {
List<String> dates = []; List<String> dates = [];
if(User.activities.length < 10){ if (User.activities.length < 10) {
return false; return false;
}else{ } else {
for (var element in User.activities) { for (var element in User.activities) {
String thisDate = DateFormat("MM/dd").format(element.startTime); String thisDate = DateFormat("MM/dd").format(element.startTime);
if(!dates.contains(thisDate)){ if (!dates.contains(thisDate)) {
dates.add(thisDate); dates.add(thisDate);
}
} }
} }
}
return (dates.length > 2); return (dates.length > 2);
} }
static Future<bool> getAdaptiveNotification() async{ static Future<bool> getAdaptiveNotification() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
bool _value = true; bool _value = true;
if(prefs.containsKey(notification_key)){ if (prefs.containsKey(notification_key)) {
_value = await prefs.getBool(adaptive_notification_key) ?? true; _value = await prefs.getBool(adaptive_notification_key) ?? true;
}else{ } else {
prefs.setBool(adaptive_notification_key,_value); prefs.setBool(adaptive_notification_key, _value);
} }
return _value; return _value;
} }
static Future<void> setAdaptiveNotification(bool value) async{ static Future<void> setAdaptiveNotification(bool value) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setBool(adaptive_notification_key, value); prefs.setBool(adaptive_notification_key, value);
} }
static Future<bool> getUntrackedUnproductive() async{ static Future<bool> getUntrackedUnproductive() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
bool _value = true; bool _value = true;
if(prefs.containsKey(untracked_unprod_key)){ if (prefs.containsKey(untracked_unprod_key)) {
_value = await prefs.getBool(untracked_unprod_key) ?? true; _value = await prefs.getBool(untracked_unprod_key) ?? true;
}else{ } else {
prefs.setBool(untracked_unprod_key,_value); prefs.setBool(untracked_unprod_key, _value);
} }
return _value; return _value;
} }
static Future<void> setUntrackedUnproductive(bool value) async{ static Future<bool> getAutoLog() async {
final prefs = await SharedPreferences.getInstance();
bool _value = true;
if (prefs.containsKey(auto_log_key)) {
_value = await prefs.getBool(auto_log_key) ?? true;
} else {
prefs.setBool(auto_log_key, _value);
}
return _value;
}
static Future<void> setUntrackedUnproductive(bool value) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setBool(untracked_unprod_key, value); prefs.setBool(untracked_unprod_key, value);
} }
static Future<void> setAutoLog(bool value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool(auto_log_key, value);
}
} }
final settings = Settings();
final settings = Settings();

View File

@@ -11,20 +11,20 @@ class BehaviourSettings extends StatefulWidget {
} }
class _BehaviourSettingsState extends State<BehaviourSettings> { class _BehaviourSettingsState extends State<BehaviourSettings> {
bool untracked_unprod = true; bool untracked_unprod = true;
bool autoUsage = true;
@override void initState() { @override
void initState() {
// TODO: implement initState // TODO: implement initState
super.initState(); super.initState();
init(); init();
} }
void init() async{ void init() async {
untracked_unprod=await Settings.getUntrackedUnproductive(); untracked_unprod = await Settings.getUntrackedUnproductive();
setState(() { autoUsage = await Settings.getAutoLog();
setState(() {});
});
} }
TextEditingController untrackedGapSettings = TextEditingController(); TextEditingController untrackedGapSettings = TextEditingController();
@@ -36,65 +36,77 @@ class _BehaviourSettingsState extends State<BehaviourSettings> {
appBar: AppBar(title: Text('Behaviour Settings')), appBar: AppBar(title: Text('Behaviour Settings')),
body: SafeArea( body: SafeArea(
child: Container( child: Container(
child:Column( child: Column(
children: [ children: [
ListTile( ListTile(
title:Text("Count untracked time as unproductive"), title: Text("Count untracked time as unproductive"),
subtitle: Text("Not tracking = Not productive"), subtitle: Text("Not tracking = Not productive"),
trailing: Switch.adaptive(value: untracked_unprod, onChanged: (val){ trailing: Switch.adaptive(
untracked_unprod=val; value: untracked_unprod,
setState(() { onChanged: (val) {
Settings.setUntrackedUnproductive(val); untracked_unprod = val;
}); setState(() {
setState(() { Settings.setUntrackedUnproductive(val);
});
}); setState(() {});
}), }),
), ),
//TODO //TODO
ListTile( ListTile(
title:Text("Untracked Delay Threshold"), title: Text("Untracked Delay Threshold"),
subtitle: Text("Makes it easier to fill in the gaps"), subtitle: Text("Makes it easier to fill in the gaps"),
trailing: trailing: Row(
Row( mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ if (untrackedGapValue > 0)
if(untrackedGapValue> 0)InkWell(onTap: (){ InkWell(
untrackedGapSettings.text = (untrackedGapValue-1).toString(); onTap: () {
setState(() { untrackedGapSettings.text =
(untrackedGapValue - 1).toString();
}); setState(() {});
}, },
child : Container(margin: EdgeInsets.all(10),child: Text('-')),), child: Container(
SizedBox( margin: EdgeInsets.all(10), child: Text('-')),
width: 25,
height: 30,
child: TextField(
textAlign: TextAlign.center,
controller: untrackedGapSettings,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],),
), ),
SizedBox(
InkWell(onTap: (){ width: 25,
untrackedGapSettings.text = (untrackedGapValue+1).toString(); height: 30,
setState(() { child: TextField(
textAlign: TextAlign.center,
}); controller: untrackedGapSettings,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
),
),
InkWell(
onTap: () {
untrackedGapSettings.text =
(untrackedGapValue + 1).toString();
setState(() {});
}, },
child: Container(margin:EdgeInsets.all(10),child: Text('+')), child: Container(
margin: EdgeInsets.all(10), child: Text('+')),
) )
], ],
), ),
) ),
ListTile(
title: Text("Automatically add tasks from Usage Data"),
subtitle: Text("Requires App Usage access"),
trailing: Switch.adaptive(
value: autoUsage,
onChanged: (val) {
autoUsage = val;
Settings.setAutoLog(val);
], setState(() {});
) }),
), ),
) ],
); )),
));
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,10 @@
import 'package:app_usage/app_usage.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tasktracker/Data.dart'; import 'package:tasktracker/Data.dart';
import 'DebugHelper.dart';
import 'User.dart' as Users; import 'User.dart' as Users;
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'theme_provider.dart'; import 'theme_provider.dart';
@@ -18,18 +20,19 @@ class SplashScreen extends StatefulWidget {
} }
class _SplashScreenState extends State<SplashScreen> { class _SplashScreenState extends State<SplashScreen> {
Future<void> initSettings() async{ Future<void> initSettings() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
bool value = true; bool value = true;
if(prefs.containsKey("theme")){ if (prefs.containsKey("theme")) {
value = ((await prefs.getInt("theme"))==0); value = ((await prefs.getInt("theme")) == 0);
}else{ } else {
await prefs.setInt("theme", 0); await prefs.setInt("theme", 0);
} }
print('Dark theme is : $value'); print('Dark theme is : $value');
final provider = Provider.of<ThemeProvider>(context, listen: false); final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value); provider.toggleTheme(value);
} }
@override @override
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
@@ -38,14 +41,16 @@ class _SplashScreenState extends State<SplashScreen> {
NotificationManager.RescheduleNotifications(); NotificationManager.RescheduleNotifications();
} }
void notificationSelected(String? payload) { void notificationSelected(String? payload) {
if(payload!=null){ if (payload != null) {
if(payload.toLowerCase().contains("activity")){ if (payload.toLowerCase().contains("activity")) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity())).then((value) => {Users.refreshUserData()}); Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => NewActivity()))
.then((value) => {Users.refreshUserData()});
} }
} }
} }
void init() async { void init() async {
await initSettings(); await initSettings();
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
@@ -53,25 +58,29 @@ class _SplashScreenState extends State<SplashScreen> {
// print(loginResponse.body); // print(loginResponse.body);
if (!prefs.containsKey("password") || !prefs.containsKey("username")) { if (!prefs.containsKey("password") || !prefs.containsKey("username")) {
Navigator.of(context).pushNamedAndRemoveUntil('/welcome', (route) => false); Navigator.of(context)
.pushNamedAndRemoveUntil('/welcome', (route) => false);
} else { } else {
try { try {
http.Response loginResponse = await Users.login( http.Response loginResponse = await Users.login(
prefs.getString("username") ?? '', prefs.getString("username") ?? '',
prefs.getString("password") ?? ''); prefs.getString("password") ?? '');
print(loginResponse.body); print(loginResponse.body);
if (loginResponse.body.toLowerCase().contains("success")) { //Login Success if (loginResponse.body.toLowerCase().contains("success")) {
//Login Success
Continue(); Continue();
} else { //Login Failed } else {
//Login Failed
LoginFailed(); LoginFailed();
} }
} catch (error) { //Login Failed } catch (error) {
//Login Failed
LoginFailed(); LoginFailed();
} }
} }
} }
void LoginFailed() async{ void LoginFailed() async {
bool dbExist = await Users.cacheDbExist(); bool dbExist = await Users.cacheDbExist();
if (dbExist) { if (dbExist) {
print('cache Database exists, Lets go CACHE!'); print('cache Database exists, Lets go CACHE!');
@@ -81,7 +90,7 @@ class _SplashScreenState extends State<SplashScreen> {
} }
} }
void Continue() async{ void Continue() async {
await Users.initUserData(); await Users.initUserData();
Navigator.of(context).pushReplacementNamed('/home'); Navigator.of(context).pushReplacementNamed('/home');
print('Going home!'); print('Going home!');
@@ -91,9 +100,12 @@ class _SplashScreenState extends State<SplashScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colors.lightBlue, Colors.blue],stops: [0,1],begin: Alignment.topLeft, end: Alignment.bottomRight) gradient: LinearGradient(
), colors: [Colors.lightBlue, Colors.blue],
// color: Colors.redAccent, stops: [0, 1],
begin: Alignment.topLeft,
end: Alignment.bottomRight)),
// color: Colors.redAccent,
padding: EdgeInsets.all(80), padding: EdgeInsets.all(80),
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
@@ -106,11 +118,15 @@ class _SplashScreenState extends State<SplashScreen> {
SpinKitPouringHourGlass(color: Colors.white), SpinKitPouringHourGlass(color: Colors.white),
], ],
), ),
DefaultTextStyle(style: TextStyle(fontSize: 15,color: Colors.white,fontStyle: FontStyle.italic), DefaultTextStyle(
child: Text('If you lie to me, That means you lie to yourself\n\n -This app (2022)',)) style: TextStyle(
fontSize: 15,
color: Colors.white,
fontStyle: FontStyle.italic),
child: Text(
'If you lie to me, That means you lie to yourself\n\n -This app (2022)',
))
// Text('Loading', style:TextStyle(color: Colors.grey, fontSize: 20,fontStyle: FontStyle.italic)) // Text('Loading', style:TextStyle(color: Colors.grey, fontSize: 20,fontStyle: FontStyle.italic))
])); ]));
} }
} }

View File

@@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
app_usage:
dependency: "direct main"
description:
name: app_usage
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
args: args:
dependency: transitive dependency: transitive
description: description:

View File

@@ -55,6 +55,7 @@ dependencies:
google_sign_in: ^5.2.3 google_sign_in: ^5.2.3
font_awesome_flutter: ^10.0.0 font_awesome_flutter: ^10.0.0
restart_app: ^1.1.0 restart_app: ^1.1.0
app_usage: ^2.1.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: