Polished
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'main.dart';
|
||||
import 'main.dart' as Main;
|
||||
import 'newActivity.dart';
|
||||
import 'Data.dart';
|
||||
import 'User.dart' as User;
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
|
||||
class Activities extends StatefulWidget {
|
||||
const Activities({Key? key}) : super(key: key);
|
||||
|
||||
@@ -14,9 +12,10 @@ class Activities extends StatefulWidget {
|
||||
_ActivitiesState createState() => _ActivitiesState();
|
||||
}
|
||||
|
||||
late ProgressDialog progressDialog;
|
||||
|
||||
|
||||
class _ActivitiesState extends State<Activities> {
|
||||
//late ProgressDialog progressDialog;
|
||||
TextEditingController searchController = TextEditingController();
|
||||
FocusNode _focus = FocusNode();
|
||||
bool searching = false;
|
||||
@@ -38,6 +37,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
super.initState();
|
||||
_focus.addListener(_onFocusChange);
|
||||
UpdateList();
|
||||
//init(context);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -47,10 +47,20 @@ class _ActivitiesState extends State<Activities> {
|
||||
_focus.removeListener(_onFocusChange);
|
||||
_focus.dispose();
|
||||
}
|
||||
void UpdateList() async {
|
||||
try {
|
||||
//progressDialog.show(max: 100, msg: 'Loading Activities');
|
||||
} catch (e) {}
|
||||
await User.refreshUserData();
|
||||
setState(() {});
|
||||
try {
|
||||
// progressDialog.update(value: 100);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
progressDialog = ProgressDialog(context: context);
|
||||
// progressDialog = ProgressDialog(context: context);
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
@@ -129,9 +139,9 @@ class _ActivitiesState extends State<Activities> {
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() async {
|
||||
await User.refreshUserData();
|
||||
UpdateList();
|
||||
UpdateList();
|
||||
setState(() {
|
||||
|
||||
});
|
||||
},
|
||||
child: Icon(Icons.refresh, size: 30),
|
||||
@@ -140,7 +150,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
),
|
||||
],
|
||||
)),
|
||||
drawer: navDrawer(context, 2),
|
||||
drawer: Main.navDrawer(context, 2),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: SingleChildScrollView(
|
||||
@@ -149,16 +159,6 @@ class _ActivitiesState extends State<Activities> {
|
||||
))));
|
||||
}
|
||||
|
||||
void UpdateList() async {
|
||||
try {
|
||||
progressDialog.show(max: 100, msg: 'Loading Activities');
|
||||
} catch (e) {}
|
||||
await User.updateActList();
|
||||
setState(() {});
|
||||
try {
|
||||
progressDialog.update(value: 100);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
List<Widget> PrintTasks() {
|
||||
List<Widget> _tasks = [];
|
||||
@@ -214,9 +214,10 @@ class _ActivitiesState extends State<Activities> {
|
||||
if (element.taskType.cat == null) {
|
||||
print('Got some null cat : ${element.taskType.name}');
|
||||
} else {
|
||||
Color color = HexColor.fromHex(element.taskType.cat?.color ?? '#000000');
|
||||
Color color = Main.HexColor.fromHex(element.taskType.cat?.color ?? '#000000');
|
||||
bool productive = element.taskType.cat?.productive ?? true;
|
||||
Widget task = ActivityCard(context, name, element.startTime, element.endTime, productive, color, element, totalMinutes[thisDate] ?? 0);
|
||||
// print('Activity : ${name} ,sTime: ${element.startTime}, eTime: ${element.endTime}');
|
||||
_tasks.add(task);
|
||||
}
|
||||
}
|
||||
@@ -252,7 +253,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
children: [
|
||||
Container(
|
||||
child: Align(
|
||||
child: FittedBox(fit: BoxFit.fitWidth,child: Text(MinutesToTimeString(prodActs),)),
|
||||
child: FittedBox(fit: BoxFit.fitWidth,child: Text(Main.MinutesToTimeString(prodActs),)),
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
width: (prodPercentage) * 1.7,
|
||||
@@ -261,7 +262,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
),
|
||||
Container(
|
||||
child: Align(
|
||||
child: Text(MinutesToTimeString(unprodActs)),
|
||||
child: Text(Main.MinutesToTimeString(unprodActs)),
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
width: (100 - prodPercentage) * 1.7,
|
||||
@@ -400,7 +401,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
}
|
||||
|
||||
void DeleteSelectedTasks() async {
|
||||
progressDialog.show(max: 100, msg: 'Deleteing ${selectedActivities.length} Activities');
|
||||
//progressDialog.show(max: 100, msg: 'Deleteing ${selectedActivities.length} Activities');
|
||||
selectedActivities.forEach((element) async {
|
||||
await User.UserOperations.deleteActivity(element, bulk: true);
|
||||
});
|
||||
@@ -411,7 +412,7 @@ class _ActivitiesState extends State<Activities> {
|
||||
selectedActivities = [];
|
||||
selecting = false;
|
||||
setState(() {
|
||||
progressDialog.update(value: 100);
|
||||
// progressDialog.update(value: 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'main.dart';
|
||||
import 'NewTask.dart';
|
||||
import 'User.dart' as User;
|
||||
import 'Data.dart';
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
class Categories extends StatefulWidget {
|
||||
const Categories({Key? key}) : super(key: key);
|
||||
|
||||
@@ -12,20 +11,25 @@ class Categories extends StatefulWidget {
|
||||
_CategoriesState createState() => _CategoriesState();
|
||||
}
|
||||
|
||||
late ProgressDialog progressDialog;
|
||||
|
||||
bool selecting=false;
|
||||
class _CategoriesState extends State<Categories> {
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
|
||||
//init(context);
|
||||
UpdateList();
|
||||
}
|
||||
|
||||
@override void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
progressDialog=ProgressDialog(context: context);
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
@@ -66,7 +70,7 @@ class _CategoriesState extends State<Categories> {
|
||||
}
|
||||
|
||||
void UpdateList() async {
|
||||
await User.updateCatsList();
|
||||
await User.refreshUserData();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@@ -92,7 +96,6 @@ class _CategoriesState extends State<Categories> {
|
||||
}
|
||||
|
||||
void DeleteSelectedCats() async{
|
||||
progressDialog.show(max: 100, msg: 'Deleteing ${selectedTasks.length} Categories');
|
||||
selectedTasks.forEach((element) async {
|
||||
await User.UserOperations.deleteCategory(element, bulk:true);
|
||||
});
|
||||
@@ -102,7 +105,6 @@ class _CategoriesState extends State<Categories> {
|
||||
selectedTasks=[];
|
||||
selecting=false;
|
||||
setState(() {
|
||||
progressDialog.update(value: 100);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'theme_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'User.dart' as User;
|
||||
class Category{
|
||||
|
||||
Category(this.category_id, this.name, this.color, this.productive);
|
||||
@@ -99,10 +101,47 @@ class Settings{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Future<void> setTheme(int value) async{
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt("theme", value);
|
||||
}
|
||||
|
||||
static String notification_key= "notification_interval";
|
||||
|
||||
static Future<int> getNotificationInterval() async{
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
int _value = 1;
|
||||
if(prefs.containsKey(notification_key)){
|
||||
_value = await prefs.getInt(notification_key) ?? 1;
|
||||
}else{
|
||||
prefs.setInt(notification_key,_value);
|
||||
}
|
||||
|
||||
return _value;
|
||||
}
|
||||
|
||||
static Future<void> setNotificationInterval(int value) async{
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setInt(notification_key, value);
|
||||
}
|
||||
static List<String> notificationOptions = <String>['Off','1 hour', '2 hour', '3 hour', '4 hour', '5 hour', '6 hour'];
|
||||
|
||||
static bool adaptiveNotificationAvailable() {
|
||||
List<String> dates = [];
|
||||
if(User.activities.length < 10){
|
||||
return false;
|
||||
}else{
|
||||
for (var element in User.activities) {
|
||||
String thisDate = DateFormat("MM/dd").format(element.startTime);
|
||||
if(!dates.contains(thisDate)){
|
||||
dates.add(thisDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (dates.length > 2);
|
||||
|
||||
}
|
||||
}
|
||||
final settings = Settings();
|
||||
41
lib/Dialogs.dart
Normal file
41
lib/Dialogs.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'main.dart';
|
||||
|
||||
class Dialogs{
|
||||
static bool showing = false;
|
||||
static BuildContext? context;
|
||||
static List<Widget> popupsOpened=[];
|
||||
static waiting( String title){
|
||||
showing=true;
|
||||
context=navigatorKey.currentContext;
|
||||
if(context!=null) {
|
||||
return showDialog(
|
||||
context: context!,
|
||||
barrierDismissible: false,
|
||||
routeSettings: const RouteSettings(name: "Progress"),
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SpinKitChasingDots(color: Colors.green),
|
||||
Expanded(child: Text(title,textAlign: TextAlign.center,)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static hide(){
|
||||
showing=false;
|
||||
Navigator.of(navigatorKey.currentContext!).popUntil((route){
|
||||
return route.settings.name!="Progress";
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,9 @@ class _NewCategoryState extends State<NewCategory> {
|
||||
}
|
||||
var hex = '#${pickerColor.value.toRadixString(16)}';
|
||||
await User.UserOperations.addCategory(catName, hex, productive);
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).popUntil((route){
|
||||
return route.isFirst;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,9 @@ class _NewTaskState extends State<NewTask> {
|
||||
return;
|
||||
}
|
||||
await User.UserOperations.addTaskType(catName,selectedCat);
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).popUntil((route){
|
||||
return route.isFirst;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tasktracker/Data.dart';
|
||||
|
||||
class NotificationSettings extends StatefulWidget {
|
||||
const NotificationSettings({Key? key}) : super(key: key);
|
||||
@@ -8,6 +9,26 @@ class NotificationSettings extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NotificationSettingsState extends State<NotificationSettings> {
|
||||
String dropdownValue = Settings.notificationOptions[1];
|
||||
|
||||
bool suggestionNotification = true;
|
||||
bool adaptiveNotification =true;
|
||||
bool adaptiveNotificationAvailable =false;
|
||||
@override void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
void updateSettings() async{
|
||||
int notificationInterval= await Settings.getNotificationInterval();
|
||||
adaptiveNotificationAvailable = Settings.adaptiveNotificationAvailable();
|
||||
setState(() {
|
||||
dropdownValue=Settings.notificationOptions[notificationInterval];
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -19,13 +40,51 @@ class _NotificationSettingsState extends State<NotificationSettings> {
|
||||
height: 10,
|
||||
),
|
||||
ListTile(
|
||||
enabled: adaptiveNotificationAvailable,
|
||||
title: Text("Adaptive Notifications"),
|
||||
trailing:(adaptiveNotificationAvailable) ?Switch.adaptive(value: adaptiveNotification, onChanged: (val){
|
||||
adaptiveNotification=val;
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}) : Text("Track more data to activate this", style: TextStyle(color: Colors.red)),
|
||||
subtitle: Text("Notifies you to track activities according to your past activities patterns"),
|
||||
|
||||
),
|
||||
ListTile(
|
||||
enabled: !adaptiveNotification,
|
||||
title: Text("New Activity Notification"),
|
||||
trailing: InkWell(onTap:(){},child: Text("1 hour")),
|
||||
trailing:(adaptiveNotification) ? (Text("Adaptive")) : DropdownButton<String>(
|
||||
value: dropdownValue,
|
||||
icon: const Icon(Icons.arrow_downward),
|
||||
elevation: 16,
|
||||
underline: Container(
|
||||
height: 2,
|
||||
color: Colors.red,
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
Settings.setNotificationInterval(Settings.notificationOptions.indexOf(newValue!));
|
||||
dropdownValue = newValue!;
|
||||
});
|
||||
},
|
||||
items:Settings.notificationOptions.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
subtitle: Text("Notify you to track activities of past time"),
|
||||
),
|
||||
Divider(),
|
||||
ListTile(
|
||||
title: Text("Suggestion Notifications"), trailing:Switch.adaptive(value: true, onChanged: (val){}),
|
||||
title: Text("Suggestion Notifications"), trailing:Switch.adaptive(value: suggestionNotification, onChanged: (val){
|
||||
suggestionNotification=val;
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}),
|
||||
subtitle: Text("Notifies you about suggestions according to your data"),
|
||||
|
||||
)
|
||||
|
||||
@@ -3,9 +3,7 @@ import 'main.dart';
|
||||
import 'NewTask.dart';
|
||||
import 'Data.dart';
|
||||
import 'User.dart' as User;
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
|
||||
late ProgressDialog progressDialog;
|
||||
class Tasks extends StatefulWidget {
|
||||
const Tasks({Key? key}) : super(key: key);
|
||||
|
||||
@@ -17,10 +15,29 @@ class _TasksState extends State<Tasks> {
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
progressDialog = ProgressDialog(context: context);
|
||||
User.progressDialog=progressDialog;
|
||||
UpdateList();
|
||||
// init(context);
|
||||
}
|
||||
|
||||
var refreshSub;
|
||||
void init(BuildContext context) async{
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
refreshSub = User.refreshStream.stream.listen((value) {
|
||||
print("Streaming refresh : $value");
|
||||
if(value){
|
||||
// dialogs.waiting(context, "Syncing");
|
||||
print("Opening progress dialog");
|
||||
}else{
|
||||
// dialogs.hide(context);
|
||||
print("Closing progress dialog");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
refreshSub?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -67,12 +84,12 @@ class _TasksState extends State<Tasks> {
|
||||
|
||||
void UpdateList() async {
|
||||
|
||||
try{progressDialog.show(max:100, msg: 'Loading Task Types...');}catch(e){}
|
||||
await User.updateTasksList();
|
||||
// try{progressDialog.show(max:100, msg: 'Loading Task Types...');}catch(e){}
|
||||
await User.refreshUserData();
|
||||
// hideProgressDialog();
|
||||
setState(() {});
|
||||
if(mounted)setState(() {});
|
||||
|
||||
try{progressDialog.update(value: 100);}catch(e){}
|
||||
// try{progressDialog.update(value: 100);}catch(e){}
|
||||
}
|
||||
|
||||
List<Widget> PrintTasks() {
|
||||
@@ -171,7 +188,6 @@ class _TasksState extends State<Tasks> {
|
||||
}
|
||||
|
||||
void DeleteSelectedTasks() async{
|
||||
progressDialog.show(max: 100, msg: "Deleting ${selectedTasks.length} ");
|
||||
selectedTasks.forEach((element) async {
|
||||
await User.UserOperations.deleteTask(element, bulk:true);
|
||||
});
|
||||
@@ -181,7 +197,6 @@ class _TasksState extends State<Tasks> {
|
||||
selectedTasks=[];
|
||||
selecting=false;
|
||||
setState(() {
|
||||
progressDialog.update(value: 100);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
540
lib/User.dart
540
lib/User.dart
@@ -1,7 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'main.dart';
|
||||
@@ -11,45 +13,38 @@ import 'Data.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
import 'Tasks.dart';
|
||||
late ProgressDialog? progressDialog;
|
||||
|
||||
late http.Response loginResponse;
|
||||
|
||||
late Database cacheDb;
|
||||
late String username;
|
||||
List<Category> categories = [];
|
||||
List<TaskType> taskTypes = [];
|
||||
List<Activity> activities=[];
|
||||
List<Activity> activities = [];
|
||||
bool offline = true;
|
||||
bool registered = false;
|
||||
bool refreshing = true;
|
||||
StreamController<bool> refreshStream = StreamController<bool>();
|
||||
Future<http.Response> login(String _username, String password) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
username = _username;
|
||||
var device_id = await Settings.UUID();
|
||||
try {
|
||||
loginResponse = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/login.php'),
|
||||
body: <String, String>{
|
||||
"username": _username,
|
||||
"password": password,
|
||||
"device_id": device_id
|
||||
}));
|
||||
loginResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/login.php'), body: <String, String>{"username": _username, "password": password, "device_id": device_id}));
|
||||
|
||||
if (loginResponse.body.toLowerCase().contains("success")) {
|
||||
offline = false;
|
||||
username = _username;
|
||||
registered =loginResponse.body.toLowerCase().contains("register");
|
||||
registered = loginResponse.body.toLowerCase().contains("register");
|
||||
|
||||
print("registered : $registered");
|
||||
if(registered){
|
||||
if (registered) {
|
||||
prefs.setBool("registered", true);
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
offline=true;
|
||||
} catch (e) {
|
||||
print("Error while login $e");
|
||||
}
|
||||
return loginResponse;
|
||||
}
|
||||
@@ -58,52 +53,48 @@ Future<void> initUserData() async {
|
||||
await initCacheDatabase();
|
||||
await refreshUserData();
|
||||
print('Initializing UserData...');
|
||||
if (offline) {
|
||||
print('Going offline mode.');
|
||||
}
|
||||
Connectivity().onConnectivityChanged.listen((result) {
|
||||
offline = (result == ConnectivityResult.none);
|
||||
if (!offline) {
|
||||
UserOperations.executeQueries();
|
||||
refreshUserData();
|
||||
}
|
||||
});
|
||||
}
|
||||
bool userDataInitiated =false;
|
||||
Future<void> refreshUserData() async{
|
||||
ShowProgress("Loading data");
|
||||
refreshing = true;
|
||||
// categories= await GetCategories(true);
|
||||
// taskTypes= await GetTaskTypes(true);
|
||||
// activities= await GetActivities(true);
|
||||
|
||||
Future<void> refreshUserData() async {
|
||||
refreshStream.add(true);
|
||||
await updateCatsList();
|
||||
await updateTasksList();
|
||||
await updateActList();
|
||||
userDataInitiated=true;
|
||||
refreshing = false;
|
||||
HideProgress();
|
||||
refreshStream.add(false);
|
||||
}
|
||||
|
||||
Future<bool> cacheDbExist() async{
|
||||
Future<bool> cacheDbExist() async {
|
||||
Directory directory = await getApplicationDocumentsDirectory();
|
||||
return databaseFactory.databaseExists(directory.path + 'cache.db');
|
||||
}
|
||||
|
||||
Future<void> updateCatsList() async{
|
||||
Future<void> updateCatsList() async {
|
||||
//print('Updating with localCache');
|
||||
// categories = await GetCategories(true);
|
||||
// categories = await GetCategories(true);
|
||||
print('Checking if can refresh');
|
||||
categories = await GetCategories(false);
|
||||
}
|
||||
|
||||
Future<void> updateTasksList() async{
|
||||
// print('Updating with localCache');
|
||||
// taskTypes = await GetTaskTypes(true);
|
||||
Future<void> updateTasksList() async {
|
||||
// print('Updating with localCache');
|
||||
// taskTypes = await GetTaskTypes(true);
|
||||
print('Checking if can refresh');
|
||||
taskTypes = await GetTaskTypes(false);
|
||||
}
|
||||
|
||||
Future<void> updateActList() async{
|
||||
Future<void> updateActList() async {
|
||||
//print('Updating with localCache');
|
||||
//activities = await GetActivities(true);
|
||||
print('Checking if can refresh');
|
||||
activities = await GetActivities(false);
|
||||
}
|
||||
|
||||
|
||||
Future<void> initCacheDatabase() async {
|
||||
Directory directory = await getApplicationDocumentsDirectory();
|
||||
print('database at ' + directory.path + 'cache.db');
|
||||
@@ -113,22 +104,20 @@ Future<void> initCacheDatabase() async {
|
||||
}
|
||||
|
||||
void onCacheDatabaseCreate(Database db, int newVersion) async {
|
||||
String CategoriesTableSQL =
|
||||
'CREATE TABLE Categories(${Category.colCatId} VARCHAR(255) PRIMARY KEY,${Category.colName} TEXT, ${Category.colColor} TEXT, ${Category.colProductive} INTEGER)';
|
||||
String CategoriesTableSQL = 'CREATE TABLE Categories(${Category.colCatId} VARCHAR(255) PRIMARY KEY,${Category.colName} TEXT, ${Category.colColor} TEXT, ${Category.colProductive} INTEGER)';
|
||||
// print(CategoriesTableSQL);
|
||||
await db.execute(CategoriesTableSQL);
|
||||
print("Initiated Categories Table");
|
||||
|
||||
String TaskTableSQL =
|
||||
'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, '
|
||||
String TaskTableSQL = 'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, '
|
||||
'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))';
|
||||
// print(TaskTableSQL);
|
||||
// print(TaskTableSQL);
|
||||
await db.execute(TaskTableSQL);
|
||||
|
||||
String ActivityTableSQL =
|
||||
'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, ${Activity.colMetadata} TEXT, '
|
||||
'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
|
||||
// print(ActivityTableSQL);
|
||||
// print(ActivityTableSQL);
|
||||
await db.execute(ActivityTableSQL);
|
||||
|
||||
String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)';
|
||||
@@ -136,24 +125,23 @@ void onCacheDatabaseCreate(Database db, int newVersion) async {
|
||||
await db.execute(QueriesTableSQL);
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
if(prefs.getBool("registered") ?? false) {
|
||||
if (prefs.getBool("registered") ?? false) {
|
||||
addInitialDataToCache();
|
||||
prefs.setBool("registered", false);
|
||||
}
|
||||
// GetCategories();
|
||||
// GetCategories();
|
||||
}
|
||||
|
||||
Future<void> addInitialDataToCache() async{
|
||||
ShowProgress("Initializing User Data");
|
||||
Future<void> addInitialDataToCache() async {
|
||||
print("adding init data");
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
//Insert Initial Entries
|
||||
for(Category element in InitialData.getCategories(username)){
|
||||
await UserOperations.addCategory(element.name, element.color, element.productive,bulk: true);
|
||||
for (Category element in InitialData.getCategories(username)) {
|
||||
await UserOperations.addCategory(element.name, element.color, element.productive, bulk: true);
|
||||
}
|
||||
|
||||
for(TaskType element in InitialData.getTaskTypes(username)){
|
||||
for (TaskType element in InitialData.getTaskTypes(username)) {
|
||||
await UserOperations.addTaskType(element.name, element.category, bulk: true);
|
||||
// Map<String,Object> data = {
|
||||
// TaskType.colName: element.name,
|
||||
@@ -161,7 +149,6 @@ Future<void> addInitialDataToCache() async{
|
||||
// };
|
||||
// await cacheDb.insert('TaskTypes', data);
|
||||
}
|
||||
HideProgress();
|
||||
await UserOperations.executeQueries();
|
||||
await refreshUserData();
|
||||
}
|
||||
@@ -171,281 +158,250 @@ void onCacheDatabaseUpgrade(Database db, int oldVersion, int newVersion) async {
|
||||
print('Upgrading CacheDB from ver.$oldVersion to ver.$newVersion');
|
||||
}
|
||||
|
||||
|
||||
Future<List<Category>> GetCategories(bool forceOffline) async{
|
||||
Future<List<Category>> GetCategories(bool forceOffline) async {
|
||||
List<Category> _categories = [];
|
||||
if(offline || forceOffline){
|
||||
if (offline || forceOffline) {
|
||||
//Retreive from cacheDB
|
||||
|
||||
}else{
|
||||
} else {
|
||||
//Check if server got updated, If not go for cache
|
||||
var android_id = await Settings.UUID();
|
||||
|
||||
//Validate device_id to check updates
|
||||
|
||||
bool catsUpdated = true;
|
||||
try{
|
||||
http.Response update_response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
|
||||
body: <String, String>{"username": username, "device_id":android_id}));
|
||||
try {
|
||||
http.Response update_response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
|
||||
final data = update_response.body.split(',');
|
||||
catsUpdated = data[0] == '1';
|
||||
}catch(e){
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
print("Need to update : ${!catsUpdated}");
|
||||
|
||||
//Update CacheDB
|
||||
//if(!catsUpdated){
|
||||
await UpdateCategoriesFromServer();
|
||||
// }
|
||||
if(!catsUpdated){
|
||||
await UpdateCategoriesFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
List<Map> cats = await cacheDb.query('Categories');
|
||||
print(cats.length);
|
||||
for(Map element in cats){
|
||||
for (Map element in cats) {
|
||||
String? catName = element[Category.colName].toString();
|
||||
String? catColor = element[Category.colColor].toString();
|
||||
String? catProductive = element[Category.colProductive].toString();
|
||||
if(catName==null || catColor==null || catProductive==null){
|
||||
if (catName == null || catColor == null || catProductive == null) {
|
||||
print("Something is null!");
|
||||
print("name:{$catName}, color:{$catColor}, prod:{$Category.colProductive}");
|
||||
continue;
|
||||
}
|
||||
print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
|
||||
// print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
|
||||
_categories.add(Category(username + catName, catName, catColor, ParseBool(catProductive)));
|
||||
}
|
||||
categories = _categories;
|
||||
return categories;
|
||||
}
|
||||
|
||||
Future<void> UpdateCategoriesFromServer() async{
|
||||
|
||||
Future<void> UpdateCategoriesFromServer() async {
|
||||
print("Updating Categories as $username");
|
||||
try {
|
||||
http.Response response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/get_categories.php'),
|
||||
body: <String, String>{
|
||||
"username": username,
|
||||
"device_id": await Settings.UUID()
|
||||
}));
|
||||
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/get_categories.php'), body: <String, String>{"username": username, "device_id": await Settings.UUID()}));
|
||||
|
||||
print(response.body);
|
||||
List<String> data = response.body.split("<td>");
|
||||
// await cacheDb.delete("Categories");
|
||||
// await cacheDb.delete("Categories");
|
||||
for (var value in data) {
|
||||
Map<String, dynamic> cat = jsonDecode(value);
|
||||
//print(catData);
|
||||
await cacheDb.rawInsert(
|
||||
"INSERT OR REPLACE INTO Categories (${Category.colCatId},${Category
|
||||
.colName},${Category.colProductive},${Category.colColor}) "
|
||||
"VALUES ('${cat['category_id']}','${cat['name']}',${cat['productive']},'${cat['color']}') ");
|
||||
await cacheDb.rawInsert("INSERT OR REPLACE INTO Categories (${Category.colCatId},${Category.colName},${Category.colProductive},${Category.colColor}) "
|
||||
"VALUES ('${cat['category_id']}','${cat['name']}',${cat['productive']},'${cat['color']}') ");
|
||||
}
|
||||
}catch(e){
|
||||
offline=true;
|
||||
} catch (e) {
|
||||
print("Error while cats $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<TaskType>> GetTaskTypes(bool forceOffline) async{
|
||||
Future<List<TaskType>> GetTaskTypes(bool forceOffline) async {
|
||||
List<TaskType> _taskTypes = [];
|
||||
if(offline || forceOffline){
|
||||
if (offline || forceOffline) {
|
||||
//Retreive from cacheDB
|
||||
|
||||
}else{
|
||||
} else {
|
||||
//Check if server got updated, If not go for cache
|
||||
var android_id = await Settings.UUID();
|
||||
|
||||
bool updated =true;
|
||||
try{
|
||||
bool updated = true;
|
||||
try {
|
||||
//Validate device_id to check updates
|
||||
http.Response update_response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
|
||||
body: <String, String>{"username": username, "device_id":android_id}));
|
||||
http.Response update_response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
|
||||
final data = update_response.body.split(',');
|
||||
updated = data[1] == '1';
|
||||
}catch(e){
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
print("Need to update : ${!updated}");
|
||||
|
||||
//Update CacheDB
|
||||
// if(!updated){
|
||||
await UpdateTaskTypesFromServer();
|
||||
// }
|
||||
if(!updated){
|
||||
await UpdateTaskTypesFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
|
||||
List<Map> cats = await cacheDb.query('TaskTypes');
|
||||
print(cats.length);
|
||||
for(Map element in cats){
|
||||
for (Map element in cats) {
|
||||
String? id = element[TaskType.colId].toString();
|
||||
String? name = element[TaskType.colName].toString();
|
||||
String? category = element[TaskType.colCategory].toString();
|
||||
Category? cat = await getCatFromId(category);
|
||||
if(id==null || name==null || category==null){
|
||||
if (id == null || name == null || category == null) {
|
||||
print("Something is null!");
|
||||
print("name:{$name}, cat:{$category}, prod:{$id}");
|
||||
continue;
|
||||
}
|
||||
print("name:{$name}, cat:{$category}, prod:{$id}");
|
||||
_taskTypes.add(TaskType(id,name,category,cat));
|
||||
// print("name:{$name}, cat:{$category}, prod:{$id}");
|
||||
_taskTypes.add(TaskType(id, name, category, cat));
|
||||
}
|
||||
taskTypes = _taskTypes;
|
||||
return taskTypes;
|
||||
}
|
||||
|
||||
Future<void> UpdateTaskTypesFromServer() async{
|
||||
|
||||
|
||||
// await GetCategories(true);
|
||||
Future<void> UpdateTaskTypesFromServer() async {
|
||||
// await GetCategories(true);
|
||||
print("Updating TaskTypes as $username");
|
||||
try {
|
||||
http.Response response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/get_taskTypes.php'),
|
||||
body: <String, String>{
|
||||
"username": username,
|
||||
"device_id": await Settings.UUID()
|
||||
}));
|
||||
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/get_taskTypes.php'), body: <String, String>{"username": username, "device_id": await Settings.UUID()}));
|
||||
|
||||
print(response.body);
|
||||
List<String> data = response.body.split("<td>");
|
||||
await cacheDb.delete("TaskTypes");
|
||||
for (var value in data) {
|
||||
Map<String, dynamic> cat = jsonDecode(value);
|
||||
print(cat);
|
||||
await cacheDb.rawInsert(
|
||||
"INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType
|
||||
.colName},${TaskType.colCategory}) "
|
||||
"VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}') ");
|
||||
//print(cat);
|
||||
await cacheDb.rawInsert("INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType.colName},${TaskType.colCategory}) "
|
||||
"VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}') ");
|
||||
|
||||
print(await cacheDb.query("TaskTypes"));
|
||||
}
|
||||
}catch(e){
|
||||
offline=true;
|
||||
} catch (e) {
|
||||
print("Error while tasks $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Activity>> GetActivities(bool forceOffline) async{
|
||||
Future<List<Activity>> GetActivities(bool forceOffline) async {
|
||||
List<Activity> _activities = [];
|
||||
if(offline || forceOffline){
|
||||
if (offline || forceOffline) {
|
||||
//Retreive from cacheDB
|
||||
print('offline, refreshing activities');
|
||||
}else{
|
||||
} else {
|
||||
//Check if server got updated, If not go for cache
|
||||
var android_id = await Settings.UUID();
|
||||
|
||||
bool updated =true;
|
||||
try{
|
||||
bool updated = true;
|
||||
try {
|
||||
//Validate device_id to check updates
|
||||
http.Response update_response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/check_update.php'),
|
||||
body: <String, String>{"username": username, "device_id":android_id}));
|
||||
http.Response update_response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/check_update.php'), body: <String, String>{"username": username, "device_id": android_id}));
|
||||
final data = update_response.body.split(',');
|
||||
updated = data[2] == '1';
|
||||
}catch(e){
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
print("Need to update activities : ${!updated}");
|
||||
|
||||
//Update CacheDB
|
||||
//if(!updated){
|
||||
await UpdateActivitiesFromServer();
|
||||
//}
|
||||
if(!updated){
|
||||
await UpdateActivitiesFromServer();
|
||||
}
|
||||
}
|
||||
|
||||
List<Map> cats = await cacheDb.rawQuery('SELECT * FROM Activities ORDER BY ${Activity.colStartTime} DESC');
|
||||
print(cats.length);
|
||||
for(Map element in cats){
|
||||
for (Map element in cats) {
|
||||
String? type = element[Activity.colType].toString();
|
||||
String? startTime = element[Activity.colStartTime].toString();
|
||||
String? endTime = element[Activity.colEndTime].toString();
|
||||
String? metadata = element[Activity.colMetadata].toString();
|
||||
TaskType? taskType = await getTaskFromId(type);
|
||||
if(type==null || startTime==null || endTime==null || taskType==null){
|
||||
print("Something is null!\ntype:${type==null}, startTime:${startTime==null}, eTime:${endTime==null}, taskType${taskType==null}");
|
||||
if (type == null || startTime == null || endTime == null || taskType == null) {
|
||||
print("Something is null!\ntype:${type == null}, startTime:${startTime == null}, eTime:${endTime == null}, taskType${taskType == null}");
|
||||
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
|
||||
continue;
|
||||
}
|
||||
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
|
||||
//print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}");
|
||||
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime), metadata: metadata));
|
||||
}
|
||||
activities = _activities;
|
||||
return activities;
|
||||
}
|
||||
|
||||
Future<void> UpdateActivitiesFromServer() async{
|
||||
|
||||
Future<void> UpdateActivitiesFromServer() async {
|
||||
print("Updating Activities as $username");
|
||||
|
||||
try {
|
||||
http.Response response = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/get_activities.php'),
|
||||
body: <String, String>{
|
||||
"username": username,
|
||||
"device_id": await Settings.UUID()
|
||||
}));
|
||||
http.Response response = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/get_activities.php'), body: <String, String>{"username": username, "device_id": await Settings.UUID()}));
|
||||
|
||||
await cacheDb.rawDelete("DELETE FROM Activities");
|
||||
print('Truncate Activity Table before');
|
||||
|
||||
print("Activity response: ${response.body}");
|
||||
if(response.body.contains("{")){
|
||||
List<String> data = response.body.split("<td>");
|
||||
if (response.body.contains("{")) {
|
||||
List<String> data = response.body.split("<td>");
|
||||
|
||||
for (var value in data){
|
||||
Map<String, dynamic> cat = jsonDecode(value);
|
||||
print(cat);
|
||||
await cacheDb.rawInsert(
|
||||
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
|
||||
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata']}') ");
|
||||
}
|
||||
}else{
|
||||
for (var value in data) {
|
||||
Map<String, dynamic> cat = jsonDecode(value);
|
||||
//print(cat);
|
||||
await cacheDb.rawInsert("INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) "
|
||||
"VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata']}') ");
|
||||
}
|
||||
} else {
|
||||
print("No activities for now");
|
||||
}
|
||||
}catch(e){
|
||||
} catch (e) {
|
||||
print("Error : $e @ updating activities");
|
||||
offline=true;
|
||||
print("Error while acts $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<TaskType?> getTaskFromId(String taskId) async{
|
||||
Future<TaskType?> getTaskFromId(String taskId) async {
|
||||
// await GetTaskTypes(false);
|
||||
TaskType? cat = null;
|
||||
for (var element in taskTypes){
|
||||
if(element.id == taskId){
|
||||
cat= element;
|
||||
for (var element in taskTypes) {
|
||||
if (element.id == taskId) {
|
||||
cat = element;
|
||||
cat?.cat = await getCatFromId((cat?.category ?? ''));
|
||||
}
|
||||
}
|
||||
if(cat==null){
|
||||
if (cat == null) {
|
||||
print('Got null tasktype for ${taskId} after searching on ${taskTypes.length}');
|
||||
}
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
Future<Category?> getCatFromId(String catId) async{
|
||||
// await GetTaskTypes(false);
|
||||
Future<Category?> getCatFromId(String catId) async {
|
||||
// await GetTaskTypes(false);
|
||||
Category? cat = null;
|
||||
for (var element in categories) {
|
||||
if(element.category_id == catId){
|
||||
cat= element;
|
||||
if (element.category_id == catId) {
|
||||
cat = element;
|
||||
}
|
||||
}
|
||||
|
||||
return cat;
|
||||
}
|
||||
|
||||
|
||||
//Helpers
|
||||
class Helpers {
|
||||
Future<String?> _getId() async {
|
||||
var deviceInfo = DeviceInfoPlugin();
|
||||
if (Platform.isIOS) { // import 'dart:io'
|
||||
if (Platform.isIOS) {
|
||||
// import 'dart:io'
|
||||
var iosDeviceInfo = await deviceInfo.iosInfo;
|
||||
return iosDeviceInfo.identifierForVendor; // unique ID on iOS
|
||||
} else {
|
||||
@@ -454,228 +410,185 @@ class Helpers {
|
||||
}
|
||||
}
|
||||
}
|
||||
bool ParseBool(obj){
|
||||
return obj.toString().toLowerCase()=="true" || obj.toString()=="1";
|
||||
|
||||
bool ParseBool(obj) {
|
||||
return obj.toString().toLowerCase() == "true" || obj.toString() == "1";
|
||||
}
|
||||
|
||||
class UserOperations {
|
||||
static DateFormat dFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
class UserOperations{
|
||||
static Future<void> addCategory(String name, String color, bool productive, {bool bulk = false}) async{
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
'name' : name,
|
||||
'color':color,
|
||||
'productive': productive ? '1':'0'
|
||||
};
|
||||
static Future<void> addCategory(String name, String color, bool productive, {bool bulk = false}) async {
|
||||
Map<String, String> queryBody = <String, String>{'username': username, 'device_id': await Settings.UUID(), 'name': name, 'color': color, 'productive': productive ? '1' : '0'};
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'add_category',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String,Object> data = {
|
||||
Category.colCatId: username+name,
|
||||
Category.colName: name,
|
||||
Category.colColor: color,
|
||||
Category.colProductive: productive
|
||||
};
|
||||
await cacheDb.insert('Categories', data);
|
||||
|
||||
await GetCategories(true);
|
||||
if(!bulk){
|
||||
//Add to server and refresh Cache
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> addTaskType(String name, String category, {bool bulk = false}) async{
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
'id':username+name,
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
'name' : name,
|
||||
'category': username + category
|
||||
};
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'add_taskType',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
Map<String, Object> query = {Queries.colLink: 'add_category', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String,Object> data = {
|
||||
TaskType.colId: username+name,
|
||||
Category.colName: name,
|
||||
Category.colCatId: username + category
|
||||
};
|
||||
await cacheDb.insert('TaskTypes', data);
|
||||
await GetTaskTypes(true);
|
||||
if(!bulk){
|
||||
Map<String, Object> data = {Category.colCatId: username + name, Category.colName: name, Category.colColor: color, Category.colProductive: productive};
|
||||
await cacheDb.insert('Categories', data);
|
||||
await refreshUserData();
|
||||
if (!bulk) {
|
||||
//Add to server and refresh Cache
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> addActivity(String type, String sTime,String eTime, {String metadata = 'null',bool bulk = false, Function(int)? onOverlap}) async{
|
||||
static Future<void> addTaskType(String name, String category, {bool bulk = false}) async {
|
||||
Map<String, String> queryBody = <String, String>{'id': username + name, 'username': username, 'device_id': await Settings.UUID(), 'name': name, 'category': username + category};
|
||||
//Add Query
|
||||
Map<String, Object> query = {Queries.colLink: 'add_taskType', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String, Object> data = {TaskType.colId: username + name, Category.colName: name, Category.colCatId: username + category};
|
||||
await cacheDb.insert('TaskTypes', data);
|
||||
await refreshUserData();
|
||||
if (!bulk) {
|
||||
//Add to server and refresh Cache
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> addActivity(String type, DateTime sTime, DateTime eTime, {String metadata = 'null', bool bulk = false, Function(int)? onOverlap}) async {
|
||||
//Check for timeoverlapse
|
||||
activities= await GetActivities(true);
|
||||
int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery("SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))"));
|
||||
activities = await GetActivities(true);
|
||||
int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery(
|
||||
"SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))"));
|
||||
|
||||
print("ActivityOverlaps: $overlapCount");
|
||||
if(overlapCount! > 0){
|
||||
if (overlapCount! > 0) {
|
||||
onOverlap!(overlapCount);
|
||||
return;
|
||||
}
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
Map<String, String> queryBody = <String, String>{
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
'type' : username+type,
|
||||
'sTime': sTime,
|
||||
'eTime':eTime,
|
||||
'type': username + type,
|
||||
'sTime': dFormat.format(sTime),
|
||||
'eTime': dFormat.format(eTime),
|
||||
'metadata': metadata
|
||||
};
|
||||
|
||||
if(metadata.length > 0){
|
||||
|
||||
}
|
||||
if (metadata.length > 0) {}
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'add_activity',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
Map<String, Object> query = {Queries.colLink: 'add_activity', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String,Object> data = {
|
||||
Activity.colType: username+type,
|
||||
Activity.colStartTime: sTime,
|
||||
Activity.colEndTime: eTime,
|
||||
Activity.colMetadata: metadata
|
||||
};
|
||||
Map<String, Object> data = {Activity.colType: username + type, Activity.colStartTime: dFormat.format(sTime), Activity.colEndTime: dFormat.format(eTime), Activity.colMetadata: metadata};
|
||||
await cacheDb.insert('Activities', data);
|
||||
activities= await GetActivities(false);
|
||||
if(!bulk){
|
||||
await refreshUserData();
|
||||
if (!bulk) {
|
||||
//Add to server and refresh Cache
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> deleteTask(String name,{bulk=false}) async{
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
'id':username+name,
|
||||
static Future<void> deleteTask(String name, {bulk = false}) async {
|
||||
Map<String, String> queryBody = <String, String>{
|
||||
'id': username + name,
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
};
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'delete_taskType',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
Map<String, Object> query = {Queries.colLink: 'delete_taskType', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String,Object> data = {
|
||||
TaskType.colId: username+name,
|
||||
Map<String, Object> data = {
|
||||
TaskType.colId: username + name,
|
||||
Category.colName: name,
|
||||
};
|
||||
await cacheDb.rawDelete("DELETE FROM TaskTypes WHERE id='${username+name}'");
|
||||
await GetTaskTypes(true);
|
||||
//Add to server and refresh Cache
|
||||
await cacheDb.rawDelete("DELETE FROM TaskTypes WHERE id='${username + name}'");
|
||||
|
||||
if(!bulk) {
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> deleteCategory(String name,{bulk=false}) async{
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
'id':username+name,
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID() ,
|
||||
};
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'delete_category',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String,Object> data = {
|
||||
TaskType.colId: username+name,
|
||||
Category.colName: name,
|
||||
};
|
||||
await cacheDb.rawDelete("DELETE FROM Categories WHERE ${Category.colCatId}='${username+name}'");
|
||||
await GetCategories(true);
|
||||
await refreshUserData();
|
||||
//Add to server and refresh Cache
|
||||
|
||||
if(!bulk) {
|
||||
if (!bulk) {
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> deleteActivity(Activity activity,{bulk=false}) async{
|
||||
Map<String,String> queryBody= <String,String>{
|
||||
static Future<void> deleteCategory(String name, {bulk = false}) async {
|
||||
Map<String, String> queryBody = <String, String>{
|
||||
'id': username + name,
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
};
|
||||
//Add Query
|
||||
Map<String, Object> query = {Queries.colLink: 'delete_category', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
Map<String, Object> data = {
|
||||
TaskType.colId: username + name,
|
||||
Category.colName: name,
|
||||
};
|
||||
await cacheDb.rawDelete("DELETE FROM Categories WHERE ${Category.colCatId}='${username + name}'");
|
||||
await refreshUserData();
|
||||
//Add to server and refresh Cache
|
||||
|
||||
if (!bulk) {
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> deleteActivity(Activity activity, {bulk = false}) async {
|
||||
Map<String, String> queryBody = <String, String>{
|
||||
'username': username,
|
||||
'device_id': await Settings.UUID(),
|
||||
'sTime': activity.startTime.toString(),
|
||||
'eTime':activity.endTime.toString(),
|
||||
'eTime': activity.endTime.toString(),
|
||||
};
|
||||
//Add Query
|
||||
Map<String,Object> query = {
|
||||
Queries.colLink: 'delete_activity',
|
||||
Queries.colData: jsonEncode(queryBody)
|
||||
};
|
||||
Map<String, Object> query = {Queries.colLink: 'delete_activity', Queries.colData: jsonEncode(queryBody)};
|
||||
|
||||
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
|
||||
|
||||
await cacheDb.insert('Queries', query);
|
||||
|
||||
//update Cache
|
||||
// Map<String,Object> data = {
|
||||
// TaskType.colId: username+name,
|
||||
// Category.colName: name,
|
||||
// };
|
||||
// await cacheDb.rawDelete("DELETE FROM Categories WHERE ${Category.colCatId}='${username+name}'");
|
||||
await GetCategories(true);
|
||||
String deleteQuery =
|
||||
"DELETE FROM Activities WHERE ${Activity.colStartTime}=datetime('${dFormat.format(activity.startTime)}') AND ${Activity.colEndTime}=datetime('${dFormat.format(activity.endTime)}')";
|
||||
print("delteQuery : $deleteQuery");
|
||||
|
||||
await cacheDb.rawDelete(deleteQuery);
|
||||
await refreshUserData();
|
||||
//Add to server and refresh Cache
|
||||
|
||||
if(!bulk) {
|
||||
if (!bulk) {
|
||||
await executeQueries();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> executeQueries() async{
|
||||
if(offline){
|
||||
static Future<void> executeQueries() async {
|
||||
if (offline) {
|
||||
print("Cannot executre queries, Offline!");
|
||||
return;
|
||||
}
|
||||
ShowProgress("Syncing");
|
||||
List<Map<String,Object?>> queries = await cacheDb.query('Queries');
|
||||
List<Map<String, Object?>> queries = await cacheDb.query('Queries');
|
||||
|
||||
for(Map<String,Object?> element in queries){
|
||||
for (Map<String, Object?> element in queries) {
|
||||
int id = int.parse(element['id'].toString());
|
||||
String? file = element[Queries.colLink].toString();
|
||||
String? data = element[Queries.colData].toString();
|
||||
if(file==null || data==null){
|
||||
if (file == null || data == null) {
|
||||
print("Null query, Ignoring...");
|
||||
continue;
|
||||
}
|
||||
@@ -684,27 +597,16 @@ class UserOperations{
|
||||
//Execute the http here
|
||||
Map<String, dynamic> body = jsonDecode(data);
|
||||
try {
|
||||
http.Response queryResponse = (await http.post(
|
||||
Uri.parse('http://161.97.127.136/task_tracker/$file.php'),
|
||||
body: body));
|
||||
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/$file.php'), body: body));
|
||||
print("Query executed : Results{${queryResponse.body}");
|
||||
if (queryResponse.body.toLowerCase().contains("success")) {
|
||||
await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id');
|
||||
}
|
||||
offline=false;
|
||||
}catch(e){
|
||||
offline=true;
|
||||
offline = false;
|
||||
} catch (e) {
|
||||
print("Error while query $e");
|
||||
}
|
||||
}
|
||||
HideProgress();
|
||||
await refreshUserData();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowProgress(msg){
|
||||
//try{progressDialog?.show(max: 100, msg: msg);}catch(e){}
|
||||
}
|
||||
|
||||
void HideProgress(){
|
||||
// try{progressDialog?.update(value: 100);}catch(e){}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -392,7 +392,7 @@ class _onlineLoginPageState extends State<onlineLoginPage>
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString("username", usernameController.text);
|
||||
prefs.setString("password", passwordController.text);
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/splash', (route) => false);
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
}else{
|
||||
showAlertDialog(context, "Failed to login", "There was an error trying to authorize you in servers.");
|
||||
}
|
||||
|
||||
166
lib/main.dart
166
lib/main.dart
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -14,11 +16,10 @@ import 'newActivity.dart';
|
||||
import 'Tasks.dart';
|
||||
import 'Activities.dart';
|
||||
import 'User.dart' as User;
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
late ProgressDialog progressDialog;
|
||||
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'Dialogs.dart';
|
||||
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
||||
showAlertDialog(BuildContext context, String title, String message) {
|
||||
// set up the button
|
||||
Widget okButton = TextButton(
|
||||
@@ -73,27 +74,28 @@ class MyApp extends StatelessWidget {
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) => ChangeNotifierProvider(
|
||||
create: (context)=>ThemeProvider(),
|
||||
builder: (context, _){
|
||||
create: (context) => ThemeProvider(),
|
||||
builder: (context, _) {
|
||||
final themeProvider = Provider.of<ThemeProvider>(context);
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Task Tracker',
|
||||
themeMode: themeProvider.themeMode,
|
||||
theme: ThemeData(accentColor: Colors.redAccent,brightness: Brightness.light, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
|
||||
darkTheme: ThemeData(accentColor: Colors.redAccent,brightness: Brightness.dark, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
|
||||
//home: const MyHomePage(),
|
||||
initialRoute: '/splash',
|
||||
routes: {
|
||||
'/splash': (context) => const SplashScreen(),
|
||||
'/welcome': (context) => const WelcomePage(),
|
||||
'/': (context) => const MyHomePage(),
|
||||
'/Tasks': (context) => const Tasks(),
|
||||
'/Categories': (context) => const Categories(),
|
||||
'/Activities': (context) => const Activities(),
|
||||
'/Settings':(context) => const SettingsPage()
|
||||
});
|
||||
});
|
||||
title: 'Task Tracker',
|
||||
themeMode: themeProvider.themeMode,
|
||||
theme: ThemeData(accentColor: Colors.redAccent, brightness: Brightness.light, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
|
||||
darkTheme: ThemeData(accentColor: Colors.redAccent, brightness: Brightness.dark, primaryColor: Colors.amber, fontFamily: 'Noto-Sans'),
|
||||
navigatorKey: navigatorKey,
|
||||
//home: const SplashScreen(),
|
||||
initialRoute: '/',
|
||||
routes: {
|
||||
'/': (context) => const SplashScreen(),
|
||||
'/welcome': (context) => const WelcomePage(),
|
||||
'/home': (context) => const MyHomePage(),
|
||||
'/Tasks': (context) => const Tasks(),
|
||||
'/Categories': (context) => const Categories(),
|
||||
'/Activities': (context) => const Activities(),
|
||||
'/Settings': (context) => const SettingsPage()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
List<String> days = [];
|
||||
@@ -135,24 +137,48 @@ class MyHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
var connectivitySub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
print("Im home!");
|
||||
init(context);
|
||||
super.initState();
|
||||
// User.refreshUserData().then((val) => LoadStats());
|
||||
// showOfflineSnack();
|
||||
print("Initializing refresh stream on main dart");
|
||||
LoadStats();
|
||||
// progressDialog = ProgressDialog(context: context);
|
||||
connectivitySub=Connectivity().onConnectivityChanged.listen((result) {
|
||||
if (this.mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
|
||||
// User.progressDialog=progressDialog;
|
||||
}
|
||||
var refreshSub;
|
||||
void init(BuildContext context) async{
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
refreshSub = User.refreshStream.stream.listen((value) {
|
||||
print("Streaming refresh : $value");
|
||||
if(value){
|
||||
Dialogs.waiting("Syncing...");
|
||||
print("Opening progress dialog");
|
||||
}else{
|
||||
Dialogs.hide();
|
||||
print("Closing progress dialog");
|
||||
}
|
||||
});
|
||||
}
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
connectivitySub?.cancel();
|
||||
}
|
||||
|
||||
void LoadStats() async {
|
||||
// return;
|
||||
|
||||
while (!User.userDataInitiated) {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
}
|
||||
|
||||
DateFormat dFormat = DateFormat("MM/dd");
|
||||
Map<Category, int> catTimeMap = <Category, int>{};
|
||||
Map<Category, int> catBriefMap = <Category, int>{};
|
||||
@@ -163,7 +189,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
firstDay = null;
|
||||
lastDay = null;
|
||||
String lastDate = "";
|
||||
days=[];
|
||||
days = [];
|
||||
for (var element in User.activities) {
|
||||
if (lastDay == null) {
|
||||
lastDay = element.endTime;
|
||||
@@ -248,7 +274,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
Color barCol = HexColor.fromHex(key.color);
|
||||
dailyData.add(CatMapData(key.name, value, barCol));
|
||||
});
|
||||
dailyData.sort((a,b){
|
||||
dailyData.sort((a, b) {
|
||||
return a.name.toLowerCase().compareTo(b.name.toLowerCase());
|
||||
});
|
||||
for (var element in days) {
|
||||
@@ -265,7 +291,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
taskTypesData.add(TaskTypeMapData(key.name, value, HexColor.fromHex(key.cat!.color)));
|
||||
});
|
||||
|
||||
taskTypesData.sort((a,b){
|
||||
taskTypesData.sort((a, b) {
|
||||
return a.time.compareTo(b.time);
|
||||
});
|
||||
|
||||
@@ -274,7 +300,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
Color barCol = HexColor.fromHex(key.color);
|
||||
catsData.add(CatMapData(key.name, value, barCol));
|
||||
});
|
||||
catsData.sort((a,b)=> a.time.compareTo(b.time));
|
||||
catsData.sort((a, b) => a.time.compareTo(b.time));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -299,26 +325,46 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
},
|
||||
label: Text("New Activity"),
|
||||
icon: Icon(Icons.add)),
|
||||
appBar: AppBar(title: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
appBar: AppBar(
|
||||
title: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Row(children: [Icon(Icons.article_outlined, color: Theme.of(context).primaryColor), SizedBox(width: 10), Text('Summary')]),
|
||||
Row(children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
LoadStats();
|
||||
});
|
||||
},
|
||||
child: Icon(Icons.refresh, size: 30),
|
||||
)
|
||||
],)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [Icon(Icons.article_outlined, color: Theme.of(context).primaryColor), SizedBox(width: 10), Text('Summary')]),
|
||||
Row(
|
||||
children: [
|
||||
(User.offline)
|
||||
? Icon(Icons.signal_cellular_connected_no_internet_4_bar_outlined)
|
||||
: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
LoadStats();
|
||||
});
|
||||
},
|
||||
child: Icon(Icons.refresh, size: 30),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
//Container(color: Colors.red,child: Text("Offline",style:TextStyle(fontSize: 5))),
|
||||
],
|
||||
)),
|
||||
drawer: navDrawer(context, 0),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: (User.activities.isEmpty) ? Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center
|
||||
,children:[
|
||||
Expanded(flex: 1,child: Container(),),
|
||||
Expanded(flex: 2,child: Image(image: AssetImage('images/empty.png'))),
|
||||
Expanded(flex:2,child: Text("Add your first activity to access Summary",style: TextStyle(color: Colors.grey, fontStyle: FontStyle.italic),))
|
||||
]) :SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -397,11 +443,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
xValueMapper: (ProductivityMapData sales, _) => sales.day,
|
||||
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
|
||||
dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
|
||||
dataLabelSettings: DataLabelSettings(
|
||||
overflowMode: OverflowMode.hide,
|
||||
showZeroValue: false,
|
||||
isVisible: true
|
||||
),
|
||||
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
|
||||
color: Colors.green)
|
||||
]),
|
||||
)
|
||||
@@ -602,7 +644,7 @@ Drawer navDrawer(BuildContext context, int pageIndex) {
|
||||
if (pageIndex == 0) {
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pushReplacementNamed('/');
|
||||
Navigator.of(context).pushReplacementNamed('/home');
|
||||
},
|
||||
),
|
||||
// ListTile(
|
||||
@@ -652,6 +694,18 @@ Drawer navDrawer(BuildContext context, int pageIndex) {
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
ListTile(
|
||||
selected: (pageIndex == 7),
|
||||
title: Text('TODO'),
|
||||
leading: Icon(Icons.check, color: Theme.of(context).primaryColor),
|
||||
onTap: () {
|
||||
if (pageIndex == 7) {
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pushReplacementNamed('/Todo');
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
ListTile(
|
||||
selected: (pageIndex == 5),
|
||||
title: Text('Settings'),
|
||||
@@ -667,7 +721,9 @@ Drawer navDrawer(BuildContext context, int pageIndex) {
|
||||
selected: (pageIndex == 6),
|
||||
title: Text('About'),
|
||||
leading: Icon(Icons.help_outline_outlined),
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
showAboutDialog(context: context);
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tasktracker/main.dart';
|
||||
import 'User.dart' as User;
|
||||
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
DateFormat durationFormat = DateFormat("HH:mm:ss");
|
||||
@@ -292,16 +293,21 @@ class _NewActivity extends State<NewActivity> {
|
||||
}
|
||||
|
||||
void add_action() async{
|
||||
|
||||
print('adding Task Type : $selectedCat at $startTime - $endTime');
|
||||
bool failed=false;
|
||||
await User.UserOperations.addActivity(selectedCat,startTime.toString(), endTime.toString(),metadata:metadataController.text, onOverlap: (overlapCount){
|
||||
await User.UserOperations.addActivity(selectedCat,startTime, endTime,metadata:metadataController.text, onOverlap: (overlapCount){
|
||||
showAlertDialog(context, 'Error adding activity', 'Cannot add activity between ${dateFormat.format(startTime)} - ${dateFormat.format(endTime)}, $overlapCount activities are already added within this time range');
|
||||
failed=true;
|
||||
});
|
||||
|
||||
if(!failed)
|
||||
Navigator.of(context).pop();
|
||||
if(!failed) {
|
||||
print("popping : ${navigatorKey.currentWidget?.toStringShort() ?? "n/a"}");
|
||||
Navigator.of(navigatorKey.currentContext!).popUntil((route){
|
||||
return route.isFirst;
|
||||
});
|
||||
}else{
|
||||
print("Failed adding new activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tasktracker/Data.dart';
|
||||
import 'User.dart' as Users;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:sn_progress_dialog/sn_progress_dialog.dart';
|
||||
import 'theme_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
late ProgressDialog progressDialog;
|
||||
import 'newActivity.dart';
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({Key? key}) : super(key: key);
|
||||
|
||||
@@ -31,11 +32,41 @@ class _SplashScreenState extends State<SplashScreen> {
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
progressDialog = ProgressDialog(context: context);
|
||||
Users.progressDialog=progressDialog;
|
||||
init();
|
||||
initNotifications();
|
||||
|
||||
}
|
||||
|
||||
void initNotifications() async{
|
||||
var androidInitilize = new AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
var iOSinitilize = new IOSInitializationSettings();
|
||||
|
||||
var initilizationsSettings =
|
||||
new InitializationSettings(android: androidInitilize, iOS: iOSinitilize);
|
||||
var fltrNotification = new FlutterLocalNotificationsPlugin();
|
||||
fltrNotification.initialize(initilizationsSettings,
|
||||
onSelectNotification: notificationSelected);
|
||||
|
||||
int notification_interval = await Settings.getNotificationInterval();
|
||||
|
||||
if(notification_interval>0) {
|
||||
var androidDetails = const AndroidNotificationDetails("Xperience", "TaskTracker", importance: Importance.max);
|
||||
var iSODetails = new IOSNotificationDetails();
|
||||
var generalNotificationDetails =
|
||||
new NotificationDetails(android: androidDetails, iOS: iSODetails);
|
||||
var scheduledTime = DateTime.now().add(Duration(hours: notification_interval));
|
||||
fltrNotification.schedule(1, "What did you do in last $notification_interval hours?", "Click here to track your last activities...",
|
||||
scheduledTime, generalNotificationDetails,);
|
||||
print("Sent notification schedule");
|
||||
}
|
||||
}
|
||||
void notificationSelected(String? payload) {
|
||||
if(payload!=null){
|
||||
if(payload.toLowerCase().contains("activity")){
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity())).then((value) => {Users.refreshUserData()});
|
||||
}
|
||||
}
|
||||
}
|
||||
void init() async {
|
||||
await initSettings();
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
@@ -73,20 +104,24 @@ class _SplashScreenState extends State<SplashScreen> {
|
||||
|
||||
void Continue() async{
|
||||
await Users.initUserData();
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
Navigator.of(context).pushReplacementNamed('/home');
|
||||
print('Going home!');
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.purple,
|
||||
color: Colors.redAccent,
|
||||
padding: EdgeInsets.all(80),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image(image: AssetImage('images/logo.png')),
|
||||
SpinKitPouringHourGlass(color: Colors.white)
|
||||
// Text('Loading', style:TextStyle(color: Colors.grey, fontSize: 20,fontStyle: FontStyle.italic))
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user