Ongoing online

This commit is contained in:
Sewmina
2022-03-21 19:43:49 +05:30
parent 211e1b70b4
commit ee678fcc88
10 changed files with 408 additions and 12 deletions

View File

@@ -50,6 +50,14 @@ class Activity{
DateTime endTime;
String? metadata;
Activity.fromJson(Map<String,dynamic> json): taskType=json['taskType'], startTime=json['sTime'], endTime=json['eTime'];
Map<String, dynamic> toJson()=>{
'taskType': taskType,
'sTime':startTime,
'eTime':endTime
};
static String colType = "type";
static String colStartTime = "s_time";
static String colEndTime = "e_time";

View File

@@ -1,7 +1,11 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tasktracker/NotificationsManager.dart';
import 'main.dart';
import 'User.dart' as User;
class Dialogs{
static String syncingMessage = "Syncing";
@@ -65,6 +69,59 @@ class Dialogs{
}
}
static ongoing() async{
List<String>? data= await User.getOngoingData();
if(data == null){return;}
context=navigatorKey.currentContext;
if(context!=null) {
return showDialog(
context: context!,
routeSettings: const RouteSettings(name: "Ongoing"),
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
backgroundColor: Color(0xFF101010),
title: Text('Take Action for Ongoing Activity'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(''),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Task : ${data[0]}'),
Text('Description: ${data[1]}'),
Text('Started Time: ${DateFormat("MM-dd hh:mm").format(DateTime.parse(data[2]))}')
],
),
],
),
actions: [
MaterialButton(onPressed: (){Navigator.of(context).pop();}, child: Text('Cancel', style:TextStyle(color: Colors.grey))),
MaterialButton(onPressed: (){
User.CancelOngoingActivity();
NotificationManager.RescheduleNotifications();
Navigator.of(context).pop();
}, child:Text('Remove', style:TextStyle(color: Colors.redAccent))),
MaterialButton(
onPressed: (){
User.StopActivityTimer();
NotificationManager.RescheduleNotifications();
Navigator.of(context).pop();
},
child: Text('Complete', style:TextStyle(color: Colors.green)),
),
],
);
}
);
}
}
static hide(){
showing=false;

View File

@@ -2,11 +2,15 @@ import 'dart:io';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Data.dart';
import 'Dialogs.dart';
import 'User.dart' as User;
class NotificationManager{
static var fltrNotification;
static void RescheduleNotifications() async{
if(!User.cacheEnabled){print('Sorry no notifications for: ');return;}
@@ -17,10 +21,10 @@ class NotificationManager{
var initilizationsSettings =
new InitializationSettings(android: androidInitilize, iOS: iOSinitilize);
var fltrNotification = new FlutterLocalNotificationsPlugin();
fltrNotification = new FlutterLocalNotificationsPlugin();
fltrNotification.initialize(initilizationsSettings, onSelectNotification: notificationSelected);
await fltrNotification.cancelAll();
await fltrNotification.cancel(0);
int notification_interval = await Settings.getNotificationInterval();
bool adaptive_notification = await Settings.getAdaptiveNotification();
@@ -30,6 +34,37 @@ class NotificationManager{
var iSODetails = new IOSNotificationDetails();
var generalNotificationDetails =
new NotificationDetails(android: androidDetails, iOS: iSODetails);
final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('current_activity')) {
String? ongoingActData = prefs.getString('current_activity');
try {
if (ongoingActData != null) {
List<String> data = ongoingActData.split("<td>");
const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails('0', 'Ongoing',
ongoing: true,
autoCancel: false);
const NotificationDetails notificationDetails = NotificationDetails(android: androidNotificationDetails);
final List<PendingNotificationRequest> pendingNotificationRequests =await fltrNotification.pendingNotificationRequests();
bool containsNotification = false;
for (var element in pendingNotificationRequests) {
if(element.id==1){
containsNotification=true;
continue;
}
}
if(!containsNotification) {
await fltrNotification.show(
1, 'Currently doing : ${data[0]}', 'Click on this notification to stop and add this activity', notificationDetails,
payload: 'ongoingActivity');
}
}
}catch(e){
print("error ongoing activity");
await fltrNotification.cancel(1);
}
}else{
await fltrNotification.cancel(1);
}
if(adaptive_notification && adaptive_notification_availabel){
print("Smart!, Using adaptive huh?");
@@ -87,7 +122,7 @@ class NotificationManager{
thisTime = thisTime.add(Duration(days: 1));
}
print("Scheduling at $thisTime");
fltrNotification.schedule(key, "Don't forget to add new activity", "Adaptive notifications suggests that you may have done by now to track.", thisTime, generalNotificationDetails);
fltrNotification.schedule(0, "Don't forget to add new activity", "Adaptive notifications suggests that you may have done by now to track.", thisTime, generalNotificationDetails);
}
});
@@ -111,5 +146,9 @@ class NotificationManager{
static void notificationSelected(val){
print("Selected notifications : $val");
if(val=="ongoingActivity"){
Dialogs.ongoing();
}
RescheduleNotifications();
}
}

View File

@@ -74,6 +74,7 @@ class _ProjectsState extends State<Projects> {
}
Widget ProjectCard(Project project){
Duration timeLeft = project.deadline.difference(DateTime.now());
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
@@ -114,7 +115,9 @@ class _ProjectsState extends State<Projects> {
),
child:Padding(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
child: Text("Deadline : " +DateFormat("yyyy-MM-dd").format(project.deadline)),
// padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
child: Text(durationToDays(timeLeft)),
// child: Text("Deadline : " +DateFormat("yyyy-MM-dd").format(project.deadline)),
))
],
)
@@ -128,3 +131,17 @@ class _ProjectsState extends State<Projects> {
);
}
}
String durationToDays(Duration duration){
String output ="";
if(duration.inDays > 30){
output += (duration.inDays/30).floor().toString() + " months";
output += (duration.inDays%30==0) ? "" : " and " + (duration.inDays %30).toString() + " days";
}else{
output += (duration.inDays %30).toString() + " days";
}
output += " left";
return output;
}

