Skip to content

Commit

Permalink
restructure main to get initial user if exists
Browse files Browse the repository at this point in the history
  • Loading branch information
seesharpguy committed Nov 7, 2024
1 parent e4b012f commit 27b5acf
Show file tree
Hide file tree
Showing 14 changed files with 407 additions and 182 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test, seed, assets
.PHONY: test seed assets

clean:
flutter clean && flutter pub get
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<!-- <uses-permission android:name="com.google.android.gms.permission.AD_ID"/> -->

<application
android:usesCleartextTraffic="true"
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>

<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<!-- <uses-permission android:name="com.google.android.gms.permission.AD_ID"/> -->

<uses-permission android:name="android.permission.BODY_SENSORS"/>
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
Expand Down
96 changes: 86 additions & 10 deletions lib/app/models/user.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,97 @@
//User Model
class UserModel {
import 'package:cloud_firestore/cloud_firestore.dart';

class Zone2User {
final String uid;
final String email;
String name;
Map<String, dynamic> fcmTokenMap;

UserModel(
{required this.uid, required this.email, required this.name, required this.fcmTokenMap});
final bool onboardingComplete;
ZoneSettings? zoneSettings;
Zone2User(
{required this.uid,
required this.email,
required this.name,
required this.onboardingComplete,
this.zoneSettings});

factory UserModel.fromJson(Map data) {
return UserModel(
factory Zone2User.fromJson(Map data) {
return Zone2User(
uid: data['uid'],
email: data['email'] ?? '',
name: data['name'] ?? '',
fcmTokenMap: data['fcmTokenMap'] ?? {});
onboardingComplete: data['onboardingComplete'] ?? false,
zoneSettings: ZoneSettings.fromJson(data['zoneSettings'] ?? {}));
}

Map<String, dynamic> toJson() => {
"uid": uid,
"email": email,
"name": name,
"onboardingComplete": onboardingComplete,
"zoneSettings": zoneSettings?.toJson() ?? {}
};
}

class ZoneSettings {
final Timestamp journeyStartDate;
final int dailyWaterGoalInOz;
final int dailyZonePointsGoal;
final int dailyCalorieIntakeGoal;
final int dailyCaloriesBurnedGoal;
final int dailyStepsGoal;
final String reasonForStartingJourney;
final double initialWeightInLbs;
final double targetWeightInLbs;
final double heightInInches;
final int heightInFeet;
final String birthDate;
final String gender;

ZoneSettings(
{required this.journeyStartDate,
required this.dailyWaterGoalInOz,
required this.dailyZonePointsGoal,
required this.dailyCalorieIntakeGoal,
required this.dailyCaloriesBurnedGoal,
required this.dailyStepsGoal,
required this.reasonForStartingJourney,
required this.initialWeightInLbs,
required this.targetWeightInLbs,
required this.heightInInches,
required this.heightInFeet,
required this.birthDate,
required this.gender});

factory ZoneSettings.fromJson(Map data) {
return ZoneSettings(
journeyStartDate: data['journeyStartDate'] as Timestamp? ?? Timestamp.now(),
dailyWaterGoalInOz: (data['dailyWaterGoalInOz'] as num?)?.toInt() ?? 100,
dailyZonePointsGoal: (data['dailyZonePointsGoal'] as num?)?.toInt() ?? 100,
dailyCalorieIntakeGoal: (data['dailyCalorieIntakeGoal'] as num?)?.toInt() ?? 0,
dailyCaloriesBurnedGoal: (data['dailyCaloriesBurnedGoal'] as num?)?.toInt() ?? 0,
dailyStepsGoal: (data['dailyStepsGoal'] as num?)?.toInt() ?? 10000,
reasonForStartingJourney: data['reasonForStartingJourney'] as String? ?? '',
initialWeightInLbs: (data['initialWeightInLbs'] as num?)?.toDouble() ?? 0.0,
targetWeightInLbs: (data['targetWeightInLbs'] as num?)?.toDouble() ?? 0.0,
heightInInches: (data['heightInInches'] as num?)?.toDouble() ?? 0.0,
heightInFeet: (data['heightInFeet'] as num?)?.toInt() ?? 0,
birthDate: data['birthDate'] as String? ?? '',
gender: data['gender'] as String? ?? '');
}

Map<String, dynamic> toJson() =>
{"uid": uid, "email": email, "name": name, "fcmTokenMap": fcmTokenMap};
Map<String, dynamic> toJson() => {
"journeyStartDate": journeyStartDate,
"dailyWaterGoalInOz": dailyWaterGoalInOz,
"dailyZonePointsGoal": dailyZonePointsGoal,
"dailyCalorieIntakeGoal": dailyCalorieIntakeGoal,
"dailyCaloriesBurnedGoal": dailyCaloriesBurnedGoal,
"dailyStepsGoal": dailyStepsGoal,
"reasonForStartingJourney": reasonForStartingJourney,
"initialWeightInLbs": initialWeightInLbs,
"targetWeightInLbs": targetWeightInLbs,
"heightInInches": heightInInches,
"heightInFeet": heightInFeet,
"birthDate": birthDate,
"gender": gender
};
}
4 changes: 4 additions & 0 deletions lib/app/modules/diary/controllers/diary_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:speech_to_text/speech_recognition_error.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:zone2/app/modules/diary/controllers/activity_manager.dart';
import 'package:zone2/app/models/food.dart';
import 'package:zone2/app/services/food_service.dart';
Expand Down Expand Up @@ -75,6 +76,8 @@ class DiaryController extends GetxController {
late MobileScannerController scannerController;
StreamSubscription<Object?>? scannerSubscription;

ChartSeriesController? chartController;

@override
void onInit() async {
super.onInit();
Expand Down Expand Up @@ -200,6 +203,7 @@ class DiaryController extends GetxController {
}
}

// TODO: Each Health Data Type should be its own method, this should aggregate them all
Future<void> getHealthDataForSelectedDay() async {
// Retrieve weight data
final sameDay = diaryDate.value.year == DateTime.now().year &&
Expand Down
43 changes: 42 additions & 1 deletion lib/app/modules/diary/views/activity/widgets/steps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,30 @@ class StepsChart extends GetView<DiaryController> {
Widget build(BuildContext context) {
return Obx(
() => SfCartesianChart(
zoomPanBehavior: ZoomPanBehavior(
enablePanning: true,
enablePinching: true,
),
trackballBehavior: TrackballBehavior(
enable: true,
activationMode: ActivationMode.singleTap,
tooltipDisplayMode: TrackballDisplayMode.floatAllPoints,
shouldAlwaysShow: true,
tooltipSettings: InteractiveTooltip(enable: true, color: Colors.red),
builder: (BuildContext context, TrackballDetails trackballDetails) {
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'${trackballDetails.point!.y?.toInt()} steps',
style: const TextStyle(color: Colors.white),
),
);
},
),
title: const ChartTitle(text: 'Total Steps'),
primaryXAxis: DateTimeAxis(
intervalType: DateTimeIntervalType.hours,
Expand Down Expand Up @@ -50,7 +74,24 @@ class StepsChart extends GetView<DiaryController> {
),
),
],
tooltipBehavior: TooltipBehavior(enable: true),
// tooltipBehavior: TooltipBehavior(
// enable: true,
// activationMode: ActivationMode.longPress,
// shouldAlwaysShow: true,
// builder: (dynamic data, dynamic point, dynamic series, int pointIndex, int seriesIndex) {
// return Container(
// padding: const EdgeInsets.all(8),
// decoration: BoxDecoration(
// color: Colors.black87,
// borderRadius: BorderRadius.circular(4),
// ),
// child: Text(
// '${data.numericValue} steps',
// style: const TextStyle(color: Colors.white),
// ),
// );
// },
// ),
),
);
}
Expand Down
41 changes: 25 additions & 16 deletions lib/app/modules/global_bindings.dart
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@
import 'package:dart_openai/dart_openai.dart';
import 'package:zone2/app/models/user.dart';
import 'package:zone2/app/modules/loading_service.dart';
import 'package:zone2/app/services/auth_service.dart';
import 'package:zone2/app/services/firebase_service.dart';
import 'package:zone2/app/services/food_service.dart';
import 'package:zone2/app/services/health_service.dart';
import 'package:zone2/app/services/notification_service.dart';
import 'package:zone2/app/services/openai_service.dart';
import 'package:zone2/app/services/shared_preferences_service.dart';
import 'package:zone2/app/services/theme_service.dart';
import 'package:zone2/app/style/palette.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:logger/logger.dart';
import 'package:super_tooltip/super_tooltip.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:zone2/app/utils/env.dart';

class GlobalBindings extends Bindings {
final Palette palette;
final Logger logger;
final SharedPreferencesService sharedPreferencesService;
final FirebaseService firebaseService;
final Zone2User? initialUser;

GlobalBindings(
{required this.palette, required this.logger, required this.sharedPreferencesService});
GlobalBindings({required this.palette, required this.firebaseService, required this.initialUser});

@override
dependencies() {
//This should remain first as many things will log to Analytics
FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(!kDebugMode);

// Set OpenAI API key and logging
// TODO: Move to server side
OpenAI.apiKey = Env.openaiApiKey;
OpenAI.showLogs = kDebugMode;

// Initialize timezone data
tz.initializeTimeZones();

// Firebase Analytics
Get.put<FirebaseAnalytics>(FirebaseAnalytics.instance, permanent: true);

// Notification service
Get.lazyPut(() => NotificationService(), fenix: true);

// Super tooltip controller
Get.lazyPut(() => SuperTooltipController(), fenix: true);

Get.put<FirebaseAuth>(FirebaseAuth.instance);
Get.put<FirebaseFirestore>(FirebaseFirestore.instance);
Get.put<GoogleSignIn>(GoogleSignIn());
// Theme service
Get.put(ThemeService(), permanent: true);

// Food service
Get.put<FoodService>(FoodService(), permanent: true);
Get.put<HealthService>(HealthService(), permanent: true);
// Get.put<FcmService>(FcmService(), permanent: true);
Get.put<AuthService>(AuthService(), permanent: true);

// Firebase service
Get.put<FirebaseService>(firebaseService, permanent: true);

Get.put<OpenAI>(OpenAI.instance);
Get.put<OpenAIService>(OpenAIService(), permanent: true);

Get.put<FirebaseService>(FirebaseService(), permanent: true);

Get.put<BusyIndicatorService>(BusyIndicatorService(), permanent: true);

// Palette needed by Settings to get theme information
Expand Down
69 changes: 62 additions & 7 deletions lib/app/modules/intro/controllers/intro_controller.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:zone2/app/models/user.dart';
import 'package:zone2/app/routes/app_pages.dart';
import 'package:zone2/app/services/auth_service.dart';
import 'package:zone2/app/services/firebase_service.dart';
import 'package:zone2/app/services/health_service.dart';
import 'package:zone2/app/services/shared_preferences_service.dart';
import 'package:get/get.dart';
Expand All @@ -24,6 +28,11 @@ class IntroController extends GetxController {
final suggestedWeightLossUpperBound = 0.0.obs;
final suggestedWeightLossTarget = ''.obs;
final zone2TargetWeight = 0.0.obs;
final RxInt dailyWaterGoalInOz = 100.obs;
final RxInt dailyZonePointsGoal = 100.obs;
final RxInt dailyCalorieIntakeGoal = 1700.obs;
final RxInt dailyCaloriesBurnedGoal = 0.obs;
final RxInt dailyStepsGoal = 10000.obs;

final suggestedWeightLossMessage =
"We'll use your progress to predict when you'll hit your target as you follow your custom plan and adopting a healthy lifestyle. Your results cannot be guaranteed, but users typically lose 1-2 lb per week."
Expand Down Expand Up @@ -120,6 +129,39 @@ class IntroController extends GetxController {
return targetWeightController.text.isNotEmpty;
}

Future<void> setDailyWaterGoal(int goal) async {
dailyWaterGoalInOz.value = goal;
showNextButton.value = await haveAllGoals();
}

Future<void> setDailyZonePointsGoal(int goal) async {
dailyZonePointsGoal.value = goal;
showNextButton.value = await haveAllGoals();
}

Future<void> setDailyCalorieIntakeGoal(int goal) async {
dailyCalorieIntakeGoal.value = goal;
showNextButton.value = await haveAllGoals();
}

Future<void> setDailyCaloriesBurnedGoal(int goal) async {
dailyCaloriesBurnedGoal.value = goal;
showNextButton.value = await haveAllGoals();
}

Future<void> setDailyStepsGoal(int goal) async {
dailyStepsGoal.value = goal;
showNextButton.value = await haveAllGoals();
}

Future<bool> haveAllGoals() async {
return dailyWaterGoalInOz.value != 0 &&
dailyZonePointsGoal.value != 0 &&
dailyCalorieIntakeGoal.value != 0 &&
dailyCaloriesBurnedGoal.value != 0 &&
dailyStepsGoal.value != 0;
}

Future<void> setReason(String reason) async {
introLogger.i('setReason: $reason');
zone2Reason.value = reason;
Expand Down Expand Up @@ -152,9 +194,12 @@ class IntroController extends GetxController {
showNextButton.value = await haveGoals();
break;
case 3:
showNextButton.value = await haveTheMotivatingFactor();
showNextButton.value = await haveAllGoals();
break;
case 4:
showNextButton.value = await haveTheMotivatingFactor();
break;
case 5:
showNextButton.value = false;
await requestHealthPermissions();
break;
Expand All @@ -164,12 +209,22 @@ class IntroController extends GetxController {
//create a method called onFinish that saves a boolean called introFinished to sharedPreferences
void onFinish() {
_sharedPreferencesService.setIsIntroductionFinished(true);
_sharedPreferencesService.setZone2Goals(
double.parse(weightController.text),
double.parse(targetWeightController.text),
zone2Reason.value,
zone2Birthdate.value,
zone2Gender.value!);
introLogger.i('Introduction Finished');
FirebaseService.to.updateUserZoneSettings(ZoneSettings(
journeyStartDate: Timestamp.now(),
dailyWaterGoalInOz: dailyWaterGoalInOz.value,
dailyZonePointsGoal: dailyZonePointsGoal.value,
dailyCalorieIntakeGoal: dailyCalorieIntakeGoal.value,
dailyCaloriesBurnedGoal: dailyCaloriesBurnedGoal.value,
dailyStepsGoal: dailyStepsGoal.value,
reasonForStartingJourney: zone2Reason.value,
initialWeightInLbs: double.parse(weightController.text),
targetWeightInLbs: double.parse(targetWeightController.text),
heightInInches: heightInches.value.toDouble(),
heightInFeet: heightFeet.value.toInt(),
birthDate: zone2Birthdate.value,
gender: zone2Gender.value!));

introLogger.i('Introduction Finished');
Get.offNamed(Routes.home);
}
Expand Down
Loading

0 comments on commit 27b5acf

Please sign in to comment.