FEATURE: Wire In Firebase support.

This commit is contained in:
Jeremy Wall (zaphar) 2017-11-22 18:30:09 -06:00
parent 46099bbf32
commit 6a82a4e98a
10 changed files with 348 additions and 242 deletions

View File

@ -26,6 +26,7 @@ DynamicBibleIonic/nbproject
DynamicBibleIonic/obj
DynamicBibleIonic/bin
DynamicBibleIonic/.vscode
DynamicBibleIonic/www/assets/
DynamicBibleUtility/.vs
DynamicBibleIonic/platforms/android/release-signing.properties
DynamicBibleIonic/platforms/android/build

View File

@ -42,18 +42,18 @@ export class MyApp
{
// close the menu when clicking a link from the menu
this.menu.close('pages');
// because the actions menu is on a Page component, and you swap the SearchPage out,
// the menu get registered multiple times. to avoid some pages not opening the menu because
// multiple menus with the same id exist and the first one in the list is returned (which happens
// be disabled when another of the same id is added) it won't show. because not enabled.
// ---
// unregistering the actions menu whenever a new page is opened fixes the problem, because the menu
// will get reregistered when SearchPage loads. Also, if you go to a non SearchPage, the actions
// menu won't be there, but the unregister function doesn't fail if a non existent id is given,
// because the actions menu is on a Page component, and you swap the SearchPage out,
// the menu get registered multiple times. to avoid some pages not opening the menu because
// multiple menus with the same id exist and the first one in the list is returned (which happens
// be disabled when another of the same id is added) it won't show. because not enabled.
// ---
// unregistering the actions menu whenever a new page is opened fixes the problem, because the menu
// will get reregistered when SearchPage loads. Also, if you go to a non SearchPage, the actions
// menu won't be there, but the unregister function doesn't fail if a non existent id is given,
// so thats ok.
this.menu._unregister(this.menu.get('actions'));
// navigate to the new page if it is not the current page
this.nav.setRoot(page.component, page.params);
}

View File

@ -1,3 +1,4 @@
import { ProfileService } from './../services/profile-service';
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
@ -24,6 +25,8 @@ import { ErrorMessage } from '../components/error-message/error-message';
import { VersePickerModal } from '../components/verse-picker/verse-picker';
import {AngularFireModule } from 'angularfire2';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireDatabaseModule } from 'angularfire2/database';
export const firebaseConfig = {
apiKey: 'AIzaSyA3UV4s56CV2EumgvZmyJBTyU-vhv0xhc8',
@ -55,7 +58,9 @@ export const firebaseConfig = {
IonicStorageModule.forRoot(),
BrowserModule,
HttpModule,
AngularFireModule.initializeApp(firebaseConfig)
AngularFireModule.initializeApp(firebaseConfig),
AngularFireAuthModule,
AngularFireDatabaseModule,
],
bootstrap: [IonicApp],
entryComponents: [
@ -71,6 +76,6 @@ export const firebaseConfig = {
Error,
ErrorMessage
],
providers: [{ provide: ErrorHandler, useClass: IonicErrorHandler }, StatusBar, SplashScreen]
providers: [{ provide: ErrorHandler, useClass: IonicErrorHandler }, StatusBar, SplashScreen, ProfileService]
})
export class AppModule { }

View File

@ -1,93 +0,0 @@
/// <reference path="../../typings/globals/jquery/index.d.ts" />
import { Storage } from '@ionic/storage';
import { CardItem } from '../pages/search/search';
export class UserProfile
{
user: User;
constructor(u: User)
{
this.user = u;
}
public textSizeChanged()
{
$('html').css('font-size', this.user.font_size + 'px');
}
public update(t: UserProfile, local: Storage)
{
let updated = false;
let k;
const user = this.user;
for (k in user)
{
if (user.hasOwnProperty(k))
{
if (t[k] === undefined)
{
t[k] = user[k];
updated = true;
}
}
}
for (k in user)
if (user.hasOwnProperty(k))
user[k] = t[k];
if (updated)
this.save(local);
this.textSizeChanged();
}
save(local: Storage)
{
local.set('profile', JSON.stringify(this.user));
}
reset(local: Storage)
{
this.user.strongs_modal = true;
this.user.clear_search_after_query = false;
this.user.items = [];
this.user.append_to_bottom = false;
this.user.insert_next_to_item = false;
this.user.font_size = 10;
this.user.saved_pages = [];
this.user.verses_on_new_line = true;
this.save(local);
}
public static createDefaultUser(): User
{
return {
strongs_modal: true,
clear_search_after_query: false,
items: [],
append_to_bottom: false,
insert_next_to_item: false,
font_size: 10,
saved_pages: [],
verses_on_new_line: true
};
}
}
export type User = {
strongs_modal: boolean,
clear_search_after_query: boolean,
items: CardItem[],
append_to_bottom: boolean,
insert_next_to_item: boolean,
font_size: number,
saved_pages: SavedPage[],
verses_on_new_line: boolean,
}
export type SavedPage = {
queries: CardItem[],
title: string,
}

