From 4576957b4c21370746c9a0608168b32a23b6e580 Mon Sep 17 00:00:00 2001 From: warlock Date: Wed, 2 Mar 2022 09:24:26 +0530 Subject: [PATCH] Summary page done --- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 5952 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 3564 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 8665 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 14085 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 19745 bytes images/hourglass_base.png | Bin 0 -> 1374 bytes images/hourglass_half.png | Bin 0 -> 3518 bytes lib/Activities.dart | 231 +++-- lib/Categories.dart | 2 +- lib/Data.dart | 4 +- lib/Tasks.dart | 18 +- lib/User.dart | 52 +- lib/main.dart | 816 +++++++++++++----- lib/newActivity.dart | 210 +++-- pubspec.lock | 47 +- pubspec.yaml | 3 +- 16 files changed, 974 insertions(+), 409 deletions(-) create mode 100644 images/hourglass_base.png create mode 100644 images/hourglass_half.png diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..ea1014dbacc05b5909c3d8eb9136587b696a987f 100644 GIT binary patch literal 5952 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 AQ2+n{ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..20f60dd50c1adeb1480a7dbae7767a08a7115c48 100644 GIT binary patch literal 3564 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..7bada5caa23def601969a48f4ad63f7c9688f0db 100644 GIT binary patch literal 14085 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 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372eebdb28e45604e46eeda8dd24651419bc0..25a23004f9bdc20524e06b61cb180e887dc33578 100644 GIT binary patch literal 19745 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 diff --git a/images/hourglass_base.png b/images/hourglass_base.png new file mode 100644 index 0000000000000000000000000000000000000000..81b18e1234808c15fa505545dc54377759fc4f6f GIT binary patch literal 1374 zcmV-k1)=(hP)R7C&)0Lhtlyn|Y{c}>HNWYVaM#EDt5 zX*jTHH>+DB$CGWcZ9LASgR*TnxqDBfWj3Z^EwX)Bo>?fHRVbQSB*Bnz%9(bWRV0>F zB=FzT*WKgK-RJ7>`|sS&>(*D3(;qB_-@9XF5=jrb2;_K(=&n9fG z0000wbW%=J0RR90|NsC0|NsC0|NjL4|NsC0|NjL4{{;X42LJ#6|NsC0|NsC0ApigW z|NsC0|Nq3`Ti{Y#;9C^1Nt*xw1OrJ#K~#90?OKUi(?AeTp|%PNlv?qEf+u)aQQ`ex z%v^2un3=tIr~RBwvOE9G&heX;uO?L$K}LIo>~DjNi3T3TpeT||rVmkhv>ifpFe**2 zAP0wdoxM!EqdmJze_cWC%$I5OgNT1ZiO()!B5kzMV3o{#nKpG{w3{6)JZxO7d^j_0*MOy$t(&!FVz6@4i9U!JBE1)_k^j?Qz}2oM}G}ytjGpv)IU;Y5(2> zc7|+4_p)a?sOzxJfxDIMe3=exGkAY^0679*rXzG3BSe%KO%TRR$LTRrl<+W|nT|zL z#6SU&STh}wp_rlkV)16$zb{Op26KwG1x!a~Cw4g7cx;&lo?}1|h`}I&Vlay12Ey{> zkTcWHw+$^64+dL|N*FPHG(JArVPW*d_GorGf4aM4QJUXDp3T(a&YthkV8rx`*<7Pq zsaCfGh`LA9p*A zQ1M6`6_d0jXZq!s;27zfItw4!61TS@PNf)`ut+Kk@JgsG)Hq@UbW-$ z>W$#g8oNt>ZKnOVr}KI=M|*ac{<@wv^RN(B;!;}6ilV8irt1KJK#+jF6Bt?!eQ)OT z_a8pCT-C<_3ae&$T~*_~dNfCSc9-@#>g8rJ>CyGHnb(U?pTF#~91IN$D{*H zsH*g(qzaoXZi>JS)8?BxaS<6pCyi|tyk|O7MTw)Q4j&X>V>)@Y=@Vqg;P)5N^v=GQ z&~;|Xktd0D7X6;iRbj3)+42|?K}_eXEn}vfslZ$y(^;#^n=ErSAsx(g?s~H4%byTq zxE7D5>p4bkq zX8!G*EWK>qto`gA9XwrJMc?|KmS5SE6-853P1gYcfglirK?KEM6vqvOg)))0<_*Zz z^7>~xR>&z{MP0Wx*I&1*+u!wA{ej{@Ywi4dcYk-ksz*1gns};q%%8%=89E^!2_v`@ g&PXp|{};3T1M|}DNa2Jq^5t=YBq)bIv{YdG0?q!`}9~AfGfJ8ylM-7-R-vMH0&> zJRB_lUd|ZH3IG`7x(Q%u^um1>;JpKKg|V^mi~ThKTk(q%EON%)8fwmp1OgRLpkVPN z0+EIz&~Tf-aRfRJPa#rhl$~87Wfw=F;_w8PN+43F=2=@RjzGZ^h&bFVk+?^pvUuX( zWGWrExNgOge+X%BE7kv1;*@9RiU;r_&ek z6ary;jj*%0LcrmPOa`-maCmkRN2AmKwx-coW31tK$EW7-L^5>+Gn^OJ4!1!^n&K&p z-PM_O0v0znyErwoFgsUL)xOTUl|?kf){!lbb>QE1hT{yAnfD($!;#12_>cZS&(fGI zEwBIovjEom4|6W8c(SnxXoAg*p>Z!(Uhfw(4v6MWFkB(MM+=h#FwSuD*M=zsgfK zAS4^?qUG?ah^()7lu~WD&=g$$VozG@Nzh-GVRTxMM9Spg`UKpmug;ja<{dcn*?Ctz z>L*-d64a(zqWJW<$qZ)oPYt%fCQnR`xCeiy%6Za&R3whR8}ZR$<{~(CG^aultz89g z@K}k9{E)DK!-yA1>SA=-szp9*2Q(uh zET_LD4|IB5(@t{>^wP9gZsN>UP>X`XcFCIPFwf4cWfdctshrVq@rf#fBAC?uFayVX zs;xa5+-_=-x)%%~{F@#kZfeSnm$wwSJPR@(r5s|=i`l>Rl2N*}THUM}j@Gff1f+ZI)C&iMG zq7W^p-nAT+@np%46ZN(oWY~M~+PK_ZO5wk!^8e7(rjCVc1HStrF)>%j2*Foan+nY; zA)1VHfQ$Pz6tC6RjU{n7e6d)ar?8!P!82C)=$>NBO63z&P~D+$**p?xH9Om+2dQ}d zegP@Uy?l#L{&sefSx=u=k-BdmVshXv{fc8y2Iv>eZlN%YUf;%_8X zXZD6HjgsB=ZU!z3f}f84DsW&`v^Z(pw`De?hAYH6c|DckeuGrd}-i`d3lu_PX9TOZJF-2h3t-mgB&?`HSz1Z5P)5F<(HC7XTk3ZCqXtKFa#!{mg&W zmCG8hu1Ufv9Qj;3X&)Z_&VPq@-gOcyh;k$kxwJ$2R%<>@N*RN?9m0PNpL4CC$q zWgAn;?nygdvrC)2Ef)Cpr;zIL;^Dlp)?shU9%yB0bq04{v#e8&@)npNGTeY$V z6Xi!&4C8!E;XzU}Ivhw|zEQIdASZCOGORYSpzEw`zGg16c`-A_$kg1lYFj{BM)ojO z?)C6lj_9{%0Q>a(O_;>3gwuz_fgm)IS}=!*4Ac zfRzuVdyJK1Iwqmw5xtkX!mk8u%fz5N?q~i`7-Mn`3HLUp2lg*<`o3W|5qMTt=k2rL z!xN}pnPwG*RlS8se*NcCXYFm+G5Uv-Kx;U+h2=qTC|YuKqs-HvCz6O8?t>oQ`*XY= zeP8ba$fPH)Rpkt*&Jq0-lBgA~%Sf83D>3BH$RFs1D7gJXomDQg^MhF0KJte~8|~!E z^glvFN!B)hxMkPnjoTLPh<(qzeVTKfqY0v9Uy^U)&w+U7xDy615P-M-lRwCr)cX&j z{psDzW>phI#b{Kq@)gI6BuB>0a(REQ3MuQ3bq=TU0+lG~FIM_q+eiego*;#cI-5)I zk&;XkPZ9QHAjVfOII$Z!K%DE6)=dH61WWSOIyAFq%_0J11wU2wdLoVMC)#sVRTMH6 zXmh+9d4~U1?`!(8+J#=;u+%)2DuL%VdFg1#=B}>UV|>#Yzx=Vrz(~+l#}KR=a_EOb zx0MnDnq;ZvLqUYUuv}^rb}pVKK0(8=O<&h;bUm(SJ-cLVN=T3%bRk*SDNA`qW9@bD zggQbHelhduui=LAKK+if%l0ybLtsZ*vkK55H{{BmN4%oQFQ5-{nlp9ydL)c`Z0ptK z%Y2tS{V9iN$R0>o{zui-2<7T!&R)Z|;zeL(UbC@BogpQaAvMW24&tAt=s%H=vNixs>uy+C?4Fo0uHY!x#|UM{B}~s1L+JlDRfnD*$5rlI0TuW z$<%3y3BId{-{CW=a(+;Zx!T3;BWNEk8KltQk7K_vH5^PxRXhO&uV?1#(RQ@0sku~%s2Brp-71pL>S*&6z1Zs# zHkW8lLgVc=vkDd@-}EJS_4_UczfoPd;La;7y9VK2QsIsZddE|zP@=qC(WPqPR9yEE z4)QiXso%iU^ieKJQg$c4UqiFY79OCop)VDiUVYCE)1~+1hqqX~qtRH{`ovkx)ey^N z?=RyjbV{~CISS%>=f2$CK;${RY#<1N@~fhno_(Yy5USG|TT5m7zmN_k{j#z5NGoGXY7>RYqb+(Iegn@EN|?Xnab9vSH%aC@cW=E~!|Im^^) z)fKhfa6>gNZLO7QZ)o+jmqejC@U^x|&15JlhEZhVoph~y5mR*R-!hVOOiMw)5qh-i zt#m)Ka_Mqy1!+gKSrY^)IErD0NF7ybEu_(^@vCP&KK!KXABGmUdGB| zIB)(i)r_5h9XJq|#iDEdW!Z6!N&%0mTc0R~2R+D{E7{z2m=*q5G5DJwmVzp)!`pT# zxHPPB+%c=$yl;7hO^r^ zg$Cr(x)I0OHcg^~e<{VS2 zPncWteCU)qN8|9%;1`ZU8LFw*(oQR8L()eH2Qmx#Q-hWBy!&;R zVmI&v{6RM*0f%5(3t>@5V+mrgv`ul0?lM>owS7=h%f2x?NF23ue<{UPoGcv|Jl&Q2 z)YNz%Jdd(GR(k55VT`fP`Su>g&ar4mp1+4k1irn}3oSKVr zIy`qegL6Tb1i`dnSZGlqxfr^R&ivURX4F8Ys;anIzK$YqeLMuS#HsoIVmOVtb9&h8 zOX&jsJ3q020qjoW&QX{wGn _ActivitiesState(); } + late ProgressDialog progressDialog; + class _ActivitiesState extends State { @override void initState() { @@ -26,9 +27,8 @@ class _ActivitiesState extends State { @override Widget build(BuildContext context) { - progressDialog=ProgressDialog(context: context); + progressDialog = ProgressDialog(context: context); return Scaffold( - floatingActionButton: FloatingActionButton.extended( onPressed: () { Navigator.of(context) @@ -39,7 +39,7 @@ class _ActivitiesState extends State { icon: Icon(Icons.add)), appBar: AppBar( title: Row( - mainAxisSize: MainAxisSize.max, + mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row(children: [ @@ -47,15 +47,29 @@ class _ActivitiesState extends State { SizedBox(width: 10), Text('Activities') ]), - (selecting)?Row(children: [ - InkWell(onTap: (){ - DeleteSelectedTasks(); - }, child: Icon(Icons.delete,size: 30,)), - SizedBox(width: 20,), - InkWell(onTap: (){setState(() { - selecting=false; - });}, child: Icon(Icons.close,size: 30),) - ]) : Container(), + (selecting) + ? Row(children: [ + InkWell( + onTap: () { + DeleteSelectedTasks(); + }, + child: Icon( + Icons.delete, + size: 30, + )), + SizedBox( + width: 20, + ), + InkWell( + onTap: () { + setState(() { + selecting = false; + }); + }, + child: Icon(Icons.close, size: 30), + ) + ]) + : Container(), ], )), drawer: navDrawer(context, 2), @@ -68,10 +82,14 @@ class _ActivitiesState extends State { } void UpdateList() async { - try{progressDialog.show(max:100,msg: 'Loading Activities');}catch(e){} + try { + progressDialog.show(max: 100, msg: 'Loading Activities'); + } catch (e) {} await User.updateActList(); setState(() {}); - try{progressDialog.update(value: 100);}catch(e){} + try { + progressDialog.update(value: 100); + } catch (e) {} } List PrintTasks() { @@ -79,19 +97,52 @@ class _ActivitiesState extends State { print('Priting cats : ' + User.taskTypes.length.toString()); String lastDate = ""; DateFormat dFormat = DateFormat("MM/dd"); + Map productivtyActs = {}; + Map unproductivtyActs = {}; + Map totalMinutes = {}; for (var element in User.activities) { String thisDate = dFormat.format(element.startTime); - if(thisDate != lastDate){ - _tasks.add(DateSeperator(thisDate)); - lastDate=thisDate; + int thisMinutes= element.endTime.difference(element.startTime).inMinutes; + if(totalMinutes.containsKey(thisDate)){ + if((totalMinutes[thisDate]??0) < thisMinutes){ + totalMinutes[thisDate] = thisMinutes; + } + }else{ + totalMinutes.putIfAbsent(thisDate, () => thisMinutes); + } + + if (element.taskType.cat?.productive ?? false) { + if (productivtyActs.containsKey(thisDate)) { + productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes); + } else { + productivtyActs.putIfAbsent(thisDate, () => thisMinutes); + } + } else { + if (unproductivtyActs.containsKey(thisDate)) { + unproductivtyActs[thisDate] = (unproductivtyActs[thisDate]! + thisMinutes); + } else { + unproductivtyActs.putIfAbsent(thisDate, () => thisMinutes); + } + } + } + print(productivtyActs); + for (var element in User.activities) { + String thisDate = dFormat.format(element.startTime); + if (thisDate != lastDate) { + int prodActs = productivtyActs[thisDate] ?? 0; + int unProdActs = unproductivtyActs[thisDate] ?? 0; + _tasks.add(DateSeperator(thisDate, prodActs, unProdActs)); + lastDate = thisDate; } String name = element.taskType.name; 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 = + 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); + Widget task = ActivityCard(context, name, element.startTime, + element.endTime, productive, color, element, totalMinutes[thisDate] ?? 0); _tasks.add(task); } } @@ -99,23 +150,65 @@ class _ActivitiesState extends State { return _tasks; } - Widget DateSeperator(date){ + Widget DateSeperator(date, prodActs, unprodActs) { + double prodPercentage = (prodActs / (prodActs + unprodActs)) * 100; return Padding( padding: const EdgeInsets.fromLTRB(10, 20, 10, 0), - child: Column(children: [ - Row(children: [ - Text(date,style: TextStyle(fontSize: 18),) - ],) - ],), + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + date, + style: TextStyle(fontSize: 18), + ), + Row(children: [ + Row( + children: [ + Container(child:Align(child:Text(MinutesToTimeString(prodActs)), alignment: Alignment.center,),width: (prodPercentage) * 1.7, height: 25,decoration: BoxDecoration(color: Colors.green,borderRadius: BorderRadius.horizontal(left: Radius.circular(10))),), + Container(child:Align(child:Text(MinutesToTimeString(unprodActs)), alignment: Alignment.center,),width: (100-prodPercentage)* 1.7,height: 25,decoration: BoxDecoration(color: Colors.red,borderRadius: BorderRadius.horizontal(right: Radius.circular(10))),), + ], + ), + SizedBox(width: 10,), + Text(prodPercentage.toStringAsFixed(1) + "%",style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold,fontSize: 20)) + ],) + // CustomPaint( + // painter: MyPlayerBar(100, prodPercentage.toInt(), + // background: Colors.green, fill: Colors.deepOrange), + // child: Container( + // alignment: Alignment.center, + // height: 25.0, + // width: 200, + // child: Text( + // "Productivity : ${prodPercentage.toStringAsFixed(1)}%", + // style: TextStyle(fontWeight: FontWeight.bold),), + // + // ), + // ), + ], + ) + ], + ), ); } bool selecting = false; - Widget ActivityCard( - BuildContext context, String name,DateTime sTime, DateTime eTime, bool productive, Color color, Activity activity) { + Widget ActivityCard(BuildContext context, String name, DateTime sTime, + DateTime eTime, bool productive, Color color, Activity activity,int totalMinutes) { DateFormat dateFormat = DateFormat("HH:mm"); + int thisMinutes = (activity.endTime.difference(activity.startTime).inMinutes); + int timePercentage = ((thisMinutes / totalMinutes) * 100).toInt(); + // print("$thisMinutes / $totalMinutes"); + bool containsMetadata = ((activity.metadata ?? 'null') != 'null') && + ((activity.metadata ?? '').isNotEmpty); var _timeSpan = eTime.difference(sTime); - String timeSpan = ((_timeSpan.inHours > 0) ? _timeSpan.inHours.toString()+'h ' : '') + ((_timeSpan.inMinutes %60 > 0) ? (_timeSpan.inMinutes%60).toString()+'m ' : ''); + String timeSpan = + ((_timeSpan.inHours > 0) ? _timeSpan.inHours.toString() + 'h ' : '') + + ((_timeSpan.inMinutes % 60 > 0) + ? (_timeSpan.inMinutes % 60).toString() + 'm' + : ''); return Row(children: [ // Container(), (selecting) @@ -132,54 +225,84 @@ class _ActivitiesState extends State { Card( // color: color, - elevation:20, + elevation: 20, shadowColor: color, child: InkWell( onTap: () { //Open Respective Category - if(selecting){ + if (selecting) { OnItemSelected(activity); } - setState(() { - - }); + setState(() {}); }, onLongPress: () { print('gonna delete'); selecting = !selecting; selectedActivities = [activity]; setState(() {}); - }, child: Container( - padding: EdgeInsets.all(10), + padding: EdgeInsets.all(15), child: Column( children: [ Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(name + " ($timeSpan)", - style: TextStyle(color: Colors.white)), - Text(dateFormat.format(sTime) + " - " + dateFormat.format(eTime)), + Row(children: [ + Text(name + " [$timeSpan]", + style: TextStyle( fontSize: 17)), + if (containsMetadata) + Icon(Icons.arrow_forward_outlined, size: 20,), + if (containsMetadata) + Text(activity.metadata ?? '',overflow: TextOverflow.clip,) + ]), + // Icon(Icons.analytics, color: color, size: 20,), - Icon(Icons.circle, - color: (productive) - ? Colors.green - : Colors.red) ]), + SizedBox( + height: 5, + ), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(dateFormat.format(sTime) + + " - " + + dateFormat.format(eTime)), + SizedBox( + width: 20, + ), + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: (productive) + ? Colors.green + : Colors.red), + child: Text( + activity.taskType.cat?.name ?? 'n/a')) + // Icon(Icons.circle, + // color: (productive) + // ? Colors.green + // : Colors.red) + ]) ], )))), Container( margin: EdgeInsets.fromLTRB(15, 0, 15, 10), height: 2, - color: color) + child:Row(children: [ + Expanded(flex:timePercentage ,child: Container(color:color)), + Expanded(flex:100-timePercentage,child:Container()) + ],)), ]), ), ]); } - void OnItemSelected(Activity activity){ + void OnItemSelected(Activity activity) { if (!selectedActivities.contains(activity)) { selectedActivities.add(activity); } else { @@ -187,23 +310,25 @@ class _ActivitiesState extends State { } } - void DeleteSelectedTasks() async{ - progressDialog.show(max: 100, msg: 'Deleteing ${selectedActivities.length} Task Types'); + void DeleteSelectedTasks() async { + progressDialog.show( + max: 100, msg: 'Deleteing ${selectedActivities.length} Activities'); selectedActivities.forEach((element) async { - await User.UserOperations.deleteActivity(element, bulk:true); + await User.UserOperations.deleteActivity(element, bulk: true); }); await Future.delayed(Duration(seconds: 2)); await User.UserOperations.executeQueries(); await User.updateActList(); - selectedActivities=[]; - selecting=false; + selectedActivities = []; + selecting = false; setState(() { progressDialog.update(value: 100); }); - } - } + + + List selectedActivities = []; diff --git a/lib/Categories.dart b/lib/Categories.dart index f123343..613e016 100644 --- a/lib/Categories.dart +++ b/lib/Categories.dart @@ -152,7 +152,7 @@ class _CategoriesState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(name, - style: TextStyle(color: Colors.white)), + ), // Icon(Icons.analytics, color: color, size: 20,), Icon(Icons.circle, color: (productive) diff --git a/lib/Data.dart b/lib/Data.dart index 08762d0..557c159 100644 --- a/lib/Data.dart +++ b/lib/Data.dart @@ -31,15 +31,17 @@ class TaskType{ class Activity{ - Activity(this.taskType, this.startTime, this.endTime); + Activity(this.taskType, this.startTime, this.endTime, {this.metadata}); TaskType taskType; DateTime startTime; DateTime endTime; + String? metadata; static String colType = "type"; static String colStartTime = "s_time"; static String colEndTime = "e_time"; + static String colMetadata= "metadata"; } class InitialData{ diff --git a/lib/Tasks.dart b/lib/Tasks.dart index 780f717..58a2a8a 100644 --- a/lib/Tasks.dart +++ b/lib/Tasks.dart @@ -85,7 +85,7 @@ class _TasksState extends State { } else { Color color = HexColor.fromHex(element.cat?.color ?? '#000000'); bool productive = element.cat?.productive ?? true; - Widget task = TaskCard(context, name, productive, color); + Widget task = TaskCard(context, name, productive, color, element.cat?.name ?? 'n/a'); _tasks.add(task); } }); @@ -95,7 +95,7 @@ class _TasksState extends State { bool selecting = false; Widget TaskCard( - BuildContext context, String name, bool productive, Color color) { + BuildContext context, String name, bool productive, Color color, String catName) { return Row(children: [ // Container(), (selecting) @@ -140,12 +140,16 @@ class _TasksState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(name, - style: TextStyle(color: Colors.white)), + ), // Icon(Icons.analytics, color: color, size: 20,), - Icon(Icons.circle, - color: (productive) - ? Colors.green - : Colors.red) + Container( + padding: EdgeInsets.symmetric(horizontal: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: (productive) ? Colors.green : Colors.red + ), + child:Text(catName) + ) ]), ], )))), diff --git a/lib/User.dart b/lib/User.dart index cfba162..76a7acc 100644 --- a/lib/User.dart +++ b/lib/User.dart @@ -61,7 +61,7 @@ Future initUserData() async { print('Going offline mode.'); } } - +bool userDataInitiated =false; Future refreshUserData() async{ ShowProgress("Loading data"); // categories= await GetCategories(true); @@ -70,6 +70,7 @@ Future refreshUserData() async{ await updateCatsList(); await updateTasksList(); await updateActList(); + userDataInitiated=true; HideProgress(); } @@ -122,7 +123,7 @@ void onCacheDatabaseCreate(Database db, int newVersion) async { await db.execute(TaskTableSQL); String ActivityTableSQL = - 'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, ' + '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); await db.execute(ActivityTableSQL); @@ -328,7 +329,7 @@ Future> GetActivities(bool forceOffline) async{ List _activities = []; if(offline || forceOffline){ //Retreive from cacheDB - + print('offline, refreshing activities'); }else{ //Check if server got updated, If not go for cache var android_id = await Settings.UUID(); @@ -359,14 +360,15 @@ Future> GetActivities(bool forceOffline) async{ 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!"); - print("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}"); + 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}"); - _activities.add(Activity(taskType, DateTime.parse(startTime), DateTime.parse(endTime))); + 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; @@ -395,8 +397,8 @@ Future UpdateActivitiesFromServer() async{ Map cat = jsonDecode(value); print(cat); await cacheDb.rawInsert( - "INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}) " - "VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}') "); + "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"); @@ -410,13 +412,15 @@ Future UpdateActivitiesFromServer() async{ Future getTaskFromId(String taskId) async{ // await GetTaskTypes(false); TaskType? cat = null; - taskTypes.forEach((element) async{ + for (var element in taskTypes){ if(element.id == taskId){ cat= element; - cat?.cat = await getCatFromId((cat?.category ?? '')); } - }); + } + if(cat==null){ + print('Got null tasktype for ${taskId} after searching on ${taskTypes.length}'); + } return cat; } @@ -424,11 +428,11 @@ Future getTaskFromId(String taskId) async{ Future getCatFromId(String catId) async{ // await GetTaskTypes(false); Category? cat = null; - categories.forEach((element) { + for (var element in categories) { if(element.category_id == catId){ cat= element; } - }); + } return cat; } @@ -519,7 +523,7 @@ class UserOperations{ } } - static Future addActivity(String type, String sTime,String eTime, {bool bulk = false, Function(int)? onOverlap}) async{ + static Future addActivity(String type, String sTime,String 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')))")); @@ -533,8 +537,13 @@ class UserOperations{ 'device_id': await Settings.UUID(), 'type' : username+type, 'sTime': sTime, - 'eTime':eTime + 'eTime':eTime, + 'metadata': metadata }; + + if(metadata.length > 0){ + + } //Add Query Map query = { Queries.colLink: 'add_activity', @@ -547,12 +556,13 @@ class UserOperations{ //update Cache Map data = { - Activity.colType: type, + Activity.colType: username+type, Activity.colStartTime: sTime, - Activity.colEndTime: eTime + Activity.colEndTime: eTime, + Activity.colMetadata: metadata }; await cacheDb.insert('Activities', data); - await GetActivities(true); + activities= await GetActivities(false); if(!bulk){ //Add to server and refresh Cache await executeQueries(); @@ -688,10 +698,10 @@ class UserOperations{ } void ShowProgress(msg){ - try{progressDialog?.show(max: 100, msg: msg);}catch(e){} + //try{progressDialog?.show(max: 100, msg: msg);}catch(e){} } void HideProgress(){ - try{progressDialog?.update(value: 100);}catch(e){} + // try{progressDialog?.update(value: 100);}catch(e){} } diff --git a/lib/main.dart b/lib/main.dart index 0a772f1..87b0c9a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,25 +1,28 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:tasktracker/Categories.dart'; import 'package:tasktracker/Welcome.dart'; import 'package:tasktracker/splash.dart'; import 'package:wakelock/wakelock.dart'; -import 'package:charts_flutter/flutter.dart' as charts; +import 'Data.dart'; import 'NewTask.dart'; 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; showAlertDialog(BuildContext context, String title, String message) { - // set up the button Widget okButton = TextButton( child: Text("OK"), - onPressed: () { Navigator.of(context).pop(); }, + onPressed: () { + Navigator.of(context).pop(); + }, ); // set up the AlertDialog @@ -57,26 +60,6 @@ extension HexColor on Color { '${blue.toRadixString(16).padLeft(2, '0')}'; } -// To keep the screen on: -final List data = [ - PopulationData( - name: "Rocket League", - value: 45, - barColor: charts.ColorUtil.fromDartColor(Colors.blue)), - PopulationData( - name: "CS:GO", - value: 15, - barColor: charts.ColorUtil.fromDartColor(Colors.yellow)), - PopulationData( - name: "Halo", - value: 10, - barColor: charts.ColorUtil.fromDartColor(Colors.grey)), - PopulationData( - name: "SneakyPeaky", - value: 30, - barColor: charts.ColorUtil.fromDartColor(Colors.red)), -]; - void main() { //Wakelock.enable(); // or Wakelock.toggle(on: true); runApp(const MyApp()); @@ -88,26 +71,52 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', - theme: 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() - } - ); + title: 'Flutter Demo', + theme: 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() + }); } } +List days = []; +String curDay = ""; + +DateTime? firstDay = null; +DateTime? lastDay = null; +DateTimeRange? taskTypeRange = null; +DateTimeRange? catsRange = null; + +List productivityData = [ + ProductivityMapData('02/24', 35), + ProductivityMapData('02/25', 28), + ProductivityMapData('02/26', 34), + ProductivityMapData('02/27', 32), + ProductivityMapData('02/28', 40) +]; + +List taskTypesData = [TaskTypeMapData('Eat', 3600, Colors.green), TaskTypeMapData('Play', 300, Colors.blue)]; +List catsData = [ + CatMapData('Jan', 35, Colors.green), + CatMapData('Feb', 28, Colors.blueAccent), + CatMapData('Mar', 34, Colors.yellow), + CatMapData('Apr', 32, Colors.grey), +]; + +List dailyData = [ + CatMapData('Jan', 35, Colors.green), + CatMapData('Feb', 28, Colors.blueAccent), + CatMapData('Mar', 34, Colors.yellow), + CatMapData('Apr', 32, Colors.grey), +]; + class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @@ -116,215 +125,572 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - List> series = [ - charts.Series( - id: "Subscribers", - data: data, - domainFn: (PopulationData series, _) => series.name, - measureFn: (PopulationData series, _) => series.value, - colorFn: (PopulationData series, _) => series.barColor) - ]; - @override void initState() { // TODO: implement initState super.initState(); - - showOfflineSnack(); - progressDialog = ProgressDialog(context: context); - User.progressDialog=progressDialog; + User.refreshUserData().then((val) => LoadStats()); + // showOfflineSnack(); + LoadStats(); + // progressDialog = ProgressDialog(context: context); + // User.progressDialog=progressDialog; } - void showOfflineSnack() async{ + void LoadStats() async { + // return; + + while (!User.userDataInitiated) { + await Future.delayed(const Duration(seconds: 1)); + } + + DateFormat dFormat = DateFormat("MM/dd"); + Map catTimeMap = {}; + Map catBriefMap = {}; + + Map productivtyActs = {}; + Map unproductivtyActs = {}; + Map taskTypesDuration = {}; + firstDay = null; + lastDay = null; + String lastDate = ""; + for (var element in User.activities) { + if (lastDay == null) { + lastDay = element.endTime; + } + if (taskTypeRange == null) { + print("$lastDay - $firstDay"); + taskTypeRange = DateTimeRange(start: lastDay!.subtract(const Duration(days: 1)), end: lastDay!); + } + if (catsRange == null) { + print("$lastDay - $firstDay"); + catsRange = DateTimeRange(start: lastDay!.subtract(const Duration(days: 1)), end: lastDay!); + } + firstDay = element.startTime; + String thisDate = dFormat.format(element.startTime); + int thisMinutes = element.endTime.difference(element.startTime).inMinutes; + if (!days.contains(thisDate)) { + days.add(dFormat.format(element.startTime)); + } + if (curDay == "") { + curDay = dFormat.format(DateTime.now()); + } + + if ((element.startTime.isAfter(taskTypeRange!.start) && element.startTime.isBefore(taskTypeRange!.end)) || + (dFormat.format(element.startTime) == dFormat.format(taskTypeRange!.start) || dFormat.format(element.startTime) == dFormat.format(taskTypeRange!.end))) { + if (taskTypesDuration.containsKey(element.taskType)) { + taskTypesDuration[element.taskType] = taskTypesDuration[element.taskType]! + thisMinutes; + } else { + taskTypesDuration.putIfAbsent(element.taskType, () => thisMinutes); + } + } + + if (element.taskType.cat?.productive ?? false) { + if (productivtyActs.containsKey(thisDate)) { + productivtyActs[thisDate] = (productivtyActs[thisDate]! + thisMinutes); + } else { + productivtyActs.putIfAbsent(thisDate, () => thisMinutes); + } + } else { + if (unproductivtyActs.containsKey(thisDate)) { + unproductivtyActs[thisDate] = (unproductivtyActs[thisDate]! + thisMinutes); + } else { + unproductivtyActs.putIfAbsent(thisDate, () => thisMinutes); + } + } + + if (thisDate == curDay) { + if (element.taskType.cat == null) { + continue; + } + print("Null : ${thisMinutes}"); + if (catTimeMap.containsKey(element.taskType.cat)) { + catTimeMap[element.taskType.cat!] = (catTimeMap[element.taskType.cat]! + thisMinutes); + } else { + catTimeMap.putIfAbsent(element.taskType.cat!, () => thisMinutes); + } + } + + if ((element.startTime.isAfter(catsRange!.start) && element.startTime.isBefore(catsRange!.end)) || + (dFormat.format(element.startTime) == dFormat.format(catsRange!.start) || dFormat.format(element.startTime) == dFormat.format(catsRange!.end))) { + if (element.taskType.cat == null) { + continue; + } + print("Null : ${thisMinutes}"); + if (catBriefMap.containsKey(element.taskType.cat)) { + catBriefMap[element.taskType.cat!] = (catBriefMap[element.taskType.cat]! + thisMinutes); + } else { + catBriefMap.putIfAbsent(element.taskType.cat!, () => thisMinutes); + } + } + } + + //curDay = days[0]; + if (this.mounted) { + setState(() { + dailyData = []; + productivityData = []; + taskTypesData = []; + catsData = []; + + catTimeMap.forEach((key, value) { + print(key.name + " : $value"); + Color barCol = HexColor.fromHex(key.color); + dailyData.add(CatMapData(key.name, value, barCol)); + }); + + for (var element in days) { + // if(productivtyActs.containsKey(element) && unproductivtyActs.containsKey(element)){ + int prodActs = (productivtyActs[element] ?? 0); + int unprodActs = (unproductivtyActs[element] ?? 0); + double prod = (prodActs / (prodActs + unprodActs)) * 100; + productivityData.add(ProductivityMapData(element, prod)); + // } + } + + taskTypesDuration.forEach((key, value) { + print("$key : $value"); + taskTypesData.add(TaskTypeMapData(key.name, value, HexColor.fromHex(key.cat!.color))); + }); + + catBriefMap.forEach((key, value) { + print(key.name + " : $value"); + Color barCol = HexColor.fromHex(key.color); + catsData.add(CatMapData(key.name, value, barCol)); + }); + }); + } + } + + void showOfflineSnack() async { await Future.delayed(const Duration(seconds: 1)); - if(User.offline){ - const SnackBar offlineSnack = SnackBar(content: Text('Offline'),duration: Duration(seconds: 100),); - ScaffoldMessenger.of(context).showSnackBar(offlineSnack); + if (User.offline) { + const SnackBar offlineSnack = SnackBar( + content: Text('Offline'), + duration: Duration(seconds: 100), + ); + // ScaffoldMessenger.of(context).showSnackBar(offlineSnack); } } @override Widget build(BuildContext context) { return Scaffold( - floatingActionButton: FloatingActionButton.extended(onPressed: (){ - Navigator.of(context).push(MaterialPageRoute(builder: (context)=> NewActivity())); - }, + floatingActionButton: FloatingActionButton.extended( + onPressed: () { + Navigator.of(context).push(MaterialPageRoute(builder: (context) => NewActivity())).then((value) => {User.refreshUserData().then((va) => LoadStats())}); + }, label: Text("New Activity"), - icon: Icon(Icons.add) - ), - appBar: AppBar(title: Row(children:[Icon(Icons.article_outlined, color: Theme.of(context).primaryColor),SizedBox(width: 10),Text('Summary')])), - drawer: navDrawer(context,0), - body: SafeArea( - child: Container( - child: Column( - children: [ - Container( - height: 300, - padding: EdgeInsets.all(20), - child: Card( - elevation: 8, - shadowColor: Colors.blueGrey, - child: Padding( - padding: EdgeInsets.all(8), - child: Column( - children: [ - cardTitle('Daily Average'), - Expanded( - child: charts.BarChart( - series, - animate: true, - barRendererDecorator: - new charts.BarLabelDecorator( - labelPosition: - charts.BarLabelPosition.inside, - labelPadding: 10, - labelAnchor: - charts.BarLabelAnchor.middle), - )) - ], - )))), - Container( - height: 300, - padding: EdgeInsets.all(20), - child: Card( - elevation: 8, - shadowColor: Colors.green, - child: Padding( - padding: EdgeInsets.all(8), - child: Column( - children: [ - cardTitle('Weekly Average'), - Expanded( - child: charts.BarChart( - series, - animate: true, - barRendererDecorator: - new charts.BarLabelDecorator( - labelPosition: - charts.BarLabelPosition.inside, - labelPadding: 10, - labelAnchor: - charts.BarLabelAnchor.middle), - )) - ], - )))) - ], - ), + icon: Icon(Icons.add)), + appBar: AppBar(title: Row(children: [Icon(Icons.article_outlined, color: Theme.of(context).primaryColor), SizedBox(width: 10), Text('Summary')])), + drawer: navDrawer(context, 0), + body: SafeArea( + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + children: [ + (false) + ? Container( + padding: EdgeInsets.all(20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text("Good\nMorning!", style: TextStyle(fontSize: 23, fontStyle: FontStyle.italic)), + Text( + "12%", + style: TextStyle(fontSize: 30), + ), + Column( + children: [ + Text(DateFormat("yy - MM-dd").format(DateTime.now())), + Text(DateFormat("HH:mm").format(DateTime.now()), style: TextStyle(fontSize: 40)), + ], + ) + ], + ), + ) + : Container(), + Container( + height: 300, + padding: EdgeInsets.all(10), + child: Card( + elevation: 8, + shadowColor: Colors.blueGrey, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20), + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 10, + ), + Text("Productivity", style: TextStyle(color: Colors.green, fontWeight: FontWeight.bold)), + ], + ), + Divider(), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Text("Today : "), + Text("${(productivityData.length > 0) ? productivityData[0].productivity.toStringAsFixed(1) : 'n/a'}%", + style: TextStyle( + fontSize: 20, + color: (productivityData.length > 1) + ? ((productivityData[0].productivity > productivityData[1].productivity) ? Colors.lightGreenAccent : Colors.red) + : Colors.white)) + ], + ), + Row( + children: [ + Text("Yesterday : "), + Text("${(productivityData.length > 1) ? productivityData[1].productivity.toStringAsFixed(1) : 'n/a'}%", style: TextStyle(fontSize: 18)) + ], + ), + ], + ), + Expanded( + child: SfCartesianChart( + // Initialize category axis + primaryXAxis: CategoryAxis(), + series: >[ + LineSeries( + // Bind data source + dataSource: productivityData.reversed.toList(), + xValueMapper: (ProductivityMapData sales, _) => sales.day, + yValueMapper: (ProductivityMapData sales, _) => sales.productivity, + color: Colors.green) + ]), + ) + ], + ), + )), + ), + Container( + height: 370, + padding: EdgeInsets.all(10), + child: Card( + elevation: 8, + shadowColor: Colors.blueGrey, + child: Padding( + padding: EdgeInsets.all(8), + child: (!days.isEmpty) + ? Column( + children: [ + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Padding(padding: EdgeInsets.all(20), child: Text('Daily Briefing', style: TextStyle(fontWeight: FontWeight.bold))), + dayPickerWidget(days, value: curDay, onChange: (_value) { + print('new val : $_value'); + curDay = _value; + setState(() { + LoadStats(); + }); + }), + ]), + Expanded( + child: SfCircularChart(legend: Legend(isVisible: true), series: [ + // Render pie chart + PieSeries( + dataSource: dailyData, + pointColorMapper: (CatMapData data, _) => data.color, + xValueMapper: (CatMapData data, _) => data.name, + yValueMapper: (CatMapData data, _) => data.time, + dataLabelMapper: (CatMapData sales, _) => MinutesToTimeString(sales.time), + dataLabelSettings: DataLabelSettings(isVisible: true, useSeriesColor: true)) + ])) + ], + ) + : Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator()])))), + Container( + height: 450, + padding: EdgeInsets.all(10), + child: Card( + elevation: 8, + shadowColor: Colors.blueGrey, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25), + child: Column(children: [ + Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text("Task Types", style: TextStyle(fontWeight: FontWeight.bold)), + InkWell( + onTap: () async { + DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now()); + if (value != null) { + taskTypeRange = value; + } + + LoadStats(); + }, + child: Text((taskTypeRange != null) ? (DateFormat("MM/dd").format(taskTypeRange!.start) + " - " + DateFormat("MM/dd").format(taskTypeRange!.end)) : 'n/a'), + ) + ]), + Expanded( + // maxHeight: 300, + // maxWidth: 100, + child: SfCartesianChart(primaryXAxis: CategoryAxis(), + //primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10), + series: >[ + BarSeries( + dataSource: taskTypesData, + xValueMapper: (TaskTypeMapData data, _) => data.task, + yValueMapper: (TaskTypeMapData data, _) => data.time / 60, + pointColorMapper: (TaskTypeMapData data, _) => data.color, + dataLabelMapper: (TaskTypeMapData data, _) => MinutesToTimeString(data.time), + dataLabelSettings: DataLabelSettings(isVisible: true), + color: Color.fromRGBO(8, 142, 255, 1)) + ]), + ) + ])))), + Container( + height: 450, + padding: EdgeInsets.all(10), + child: Card( + elevation: 8, + shadowColor: Colors.blueGrey, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25), + child: Column(children: [ + Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text("Categories", style: TextStyle(fontWeight: FontWeight.bold)), + InkWell( + onTap: () async { + DateTimeRange? value = await showDateRangePicker(context: context, firstDate: firstDay ?? DateTime.now(), lastDate: lastDay ?? DateTime.now()); + if (value != null) { + catsRange = value; + } + + LoadStats(); + }, + child: Text((catsRange != null) ? (DateFormat("MM/dd").format(catsRange!.start) + " - " + DateFormat("MM/dd").format(catsRange!.end)) : 'n/a'), + ) + ]), + Expanded( + // maxHeight: 300, + // maxWidth: 100, + child: SfCartesianChart(primaryXAxis: CategoryAxis(), + //primaryYAxis: NumericAxis(minimum: 0, maximum: 40, interval: 10), + series: >[ + BarSeries( + dataSource: catsData, + xValueMapper: (CatMapData data, _) => data.name, + yValueMapper: (CatMapData data, _) => data.time / 60, + pointColorMapper: (CatMapData data, _) => data.color, + dataLabelMapper: (CatMapData data, _) => MinutesToTimeString(data.time), + dataLabelSettings: DataLabelSettings(isVisible: true), + color: Color.fromRGBO(8, 142, 255, 1)) + ]), + ) + ])))), + ], ), - )); + ), + ), + ); + } + + Widget dayPickerWidget(List list, {required String value, required Function(String value) onChange}) { + if (!list.contains(value)) { + print("resetting"); + onChange(list[0]); + } + bool nextAvailable = (list.indexOf(value) < (list.length - 1)); + bool prevAvailable = (list.indexOf(value) > 0); + return Row( + children: [ + InkWell( + onTap: () { + if (nextAvailable) { + onChange(list[list.indexOf(value) + 1]); + } + }, + child: Container( + height: 40, + width: 40, + child: Icon(Icons.arrow_back_ios, size: 18, color: (nextAvailable) ? Colors.white : Colors.grey), + ), + ), + Text( + value, + ), + InkWell( + onTap: () { + if (prevAvailable) { + onChange(list[list.indexOf(value) - 1]); + } + }, + child: Container( + height: 40, + width: 40, + child: Icon(Icons.arrow_forward_ios, size: 18, color: (prevAvailable) ? Colors.white : Colors.grey), + )) + ], + ); } } -Widget cardTitle(String title) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children:[ - Padding(padding: EdgeInsets.all(20),child:Text(title, - style: TextStyle(fontWeight: FontWeight.bold))), - MaterialButton(onPressed: (){},child:moreButton())]); +Widget moreButton() { + return MaterialButton( + onPressed: () {}, + color: Colors.green, + child: Row( + children: [Text('More'), Icon(Icons.keyboard_arrow_right)], + )); } -Widget moreButton(){ - return MaterialButton( - onPressed: (){ - - }, - color: Colors.green, - child:Row( +Drawer navDrawer(BuildContext context, int pageIndex) { + return Drawer( + child: ListView( children: [ - Text('More'),Icon(Icons.keyboard_arrow_right) + Padding( + padding: EdgeInsets.all(16), + child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text("Time Tracker", style: TextStyle(fontSize: 25, color: Theme.of(context).accentColor, fontWeight: FontWeight.bold)), + Icon( + Icons.more_time, + size: 30, + ), + ])), + Divider(), + ListTile( + selected: (pageIndex == 0), + title: Text('Summary'), + leading: Icon(Icons.article_outlined, color: Theme.of(context).primaryColor), + onTap: () { + if (pageIndex == 0) { + return; + } + Navigator.of(context).pushReplacementNamed('/'); + }, + ), + // ListTile( + // selected: (pageIndex == 1), + // title: Text('Analytics'), + // leading: Icon(Icons.analytics_outlined, + // color: Theme.of(context).primaryColor), + // onTap: () { + // if (pageIndex == 1) { + // return; + // } + // // Navigator.of(context).pushReplacementNamed('/'); + // }, + // ), + Divider(), + ListTile( + selected: (pageIndex == 2), + title: Text('Activities'), + leading: Icon(Icons.task, color: Theme.of(context).primaryColor), + onTap: () { + if (pageIndex == 2) { + return; + } + Navigator.of(context).pushReplacementNamed('/Activities'); + }, + ), + ListTile( + selected: (pageIndex == 3), + title: Text('Task Types'), + leading: Icon(Icons.task, color: Theme.of(context).primaryColor), + onTap: () { + if (pageIndex == 3) { + return; + } + Navigator.of(context).pushReplacementNamed('/Tasks'); + }, + ), + ListTile( + selected: (pageIndex == 4), + title: Text('Categories'), + leading: Icon(Icons.account_tree_outlined, color: Theme.of(context).primaryColor), + onTap: () { + if (pageIndex == 4) { + return; + } + Navigator.of(context).pushReplacementNamed('/Categories'); + }, + ), + Divider(), + ListTile( + selected: (pageIndex == 5), + title: Text('Settings'), + leading: Icon(Icons.settings, color: Colors.blueGrey), + onTap: () {}, + ), + ListTile( + selected: (pageIndex == 6), + title: Text('About'), + leading: Icon(Icons.help_outline_outlined), + onTap: () {}, + ), ], )); } -class PopulationData { - String name; - int value; - charts.Color barColor; - PopulationData( - {required this.name, required this.value, required this.barColor}); +class MyPlayerBar extends CustomPainter { + MyPlayerBar(this.max, this.value, {this.background = Colors.lightBlue, this.fill = Colors.blue}); + + Color background = Colors.lightBlue; + Color fill = Colors.blue; + final int max; + final int value; + + @override + void paint(Canvas canvas, Size size) { + Paint paint = Paint(); + double cursor = (value * size.width) / max; + Radius cornerRadius = Radius.circular(10.0); + + // Already played half color (your darker orange) + paint.color = background; + + // Painting already played half + canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(0.0, 0.0, cursor, size.height), topLeft: cornerRadius, bottomLeft: cornerRadius), paint); + + // Yet to play half color (your lighter orange) + paint.color = fill; + + // Painting the remaining space + canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(cursor, 0.0, size.width - cursor, size.height), bottomRight: cornerRadius, topRight: cornerRadius), paint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => true; } -Drawer navDrawer(BuildContext context, int pageIndex){ - return Drawer( - child: ListView( - children: [ - Padding( - padding: EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children:[Text("Time Tracker", - style: TextStyle( - fontSize: 25, - color: Theme.of(context).accentColor, - fontWeight: FontWeight.bold)), - Icon(Icons.more_time,size: 30,), - ]) - ), - Divider(), - ListTile( - selected: (pageIndex == 0), - title: Text('Summary'), - leading: Icon(Icons.article_outlined,color: Theme.of(context).primaryColor), - onTap: () { - if(pageIndex==0){return;} - Navigator.of(context).pushReplacementNamed('/'); - }, - ), - ListTile( - selected: (pageIndex == 1), - title: Text('Analytics'), - leading: Icon(Icons.analytics_outlined,color: Theme.of(context).primaryColor), - onTap: () { - if(pageIndex==1){return;} - // Navigator.of(context).pushReplacementNamed('/'); - }, - ), - Divider(), - ListTile( - selected: (pageIndex == 2), - title: Text('Activities'), - leading: Icon(Icons.task,color: Theme.of(context).primaryColor), - onTap: () { - if(pageIndex==2){return;} - Navigator.of(context).pushReplacementNamed('/Activities'); - }, - ), - ListTile( - selected: (pageIndex == 3), - title: Text('Task Types'), - leading: Icon(Icons.task,color: Theme.of(context).primaryColor), - onTap: () { - if(pageIndex==3){return;} - Navigator.of(context).pushReplacementNamed('/Tasks'); - }, - ), - ListTile( - selected: (pageIndex == 4), - title: Text('Categories'), - leading: Icon(Icons.account_tree_outlined,color: Theme.of(context).primaryColor), - onTap: () { - if(pageIndex==4){return;} - Navigator.of(context).pushReplacementNamed('/Categories'); - }, - ), - Divider(), - ListTile( - selected: (pageIndex == 5), - title: Text('Settings'), - leading: Icon(Icons.settings,color: Colors.blueGrey), - onTap: () { - - }, - ), - ListTile( - selected: (pageIndex == 6), - title: Text('About'), - leading: Icon(Icons.help_outline_outlined), - onTap: () { - - }, - ), - ], - )); -} \ No newline at end of file +class CatMapData { + CatMapData(this.name, this.time, this.color); + final String name; + final int time; + final Color color; +} + +class ProductivityMapData { + ProductivityMapData(this.day, this.productivity); + + final String day; + final double productivity; +} + +class TaskTypeMapData { + TaskTypeMapData(this.task, this.time, this.color); + final Color color; + final String task; + final int time; +} + +String MinutesToTimeString(minutes) { + int hours = (minutes / 60).floor(); + int mins = minutes % 60; + + String str = ""; + if (hours > 0) { + str += hours.toString() + "h"; + } + if (mins > 0) { + str += ((hours > 0) ? " " : "") + mins.toString() + "m"; + } + + return str; +} diff --git a/lib/newActivity.dart b/lib/newActivity.dart index 143f1ac..5ff6514 100644 --- a/lib/newActivity.dart +++ b/lib/newActivity.dart @@ -1,4 +1,5 @@ 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 'User.dart' as User; @@ -31,6 +32,7 @@ class _NewActivity extends State { DateTime startTime = DateTime.now(); DateTime endTime = DateTime.now().add(Duration(minutes: 30)); + TextEditingController metadataController = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( @@ -50,6 +52,7 @@ class _NewActivity extends State { Container( padding: EdgeInsets.all(10), child: Text('Task')), + Container( padding: EdgeInsets.symmetric( horizontal: 12, vertical: 1), @@ -78,6 +81,25 @@ class _NewActivity extends State { selectedCat = _value ?? 'n/a'; }); })), + + Container( + padding: EdgeInsets.all(10), + child:Column( + children: [ + + TextField( + controller: metadataController, + decoration: InputDecoration( + hintText: 'Description (optional)', + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(20) + ) + ), + ), + ], + ) + ), Container( child: Divider( height: 30, @@ -85,82 +107,107 @@ class _NewActivity extends State { Container( padding: EdgeInsets.all(10), child: Text('Start Time')), - Container( - padding: EdgeInsets.symmetric( - horizontal: 12, vertical: 1), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Colors.grey, width: 2)), - child: MaterialButton( - onPressed: () { - setState(() { - DatePicker.showDateTimePicker( - context, - showTitleActions: true, - onChanged: (date) { - // print('change $date'); - }, onConfirm: (date) { + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickTimeButton('Last', Function: (){ + if(User.activities.length > 0) { + startTime= User.activities[0].endTime; + } + }) + , + Container( + padding: EdgeInsets.symmetric( + horizontal: 12, vertical: 1), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.grey, width: 2)), + child: MaterialButton( + onPressed: () { setState(() { - if(endTime.compareTo(date) < 0){ - const snackBar = SnackBar( - content: Text('You cannot start something after you ended it!'), - ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - }else { - startTime = date; - } + DatePicker.showDateTimePicker( + context, + showTitleActions: true, + onChanged: (date) { + // print('change $date'); + }, onConfirm: (date) { + setState(() { + if(endTime.compareTo(date) < 0){ + const snackBar = SnackBar( + content: Text('You cannot start something after you ended it!'), + ); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + }else { + startTime = date; + } + }); + }, + currentTime: startTime, + locale: LocaleType.en); }); }, - currentTime: startTime, - locale: LocaleType.en); - }); - }, - child: Text( - dateFormat.format(startTime), - style: TextStyle( - color: Colors.blue)))), + child: Text( + dateFormat.format(startTime), + style: TextStyle( + color: Colors.blue)))), + QuickTimeButton('Now', Function: (){ + startTime = DateTime.now(); + }) + ], + ), SizedBox( height: 10, ), Container( padding: EdgeInsets.all(10), child: Text('Ended Time')), - Container( - padding: EdgeInsets.symmetric( - horizontal: 12, vertical: 1), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Colors.grey, width: 2)), - child: MaterialButton( + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container(width: 60,), + Container( + padding: EdgeInsets.symmetric( + horizontal: 12, vertical: 1), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.grey, width: 2)), + child: MaterialButton( - onPressed: () { - setState(() { - DatePicker.showDateTimePicker( - context, - showTitleActions: true, - onChanged: (date) { - // print('change $date'); - }, onConfirm: (date) { + onPressed: () { setState(() { - if(startTime.compareTo(date) > 0){ - const snackBar = SnackBar( - content: Text('You cannot end something before you start it!'), - ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - }else { - endTime = date; - } + DatePicker.showDateTimePicker( + context, + showTitleActions: true, + onChanged: (date) { + // print('change $date'); + }, onConfirm: (date) { + setState(() { + if(startTime.compareTo(date) > 0){ + const snackBar = SnackBar( + content: Text('You cannot end something before you start it!'), + ); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + }else { + endTime = date; + } + }); + }, + currentTime: endTime, + locale: LocaleType.en); }); }, - currentTime: endTime, - locale: LocaleType.en); - }); - }, - child: Text(dateFormat.format(endTime), - style: TextStyle( - color: Colors.blue)))), + child: Text(dateFormat.format(endTime), + style: TextStyle( + color: Colors.blue)))), + QuickTimeButton('Now', Function: (){ + endTime = DateTime.now(); + }) + ], + ), SizedBox( height: 30, ), @@ -173,6 +220,12 @@ class _NewActivity extends State { Divider( height: 30, ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + ], + ) ]), ], ))), @@ -194,9 +247,7 @@ class _NewActivity extends State { shape: StadiumBorder() ), onPressed: () { - setState(() { - Navigator.pop(context); - }); + Navigator.pop(context); }, child: Text('Back', style: TextStyle(fontSize: 20))))), @@ -212,10 +263,6 @@ class _NewActivity extends State { onPressed: () { add_action(); - setState(() { - - }); - }, child: Text('Add Entry', style: TextStyle(fontSize: 20))))), @@ -224,14 +271,33 @@ class _NewActivity extends State { ]))); } + Widget QuickTimeButton(text, {Function}){ + return InkWell( + child: Container( + padding:EdgeInsets.symmetric(horizontal: 15), + height: 30, + decoration:BoxDecoration( + color: Colors.blueAccent, + borderRadius: BorderRadius.circular(50) + ), + child:Align(child: Text(text),alignment: Alignment.center,) + ), + + onTap: (){ + Function(); + setState(() { + + }); + },); + } + void add_action() async{ print('adding Task Type : $selectedCat at $startTime - $endTime'); bool failed=false; - await User.UserOperations.addActivity(selectedCat,startTime.toString(), endTime.toString(), onOverlap: (overlapCount){ + await User.UserOperations.addActivity(selectedCat,startTime.toString(), endTime.toString(),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) diff --git a/pubspec.lock b/pubspec.lock index b7b0b61..92230df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,20 +29,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" - charts_common: - dependency: transitive - description: - name: charts_common - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.0" - charts_flutter: - dependency: "direct main" - description: - name: charts_flutter - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.0" clock: dependency: transitive description: @@ -77,7 +63,7 @@ packages: name: device_info_plus url: "https://pub.dartlang.org" source: hosted - version: "3.2.1" + version: "3.2.2" device_info_plus_linux: dependency: transitive description: @@ -205,13 +191,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" matcher: dependency: transitive description: @@ -253,14 +232,14 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.0.8" path_provider_linux: dependency: transitive description: @@ -330,7 +309,7 @@ packages: name: shared_preferences_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.10" + version: "2.1.0" shared_preferences_linux: dependency: transitive description: @@ -420,6 +399,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + syncfusion_flutter_charts: + dependency: "direct main" + description: + name: syncfusion_flutter_charts + url: "https://pub.dartlang.org" + source: hosted + version: "19.4.53" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + url: "https://pub.dartlang.org" + source: hosted + version: "19.4.54" synchronized: dependency: transitive description: @@ -454,7 +447,7 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" vector_math: dependency: transitive description: @@ -503,7 +496,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.3.10" + version: "2.4.1" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9931de2..631705e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,11 +30,10 @@ dependencies: flutter: sdk: flutter - cupertino_icons: ^1.0.2 uuid: ^3.0.5 wakelock: ^0.6.1+1 - charts_flutter: ^0.12.0 + syncfusion_flutter_charts: ^19.4.53 flutter_datetime_picker: ^1.5.1 sqflite: ^2.0.2 intl: ^0.17.0