private void ExecuteNavigateToLandingPageCheckSelectionCommand() { if (!ApplicationInstanceData.SelectedLocalization.Abbreviation.Equals(SelectedLocalization.Abbreviation)) { ApplicationInstanceData.SetLocalization(SelectedLocalization.Abbreviation); SetLocalizationSelectionChanged(); // save pref ApplicationInstanceData.SerializedApplicationInstanceData.Localization = SelectedLocalization.Abbreviation; ApplicationInstanceData.SaveSerializedApplicationInstanceData(); } if (isFromMainMenu) { // this view localization refresh NotifyPropertyChange(nameof(ApplicationInstanceData)); // menu model localization refresh var menuContentPageModel = (MenuContentPageModel)ApplicationInstanceData.RootPage.Master.BindingContext; menuContentPageModel.NotifyPropertyChange(nameof(menuContentPageModel.ApplicationInstanceData)); return; } Application.Current.MainPage = new LandingContentPage { BindingContext = new LandingContentPageModel(ApplicationInstanceData) }; }
public App() { InitializeComponent(); var databasePath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), @"DATA.db"); var localizationDatabasePath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), @"LOCAL.db"); // Application Instance Data var applicationInstanceData = new ApplicationInstanceData { PlatformDataPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal), ApplicationInstanceDataFileName = @"AppData.json", DatabasePath = databasePath, LocalizationDatabasePath = localizationDatabasePath, SerializedApplicationInstanceData = new SerializedApplicationInstanceData(), AvailableLocalizations = new ObservableCollection <Localization>(), App = this }; var applicationInstanceDataFilePath = System.IO.Path.Combine(applicationInstanceData.PlatformDataPath, applicationInstanceData.ApplicationInstanceDataFileName); if (!System.IO.File.Exists(applicationInstanceDataFilePath)) { Helper.Json.JsonFileHelper.SaveDataToJsonFile(applicationInstanceData.SerializedApplicationInstanceData, applicationInstanceDataFilePath); } applicationInstanceData.SerializedApplicationInstanceData = Helper.Json.JsonFileHelper.GetDataFromJsonFile <SerializedApplicationInstanceData>(applicationInstanceDataFilePath); // Init db var db = new Database.Data.Database.MDPMSDatabaseContext(applicationInstanceData.DatabasePath); //db.Database.EnsureCreated(); db.Database.Migrate(); db.LoadRelatedData(); Database.Data.Database.DatabaseSeed.SeedDatabase(db); applicationInstanceData.Data = db; // Init Language Database var localizationDb = new Database.Localization.Database.LocalizationDatabaseContext(applicationInstanceData.LocalizationDatabasePath); //localizationDb.Database.EnsureCreated(); localizationDb.Database.Migrate(); Database.Localization.Database.DatabaseSeed.SeedDatabase(localizationDb); applicationInstanceData.Localization = localizationDb; // Load Localizations applicationInstanceData.GetAvailableLocalizations(); // Load saved localization preference try { applicationInstanceData.SetLocalization(applicationInstanceData.SerializedApplicationInstanceData.Localization); } catch { // revert to en on error applicationInstanceData.SerializedApplicationInstanceData.Localization = @"en"; applicationInstanceData.SaveSerializedApplicationInstanceData(); applicationInstanceData.SetLocalization(@"en"); } // Load view applicationInstanceData.NavigateToLandingView(); }
/* * SYNC STRATEGY * ============= * SUMMARY => Examine record existence and last update age * For now, mobile can not edit households after it is synced to parent * Use integer id from parent to identify records * Mobile will have internal and external (parent DPMS) ids * Record age will be determined by updated_at/LastUpdatedAt datetimes * * Mobile Parent_DPMS * ====== =========== * GetRecordFromParent <------------------------------- Exists on parent but not on mobile * Exists on Mobile but not on parent ----------------> GetRecordFromMobile (if not previously synced, otherwise soft/hard delete from mobile) * Older on mobile than parent <--UpdateMobileRecord--- Newer on parent than mobile * Newer on mobile than parent ---NotYetSupported-----> Older on parent than mobile (Currently invalid, would be supported by updating parent record) * * REASONING => * * Exists * ====== * Mobile | Parent * --------------- * 0 | 0 * N/A * 0 | 1 * Exists only on parent, mobile get from parent * 1 | 0 * Exists only on mobile, send to parent !!! NOTE check for internal id since it could have been deleted from parent * 1 | 1 * Exists on both, see Record_Age table ==> * * Exists_Special_Case * =================== * 1 | 0 * If no external id, send to parent * 1 | 0 * If has external id, delete or soft delete internally * * Record_Age * ========== * Mobile | Parent * --------------- * 0 | 0 * Same age, no action * 0 | 1 * Newer on parent, update mobile * 1 | 0 * Newer on mobile, update parent (NOT_YET_SUPPORTED) * 1 | 1 * Same age, no action * * NOTE on newer on mobile: * For now we can send those to the parent and mark as NEEDS_TO_BE_MANUALLY_RESOLVED * * ALSO, deleted from parent, if already synced but no longer on parent delete on mobile, use soft delete? * this would require the parent to support deleting households */ public static Tuple <bool, string> Sync(ApplicationInstanceData applicationInstanceData, bool allowAlreadySyncedUpdateToParent) { try { // Look Ups // PersonRelationship var personRelationshipResult = SyncObject( applicationInstanceData, false, @"/api/relationships", applicationInstanceData.Data.PersonRelationships); if (!personRelationshipResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Custom Fields var customFieldResult = SyncObject( applicationInstanceData, false, @"/api/custom_fields", applicationInstanceData.Data.CustomFields); if (!customFieldResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Status Customization Look Ups var statusCustomizationHazardousConditionsResult = SyncObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/status_customization_hazardous_conditions", applicationInstanceData.Data.StatusCustomizationHazardousConditions); if (!statusCustomizationHazardousConditionsResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var statusCustomizationHouseholdTasksResult = SyncObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/status_customization_household_tasks", applicationInstanceData.Data.StatusCustomizationHouseholdTasks); if (!statusCustomizationHouseholdTasksResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var statusCustomizationWorkActivitiesResult = SyncObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/status_customization_work_activities", applicationInstanceData.Data.StatusCustomizationWorkActivities); if (!statusCustomizationWorkActivitiesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Service Type Categories // TODO: add new method for non datetime based sync for this table var serviceTypeCategoriesResult = SyncObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/service_type_categories", applicationInstanceData.Data.ServiceTypeCategories); if (!serviceTypeCategoriesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Service Types var serviceTypesResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/service_types", applicationInstanceData.Data.ServiceTypes, @"service_type_category_id", applicationInstanceData.Data.ServiceTypeCategories); if (!serviceTypesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // set service type parent internal ids since not added through ui // TODO: alternate method for server only child records? foreach (var serviceTypeCategory in applicationInstanceData.Data.ServiceTypeCategories) { serviceTypeCategory.SetParentIdsInChildObjects(); } applicationInstanceData.Data.SaveChanges(); // Services var servicesResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/services", applicationInstanceData.Data.Services, @"service_type_id", applicationInstanceData.Data.ServiceTypes); if (!servicesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } foreach (var serviceType in applicationInstanceData.Data.ServiceTypes) { serviceType.SetParentIdsInChildObjects(); } applicationInstanceData.Data.SaveChanges(); // Data var householdsResult = SyncObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/households", applicationInstanceData.Data.Households); if (!householdsResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var householdsNewResult = SyncNewParentObjects( applicationInstanceData, @"/api/households", applicationInstanceData.Data.Households); if (!householdsNewResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } //< IncomeSource, Household > var incomeSourcesResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/income_sources", applicationInstanceData.Data.IncomeSources, @"household_id", applicationInstanceData.Data.Households); if (!incomeSourcesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var incomeSourcesNewResult = SyncNewChildObjects( applicationInstanceData, @"/api/income_sources", applicationInstanceData.Data.IncomeSources, @"household_id", applicationInstanceData.Data.Households); if (!incomeSourcesNewResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } //<Person, Household> var peopleResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/people", applicationInstanceData.Data.People, @"household_id", applicationInstanceData.Data.Households); if (!peopleResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var peopleNewResult = SyncNewChildObjects( applicationInstanceData, @"/api/people", applicationInstanceData.Data.People, @"household_id", applicationInstanceData.Data.Households); if (!peopleNewResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // <PersonFollowUp, Person> var peopleFollowUpResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/follow_ups", applicationInstanceData.Data.PersonFollowUps, @"person_id", applicationInstanceData.Data.People); if (!peopleFollowUpResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var peopleFollowUpNewResult = SyncNewChildObjects( applicationInstanceData, @"/api/follow_ups", applicationInstanceData.Data.PersonFollowUps, @"person_id", applicationInstanceData.Data.People); if (!peopleFollowUpNewResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Service Instances var serviceInstancesResult = SyncChildObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/service_instances", applicationInstanceData.Data.ServiceInstances, @"person_id", applicationInstanceData.Data.People); if (!serviceInstancesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } foreach (var person in applicationInstanceData.Data.People) { person.SetParentIdsInChildObjects(); } applicationInstanceData.Data.SaveChanges(); // new var serviceInstancesNewResult = SyncNewChildObjects( applicationInstanceData, @"/api/service_instances", applicationInstanceData.Data.ServiceInstances, @"person_id", applicationInstanceData.Data.People); if (!serviceInstancesNewResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Custom Household Values var customHouseholdValuesResult = SyncCustomValueObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/custom_values", applicationInstanceData.Data.CustomHouseholdValues, applicationInstanceData.Data.CustomFields.Where(a => a.ModelType == @"Household").ToList()); if (!customHouseholdValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var postNewCustomHouseholdValuesResult = PostCustomValues( applicationInstanceData, @"/api/custom_values", applicationInstanceData.Data.CustomHouseholdValues); if (!postNewCustomHouseholdValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Custom Person Values var customPersonValuesResult = SyncCustomValueObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/custom_values", applicationInstanceData.Data.CustomPersonValues, applicationInstanceData.Data.CustomFields.Where(a => a.ModelType == @"Person").ToList()); if (!customPersonValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var postNewCustomPersonValuesResult = PostCustomValues( applicationInstanceData, @"/api/custom_values", applicationInstanceData.Data.CustomPersonValues); if (!postNewCustomPersonValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // Custom PersonFollowUp Values var customPersonFollowUpValuesResult = SyncCustomValueObject( applicationInstanceData, allowAlreadySyncedUpdateToParent, @"/api/custom_values", applicationInstanceData.Data.CustomPersonFollowUpValues, applicationInstanceData.Data.CustomFields.Where(a => a.ModelType == @"FollowUp").ToList()); if (!customPersonFollowUpValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } var postNewCustomPersonFollowUpValuesResult = PostCustomValues( applicationInstanceData, @"/api/custom_values", applicationInstanceData.Data.CustomPersonFollowUpValues); if (!postNewCustomPersonFollowUpValuesResult.Item1) { return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } } catch { // TODO: error log return(new Tuple <bool, string>(false, applicationInstanceData.SelectedLocalization.Translations[@"ErrorSyncError"])); } // successful sync applicationInstanceData.SerializedApplicationInstanceData.LastSync = DateTime.UtcNow; applicationInstanceData.SaveSerializedApplicationInstanceData(); return(new Tuple <bool, string>(true, @"")); }