View File

@ -22,28 +22,28 @@
<ion-list-header>Search Settings</ion-list-header>
<ion-item>
<ion-label>Show Strongs as Modal</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.strongs_modal" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="this.profileService.profile().strongs_modal" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Clear Search after Query</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.clear_search_after_query" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="this.profileService.profile().clear_search_after_query" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Append Results Below</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.append_to_bottom" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="this.profileService.profile().append_to_bottom" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Insert Result Next to Item</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.insert_next_to_item" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="this.profileService.profile().insert_next_to_item" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Each Verse on New Line</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.verses_on_new_line" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="this.profileService.profile().verses_on_new_line" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-list-header>Adjust Text</ion-list-header>
<ion-list>
<ion-item>
<ion-range min="6" max="20" step="1" snaps="true" [(ngModel)]="userProfile.user.font_size" (ionChange)="textSizeChanged()">
<ion-range min="6" max="20" step="1" snaps="true" [(ngModel)]="this.profileService.profile().font_size" (ionChange)="textSizeChanged()">
<ion-label range-left class="small-text">A</ion-label>
<ion-label range-right>A</ion-label>
</ion-range>
@ -70,10 +70,10 @@
</ion-header>
<ion-content #searchcontent padding class="search-card">
<ion-card *ngFor="let item of userProfile.user.items">
<ion-card *ngFor="let item of this.profileService.profile().items">
<passage *ngIf="isPassage(item.type)"
[cardItem]="item"
[versesOnNewLine]="userProfile.user.verses_on_new_line"
[versesOnNewLine]="this.profileService.profile().verses_on_new_line"
(onClose)="removeItem($event)"
(onItemClicked)="getItemsNextToCard($event)"></passage>
<strongs *ngIf="isStrongs(item.type)"
@ -88,4 +88,4 @@
[cardItem]="item"
(onClose)="removeItem($event)"></error>
</ion-card>
</ion-content>
</ion-content>

View File

