diff --git a/Ionic2/package.json b/Ionic2/package.json
index ef7f9c2..0bb6531 100644
--- a/Ionic2/package.json
+++ b/Ionic2/package.json
@@ -16,7 +16,8 @@
"ionic-angular": "^2.0.0-rc.0",
"ionicons": "^3.0.0",
"@ionic/storage": "^1.0.3",
- "ionic-native": "^2.0.3"
+ "ionic-native": "^2.0.3",
+ "angular2-jwt": "^0.1.21"
},
"devDependencies": {
"@ionic/app-scripts": "^0.0.23",
diff --git a/Ionic2/src/app/app.component.ts b/Ionic2/src/app/app.component.ts
index de096f5..20f33b0 100644
--- a/Ionic2/src/app/app.component.ts
+++ b/Ionic2/src/app/app.component.ts
@@ -1,21 +1,79 @@
-import { Component } from '@angular/core';
-import { Platform } from 'ionic-angular';
+import { Component, ViewChild, provide } from '@angular/core';
+import { Platform, MenuController, Nav } from 'ionic-angular';
import { StatusBar } from 'ionic-native';
-import { TabsPage } from '../pages/tabs/tabs';
+import {Page1} from '../pages/page1/page1';
+import {Page3} from '../pages/page3/page3';
+import {LoginPage} from '../pages/loginPage/loginPage';
+import {ProfilePage} from '../pages/profilePage/profilePage';
+import {ContactsPage} from '../pages/contactsPage/contactsPage';
+import {PendingInvitesPage} from '../pages/pendingInvitesPage/pendingInvitesPage';
+import {SettingsPage} from '../pages/settingsPage/settingsPage';
+import {DiscoverUsersPage} from '../pages/discoverUsersPage/discoverUsersPage';
+import {ContactsService} from '../services/contacts.service';
+import {StorageService} from '../services/storage.service';
+import {PreferencesService} from '../services/preferences.service';
+import {UserInfoService} from '../services/userInfo.service';
+
+import {Http} from '@angular/http';
+import {AuthHttp, AuthConfig} from 'angular2-jwt';
+import {AuthService} from '../services/auth.service';
+import {Secret} from '../secrets/secret';
+
@Component({
- template: ``
+ templateUrl: `app.html`
})
export class MyApp {
- rootPage = TabsPage;
+ @ViewChild('nav') nav: Nav;
+ public primaryPages:any[];
+ public settingsPages:any[];
+ public rootPage:any;
+
+ constructor(public platform: Platform, public menu: MenuController,
+ public preferencesService: PreferencesService,
+ public auth: AuthService, public userInfoService: UserInfoService) {
+
+ this.initializeApp();
+
+ // set our app's pages (they appear in menu)
+ this.primaryPages = [
+ { title: 'My Profile', component: ProfilePage, icon: 'person' },
+ { title: 'My Contacts', component: ContactsPage, icon: 'contacts' },
+ { title: 'Pending Invites', component: PendingInvitesPage, icon: 'person-add' },
+ { title: 'Discover Users', component: DiscoverUsersPage, icon: 'people' }
+ ];
+
+ this.settingsPages = [
+ { title: 'Settings', component: SettingsPage, icon: 'settings' }
+ ];
- constructor(platform: Platform) {
- platform.ready().then(() => {
+ this.rootPage = LoginPage;
+ }
+
+ initializeApp() {
+ this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
+ this.userInfoService.initialize();
+ this.preferencesService.initializePreferences();
+ this.auth.startupTokenRefresh();
});
}
+
+ openPage(page) {
+ // close the menu when clicking a link from the menu
+ this.menu.close();
+ // navigate to the new page if it is not the current page
+ //let nav = this.app.getComponent('nav');
+ this.nav.setRoot(page.component);
+ }
+
+ sendFeedback(){
+ window.open(
+ 'mailto:' + Secret.FEEDBACK_EMAIL +
+ '?subject=' + Secret.FEEDBACK_SUBJECT, '_system');
+ }
}
diff --git a/Ionic2/src/app/app.html b/Ionic2/src/app/app.html
new file mode 100644
index 0000000..125126f
--- /dev/null
+++ b/Ionic2/src/app/app.html
@@ -0,0 +1,24 @@
+
+
+ Menu
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ionic2/src/app/app.module.ts b/Ionic2/src/app/app.module.ts
index 36bcff0..9c1f168 100644
--- a/Ionic2/src/app/app.module.ts
+++ b/Ionic2/src/app/app.module.ts
@@ -1,30 +1,83 @@
-import { NgModule } from '@angular/core';
+import { NgModule, provide } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
-import { AboutPage } from '../pages/about/about';
-import { ContactPage } from '../pages/contact/contact';
-import { HomePage } from '../pages/home/home';
-import { TabsPage } from '../pages/tabs/tabs';
+
+//pages
+import {Page1} from '../pages/page1/page1';
+import {Page3} from '../pages/page3/page3';
+import {LoginPage} from '../pages/loginPage/loginPage';
+import {ProfilePage} from '../pages/profilePage/profilePage';
+import {ContactsPage} from '../pages/contactsPage/contactsPage';
+import {PendingInvitesPage} from '../pages/pendingInvitesPage/pendingInvitesPage';
+import {SettingsPage} from '../pages/settingsPage/settingsPage';
+import {DiscoverUsersPage} from '../pages/discoverUsersPage/discoverUsersPage';
+import {ChatPage} from '../pages/chatPage/chatPage';
+import {ContactPage} from '../pages/contactPage/contactPage';
+
+//components
+import {ElasticTextarea} from '../components/elasticTextarea';
+import {ProfileHeader} from '../components/profileHeader';
+import {ChatBubble} from '../components/chatBubble/chatBubble';
+
+//services (providers)
+import {AuthService} from '../services/auth.service';
+import {ContactsService} from '../services/contacts.service';
+import {PreferencesService} from '../services/preferences.service';
+import {StorageService} from '../services/storage.service';
+import {UserInfoService} from '../services/userInfo.service';
+
+//external
+import {Http} from '@angular/http';
+import {AuthHttp, AuthConfig} from 'angular2-jwt';
@NgModule({
declarations: [
MyApp,
- AboutPage,
+ Page1,
+ Page3,
+ LoginPage,
+ ProfilePage,
+ ContactsPage,
+ PendingInvitesPage,
+ SettingsPage,
+ DiscoverUsersPage,
+ ChatPage,
ContactPage,
- HomePage,
- TabsPage
+ ElasticTextarea,
+ ProfileHeader,
+ ChatBubble
],
imports: [
- IonicModule.forRoot(MyApp)
+ IonicModule.forRoot(MyApp, {})//config object here
+ ],
+ bootstrap: [
+ IonicApp
],
- bootstrap: [IonicApp],
entryComponents: [
MyApp,
- AboutPage,
- ContactPage,
- HomePage,
- TabsPage
+ Page1,
+ Page3,
+ LoginPage,
+ ProfilePage,
+ ContactsPage,
+ PendingInvitesPage,
+ SettingsPage,
+ DiscoverUsersPage,
+ ChatPage,
+ ContactPage
],
- providers: []
+ providers: [
+ ContactsService,
+ PreferencesService,
+ StorageService,
+ UserInfoService,
+ provide(AuthHttp, {
+ useFactory: (http) => {
+ return new AuthHttp(new AuthConfig({noJwtError: true}), http);
+ },
+ deps: [Http]
+ }),
+ AuthService
+ ]
})
export class AppModule {}
diff --git a/Ionic2/src/components/chatBubble/chatBubble.scss b/Ionic2/src/components/chatBubble/chatBubble.scss
new file mode 100644
index 0000000..a2862a2
--- /dev/null
+++ b/Ionic2/src/components/chatBubble/chatBubble.scss
@@ -0,0 +1,83 @@
+.chatBubble{
+
+ //position: relative;
+
+ // :last-child {
+ // margin-bottom: 10px;
+ // }
+
+ img.profile-pic {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ position: absolute;
+ bottom: 10px;
+ }
+
+ img.profile-pic.left {
+ left: 10px;
+ }
+
+ img.profile-pic.right {
+ right: 10px;
+ }
+
+ .message {
+ font-size: medium;
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ }
+
+ .message-detail {
+ white-space: nowrap;
+ font-size: 14px;
+ }
+
+ .chat-bubble {
+ border-radius: 5px;
+ display: inline-block;
+ padding: 10px 18px;
+ position: relative;
+ margin: 10px;
+ max-width: 80%;
+ }
+
+ .chat-bubble:before {
+ content: "\00a0";
+ display: block;
+ height: 16px;
+ width: 9px;
+ position: absolute;
+ bottom: -7.5px;
+ }
+
+ .chat-bubble.left {
+ background-color: map-get($chat-bubble, background-left);
+ float: left;
+ margin-left: 45px;
+ }
+
+ .chat-bubble.left:before {
+ background-color: map-get($chat-bubble, background-left);
+ left: 10px;
+ -webkit-transform: rotate(70deg) skew(5deg);
+ }
+
+ .chat-bubble.right {
+ background-color: map-get($chat-bubble, background-right);
+ color: #000;
+ float: right;
+ margin-right: 45px;
+ }
+
+ .chat-bubble.right:before {
+ background-color: map-get($chat-bubble, background-right);
+ right: 10px;
+ -webkit-transform: rotate(118deg) skew(-5deg);
+ }
+
+ .chat-bubble.right a.autolinker {
+ color: #000;
+ font-weight: bold;
+ }
+}
diff --git a/Ionic2/src/components/chatBubble/chatBubble.ts b/Ionic2/src/components/chatBubble/chatBubble.ts
new file mode 100644
index 0000000..e0ef369
--- /dev/null
+++ b/Ionic2/src/components/chatBubble/chatBubble.ts
@@ -0,0 +1,31 @@
+import {Component} from '@angular/core';
+
+@Component({
+ selector: 'chat-bubble',
+ inputs: ['msg: message'],
+ template:
+ `
+
+
+
+
{{msg.content}}
+
+ {{msg.senderName}} ,
+ {{msg.time}}
+
+
+
+ `
+})
+export class ChatBubble {
+ public msg:any;
+
+ constructor() {
+ this.msg = {
+ content : 'Am I dreaming?',
+ position : 'left',
+ time : '12/3/2016',
+ senderName : 'Gregory'
+ }
+ }
+}
diff --git a/Ionic2/src/components/elasticTextarea.ts b/Ionic2/src/components/elasticTextarea.ts
new file mode 100644
index 0000000..b74348a
--- /dev/null
+++ b/Ionic2/src/components/elasticTextarea.ts
@@ -0,0 +1,44 @@
+import {Component, ViewChild} from '@angular/core';
+
+@Component({
+ selector: 'elastic-textarea',
+ inputs: ['placeholder', 'lineHeight'],
+ template:
+ `
+
+ `
+})
+export class ElasticTextarea {
+ @ViewChild('ionTxtArea') ionTxtArea:any;
+ public txtArea:any;
+ public content:string;
+ public lineHeight:string;
+
+ constructor() {
+ this.content = "";
+ this.lineHeight = "22px";
+ }
+
+ public ngAfterViewInit(){
+ this.txtArea = this.ionTxtArea._elementRef.nativeElement.children[0];
+ this.txtArea.style.height = this.lineHeight + "px";
+ this.txtArea.style.resize = 'none';
+ }
+
+ public onChange(newValue){
+ this.txtArea.style.height = this.lineHeight + "px";
+ this.txtArea.style.height = this.txtArea.scrollHeight + "px";
+ }
+
+ public clearInput(){
+ this.content = "";
+ this.txtArea.style.height = this.lineHeight + "px";
+ }
+
+ public setFocus(){
+ this.ionTxtArea.setFocus()
+ }
+}
diff --git a/Ionic2/src/components/profileHeader.ts b/Ionic2/src/components/profileHeader.ts
new file mode 100644
index 0000000..aa0f024
--- /dev/null
+++ b/Ionic2/src/components/profileHeader.ts
@@ -0,0 +1,26 @@
+import {Component} from '@angular/core';
+
+@Component({
+ selector: 'profile-header',
+ inputs: ['fullName', 'profileImage'],
+ template:
+ `
+
+
+
+
+ `
+})
+export class ProfileHeader {
+ public fullName:string;
+ public profileImage:string;
+
+ constructor() {
+ this.fullName = 'Dr. House';
+ this.profileImage = 'build/img/hugh.png';
+ }
+
+ public setFullName(fullName){
+ this.fullName = fullName;
+ }
+}
diff --git a/Ionic2/src/index.html b/Ionic2/src/index.html
index 348c2c4..4e8413a 100644
--- a/Ionic2/src/index.html
+++ b/Ionic2/src/index.html
@@ -22,6 +22,11 @@
+
+
+
+
+
diff --git a/Ionic2/src/models/contactModel.ts b/Ionic2/src/models/contactModel.ts
new file mode 100644
index 0000000..767f983
--- /dev/null
+++ b/Ionic2/src/models/contactModel.ts
@@ -0,0 +1,27 @@
+export class ContactModel {
+
+ public firstName:string;
+ public lastName:string;
+ public employment:string;
+ public education:string;
+ public knowledgeableIn:string;
+ public interests:string;
+ public currentGoals:string;
+ public profileImage:string;
+
+ constructor(firstName, lastName, employment, education){
+
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.employment = employment || '';
+ this.education = education || '';
+ this.knowledgeableIn = '';
+ this.interests = '';
+ this.currentGoals = '';
+ this.profileImage = '';
+ }
+
+ public getFullName(){
+ return this.firstName + ' ' + this.lastName;
+ }
+}
diff --git a/Ionic2/src/pages/chatPage/chatPage.html b/Ionic2/src/pages/chatPage/chatPage.html
new file mode 100644
index 0000000..f99e8e6
--- /dev/null
+++ b/Ionic2/src/pages/chatPage/chatPage.html
@@ -0,0 +1,35 @@
+
+
+
+ {{contactName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ionic2/src/pages/chatPage/chatPage.scss b/Ionic2/src/pages/chatPage/chatPage.scss
new file mode 100644
index 0000000..0c53535
--- /dev/null
+++ b/Ionic2/src/pages/chatPage/chatPage.scss
@@ -0,0 +1,12 @@
+page-chat {
+ //because chat-bubbles are wrapped inside ion-label when ion-item is rendered
+ ion-label {
+ margin: 0px 8px 13px 0;
+ }
+}
+
+.chatPageFooter {
+ .toolbar-background {
+ background: map-get($colors, background-color);
+ }
+}
diff --git a/Ionic2/src/pages/chatPage/chatPage.ts b/Ionic2/src/pages/chatPage/chatPage.ts
new file mode 100644
index 0000000..987ce2c
--- /dev/null
+++ b/Ionic2/src/pages/chatPage/chatPage.ts
@@ -0,0 +1,110 @@
+import {Component, ViewChild} from '@angular/core';
+import {NavController, NavParams} from 'ionic-angular';
+
+@Component({
+ selector: 'page-chat',
+ templateUrl: 'chatPage.html'
+})
+export class ChatPage {
+ @ViewChild('txtChat') txtChat:any;
+ @ViewChild('content') content:any;
+ public messages:any[];
+ public contactName:string;
+
+ constructor(public nav: NavController, public navParams: NavParams) {
+ this.contactName = this.navParams.get('contactName');
+
+ this.messages = [
+ {
+ img: 'build/img/hugh.png',
+ position: 'left',
+ content: 'Hello from the other side.',
+ senderName: 'Gregory',
+ time: '28-Jun-2016 21:53'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'right',
+ content: 'Hi! How are?',
+ senderName: 'Me',
+ time: '28-Jun-2016 21:55'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'left',
+ content: "This is some really long test that I'm writing here. Let's see how it wraps.",
+ senderName: 'Gregory',
+ time: '28-Jun-2016 21:57'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'right',
+ content: 'Hi! How are?',
+ senderName: 'Me',
+ time: '28-Jun-2016 21:55'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'left',
+ content: "This is some really long test that I'm writing here. Let's see how it wraps.",
+ senderName: 'Gregory',
+ time: '28-Jun-2016 21:57'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'right',
+ content: 'Hi! How are?',
+ senderName: 'Me',
+ time: '28-Jun-2016 21:55'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'left',
+ content: "This is some really long test that I'm writing here. Let's see how it wraps.",
+ senderName: 'Gregory',
+ time: '28-Jun-2016 21:57'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'right',
+ content: 'Hi! How are?',
+ senderName: 'Me',
+ time: '28-Jun-2016 21:55'
+ },
+ {
+ img: 'build/img/hugh.png',
+ position: 'left',
+ content: "This is some really long test that I'm writing here. Let's see how it wraps.",
+ senderName: 'Gregory',
+ time: '28-Jun-2016 21:57'
+ }
+ ];
+ }
+
+ public ionViewDidEnter(){
+ this.content.scrollToBottom(300);//300ms animation speed
+ }
+
+ public sendMessage(){
+ this.txtChat.setFocus();
+
+ this.messages.push({
+ img: 'build/img/hugh.png',
+ position: 'right',
+ content: this.txtChat.content,
+ senderName: 'Me',
+ time: new Date().toLocaleTimeString()
+ });
+
+ //console.log(this.txtChat.content);
+ this.txtChat.clearInput();
+
+ //without this timeout the list scrolls
+ //to the second to last element.
+ //It's some kind of race condition
+ setTimeout(() => {
+ this.content.scrollToBottom(300);//300ms animation speed
+ });
+ }
+
+}
diff --git a/Ionic2/src/pages/contactPage/contactPage.html b/Ionic2/src/pages/contactPage/contactPage.html
new file mode 100644
index 0000000..78cfec1
--- /dev/null
+++ b/Ionic2/src/pages/contactPage/contactPage.html
@@ -0,0 +1,42 @@
+
+
+
+
+ Contact
+
+
+
+
+
+
+
+
+
+ {{contact.employment}}
+
+
+ {{contact.education}}
+
+
+ Interests
+ {{contact.interests}}
+
+
+ Knowledgeable In
+ {{contact.knowledgeable}}
+
+
+ Goals
+ {{contact.currentGoals}}
+
+
+
+
+
diff --git a/Ionic2/src/pages/contactPage/contactPage.scss b/Ionic2/src/pages/contactPage/contactPage.scss
new file mode 100644
index 0000000..9620ca4
--- /dev/null
+++ b/Ionic2/src/pages/contactPage/contactPage.scss
@@ -0,0 +1,13 @@
+page-contact {
+
+ .section-name {
+ font-weight: bold;
+ font-size: medium;
+ color: map-get($colors, secondary-text);
+ }
+
+ p {
+ font-size: large;
+ color: map-get($colors, primary-text);
+ }
+}
diff --git a/Ionic2/src/pages/contactPage/contactPage.ts b/Ionic2/src/pages/contactPage/contactPage.ts
new file mode 100644
index 0000000..afc4bc4
--- /dev/null
+++ b/Ionic2/src/pages/contactPage/contactPage.ts
@@ -0,0 +1,33 @@
+import {Component} from '@angular/core';
+import {ViewChild} from '@angular/core';
+import {NavController, NavParams} from 'ionic-angular';
+
+import {ChatPage} from '../chatPage/chatPage';
+
+
+@Component({
+ selector: 'page-contact',
+ templateUrl: 'contactPage.html'
+})
+export class ContactPage {
+ @ViewChild('header') header:any;
+ public contact:any;
+
+ constructor(public nav: NavController, public navParams:NavParams) {
+ this.contact = this.navParams.get('contact');
+
+ // this.employment = 'Head of Diagnostic @ PPT Hospital';
+ // this.education = 'Attended Hopkins University 1979-1984';
+ // this.interests = 'Chemistry, Piano , Guitar, Android, Economy, Football';
+ // this.knowledgeable = 'Classical Music, Fitness, Movie Trivia, HTML5, Android, JavaScript';
+ // this.currentGoals = 'Learn Ionic2, Find a team for basketball';
+ }
+
+ public ionViewWillEnter(){
+ this.header.setFullName("Dr. Gregory House");
+ }
+
+ public openChat(){
+ this.nav.push(ChatPage, {contactName: "Dr. Gregory House"});
+ }
+}
diff --git a/Ionic2/src/pages/contactsPage/contactsPage.html b/Ionic2/src/pages/contactsPage/contactsPage.html
new file mode 100644
index 0000000..00f5abd
--- /dev/null
+++ b/Ionic2/src/pages/contactsPage/contactsPage.html
@@ -0,0 +1,22 @@
+
+
+
+
+ My Contacts
+
+
+
+
+
+
+
+
+
+ {{cnt.employment}}
+ {{cnt.education}}
+
+
+
+
diff --git a/Ionic2/src/pages/contactsPage/contactsPage.scss b/Ionic2/src/pages/contactsPage/contactsPage.scss
new file mode 100644
index 0000000..ddbb0f1
--- /dev/null
+++ b/Ionic2/src/pages/contactsPage/contactsPage.scss
@@ -0,0 +1,10 @@
+page-contacts {
+ profile-header{
+ div{
+ img{
+ width: 50px !important;
+ height: 50px !important;
+ }
+ }
+ }
+}
diff --git a/Ionic2/src/pages/contactsPage/contactsPage.ts b/Ionic2/src/pages/contactsPage/contactsPage.ts
new file mode 100644
index 0000000..690a144
--- /dev/null
+++ b/Ionic2/src/pages/contactsPage/contactsPage.ts
@@ -0,0 +1,21 @@
+import {Component} from '@angular/core';
+import {NavController} from 'ionic-angular';
+import {ContactsService} from '../../services/contacts.service';
+import {ContactPage} from '../contactPage/contactPage';
+
+
+@Component({
+ selector : 'page-contacts',
+ templateUrl: 'contactsPage.html'
+})
+export class ContactsPage {
+ public contacts:any[];
+
+ constructor(public nav:NavController, public contactsService:ContactsService) {
+ this.contacts = this.contactsService.getContacts();
+ }
+
+ public contactSelected(cnt){
+ this.nav.push(ContactPage, {contact: cnt});
+ }
+}
diff --git a/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.html b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.html
new file mode 100644
index 0000000..8cfd971
--- /dev/null
+++ b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.html
@@ -0,0 +1,59 @@
+
+
+
+
+ Discover Users
+
+
+
+
+
+
+
+
+
+
+
+ {{usr.employment}}
+
+
+ {{usr.education}}
+
+
+ Interests
+ {{usr.interests}}
+
+
+ Knowledgeable In
+ {{usr.knowledgeable}}
+
+
+ Goals
+ {{usr.currentGoals}}
+
+
+
+
+ No More Users Nearby
+
+
+
+
+
+
diff --git a/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.scss b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.scss
new file mode 100644
index 0000000..e87519d
--- /dev/null
+++ b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.scss
@@ -0,0 +1,18 @@
+page-discover-users {
+ .section-name {
+ font-weight: bold;
+ font-size: medium;
+ color: map-get($colors, secondary-text);
+ }
+
+ p {
+ font-size: large;
+ color: map-get($colors, primary-text);
+ }
+
+ /* prevents the slide content
+ from being centered in the middle */
+ .user-slide .slide-zoom {
+ height: 100%;
+ }
+}
diff --git a/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.ts b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.ts
new file mode 100644
index 0000000..d3b53ba
--- /dev/null
+++ b/Ionic2/src/pages/discoverUsersPage/discoverUsersPage.ts
@@ -0,0 +1,87 @@
+import {Component, ViewChild} from '@angular/core';
+import{
+ Input,
+ trigger,
+ state,
+ style,
+ transition,
+ animate} from '@angular/core';
+import {ContactsService} from '../../services/contacts.service';
+
+
+@Component({
+ selector: 'page-discover-users',
+ templateUrl: 'discoverUsersPage.html',
+ animations: [
+ trigger('fabState',[
+ state('inactive', style({
+ transform: 'scale(0)'
+ })),
+ state('active', style({
+ transform: 'scale(1)'
+ })),
+ transition('inactive <=> active', animate('150ms ease-out'))
+ ])
+ ]
+})
+export class DiscoverUsersPage {
+ @ViewChild('slider') slider:any;
+ public sliderOptions:any;
+ public users:any[];
+ public itemToDelete:number;
+ public btnState:string;
+
+ constructor(public contactsService: ContactsService) {
+ this.sliderOptions = {
+ nested: true,
+ watchSlidesProgress: true,
+ loop: false
+ };
+
+ this.users = this.contactsService.getNearbyUsers();
+ this.itemToDelete = -1;
+
+ this.btnState = 'active';
+ }
+
+ public onBtnDismissClicked(){
+ let currentIndex = this.slider.getActiveIndex();
+ //TODO: update db
+ this._slideAndRemove(currentIndex)
+ }
+
+ public onBtnAcceptClicked(){
+ let currentIndex = this.slider.getActiveIndex();
+ //TODO: update db
+ this._slideAndRemove(currentIndex)
+ }
+
+ public onSlideChanged(){
+ console.log("onSlideChanged");
+ let pendingDeletePosition = this.itemToDelete;
+ if(pendingDeletePosition !== -1){
+ this.itemToDelete = -1;
+ this.users.splice(pendingDeletePosition, 1);
+ //slider's slider is a swiper
+ this.slider.slider.removeSlide(pendingDeletePosition);
+ this.slider.slider.update();
+ }
+
+ if(this.slider.length() === 1 || this.slider.getActiveIndex() + 1 === this.slider.length()){
+ console.log('inactive');
+ this.btnState= 'inactive';
+ }else{
+ console.log('active');
+ this.btnState= 'active';
+ }
+ }
+
+ public _slideAndRemove(currentIndex){
+ //don't remove the last "No More Users Nearby" slide
+ if(this.slider.length() === 1 || currentIndex + 1 === this.slider.length())
+ return;
+
+ this.itemToDelete = currentIndex;
+ this.slider.slideTo(currentIndex+1, 500);
+ }
+}
diff --git a/Ionic2/src/pages/loginPage/loginPage.html b/Ionic2/src/pages/loginPage/loginPage.html
new file mode 100644
index 0000000..3293184
--- /dev/null
+++ b/Ionic2/src/pages/loginPage/loginPage.html
@@ -0,0 +1,19 @@
+
+
+
+ Ionic
+
+
+
+
+
+
+
+
+
Welcome to Ionic
+
Please wait while we try to sign you in...
+
+
+
+
+
diff --git a/Ionic2/src/pages/loginPage/loginPage.scss b/Ionic2/src/pages/loginPage/loginPage.scss
new file mode 100644
index 0000000..881b681
--- /dev/null
+++ b/Ionic2/src/pages/loginPage/loginPage.scss
@@ -0,0 +1,18 @@
+page-login {
+
+ .Aligner {
+ display: flex;
+ align-items: center;
+ min-height: 100%;
+ // min-height: 24em;
+ justify-content: center;
+ }
+
+ .Aligner-item {
+ flex: 1;
+ }
+
+ button {
+ margin-top: 15px;
+ }
+}
diff --git a/Ionic2/src/pages/loginPage/loginPage.ts b/Ionic2/src/pages/loginPage/loginPage.ts
new file mode 100644
index 0000000..2b70b02
--- /dev/null
+++ b/Ionic2/src/pages/loginPage/loginPage.ts
@@ -0,0 +1,45 @@
+import {Component, ViewChild} from '@angular/core';
+import {NavController} from 'ionic-angular';
+import {ProfilePage} from '../profilePage/profilePage';
+import {AuthService} from '../../services/auth.service';
+import {UserInfoService} from '../../services/userInfo.service';
+
+
+@Component({
+ selector: 'page-login',
+ templateUrl: 'loginPage.html',
+})
+export class LoginPage {
+ public nextPage:any;
+ public showLoginButton:boolean;
+
+ constructor(public nav: NavController, public auth: AuthService, public userInfoService: UserInfoService) {
+ this.nextPage = ProfilePage;
+ this.showLoginButton = false;
+ }
+
+ public ionViewWillEnter(){
+ this.showLoginButton = false;
+ }
+
+ public ionViewDidEnter(){
+ if(this.auth.authenticated()){
+ //give some time for local storage to initialize
+ setTimeout(() => {
+ this.nav.setRoot(ProfilePage);
+ }, 1000)
+ }else{
+ this.showLoginButton = true;
+ }
+ }
+
+ public login(){
+ this.auth.login(() =>
+ setTimeout(() => {
+ this.nav.setRoot(ProfilePage)
+ }, 1000)//I need this delay because otherwise the navigation occurs
+ //before the InAppBrowser closes, and the content ends up under
+ //the top bar.
+ );
+ }
+}
diff --git a/Ionic2/src/pages/page1/page1.html b/Ionic2/src/pages/page1/page1.html
new file mode 100644
index 0000000..065f74e
--- /dev/null
+++ b/Ionic2/src/pages/page1/page1.html
@@ -0,0 +1,21 @@
+
+
+
+ Tab 1
+
+
+
+
+ Welcome to Ionic2 beta 11!
+
+ This starter project comes with simple tabs-based layout for apps
+ that are going to primarily use a Tabbed UI.
+
+
+ Take a look at the app/
directory to add or change tabs,
+ update any existing page or create new pages.
+
+
+
diff --git a/Ionic2/src/pages/page1/page1.scss b/Ionic2/src/pages/page1/page1.scss
new file mode 100644
index 0000000..50a5175
--- /dev/null
+++ b/Ionic2/src/pages/page1/page1.scss
@@ -0,0 +1,3 @@
+page-one {
+
+}
diff --git a/Ionic2/src/pages/page1/page1.ts b/Ionic2/src/pages/page1/page1.ts
new file mode 100644
index 0000000..d8748b4
--- /dev/null
+++ b/Ionic2/src/pages/page1/page1.ts
@@ -0,0 +1,16 @@
+import {Component} from '@angular/core';
+import {NavController, NavParams} from 'ionic-angular';
+
+
+@Component({
+ selector: 'page-one',
+ templateUrl: 'page1.html'
+})
+export class Page1 {
+ public selectedItem:any;
+
+ constructor(public nav: NavController, public navParams: NavParams) {
+ // If we navigated to this page, we will have an item available as a nav param
+ this.selectedItem = navParams.get('item');
+ }
+}
diff --git a/Ionic2/src/pages/page3/page3.html b/Ionic2/src/pages/page3/page3.html
new file mode 100644
index 0000000..b713fcc
--- /dev/null
+++ b/Ionic2/src/pages/page3/page3.html
@@ -0,0 +1,32 @@
+
+
+
+
+ Tab 3
+
+
+
+
+
+ Welcome to Ionic2 beta 11!
+
+
+ This is a primary text.
+
+
+
+ And this is a secondary text.
+
+
+
+
+
+
+
+
+
+
diff --git a/Ionic2/src/pages/page3/page3.scss b/Ionic2/src/pages/page3/page3.scss
new file mode 100644
index 0000000..1fd953d
--- /dev/null
+++ b/Ionic2/src/pages/page3/page3.scss
@@ -0,0 +1,3 @@
+page-three {
+
+}
diff --git a/Ionic2/src/pages/page3/page3.ts b/Ionic2/src/pages/page3/page3.ts
new file mode 100644
index 0000000..b921d84
--- /dev/null
+++ b/Ionic2/src/pages/page3/page3.ts
@@ -0,0 +1,12 @@
+import {Component} from '@angular/core';
+
+
+@Component({
+ selector: 'page-three',
+ templateUrl: 'page3.html'
+})
+export class Page3 {
+ constructor() {
+
+ }
+}
diff --git a/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.html b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.html
new file mode 100644
index 0000000..6c92d68
--- /dev/null
+++ b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.html
@@ -0,0 +1,34 @@
+
+
+
+
+ Pending Invites
+
+
+
+
+
+
+
+
+
+
+
+ {{cnt.employment}}
+ {{cnt.education}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.scss b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.scss
new file mode 100644
index 0000000..7d7d1dc
--- /dev/null
+++ b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.scss
@@ -0,0 +1,10 @@
+page-pending-invites {
+ profile-header{
+ div{
+ img{
+ width: 50px !important;
+ height: 50px !important;
+ }
+ }
+ }
+}
diff --git a/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.ts b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.ts
new file mode 100644
index 0000000..adf0bf8
--- /dev/null
+++ b/Ionic2/src/pages/pendingInvitesPage/pendingInvitesPage.ts
@@ -0,0 +1,36 @@
+import {Component} from '@angular/core';
+import {NavController} from 'ionic-angular';
+import {ContactsService} from '../../services/contacts.service';
+import {ContactPage} from '../contactPage/contactPage';
+
+
+@Component({
+ selector: 'page-pending-invites',
+ templateUrl: 'pendingInvitesPage.html'
+})
+export class PendingInvitesPage {
+ public contacts:any[];
+
+ constructor(public nav: NavController, public contactsService:ContactsService) {
+ this.contacts = this.contactsService.getContacts();
+ }
+
+ public openInvite(cnt){
+ this.nav.push(ContactPage, {contact: cnt});
+ }
+
+ public dismissInvite(cnt){
+ this._removeContact(cnt);
+ }
+
+ public acceptInvite(cnt){
+ this._removeContact(cnt);
+ }
+
+ public _removeContact(cnt){
+ let index = this.contacts.indexOf(cnt);
+ if (index > -1) {
+ this.contacts.splice(index, 1);
+ }
+ }
+}
diff --git a/Ionic2/src/pages/profilePage/profilePage.html b/Ionic2/src/pages/profilePage/profilePage.html
new file mode 100644
index 0000000..d914586
--- /dev/null
+++ b/Ionic2/src/pages/profilePage/profilePage.html
@@ -0,0 +1,53 @@
+
+
+
+
+ My Profile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Interests
+
+
+
+ Knowledgeable In
+
+
+
+ Goals
+
+
+
+
+
diff --git a/Ionic2/src/pages/profilePage/profilePage.scss b/Ionic2/src/pages/profilePage/profilePage.scss
new file mode 100644
index 0000000..ba029cf
--- /dev/null
+++ b/Ionic2/src/pages/profilePage/profilePage.scss
@@ -0,0 +1,19 @@
+page-profile {
+ ion-label{
+ font-weight: bold;
+ font-size: medium;
+ }
+ ion-input {
+ input {
+ margin-left: 0px;
+ }
+ }
+
+ /*
+ hack to prevent border highlight in input elements.
+ */
+ .item-input.ng-valid.input-has-value:not(.input-has-focus) .item-inner {
+ border-bottom-color: #dedede !important;
+ box-shadow: none !important;
+ }
+}
diff --git a/Ionic2/src/pages/profilePage/profilePage.ts b/Ionic2/src/pages/profilePage/profilePage.ts
new file mode 100644
index 0000000..b2fb9e1
--- /dev/null
+++ b/Ionic2/src/pages/profilePage/profilePage.ts
@@ -0,0 +1,45 @@
+import {Component} from '@angular/core';
+import {UserInfoService} from '../../services/userInfo.service';
+
+
+@Component({
+ selector: 'page-profile',
+ templateUrl: 'profilePage.html'
+})
+export class ProfilePage {
+
+ public isEditMode:boolean;
+ public fullName:string;
+ public profileImageUrl:string;
+ public employment:string;
+ public education:string;
+ public interests:string;
+ public knowledgeable:string;
+ public currentGoals:string;
+
+ constructor(public userInfo:UserInfoService) {
+ this.isEditMode = false;
+ }
+
+ public ionViewWillEnter(){
+ this.fullName = this.userInfo.getUserInfo(UserInfoService.PREF_USER_NAME);
+ this.profileImageUrl = this.userInfo.getUserInfo(UserInfoService.PREF_USER_PICTURE_URL);
+ this.employment = this.userInfo.getUserInfo(UserInfoService.PREF_USER_EMPLOYMENT);
+ this.education = this.userInfo.getUserInfo(UserInfoService.PREF_USER_EDUCATION);
+ this.interests = this.userInfo.getUserInfo(UserInfoService.PREF_USER_INTERESTS);
+ this.knowledgeable = this.userInfo.getUserInfo(UserInfoService.PREF_USER_KNOWLEDGEABLE_IN);
+ this.currentGoals = this.userInfo.getUserInfo(UserInfoService.PREF_USER_CURRENT_GOALS);
+ }
+
+ public edit(){
+ if(this.isEditMode){
+ //it was in edit mode, so save the changes
+ this.userInfo.setUserInfo(UserInfoService.PREF_USER_EMPLOYMENT, this.employment);
+ this.userInfo.setUserInfo(UserInfoService.PREF_USER_EDUCATION, this.education);
+ this.userInfo.setUserInfo(UserInfoService.PREF_USER_INTERESTS, this.interests);
+ this.userInfo.setUserInfo(UserInfoService.PREF_USER_KNOWLEDGEABLE_IN, this.knowledgeable);
+ this.userInfo.setUserInfo(UserInfoService.PREF_USER_CURRENT_GOALS, this.currentGoals);
+ }
+ this.isEditMode = !this.isEditMode;
+ }
+}
diff --git a/Ionic2/src/pages/settingsPage/settingsPage.html b/Ionic2/src/pages/settingsPage/settingsPage.html
new file mode 100644
index 0000000..88668d5
--- /dev/null
+++ b/Ionic2/src/pages/settingsPage/settingsPage.html
@@ -0,0 +1,42 @@
+
+
+
+
+ Settings
+
+
+
+
+
+
+
+ General
+
+
+ Make me discoverable by others
+
+
+
+ Notifications for Messages
+
+
+
+ Notifications for Invites
+
+
+
+ Account
+
+
+
+
diff --git a/Ionic2/src/pages/settingsPage/settingsPage.scss b/Ionic2/src/pages/settingsPage/settingsPage.scss
new file mode 100644
index 0000000..3c6f099
--- /dev/null
+++ b/Ionic2/src/pages/settingsPage/settingsPage.scss
@@ -0,0 +1,9 @@
+page-settings {
+ ion-list-header{
+ color: map-get($colors, secondary);
+ border-bottom: none !important;
+ ion-label{
+ margin-bottom: -5px !important;
+ }
+ }
+}
diff --git a/Ionic2/src/pages/settingsPage/settingsPage.ts b/Ionic2/src/pages/settingsPage/settingsPage.ts
new file mode 100644
index 0000000..049f0f8
--- /dev/null
+++ b/Ionic2/src/pages/settingsPage/settingsPage.ts
@@ -0,0 +1,42 @@
+import {Component} from '@angular/core';
+import {NavController} from 'ionic-angular';
+import {PreferencesService} from '../../services/preferences.service';
+import {AuthService} from '../../services/auth.service';
+import {LoginPage} from '../loginPage/loginPage';
+
+
+@Component({
+ selector: 'page-settings',
+ templateUrl: 'settingsPage.html'
+})
+export class SettingsPage {
+ public preferences:any;
+ public PREF_DISCOVERABLE:string;
+ public PREF_NOTIFY_MESSAGES:string;
+ public PREF_NOTIFY_INVITES:string;
+
+ constructor(public nav: NavController, public preferencesService:PreferencesService, public auth:AuthService) {
+ this.preferences = {};
+
+ this.PREF_DISCOVERABLE = PreferencesService.PREF_DISCOVERABLE;
+ this.PREF_NOTIFY_MESSAGES = PreferencesService.PREF_NOTIFY_MESSAGES;
+ this.PREF_NOTIFY_INVITES = PreferencesService.PREF_NOTIFY_INVITES;
+ }
+
+ public ionViewWillEnter(){
+ this.preferences[PreferencesService.PREF_DISCOVERABLE]
+ = this.preferencesService.getPreference(PreferencesService.PREF_DISCOVERABLE);
+ this.preferences[PreferencesService.PREF_NOTIFY_MESSAGES]
+ = this.preferencesService.getPreference(PreferencesService.PREF_NOTIFY_MESSAGES);
+ this.preferences[PreferencesService.PREF_NOTIFY_INVITES]
+ = this.preferencesService.getPreference(PreferencesService.PREF_NOTIFY_INVITES);
+ }
+
+ public changePreference(event, key){
+ this.preferencesService.setPreference(key, event.checked);
+ }
+
+ public logout(){
+ this.auth.logout(() => this.nav.setRoot(LoginPage));
+ }
+}
diff --git a/Ionic2/src/services/auth.service.ts b/Ionic2/src/services/auth.service.ts
new file mode 100644
index 0000000..0861b02
--- /dev/null
+++ b/Ionic2/src/services/auth.service.ts
@@ -0,0 +1,180 @@
+import {Storage} from '@ionic/storage';
+import {AuthHttp, JwtHelper, tokenNotExpired} from 'angular2-jwt';
+import {Injectable, NgZone} from '@angular/core';
+import {Observable} from 'rxjs/Rx';
+import {Secret} from '../secrets/secret';
+import {UserInfoService} from './userInfo.service';
+
+@Injectable()
+export class AuthService {
+ public jwtHelper:JwtHelper;
+ public auth0:any;
+ public lock:any;
+ public local:Storage;
+ public zoneImpl:NgZone;
+
+ constructor(public authHttp: AuthHttp, public zone:NgZone, public userInfoService: UserInfoService) {
+ this.jwtHelper = new JwtHelper();
+ this.auth0 = new Auth0({clientID: Secret.AUTH0_CLIENT_ID, domain: Secret.AUTH0_DOMAIN});
+ this.lock = new Auth0Lock(Secret.AUTH0_CLIENT_ID, Secret.AUTH0_DOMAIN, {
+ auth: {
+ redirect: false,
+ params: {
+ scope: 'openid offline_access',
+ }
+ }
+ });
+ this.local = new Storage(LocalStorage);
+ this.refreshSubscription = undefined;
+ this.user = {};
+
+ this.userInfoService = userInfoService;
+ this.zoneImpl = zone;
+ // Check if there is a profile saved in local storage
+ this.local.get('profile').then(profile => {
+ this.user = JSON.parse(profile);
+ }).catch(error => {
+ console.log(error);
+ });
+
+ this.lock.on('authenticated', authResult => {
+ this.local.set('id_token', authResult.idToken);
+
+ // Fetch profile information
+ this.lock.getProfile(authResult.idToken, (error, profile) => {
+ if (error) {
+ // Handle error
+ alert(error);
+ return;
+ }
+
+ console.log(profile);
+
+ profile.user_metadata = profile.user_metadata || {};
+
+ if(this.userInfoService.getUserInfo(UserInfoService.PREF_USER_NAME) === ''){
+ //there is no user information stored, store the new info obtained from auth0
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_NAME, profile.name);
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_EMAIL, profile.email);
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_AUTH_ID, profile.user_id);
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_PICTURE_URL, profile.picture);
+ }
+
+ this.local.set('profile', JSON.stringify(profile));
+ this.user = profile;
+ });
+
+ this.lock.hide();
+
+ this.local.set('refresh_token', authResult.refreshToken);
+ this.zoneImpl.run(() => this.user = authResult.profile);
+
+ if(this.onAuthenticatedCallback != null){
+ this.onAuthenticatedCallback();
+ }
+ });
+
+ }
+
+ authenticated() {
+ // Check if there's an unexpired JWT
+ return tokenNotExpired();
+ }
+
+ login(onAuthenticatedCallback) {
+ // Show the Auth0 Lock widget
+ this.lock.show();
+ this.onAuthenticatedCallback = onAuthenticatedCallback;
+ }
+
+ logout(onLogOutCallback) {
+ this.onLogOutCallback = onLogOutCallback;
+ this.local.remove('profile');
+ this.local.remove('id_token');
+ this.local.remove('refresh_token');
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_NAME, '');
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_EMAIL, '');
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_AUTH_ID, '');
+ this.userInfoService.setUserInfo(UserInfoService.PREF_USER_PICTURE_URL, '');
+ this.zoneImpl.run(() => this.user = null);
+ // Unschedule the token refresh
+ this.unscheduleRefresh();
+ if(this.onLogOutCallback != null){
+ this.onLogOutCallback();
+ }
+ }
+
+ scheduleRefresh() {
+ // If the user is authenticated, use the token stream
+ // provided by angular2-jwt and flatMap the token
+ let source = this.authHttp.tokenStream.flatMap(
+ token => {
+ // The delay to generate in this case is the difference
+ // between the expiry time and the issued at time
+ let jwtIat = this.jwtHelper.decodeToken(token).iat;
+ let jwtExp = this.jwtHelper.decodeToken(token).exp;
+ let iat = new Date(0);
+ let exp = new Date(0);
+
+ let delay = (exp.setUTCSeconds(jwtExp) - iat.setUTCSeconds(jwtIat));
+
+ return Observable.interval(delay);
+ });
+
+ this.refreshSubscription = source.subscribe(() => {
+ this.getNewJwt();
+ });
+ }
+
+startupTokenRefresh() {
+ // If the user is authenticated, use the token stream
+ // provided by angular2-jwt and flatMap the token
+ if (this.authenticated()) {
+ let source = this.authHttp.tokenStream.flatMap(
+ token => {
+ // Get the expiry time to generate
+ // a delay in milliseconds
+ let now = new Date().valueOf();
+ let jwtExp = this.jwtHelper.decodeToken(token).exp;
+ let exp = new Date(0);
+ exp.setUTCSeconds(jwtExp);
+ let delay = exp.valueOf() - now;
+
+ // Use the delay in a timer to
+ // run the refresh at the proper time
+ return Observable.timer(delay);
+ });
+
+ // Once the delay time from above is
+ // reached, get a new JWT and schedule
+ // additional refreshes
+ source.subscribe(() => {
+ this.getNewJwt();
+ this.scheduleRefresh();
+ });
+ }
+}
+
+unscheduleRefresh() {
+ // Unsubscribe fromt the refresh
+ if (this.refreshSubscription) {
+ console.log(this.refreshSubscription);
+ this.refreshSubscription.unsubscribe();
+ }
+}
+
+getNewJwt() {
+ // Get a new JWT from Auth0 using the refresh token saved
+ // in local storage
+ this.local.get('refresh_token').then(token => {
+ this.auth0.refreshToken(token, (err, delegationRequest) => {
+ if (err) {
+ alert(err);
+ }
+ this.local.set('id_token', delegationRequest.id_token);
+ });
+ }).catch(error => {
+ console.log(error);
+ });
+ }
+}
diff --git a/Ionic2/src/services/contacts.service.ts b/Ionic2/src/services/contacts.service.ts
new file mode 100644
index 0000000..028b262
--- /dev/null
+++ b/Ionic2/src/services/contacts.service.ts
@@ -0,0 +1,41 @@
+import {Injectable} from '@angular/core';
+
+import {ContactModel} from '../models/contactModel';
+
+@Injectable()
+export class ContactsService {
+ public contacts:any[];
+
+ constructor(){
+ this.contacts = [];
+
+ let cnt = new ContactModel('#1 Gregory', 'House', 'Head of Diagnostic @ PPT Hospital', 'Attended Hopkins University 1979-1984');
+ cnt.profileImage = 'build/img/hugh.png'
+ let cnt2 = new ContactModel('#2 Hugh', 'Laurie', 'Actor, Writer, Director, Author, etc.', 'Attended Selwyn College, Cambridge 1978 - 1984');
+ cnt2.profileImage = 'build/img/hugh.png'
+ let cnt3 = new ContactModel('#3 Gregory', 'House', 'Head of Diagnostic @ PPT Hospital', 'Attended Hopkins University 1979-1984');
+ cnt3.profileImage = 'build/img/hugh.png'
+ let cnt4 = new ContactModel('#4 Hugh', 'Laurie', 'Actor, Writer, Director, Author, etc.', 'Attended Selwyn College, Cambridge 1978 - 1984');
+ cnt4.profileImage = 'build/img/hugh.png'
+
+ this.contacts.push(cnt);
+ this.contacts.push(cnt2);
+ this.contacts.push(cnt3);
+ this.contacts.push(cnt4);
+ }
+
+ public removeContact(cnt){
+ let index = this.contacts.indexOf(cnt);
+ if (index > -1) {
+ this.contacts.splice(index, 1);
+ }
+ }
+
+ public getContacts(){
+ return [...this.contacts];
+ }
+
+ public getNearbyUsers(){
+ return [...this.contacts];
+ }
+}
diff --git a/Ionic2/src/services/preferences.service.ts b/Ionic2/src/services/preferences.service.ts
new file mode 100644
index 0000000..9afb94d
--- /dev/null
+++ b/Ionic2/src/services/preferences.service.ts
@@ -0,0 +1,73 @@
+import {Injectable} from '@angular/core';
+import {StorageService} from './storage.service';
+
+@Injectable()
+export class PreferencesService {
+
+ static get PREF_INITIALIZED() { return 'preferencesInitialized';}
+ static get PREF_DISCOVERABLE() { return 'pref_discoverable';}
+ static get PREF_NOTIFY_MESSAGES() { return 'pref_notification_messages';}
+ static get PREF_NOTIFY_INVITES() { return 'pref_notification_invites';}
+
+ public _preferences:any;
+
+ constructor(public _storageService: StorageService) {
+ this._preferences = {};
+ }
+
+ public initializePreferences(){
+ console.log('initializePreferences');
+ this._storageService.storage.get(PreferencesService.PREF_INITIALIZED).then((result) => {
+ if(result == null || result == false){
+ console.log('initializePreferences with default values');
+ this._storageService.storage.set(PreferencesService.PREF_INITIALIZED, true);
+ this._storageService.storage.set(PreferencesService.PREF_DISCOVERABLE, true);
+ this._storageService.storage.set(PreferencesService.PREF_NOTIFY_MESSAGES, true);
+ this._storageService.storage.set(PreferencesService.PREF_NOTIFY_INVITES, true);
+
+ //initialize in memory preferences
+ this._preferences[PreferencesService.PREF_DISCOVERABLE] = true;
+ this._preferences[PreferencesService.PREF_NOTIFY_MESSAGES] = true;
+ this._preferences[PreferencesService.PREF_NOTIFY_INVITES] = true;
+ }else{
+ console.log('preferences obtained from storage');
+ let prefs =
+ [
+ PreferencesService.PREF_DISCOVERABLE,
+ PreferencesService.PREF_NOTIFY_MESSAGES,
+ PreferencesService.PREF_NOTIFY_INVITES
+ ];
+
+ let thisRef = this;
+ this._getAllPreferences(prefs).then(function(results){
+ //initialize in memory preferences
+ for(let i = 0; i < prefs.length; i++){
+ thisRef._preferences[prefs[i]] = results[i];
+ }
+ }, function (err) {
+ // If any of the preferences fail to read, err is the first error
+ console.log(err);
+ });
+ }
+ });
+ }
+
+ public getPreference(key){
+ return this._preferences[key];
+ }
+
+ public setPreference(key, value){
+ this._preferences[key] = value;//update pref in memory
+ this._storageService.storage.set(key, value);//update pref in db
+ }
+
+ public _getAllPreferences(prefs){
+ return Promise.all(prefs.map((key) => {
+ return this._storageService.storage.get(key);
+ }));
+ }
+
+ public _getPreference(key){
+ return this._storageService.storage.get(key);
+ }
+}
diff --git a/Ionic2/src/services/storage.service.ts b/Ionic2/src/services/storage.service.ts
new file mode 100644
index 0000000..c6e6480
--- /dev/null
+++ b/Ionic2/src/services/storage.service.ts
@@ -0,0 +1,11 @@
+import {Storage} from '@ionic/storage';
+import {Injectable} from '@angular/core';
+
+@Injectable()
+export class StorageService {
+ public storage:Storage;
+
+ constructor() {
+ this.storage = new Storage();
+ }
+}
diff --git a/Ionic2/src/services/userInfo.service.ts b/Ionic2/src/services/userInfo.service.ts
new file mode 100644
index 0000000..663c351
--- /dev/null
+++ b/Ionic2/src/services/userInfo.service.ts
@@ -0,0 +1,110 @@
+import {Injectable} from '@angular/core';
+import {StorageService} from './storage.service';
+
+@Injectable()
+export class UserInfoService {
+
+ static get PREF_INITIALIZED() { return 'pref_user_info_initialized';}
+ static get PREF_USER_NAME() { return 'pref_user_name';}
+ static get PREF_USER_EMAIL() { return 'pref_user_email';}
+ static get PREF_USER_AUTH_ID() { return 'pref_user_auth_id';}
+ static get PREF_USER_PICTURE_URL() { return 'pref_user_picture_url';}
+
+ static get PREF_USER_EMPLOYMENT() { return 'pref_user_employment';}
+ static get PREF_USER_EDUCATION() { return 'pref_user_education';}
+ static get PREF_USER_KNOWLEDGEABLE_IN() { return 'pref_user_knowledgeable_in';}
+ static get PREF_USER_INTERESTS() { return 'pref_user_interests';}
+ static get PREF_USER_CURRENT_GOALS() { return 'pref_user_current_goals';}
+
+ public _userInfo:any;
+ public _keys:string[];
+
+ constructor(public _storageService:StorageService) {
+ this._userInfo = {};
+
+ this._keys = [
+ UserInfoService.PREF_USER_NAME,
+ UserInfoService.PREF_USER_EMAIL,
+ UserInfoService.PREF_USER_AUTH_ID,
+ UserInfoService.PREF_USER_PICTURE_URL,
+ UserInfoService.PREF_USER_EMPLOYMENT,
+ UserInfoService.PREF_USER_EDUCATION,
+ UserInfoService.PREF_USER_KNOWLEDGEABLE_IN,
+ UserInfoService.PREF_USER_INTERESTS,
+ UserInfoService.PREF_USER_CURRENT_GOALS,
+ ];
+ }
+
+ public initialize(){
+ console.log('initialize user info');
+ this._storageService.storage.get(UserInfoService.PREF_INITIALIZED).then((result) => {
+ if(result == null || result == false){
+ console.log('initialize user info with default values');
+ this._storageService.storage.set(UserInfoService.PREF_INITIALIZED, true);
+ this._storageService.storage.set(UserInfoService.PREF_USER_NAME, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_EMAIL, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_AUTH_ID, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_PICTURE_URL, '');
+
+ this._storageService.storage.set(UserInfoService.PREF_USER_EMPLOYMENT, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_EDUCATION, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_KNOWLEDGEABLE_IN, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_INTERESTS, '');
+ this._storageService.storage.set(UserInfoService.PREF_USER_CURRENT_GOALS, '');
+
+
+ //initialize in memory
+ this._userInfo[UserInfoService.PREF_USER_NAME] = '';
+ this._userInfo[UserInfoService.PREF_USER_EMAIL] = '';
+ this._userInfo[UserInfoService.PREF_USER_AUTH_ID] = '';
+ this._userInfo[UserInfoService.PREF_USER_PICTURE_URL] = '';
+
+ this._userInfo[UserInfoService.PREF_USER_EMPLOYMENT] = '';
+ this._userInfo[UserInfoService.PREF_USER_EDUCATION] = '';
+ this._userInfo[UserInfoService.PREF_USER_KNOWLEDGEABLE_IN] = '';
+ this._userInfo[UserInfoService.PREF_USER_INTERESTS] = '';
+ this._userInfo[UserInfoService.PREF_USER_CURRENT_GOALS] = '';
+ }else{
+ console.log('user info obtained from storage');
+
+ let thisRef = this;
+ this._getAllUserInfo(this._keys).then(function(results){
+ //initialize in memory user information
+ for(let i = 0; i < thisRef._keys.length; i++){
+ thisRef._userInfo[thisRef._keys[i]] = results[i];
+ }
+ console.log('stored user info:');
+ console.log(thisRef._userInfo);
+ }, function (err) {
+ // If any of the information fail to read, err is the first error
+ console.log(err);
+ });
+ }
+ });
+ }
+
+ /* retrieve stored user information */
+ public getAllUserInfo(){
+ return this._getAllUserInfo(this._keys);
+ }
+
+ public getUserInfo(key){
+ return this._userInfo[key];
+ }
+
+ public setUserInfo(key, value){
+ this._userInfo[key] = value;//update in memory
+ this._storageService.storage.set(key, value);//update in db
+ }
+
+ public _getAllUserInfo(keys){
+ return Promise.all(keys.map((key) => {
+ return this._storageService.storage.get(key);
+ }));
+ }
+
+ public _getUserInfo(key){
+ return this._storageService.storage.get(key);
+ }
+
+}
diff --git a/Ionic2/src/theme/global.scss b/Ionic2/src/theme/global.scss
index 782f2ce..4ec0e35 100644
--- a/Ionic2/src/theme/global.scss
+++ b/Ionic2/src/theme/global.scss
@@ -2,7 +2,7 @@
// Global CSS
-// --------------------------------------------------
+// --------------------------------------------------
// Put CSS rules here that you want to apply globally.
//
// To declare rules for a specific mode, create a child rule
@@ -10,3 +10,51 @@
// automatically applied to the element in the app.
//
// App Shared Sass variables belong in app.variables.scss.
+
+.profile-header {
+ font-size: $header-font-size;
+ font-weight: $header-font-weight;
+ margin-left: 10px;
+ line-height: 100%;
+}
+
+.content-center-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.content-center-left {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;;
+}
+
+.content-center-right {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+}
+
+ion-item{
+ .text-input {
+ font-size: large;
+ }
+}
+
+//makes the paragraph properly wrap the text inside it in multiple lines
+p {
+ word-wrap: break-word;
+ white-space: normal;
+}
+
+ion-menu{
+ ion-content{
+ ion-list{
+ ion-icon{
+ margin-right: 20px;
+ color: #595959;
+ }
+ }
+ }
+}
diff --git a/Ionic2/src/theme/variables.scss b/Ionic2/src/theme/variables.scss
index 0ab6bf7..c8798b8 100644
--- a/Ionic2/src/theme/variables.scss
+++ b/Ionic2/src/theme/variables.scss
@@ -11,7 +11,16 @@
// http://ionicframework.com/docs/v2/theming/overriding-ionic-variables/
$text-color: #000;
-$background-color: #fff;
+
+$background-ios-color: #FAFAFA;
+$background-md-color: #FAFAFA;
+$background-wp-color: #FAFAFA;
+
+$list-background-color: #FAFAFA;
+
+$header-font-size: 2.2rem;
+$header-font-weight: 500;
+
// Named Color Variables
@@ -23,14 +32,40 @@ $background-color: #fff;
// The "primary" color is the only required color in the map.
$colors: (
- primary: #387ef5,
- secondary: #32db64,
+ dark-primary: #1976D2,
+ primary: #2196F3,
+ light: #BBDEFB,
+ text-icons: #FFFFFF,
+ secondary: #FF5722,
+ primary-text: #212121,
+ secondary-text: #727272,
+ divider: #B6B6B6,
+ background-color: #FAFAFA,
+
danger: #f53d3d,
- light: #f4f4f4,
dark: #222,
- favorite: #69BB7B
+ favorite: #8bc34a, /* #69BB7B */
+
+ facebook: #3b5998,
+ googleplus: #dc4e41,
+ linkedin: #0077b5,
+);
+
+$chat-bubble:(
+ background-left: #fea21c,
+ background-right: #8abefa,
);
+//To make the input use the secondary color when active, instead of primary
+//https://github.com/driftyco/ionic/blob/2.0/src/components/input/input.md.scss
+//https://github.com/driftyco/ionic/blob/2.0/src/components/label/label.md.scss
+$label-ios-text-color-focused: map-get($colors, secondary);
+$label-md-text-color-focused: map-get($colors, secondary);
+$label-wp-text-color-focused: map-get($colors, secondary);
+
+$text-input-ios-highlight-color: map-get($colors, secondary);
+$text-input-md-highlight-color: map-get($colors, secondary);
+$text-input-wp-highlight-color: map-get($colors, secondary);
// App Theme
// --------------------------------------------------