Files
TaskTracker/lib/User.dart
warlock d4dd0864fa Init
2022-02-20 04:29:06 +05:30

565 lines
17 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
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';
late http.Response loginResponse;
late Database cacheDb;
late String username;
List<Category> categories = [];
List<TaskType> taskTypes = [];
List<Activity> activities=[];
bool offline = true;
Future<http.Response> login(String _username, String password) async {
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 ?? 'n/a'
}));
if (loginResponse.body.toLowerCase().contains("success")) {
offline = false;
username = _username;
}
}catch(e){
offline=true;
}
return loginResponse;
}
Future<void> initUserData() async {
await initCacheDatabase();
await UpdateCategoriesFromServer();
await UpdateTaskTypesFromServer();
await GetCategories(true);
await GetTaskTypes(true);
print('Initializing UserData...');
if (offline) {
print('Going offline mode.');
}
}
Future<bool> cacheDbExist() async{
Directory directory = await getApplicationDocumentsDirectory();
return databaseFactory.databaseExists(directory.path + 'cache.db');
}
Future<void> updateCatsList() async{
print('Updating with localCache');
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);
print('Checking if can refresh');
taskTypes = await GetTaskTypes(false);
}
Future<void> initCacheDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
print('database at ' + directory.path + 'cache.db');
cacheDb = await openDatabase(directory.path + 'cache.db', version: 1, onCreate: onCacheDatabaseCreate, onUpgrade: onCacheDatabaseUpgrade);
await UserOperations.executeQueries();
}
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)';
// 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, '
'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))';
// 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, '
'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))';
// print(ActivityTableSQL);
await db.execute(ActivityTableSQL);
String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)';
// print(QueriesTableSQL);
await db.execute(QueriesTableSQL);
addInitialDataToCache();
// GetCategories();
}
Future<void> addInitialDataToCache() async{
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(TaskType element in InitialData.getTaskTypes(username)){
await UserOperations.addTaskType(element.name, element.category, bulk: true);
// Map<String,Object> data = {
// TaskType.colName: element.name,
// TaskType.colCategory: element.category
// };
// await cacheDb.insert('TaskTypes', data);
}
UserOperations.executeQueries();
}
void onCacheDatabaseUpgrade(Database db, int oldVersion, int newVersion) async {
//ValidateCacheDB();
print('Upgrading CacheDB from ver.$oldVersion to ver.$newVersion');
}
Future<List<Category>> GetCategories(bool forceOffline) async{
List<Category> _categories = [];
if(offline || forceOffline){
//Retreive from cacheDB
}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??'n/a'}));
final data = update_response.body.split(',');
catsUpdated = data[0] == '1';
}catch(e){
print(e);
}
print("Need to update : ${!catsUpdated}");
//Update CacheDB
if(!catsUpdated){
await UpdateCategoriesFromServer();
}
}
List<Map> cats = await cacheDb.query('Categories');
print(cats.length);
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){
print("Something is null!");
print("name:{$catName}, color:{$catColor}, prod:{$Category.colProductive}");
continue;
}
print("name:{$catName}, color:{$catColor}, prod:{$catProductive}");
_categories.add(Category(username + catName, catName, catColor, ParseBool(catProductive)));
}
categories = _categories;
return categories;
}
Future<void> UpdateCategoriesFromServer() async{
print("Updating Categories");
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() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
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']}') ");
});
}catch(e){
offline=true;
}
}
Future<List<TaskType>> GetTaskTypes(bool forceOffline) async{
List<TaskType> _taskTypes = [];
if(offline || forceOffline){
//Retreive from cacheDB
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
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??'n/a'}));
final data = update_response.body.split(',');
updated = data[1] == '1';
}catch(e){
print(e);
}
print("Need to update : ${!updated}");
//Update CacheDB
if(!updated){
await UpdateTaskTypesFromServer();
}
}
List<Map> cats = await cacheDb.query('TaskTypes');
print(cats.length);
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){
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));
}
taskTypes = _taskTypes;
return taskTypes;
}
Future<void> UpdateTaskTypesFromServer() async{
print("Updating TaskTypes");
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() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType
.colName},${TaskType.colCategory}) "
"VALUES ('${cat['id']}','${cat['name']}',${cat['category']}) ");
});
}catch(e){
offline=true;
}
}
Future<List<TaskType>> GetActivities(bool forceOffline) async{
List<Activity> _activities = [];
if(offline || forceOffline){
//Retreive from cacheDB
}else{
//Check if server got updated, If not go for cache
var android_id = await Settings.UUID();
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??'n/a'}));
final data = update_response.body.split(',');
updated = data[2] == '1';
}catch(e){
print(e);
}
print("Need to update activities : ${!updated}");
//Update CacheDB
if(!updated){
await UpdateActivitiesFromServer();
}
}
List<Map> cats = await cacheDb.query('Activities');
print(cats.length);
for(Map element in cats){
String? type = element[Activity.colType].toString();
String? startTime = element[Activity.colStartTime].toString();
String? endTime = element[Activity.colStartTime].toString();
TaskType? taskType = await getTaskFromId(type);
if(type==null || startTime==null || endTime==null || taskType==null){
print("Something is null!");
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
continue;
}
print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}");
_activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime)));
}
activities = _activities;
return taskTypes;
}
Future<void> UpdateActivitiesFromServer() async{
print("Updating TaskTypes");
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() ?? 'n/a'
}));
print(response.body);
List<String> data = response.body.split("<td>");
data.forEach((value) async {
Map<String, dynamic> cat = jsonDecode(value);
//print(catData);
await cacheDb.rawInsert(
"INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}) "
"VALUES ('${cat['type']}', '${cat['sTime']}','${cat['eTime']}') ");
});
}catch(e){
offline=true;
}
}
Future<TaskType?> getTaskFromId(String taskId) async{
// await GetTaskTypes(false);
TaskType? cat = null;
taskTypes.forEach((element) async{
if(element.id == taskId){
cat= element;
cat?.cat = await getCatFromId((cat?.category ?? ''));
}
});
return cat;
}
Future<Category?> getCatFromId(String catId) async{
// await GetTaskTypes(false);
Category? cat = null;
categories.forEach((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'
var iosDeviceInfo = await deviceInfo.iosInfo;
return iosDeviceInfo.identifierForVendor; // unique ID on iOS
} else {
var androidDeviceInfo = await deviceInfo.androidInfo;
return androidDeviceInfo.androidId; // unique ID on Android
}
}
}
bool ParseBool(obj){
return obj.toString().toLowerCase()=="true" || obj.toString()=="1";
}
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() ?? 'n/a',
'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() ?? 'n/a',
'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 GetTaskTypes(true);
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,
'username': username,
'device_id': await Settings.UUID() ?? 'n/a',
};
//Add Query
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,
Category.colName: name,
};
await cacheDb.rawDelete("DELETE FROM TaskTypes WHERE id='${username+name}'");
await GetTaskTypes(true);
//Add to server and refresh Cache
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() ?? 'n/a',
};
//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);
//Add to server and refresh Cache
if(!bulk) {
await executeQueries();
}
}
static Future<void> executeQueries() async{
if(offline){
print("Cannot executre queries, Offline!");
return;
}
List<Map<String,Object?>> queries = await cacheDb.query('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){
print("Null query, Ignoring...");
continue;
}
print("Query[\n file:$file, \ndata:$data]");
//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));
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;
}
}
}
}