@ -5,7 +5,7 @@ import { Storage } from '@ionic/storage';
import { StrongsModal } from '../../components/strongs-modal/strongs-modal';
import { PagesService } from '../../services/pages-service';
import { UserProfile } from '../../libs/UserProfile';
import { ProfileService, User } from './../../services/profile-service';
import { Reference } from '../../libs/Reference';
import { VersePickerModal } from '../../components/verse-picker/verse-picker';
@ -15,7 +15,6 @@ import { VersePickerModal } from '../../components/verse-picker/verse-picker';
export class SearchPage implements OnInit
{
searchQuery = '';
userProfile: UserProfile;
last: CardItem;
loader: Loading;
title: string;
@ -26,57 +25,44 @@ export class SearchPage implements OnInit
, private menu: MenuController
, public loadingCtrl: LoadingController
, public modalCtrl: ModalController
, public local: Storage
, public profileService: ProfileService
, public params: NavParams
)
{
this.userProfile = new UserProfile(UserProfile.createDefaultUser());
}
ngOnInit(): void
{
ngOnInit(): void
{
let t = this.profileService.profile();
// Check if there is a profile saved in local storage
this.local.get('profile').then(profile =>
{
let t = this.userProfile;
this.loader = this.loadingCtrl.create({ content: 'Loading Page...' });
this.loader.present().then(() =>
{
this.initializeItems(t);
if (profile !== null)
t = JSON.parse(profile);
this.loader = this.loadingCtrl.create({ content: 'Loading Page...' });
this.loader.present().then(
() =>
{
this.userProfile.update(t, this.local);
this.initializeItems(this.userProfile);
this.loader.dismiss();
});
}).catch(error =>
{
console.log(error);
});
}
initializeItems(u: UserProfile)
this.loader.dismiss();
});
}
initializeItems(u: User)
{
// migrate old way of storing card items to the new.
let has_migrated = false;
for (let i in u.user.items)
for (let i in u.items)
{
if (u.user.items.hasOwnProperty(i))
if (u.items.hasOwnProperty(i))
{
let ci = u.user.items[i];
let ci = u.items[i];
if (ci['data'] !== undefined)
{
if (ci['data'].qry !== undefined)
u.user.items[i] = { qry: ci['data'].qry, dict: ci.dict, type: ci.type };
u.items[i] = { qry: ci['data'].qry, dict: ci.dict, type: ci.type };
else if (ci['data'].ref !== undefined)
u.user.items[i] = { qry: ci['data'].ref, dict: ci.dict, type: ci.type };
u.items[i] = { qry: ci['data'].ref, dict: ci.dict, type: ci.type };
else if (ci['data'].word !== undefined)
u.user.items[i] = { qry: ci['data'].word, dict: ci.dict, type: ci.type };
u.items[i] = { qry: ci['data'].word, dict: ci.dict, type: ci.type };
else if (ci['data'].sn !== undefined)
u.user.items[i] = {
u.items[i] = {
qry: ci['data'].sn,
dict: ci['prefix'] === 'G' ? 'grk' : 'heb',
type: ci.type
@ -87,7 +73,7 @@ export class SearchPage implements OnInit
}
}
for (let pg of u.user.saved_pages)
for (let pg of u.saved_pages)
{
for (let i in pg.queries)
{
@ -116,32 +102,33 @@ export class SearchPage implements OnInit
}
// initialize the pages.
this.pagesService.initializePages(u.user.saved_pages);
if (this.params.data.queries !== undefined)
this.userProfile.user.items = this.params.data.queries.slice();
if (this.params.data.title === undefined)
this.title = 'Search';
else
this.title = this.params.data.title;
this.pagesService.initializePages(u.saved_pages);
if (has_migrated)
this.userProfile.save(this.local);
if (this.params.data.queries !== undefined)
this.profileService.profile().items = this.params.data.queries.slice();
if (this.params.data.title === undefined)
this.title = 'Search';
else
this.title = this.params.data.title;
if (has_migrated)
this.profileService.save();
}
save()
{
this.userProfile.save(this.local);
this.profileService.save();
}
textSizeChanged()
{
this.userProfile.textSizeChanged();
this.profileService.textSizeChanged();
this.save();
}
actionsMenu()
{
this.menu.open('actions');
}
actionsMenu()
{
this.menu.open('actions');
}
addPage()
@ -167,9 +154,9 @@ export class SearchPage implements OnInit
text: 'Save',
handler: data =>
{
const p = { queries: this.userProfile.user.items.slice(), title: data.title };
this.userProfile.user.saved_pages.push(p);
this.userProfile.save(this.local);
const p = { queries: this.profileService.profile().items.slice(), title: data.title };
this.profileService.profile().saved_pages.push(p);
this.profileService.save();
this.pagesService.addPage(p);
}
}
@ -178,14 +165,14 @@ export class SearchPage implements OnInit
alert.present();
}
updatePage()
updatePage()
{
const page = this.userProfile.user.saved_pages.find(
const page = this.profileService.profile().saved_pages.find(
i =>
i.title === this.params.data.title
);
page.queries = this.userProfile.user.items.slice();
this.userProfile.save(this.local);
page.queries = this.profileService.profile().items.slice();
this.profileService.save();
}
setQuery(searchbar)
@ -222,31 +209,31 @@ export class SearchPage implements OnInit
removeItem(item)
{
const idx = this.userProfile.user.items.indexOf(item);
this.userProfile.user.items.splice(idx, 1);
const idx = this.profileService.profile().items.indexOf(item);
this.profileService.profile().items.splice(idx, 1);
// save the users settings.
this.userProfile.save(this.local);
this.profileService.save();
}
addItemToList(item: CardItem)
{
if (this.userProfile.user.append_to_bottom)
if (this.profileService.profile().append_to_bottom)
{
if (this.last != null && this.userProfile.user.insert_next_to_item)
if (this.last != null && this.profileService.profile().insert_next_to_item)
{
const idx = this.userProfile.user.items.indexOf(this.last);
this.userProfile.user.items.splice(idx + 1, 0, item);
const idx = this.profileService.profile().items.indexOf(this.last);
this.profileService.profile().items.splice(idx + 1, 0, item);
} else
this.userProfile.user.items.push(item);
this.profileService.profile().items.push(item);
}
else
{
if (this.last != null && this.userProfile.user.insert_next_to_item)
if (this.last != null && this.profileService.profile().insert_next_to_item)
{
const idx = this.userProfile.user.items.indexOf(this.last);
this.userProfile.user.items.splice(idx, 0, item);
const idx = this.profileService.profile().items.indexOf(this.last);
this.profileService.profile().items.splice(idx, 0, item);
} else
this.userProfile.user.items.unshift(item);
this.profileService.profile().items.unshift(item);
}
this.last = null;
}
@ -258,7 +245,7 @@ export class SearchPage implements OnInit
getItemList(search: string): Promise<CardItem[]>
{
return new Promise((resolve) =>
return new Promise((resolve) =>
{
const list: CardItem[] = [];
@ -300,10 +287,10 @@ export class SearchPage implements OnInit
}
}
}
if (this.userProfile.user.clear_search_after_query)
if (this.profileService.profile().clear_search_after_query)
$('.searchbar-input').val('');
this.userProfile.save(this.local);
this.profileService.save();
}
catch (error)
{
@ -317,7 +304,7 @@ export class SearchPage implements OnInit
updateUIwithItems(search: string, from_search_bar: boolean)
{
this.getItemList(search).then(lst =>
this.getItemList(search).then(lst =>
{
this.loader = this.loadingCtrl.create({ content: 'Looking up Query...' });
this.loader.present().then(
@ -325,7 +312,7 @@ export class SearchPage implements OnInit
{
for (let item of lst)
{
if (item.type === 'Strongs' && this.userProfile.user.strongs_modal && !from_search_bar)
if (item.type === 'Strongs' && this.profileService.profile().strongs_modal && !from_search_bar)
{
const modal = this.modalCtrl.create(StrongsModal, { sn: parseInt(item.qry), dict: item.dict, onItemClicked: this });
modal.present();
@ -340,7 +327,7 @@ export class SearchPage implements OnInit
}
export type OpenData = { card: CardItem, qry: string, from_search_bar: boolean }
export type CardItem = { qry: string, type: string, dict: string }
class Item

View File

@ -7,37 +7,47 @@
</ion-navbar>
</ion-header>
<ion-content padding>
<ng-template [ngIf]="userProfile.user">
<ng-template [ngIf]="profileService.profile()">
<h4>Search Settings</h4>
<ion-item>
<button ion-button (click)="reset()">Reset Settings</button>
<button ion-button (click)="profileService.reset()">Reset Settings</button>
</ion-item>
<ng-template [ngIf]="!profileService.currentUser()">
<ion-item>
<button ion-button (click)="profileService.authenticate()">Login With Google</button>
</ion-item>
</ng-template>
<ng-template [ngIf]="profileService.currentUser()">
<ion-item>
<button ion-button (click)="profileService.logout()">Logout</button>
</ion-item>
</ng-template>
<ion-item>
<ion-label>Show Strongs as Modal</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.strongs_modal" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="profileService.profile().strongs_modal" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Clear Search after Query</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.clear_search_after_query" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="profileService.profile().clear_search_after_query" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Append Results Below</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.append_to_bottom" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="profileService.profile().append_to_bottom" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Insert Result Next to Item</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.insert_next_to_item" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="profileService.profile().insert_next_to_item" (ionChange)="save()"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Each Verse on New Line</ion-label>
<ion-toggle color="dark" [(ngModel)]="userProfile.user.verses_on_new_line" (ionChange)="save()"></ion-toggle>
<ion-toggle color="dark" [(ngModel)]="profileService.profile().verses_on_new_line" (ionChange)="save()"></ion-toggle>
</ion-item>
<h4>Adjust Text</h4>
<ion-list>
<ion-item>
<ion-range min="6" max="20" step="1" snaps="true" [(ngModel)]="userProfile.user.font_size" (ionChange)="textSizeChanged()">
<ion-range min="6" max="20" step="1" snaps="true" [(ngModel)]="profileService.profile().font_size" (ionChange)="textSizeChanged()">
<ion-label range-left class="small-text">A</ion-label>
<ion-label range-right>A</ion-label>
</ion-range>
@ -46,7 +56,7 @@
<h4>Manage Pages</h4>
<ion-list>
<ion-item *ngFor="let p of userProfile.user.saved_pages">
<ion-item *ngFor="let p of profileService.profile().saved_pages">
{{p.title}}
<button ion-button item-end outline icon-end (click)="removePage(p)">
Delete Page <ion-icon name="trash"></ion-icon>
@ -54,4 +64,4 @@
</ion-item>
</ion-list>
</ng-template>
</ion-content>
</ion-content>

View File

@ -2,53 +2,35 @@
import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { Storage } from '@ionic/storage';
import { SavedPage, UserProfile } from '../../libs/UserProfile';
import { ProfileService, SavedPage } from '../../services/profile-service';
@Component({
selector: 'settings',
templateUrl: 'settings.html'
templateUrl: 'settings.html',
})
export class SettingsPage
{
textSize = 0;
userProfile: UserProfile;
constructor(
public navCtrl: NavController
, public local: Storage
, private alertCtrl: AlertController)
{
this.userProfile = new UserProfile(UserProfile.createDefaultUser());
// Check if there is a profile saved in local storage
this.local.get('profile').then(profile =>
{
let t = this.userProfile;
if (profile !== null)
t = JSON.parse(profile);
this.userProfile.update(t, local);
}).catch(error =>
{
console.log(error);
});
}
, private alertCtrl: AlertController
, public profileService: ProfileService
) {}
textSizeChanged()
{
this.userProfile.textSizeChanged();
this.profileService.textSizeChanged();
this.save();
}
save()
{
this.userProfile.save(this.local);
this.profileService.save()
}
reset()
{
this.userProfile.reset(this.local);
this.profileService.reset()
}
removePage(page: SavedPage)
@ -69,15 +51,11 @@ export class SettingsPage
text: 'Ok',
handler: () =>
{
let idx = this.userProfile.user.saved_pages.indexOf(page);
this.userProfile.user.saved_pages.splice(idx, 1);
// save the users settings.
this.userProfile.save(this.local);
this.profileService.removePage(page);
}
}
]
});
alert.present();
}
}
}

View File

@ -1,10 +1,10 @@
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';
import { SearchPage } from '../pages/search/search';
import { SearchPage } from '../pages/search/search';
import { SettingsPage } from '../pages/settings/settings';
import { HelpPage } from '../pages/help/help';
import { SavedPage } from '../libs/UserProfile';
import { SavedPage } from './profile-service';
@Injectable()
export class PagesService
@ -14,10 +14,10 @@ export class PagesService
constructor(public local: Storage)
{
this.pages = [
{ title: 'Search', component: SearchPage, params: { queries: [], title: 'Search' }, icon: 'search' },
{ title: 'Settings', component: SettingsPage, params: {}, icon: 'settings' },
{ title: 'Help', component: HelpPage, params: {}, icon: 'help-circle' }
this.pages = [
{ title: 'Search', component: SearchPage, params: { queries: [], title: 'Search' }, icon: 'search' },
{ title: 'Settings', component: SettingsPage, params: {}, icon: 'settings' },
{ title: 'Help', component: HelpPage, params: {}, icon: 'help-circle' }
];
this.savedPages = [];
}
@ -46,4 +46,4 @@ export class PagesService
this.savedPages.push({ title: p.title, component: SearchPage, params: { queries: p.queries, title: p.title } });
}
}
}
}

View File

@ -0,0 +1,218 @@
/// <reference path="../../typings/globals/jquery/index.d.ts" />
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Observable } from 'rxjs/Observable';
import { Catch } from 'rxjs/add/operator';
import { Storage } from '@ionic/storage';
import { CardItem } from '../pages/search/search';
type fbObject<T> = {
ref: AngularFireObject<T>,
stream: Observable<T>,
};
export const DEFAULT_USER_NAME = 'john_doe';
export type User = {
username: string,
uid: string|null,
strongs_modal: boolean,
clear_search_after_query: boolean,
items: CardItem[],
append_to_bottom: boolean,
insert_next_to_item: boolean,
font_size: number,
saved_pages: SavedPage[],
verses_on_new_line: boolean,
}
export type SavedPage = {
queries: CardItem[],
title: string,
}
@Injectable()
export class ProfileService {
localProfile: User;
remoteProfile: fbObject<User> | null;
constructor(
private local: Storage
, private db: AngularFireDatabase
, public fbAuth: AngularFireAuth
)
{
console.log("Setting up default user initially");
this.fbAuth.authState.subscribe(state => this.subscribeToRemoteProfile(db, state));
let localObserver = this.userObserver().subscribe(
user => {
this.update(user);
this.localProfile = user;
},
error => console.log(error));
}
userObserver(): Observable<User> {
return Observable.fromPromise(this.local.get('profile')).map(json_profile => {
let t = this.profile();
if (json_profile !== null) t = JSON.parse(json_profile);
return t;
});
}
profile(): User {
if (!this.localProfile)
{
console.log("Initializing default user");
this.localProfile = ProfileService.createDefaultUser();
}
console.log("Returning Profile with user: " + this.localProfile);
return this.localProfile
}
subscribeToRemoteProfile(db: AngularFireDatabase, user: firebase.User)
{
if (!user) return;
console.log("Subscribing to remote settings for user id%s", user.uid);
let obj = db.object(
'/settings/' + user.uid);
this.remoteProfile = {
ref: obj,
stream: obj.valueChanges(),
};
this.profile().username = user.displayName;
this.save();
this.remoteProfile.stream.subscribe(
user => this.handleRemotePreferenceChange(user),
error => console.log(error));
}
handleRemotePreferenceChange(user: User)
{
if (user) {
console.log("handling remote settings for user %s", user.username);
if (!user.saved_pages) user.saved_pages = [];
this.localProfile = user;
console.log("Stashed remote changes locally");
// We only save the local change here since this is an update from our remote profile.
this.localSave();
console.log("Saved remote changes locally");
} else {
// No user is there so we should save our local to the remote.
console.log("Saving local to remote for user %s", user.username);
this.save()
console.log("Saved remote for user %s", user.username);
}
}
currentUser(): firebase.User
{
return this.fbAuth.auth.currentUser;
}
authenticate()
{
this.fbAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
logout()
{
this.fbAuth.auth.signOut();
}
private localSave()
{
this.local.set('profile', JSON.stringify(this.profile()));
}
save()
{
// First we save our local copy of the settings.
this.localSave();
// If we have a remote profile then save it there too
if (this.remoteProfile) {
console.log("Saving remote settings profile for remote user id " + this.profile().uid);
this.remoteProfile.ref.set(this.profile());
}
}
public update(t: User): boolean
{
let updated = false;
let k;
const user = this.localProfile;
for (k in user)
{
if (user.hasOwnProperty(k))
{
if (t[k] === undefined)
{
t[k] = user[k];
updated = true;
}
}
}
for (k in user)
if (user.hasOwnProperty(k))
user[k] = t[k];
this.textSizeChanged();
return updated;
}
private resetUser()
{
this.localProfile.strongs_modal = true;
this.localProfile.clear_search_after_query = false;
this.localProfile.items = [];
this.localProfile.append_to_bottom = false;
this.localProfile.insert_next_to_item = false;
this.localProfile.font_size = 10;
this.localProfile.saved_pages = [];
this.localProfile.verses_on_new_line = true;
}
reset()
{
this.resetUser();
this.remoteProfile.ref.set(this.localProfile)
this.save()
}
removePage(page: SavedPage)
{
let idx = this.localProfile.saved_pages.indexOf(page);
this.localProfile.saved_pages.splice(idx, 1);
// save the users settings.
this.save();
}
// TODO(jwall): This belongs somewhere else.
public textSizeChanged()
{
$('html').css('font-size', this.localProfile.font_size + 'px');
}
public static createDefaultUser(): User
{
return {
username: DEFAULT_USER_NAME,
uid: null,
strongs_modal: true,
clear_search_after_query: false,
items: [],
append_to_bottom: false,
insert_next_to_item: false,
font_size: 10,
saved_pages: [],
verses_on_new_line: true
};
}
}