View File

@@ -104,11 +104,19 @@ Future<void> BuildBridgeToServer() async{
prefs.setString('rev', response.body);
await refreshUserData();
}
if(data[4].contains('<td>')){
List<String> ongoingData = data[4].split("<td>");
if(!prefs.containsKey('current_activity')) {
StartActivityTimer(ongoingData[0], ongoingData[1], DateTime.parse(ongoingData[2]));
}
}else{
CancelOngoingActivity();
}
}catch(e){
print("Error with bridge : $e");
}
await Future.delayed(Duration(seconds: 5));
}
}
@@ -424,6 +432,46 @@ Future<void> UpdateTaskTypesFromServer() async {
}
}
void StartActivityTimer(String taskType, String metadata, DateTime startTime) async{
final prefs = await SharedPreferences.getInstance();
prefs.setString('current_activity', "$taskType<td>$metadata<td>${UserOperations.dFormat.format(startTime)}");
NotificationManager.RescheduleNotifications();
UserOperations.startOngoing(prefs.getString('current_activity')!);
}
Future<List<String>?> getOngoingData() async{
final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('current_activity')){
List<String> data = [];
try{
data = prefs.getString('current_activity')!.split('<td>');
return data;
}catch(e){
}
}else{
}
}
void StopActivityTimer() async{
final prefs = await SharedPreferences.getInstance();
try {
List<String> data = prefs.getString('current_activity')!.split("<td>");
UserOperations.addActivity(data[0], DateTime.parse(data[2]), DateTime.now(),metadata: data[1]);
}catch(e){}
prefs.remove('current_activity');
UserOperations.stopOngoing();
}
void CancelOngoingActivity() async{
final prefs = await SharedPreferences.getInstance();
prefs.remove('current_activity');
UserOperations.stopOngoing();
}
Future<List<Activity>> GetActivities(bool forceOffline) async {
if (cacheEnabled) {
List<Activity> _activities = [];
@@ -930,6 +978,61 @@ class UserOperations {
}
}
static Future<void> startOngoing(String activityData) async {
Map<String, String> queryBody = <String, String>{
'username': username,
'current_activity': activityData,
};
if (cacheEnabled) {
//Add Query
Map<String, Object> query = {Queries.colLink: 'start_ongoing', Queries.colData: jsonEncode(queryBody)};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
} else {
try {
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/start_ongoing.php'), body: queryBody));
print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) {
//Success
}
} catch (e) {
print('NC: Error adding ongoing $e}');
}
}
await executeQueries();
}
static Future<void> stopOngoing() async {
Map<String, String> queryBody = <String, String>{
'username': username,
};
if (cacheEnabled) {
//Add Query
Map<String, Object> query = {Queries.colLink: 'stop_ongoing', Queries.colData: jsonEncode(queryBody)};
print("adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}");
await cacheDb.insert('Queries', query);
} else {
try {
http.Response queryResponse = (await http.post(Uri.parse('http://161.97.127.136/task_tracker/stop_ongoing.php'), body: queryBody));
print("Query executed : Results{${queryResponse.body}");
if (queryResponse.body.toLowerCase().contains("success")) {
//Success
}
} catch (e) {
print('NC: Error adding ongoing $e}');
}
}
await executeQueries();
}
static Future<void> addProject(String name, String category, List<ProjectStep> steps, DateTime deadline) async {
Map<String, String> queryBody = <String, String>{
'name': username + name,

View File

@@ -4,8 +4,10 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tasktracker/Categories.dart';
import 'package:tasktracker/Projects.dart';
import 'package:tasktracker/Todo.dart';
@@ -169,8 +171,24 @@ class _MyHomePageState extends State<MyHomePage> {
}
});
LoadStats();
startLoadStatRefresher();
// User.progressDialog=progressDialog;
}
void startLoadStatRefresher() async{
int lastMinute = 0;
while(true){
if(DateTime.now().minute != lastMinute){
lastMinute = DateTime.now().minute;
LoadStats();
}
await Refresh();
await Future.delayed(Duration(seconds: 1));
}
}
void init(BuildContext context) async{
await Future.delayed(Duration(seconds: 1));
refreshSub = User.refreshStream.stream.listen((value) {
@@ -194,9 +212,35 @@ class _MyHomePageState extends State<MyHomePage> {
connectivitySub?.cancel();
refreshSub?.closeSteam();
}
String ongoingActName = "";
DateTime ongoingActStime=DateTime.now();
Future<void> Refresh() async{
final prefs = await SharedPreferences.getInstance();
if(prefs.containsKey('current_activity')){
List<String> data = [];
try{
data = prefs.getString('current_activity')!.split('<td>');
ongoingActName=data[0];
ongoingActStime = DateTime.parse(data[2]);
}catch(e){
ongoingActName = "";
}
}else{
ongoingActName = "";
}
setState(() {
});
}
void LoadStats() async {
// return;
// await User.refreshUserData();
await Refresh();
DateFormat dFormat = DateFormat("MM/dd");
Map<Category, int> catTimeMap = <Category, int>{};
Map<Category, int> catBriefMap = <Category, int>{};
@@ -430,6 +474,59 @@ class _MyHomePageState extends State<MyHomePage> {
),
)
: Container(),
//Ongoing activity card
(ongoingActName == "") ? Container():
Container(
padding: EdgeInsets.all(10),
child: Card(
color: Colors.white12,
elevation: 20,
shadowColor: Colors.green,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SpinKitPouringHourGlass(color: Colors.amber),
SizedBox(width: 20,),
Flexible(child: Text("You are engaged in '$ongoingActName' since ${DateFormat("hh:mm").format(ongoingActStime)}.", style: TextStyle(fontSize: 19),textAlign: TextAlign.center,)),
],
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
child:Text(MinutesToTimeString(DateTime.now().difference(ongoingActStime).inMinutes))
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: (){
Dialogs.ongoing();
},
child: Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(10)
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8,horizontal: 15),
child:Text('Take Action')
)
)
),
],
),
],
)
],
),
)),
),
Container(
height: 350,
padding: EdgeInsets.all(10),
@@ -446,6 +543,7 @@ class _MyHomePageState extends State<MyHomePage> {
width: 10,
),
Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)),
],
),
Divider(),
@@ -484,6 +582,9 @@ class _MyHomePageState extends State<MyHomePage> {
yValueMapper: (ProductivityMapData sales, _) => sales.productivity,
dataLabelMapper: (ProductivityMapData sales, _) => sales.productivity.toStringAsFixed(1) + "%",
dataLabelSettings: DataLabelSettings(overflowMode: OverflowMode.hide, showZeroValue: false, isVisible: true),
onPointTap: (ChartPointDetails point){
showAlertDialog(context, productivityData[point.pointIndex!].day, "I'll show you detailed info about this day in future, When my master creates the feature");
},
color: Colors.green)
]),
),

