async void RefreshFromUserDataAsync() { try { IncrementPendingRequestCount(); // show loading // do async data read var todaysWeightEntry = await DataService.GetWeightEntryForDate(DateTime.Today.Date); var goal = await DataService.GetGoal(); // update the UI color (NOTE:: both goal and todaysWeightEntry could be null) var infoForToday = WeightLogicHelpers.GetTodaysDisplayInfo(goal, todaysWeightEntry); WindowColorService.ChangeAppBaseColor(infoForToday.ColorToShow); } catch (Exception ex) { AnalyticsService.TrackFatalError($"{nameof(RefreshFromUserDataAsync)} - an exception occurred.", ex); // NOTE:: not showing an error here as this is not in response to user action. potentially should show a non-intrusive error banner } finally { DecrementPendingRequestCount(); // hide loading } }
async void RefreshFromUserDataAsync() { try { IncrementPendingRequestCount(); // show loading IsWeightListingVisible = false; PlaceholderText = Constants.Strings.GraphPage_PlaceholderText_Loading; // defaults to 'loading..' as it is seen briefly // do async data read var todaysWeightEntry = await DataService.GetWeightEntryForDate(DateTime.Today.Date); var goal = await DataService.GetGoal(); // update the UI color (NOTE:: both goal and todaysWeightEntry could be null) var infoForToday = WeightLogicHelpers.GetTodaysDisplayInfo(goal, todaysWeightEntry); WindowColorService.ChangeAppBaseColor(infoForToday.ColorToShow); // update the listing of weight entries var latestWeightEntries = await DataService.GetLatestWeightEntries(Constants.App.WeightListingMaxCount) .ConfigureAwait(false) as List <WeightEntry>; IsWeightListingVisible = latestWeightEntries.Count > 0; // will show/hide list and placeholder label PlaceholderText = IsWeightListingVisible ? string.Empty : Constants.Strings.GraphPage_PlaceholderText_NoEntries; // create a lookup of success/failure values for weight entries and set on converter (used for showing/hiding checkmark per row) Dictionary <WeightEntry, bool> successForDateLookup = new Dictionary <WeightEntry, bool>(); foreach (var entry in latestWeightEntries) { bool success = WeightLogicHelpers.WeightMetGoalOnDate(goal, entry.Date, entry.Weight); successForDateLookup.Add(entry, success); } CheckmarkVisibilityConverter.SuccessForDateLookup = successForDateLookup; // NOTE:: Updates to observable collections must happen on UI thread Device.BeginInvokeOnMainThread(() => { LatestWeightEntries = (latestWeightEntries == null) ? LatestWeightEntries = new ObservableCollection <WeightEntry>() : LatestWeightEntries = new ObservableCollection <WeightEntry>(latestWeightEntries); }); // NOTE:: we limit how many points are graphed as it can be a performance concern if too high, and OxyPlot appears to stop drawing connecting lines beyond ~530 items int maxGraphPoints = (Device.RuntimePlatform == Device.Android) ? Constants.App.WeightGraphingMaxCount_Android : Constants.App.WeightGraphingMaxCount; var limitedEntries = latestWeightEntries.OrderByDescending(x => x.Date).Take(maxGraphPoints).ToList(); RefreshGraphDataModel(limitedEntries, goal); } catch (Exception ex) { AnalyticsService.TrackFatalError($"{nameof(RefreshFromUserDataAsync)} - an exception occurred.", ex); // NOTE:: not showing an error here as this is not in response to user action. potentially should show a non-intrusive error banner } finally { DecrementPendingRequestCount(); // hide loading } }
async void RefreshFromUserDataAsync() { if (_isFirstStartup) { _isFirstStartup = false; // if we need to show the welcome flow don't bother updating data (will be updated when this page appears again) if (await ShowWelcomeFlowIfNeeded()) { return; } } try { IncrementPendingRequestCount(); // show loading // do async data read var todaysWeightEntry = await DataService.GetWeightEntryForDate(DateTime.Today.Date); var goal = await DataService.GetGoal(); // get all the info needed to update the UI (NOTE:: both goal and todaysWeightEntry could be null) var infoForToday = WeightLogicHelpers.GetTodaysDisplayInfo(goal, todaysWeightEntry); TodaysWeight = infoForToday.TodaysDisplayWeight; TodaysMessage = infoForToday.TodaysMessage; HowToEatText = infoForToday.HowToEatMessage; IsEnterWeightButtonVisible = infoForToday.IsEnterWeightButtonVisible; IsSetGoalButtonVisible = infoForToday.IsSetGoalButtonVisible; MainLabelFontSize = SettingsService.WeightUnit == Enumerations.WeightUnitEnum.StonesAndPounds ? Constants.UI.DailyInfoFontSize_Stones : Constants.UI.DailyInfoFontSize_Normal; WindowColorService.ChangeAppBaseColor(infoForToday.ColorToShow); } catch (Exception ex) { AnalyticsService.TrackFatalError($"{nameof(RefreshFromUserDataAsync)} - an exception occurred.", ex); // NOTE:: not showing an error here as this is not in response to user action. potentially should show a non-intrusive error banner } finally { DecrementPendingRequestCount(); // hide loading } }
void RefreshGraphDataModel(List <WeightEntry> entries, WeightLossGoal goal) { // TODO:: FUTURE:: does all of this have to be done for each refresh? could the axis's be re-used and just // have the data points repopulated? var dateRange = WeightLogicHelpers.GetGraphDateRange(entries); DateTime dateRangeStart = dateRange.Item1; DateTime dateRangeEnd = dateRange.Item2; var weightRange = WeightLogicHelpers.GetMinMaxWeightRange(goal, entries, dateRangeStart, dateRangeEnd); decimal minGraphWeight = weightRange.Item1; decimal maxGraphWeight = weightRange.Item2; // OxyPlot var plotModel = new PlotModel(); // { Title = "OxyPlot Demo" }; plotModel.IsLegendVisible = false; plotModel.PlotAreaBorderColor = GRID_LINES_COLOR_BORDER; // NOTE:: it is assumed the date will always be the first axes in the AxisChanged wiring/un-wiring as that is used // to adjust line markers to show months instead of weeks at a certain zoom level // XAxis - dates plotModel.Axes.Add( new DateTimeAxis { Position = AxisPosition.Bottom, Minimum = DateTimeAxis.ToDouble(dateRangeStart), Maximum = DateTimeAxis.ToDouble(dateRangeEnd), AxislineColor = OxyColors.White, TicklineColor = OxyColors.White, MajorGridlineColor = GRID_LINES_COLOR_MAJOR, MinorGridlineColor = GRID_LINES_COLOR_MINOR, AxislineStyle = LineStyle.Solid, TextColor = OxyColors.White, TickStyle = TickStyle.Outside, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MinorIntervalType = DateTimeIntervalType.Days, IntervalType = DateTimeIntervalType.Days, MinorStep = WeekScale_MinorStep, MajorStep = WeekScale_MajorStep, // a week StringFormat = WeekScale_AxisFormat, // TODO:: FUTURE:: make swap for some cultures? IsZoomEnabled = true, MinimumRange = Constants.App.Graph_MinDateRangeVisible, // closest zoom in shows at least 5 days MaximumRange = Constants.App.Graph_MaxDateRangeVisible, // furthest zoom out shows at most 1 year }); // YAxis - weights plotModel.Axes.Add( new LinearAxis { Position = AxisPosition.Left, Minimum = (double)minGraphWeight, Maximum = (double)maxGraphWeight, AxislineColor = OxyColors.White, TicklineColor = OxyColors.White, MajorGridlineColor = GRID_LINES_COLOR_MAJOR, MinorGridlineColor = GRID_LINES_COLOR_MINOR, AxislineStyle = LineStyle.Solid, TextColor = OxyColors.White, TickStyle = TickStyle.Outside, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MinorStep = 1, MajorStep = 5, IsZoomEnabled = true, MinimumRange = Constants.App.Graph_MinWeightRangeVisible, // closest zoom in shows at least 5 pounds MaximumRange = Constants.App.Graph_MaxWeightRangeVisible // furthest zoom out shows at most 100 pounds }); var series1 = new LineSeries { MarkerType = MarkerType.Circle, MarkerSize = 4, MarkerStroke = OxyColors.White, MarkerFill = OxyColors.White, StrokeThickness = 4, MarkerStrokeThickness = 1, Color = OxyColors.White }; foreach (var entry in entries) { series1.Points.Add(new DataPoint(DateTimeAxis.ToDouble(entry.Date), Decimal.ToDouble(entry.Weight))); } plotModel.Series.Clear(); plotModel.Series.Add(series1); // setup goal line if (goal != null) { var series2 = new LineSeries { MarkerType = MarkerType.None, LineStyle = LineStyle.Dash, Color = OxyColors.White }; // diet line // we want to extend the goal line at least 30 days past the end of the goal and extend it further if they are already past // the goal date (ex: they are 90 days past goal end date and just using the line for maintenance) var goalExtendedDate = goal.GoalDate + TimeSpan.FromDays(30); if (DateTime.Today.Date > goalExtendedDate) { goalExtendedDate = DateTime.Today.Date + TimeSpan.FromDays(30); } series2.Points.Add(new DataPoint(DateTimeAxis.ToDouble(goal.StartDate - TimeSpan.FromDays(30)), (double)goal.StartWeight)); series2.Points.Add(new DataPoint(DateTimeAxis.ToDouble(goal.StartDate), (double)goal.StartWeight)); series2.Points.Add(new DataPoint(DateTimeAxis.ToDouble(goal.GoalDate), (double)goal.GoalWeight)); series2.Points.Add(new DataPoint(DateTimeAxis.ToDouble(goalExtendedDate), (double)goal.GoalWeight)); plotModel.Series.Add(series2); } UnwireDateAxisChangedEvent(); // unwire any previous event handlers for axis zoom changing PlotModel = plotModel; PlotModel.Axes[0].AxisChanged += DateAxis_Changed; }
public async Task <ResultWithErrorText> ChangeWeightAndGoalUnits(WeightUnitEnum newUnits, bool convertValues) { // convert all values bool success = true; string errorText = string.Empty; var allEntries = await GetAllWeightEntries(); if (allEntries == null) { AnalyticsService.TrackFatalError($"{nameof(ChangeWeightAndGoalUnits)} - an error occurred trying to get weights!"); success = false; errorText = Constants.Strings.DataService_ChangeWeightAndGoalUnits_UnableToGetWeights; } else { var weightsWithDifferentUnits = allEntries.Where(w => w.WeightUnit != newUnits); if (weightsWithDifferentUnits.Any()) { foreach (var weight in weightsWithDifferentUnits) { if (!await RemoveWeightEntryForDate(weight.Date.Date)) { AnalyticsService.TrackFatalError($"{nameof(ChangeWeightAndGoalUnits)} - an error occurred removing weight entry for date {weight.Date.Date}!"); success = false; errorText = string.Format(Constants.Strings.DataService_ChangeWeightAndGoalUnits_FailedRemovingWeight, weight.Date.Date); break; } if (convertValues) { weight.Weight = WeightLogicHelpers.ConvertWeightUnits(weight.Weight, weight.WeightUnit, newUnits); } weight.WeightUnit = newUnits; if (!await AddWeightEntry(weight)) { AnalyticsService.TrackFatalError($"{nameof(ChangeWeightAndGoalUnits)} - an error occurred adding weight entry for date {weight.Date.Date}!"); success = false; errorText = string.Format(Constants.Strings.DataService_ChangeWeightAndGoalUnits_FailedAddingWeight, weight.Date.Date); break; } } } // if we have converted all weights, now update the goal (if exists) if (success) { var goal = await GetGoal(); if (goal != null) { if (convertValues) { goal.StartWeight = WeightLogicHelpers.ConvertWeightUnits(goal.StartWeight, goal.WeightUnit, newUnits); goal.GoalWeight = WeightLogicHelpers.ConvertWeightUnits(goal.GoalWeight, goal.WeightUnit, newUnits); } goal.WeightUnit = newUnits; if (!await RemoveGoal()) { AnalyticsService.TrackFatalError($"{nameof(ChangeWeightAndGoalUnits)} - an error occurred removing previous goal!"); errorText = Constants.Strings.DataService_ChangeWeightAndGoalUnits_FailedRemovingGoal; success = false; } else { if (!await SetGoal(goal)) { AnalyticsService.TrackFatalError($"{nameof(ChangeWeightAndGoalUnits)} - an error occurred adding new goal!"); errorText = Constants.Strings.DataService_ChangeWeightAndGoalUnits_FailedAddingGoal; success = false; } } } } } return(new ResultWithErrorText(success, errorText)); }