View File

@@ -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/NotificationsManager.dart';
import 'package:tasktracker/main.dart';
import 'Data.dart';
import 'User.dart' as User;
@@ -80,12 +81,12 @@ class _NewActivity extends State<NewActivity> {
padding: EdgeInsets.symmetric(
horizontal: 12, vertical: 1),
decoration: BoxDecoration(
color: Colors.blueGrey,
color: Colors.black12,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.grey, width: 2)),
child: DropdownButton<String>(
dropdownColor: Colors.blueGrey,
dropdownColor: Color(0xFF222222),
iconSize: 30,
elevation: 10,
borderRadius: BorderRadius.circular(10),
@@ -187,6 +188,7 @@ class _NewActivity extends State<NewActivity> {
Container(
padding: EdgeInsets.all(10),
child: Text('Ended Time')),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
@@ -233,6 +235,60 @@ class _NewActivity extends State<NewActivity> {
})
],
),
SizedBox(height: 15,),
(!editing)?Container(
child: Card(
shadowColor: Colors.blue,
elevation: 20,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
// color: Color(0xAA51AAFF),
color: Colors.deepPurpleAccent,
child: Column(
mainAxisSize: MainAxisSize.max,
children:[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.lightbulb, color: Colors.yellowAccent),
Text('Not finished yet?', style: TextStyle(fontSize: 18)),
Container(width: 15,),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Click following button to start tracking an unfinished Activity. Activity will be added when you finish it.', textAlign: TextAlign.center,),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
color: Colors.green,
onPressed: (){
User.StartActivityTimer(selectedCat, metadataController.text, startTime);
//Go home and show card
Navigator.of(context).pop();
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20,vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.access_time),
SizedBox(width: 10,),
Text('Start Timer'),
],
),
),
),
)
]
)
),
) : Container(),
SizedBox(
height: 30,
),
@@ -252,7 +308,9 @@ class _NewActivity extends State<NewActivity> {
],
)
]),
],
)),
),
),