diff --git a/README.md b/README.md index 8fc6118..b58c3e5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ -# angular2byexample -Source code repository for the book "Angular2 by Example" +# Angular2 By Example + +[![Angular2 By Example Front Cover](https://d1ldz4te4covpm.cloudfront.net/sites/default/files/imagecache/ppv4_main_book_cover/B05079_MockupCover_Normal.jpg)](https://www.packtpub.com/web-development/angular-2-example) + +Source code repository for the book [Angular2 by Example](https://www.packtpub.com/web-development/angular-2-example) + +**Releasing soon!!** + +To setup code for Guess The Number see the README.md in **guessthenumber** folder. + +To setup code for Personal Trainer see the README.md in **trainer** folder. + +## Note + +The **master** branch contains the final outcome for both the samples we build throughout the book. + +Chapter progress is tracked using individual branches. Each **chapter has checkpoints** and each checkpoint code is **available on a seperate branch**. + +For example, branches *base*, *checkpoint2.1*, *checkpoint2.2*, *checkpoint2.3* and *checkpoint2.4* contain code checkpoints for **Chapter 2**. diff --git a/guessthenumber/app.ts b/guessthenumber/app.ts deleted file mode 100644 index 4e02bbe..0000000 --- a/guessthenumber/app.ts +++ /dev/null @@ -1,51 +0,0 @@ -//import 'zone.js'; -//import 'reflect-metadata'; -import { -Component, View, bootstrap -}from 'angular2/angular2'; - -@Component({ - selector: 'my-app' -}) -@View({ - template: ` -
-

Guess the Number !

-

Guess the computer generated random number between 1 and 1000.

- - - - -

-

Your guess is higher.

-

Your guess is lower.

-

Yes! That"s it.

-

-

No of guesses : - {{noOfTries}} -

-
-` -}) -class GuessTheNumberComponent { - deviation: number; - noOfTries: number; - original: number; - guess: number; - - constructor() { - this.initializeGame(); - } - verifyGuess() { - this.deviation = this.original - this.guess; - this.noOfTries = this.noOfTries + 1; - } - initializeGame() { - this.noOfTries = 0; - this.original = Math.floor((Math.random() * 1000) + 1); - this.guess = null; - this.deviation = null; - } -} - -bootstrap(GuessTheNumberComponent); diff --git a/guessthenumber/app/app.module.ts b/guessthenumber/app/app.module.ts new file mode 100644 index 0000000..710d89b --- /dev/null +++ b/guessthenumber/app/app.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { GuessTheNumberComponent } from './guess-the-number.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ GuessTheNumberComponent ], + bootstrap: [ GuessTheNumberComponent ] +}) + +export class AppModule { } diff --git a/guessthenumber/app/guess-the-number.component.ts b/guessthenumber/app/guess-the-number.component.ts new file mode 100644 index 0000000..0992fb2 --- /dev/null +++ b/guessthenumber/app/guess-the-number.component.ts @@ -0,0 +1,43 @@ +import { Component }from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +
+

Guess the Number !

+

Guess the computer generated random number between 1 and 1000.

+ + + + +
+

Your guess is higher.

+

Your guess is lower.

+

Yes! That's it.

+
+

No of guesses : + {{noOfTries}} +

+
+ ` +}) +export class GuessTheNumberComponent { + deviation: number; + noOfTries: number; + original: number; + guess: number; + + constructor() { + this.initializeGame(); + } + initializeGame() { + this.noOfTries = 0; + this.original = Math.floor((Math.random() * 1000) + 1); + this.guess = null; + this.deviation = null; + } + verifyGuess() { + this.deviation = this.original - this.guess; + this.noOfTries = this.noOfTries + 1; + } +} \ No newline at end of file diff --git a/guessthenumber/app/main.ts b/guessthenumber/app/main.ts new file mode 100644 index 0000000..44f34b2 --- /dev/null +++ b/guessthenumber/app/main.ts @@ -0,0 +1,6 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; + +const platform = platformBrowserDynamic(); +platform.bootstrapModule(AppModule); diff --git a/guessthenumber/index.html b/guessthenumber/index.html index 8f843f8..c351c05 100644 --- a/guessthenumber/index.html +++ b/guessthenumber/index.html @@ -1,25 +1,19 @@ - - - Guess the Number! - - - - - - - - - Loading... - - + + Guess the Number! + + + + + + + + + + + Loading... + diff --git a/guessthenumber/systemjs.config.js b/guessthenumber/systemjs.config.js new file mode 100644 index 0000000..c7fa815 --- /dev/null +++ b/guessthenumber/systemjs.config.js @@ -0,0 +1,24 @@ +System.config({ + map : { + 'app': 'app', + 'rxjs': 'https://unpkg.com/rxjs@5.0.0-beta.12', + '@angular/common': 'https://unpkg.com/@angular/common@2.0.0', + '@angular/compiler': 'https://unpkg.com/@angular/compiler@2.0.0', + '@angular/core': 'https://unpkg.com/@angular/core@2.0.0', + '@angular/platform-browser': 'https://unpkg.com/@angular/platform-browser@2.0.0', + '@angular/platform-browser-dynamic': 'https://unpkg.com/@angular/platform-browser-dynamic@2.0.0' + }, + packages:{ + 'app': { main: 'main.ts', defaultExtension: 'ts' }, + '@angular/common': { main: 'bundles/common.umd.js', defaultExtension: 'js' }, + '@angular/compiler': { main: 'bundles/compiler.umd.js', defaultExtension: 'js' }, + '@angular/core': { main: 'bundles/core.umd.js', defaultExtension: 'js' }, + '@angular/platform-browser': { main: 'bundles/platform-browser.umd.js', defaultExtension: 'js' }, + '@angular/platform-browser-dynamic': { main: 'bundles/platform-browser-dynamic.umd.js', defaultExtension: 'js' }, + }, + // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER + transpiler: 'typescript', + typescriptOptions: { + emitDecoratorMetadata: true + } +}); \ No newline at end of file diff --git a/trainer/.gitignore b/trainer/.gitignore index f06235c..c5ac28a 100644 --- a/trainer/.gitignore +++ b/trainer/.gitignore @@ -1,2 +1,3 @@ node_modules dist +typings/** \ No newline at end of file diff --git a/trainer/README.md b/trainer/README.md index eb6a127..e5374cd 100644 --- a/trainer/README.md +++ b/trainer/README.md @@ -1,3 +1,23 @@ # Personal Trainer Personal Trainer built using Angular2 and TypeScript + +## Install + +Clone this repo and execute in your favourite shell: + +* `npm i -g gulp` to install gulp globally (if you don't have it installed already) +* `npm install` to install local npm dependencies + +## Play + +After completing installation type in your favourite shell: + +* `gulp play` to start the app in a new browser window. App files are observed and will be re-transpiled on each change. + +> ~~If you see a bunch of **TypeScript** compilation errors while running `gulp play`, the required **typings** did not get installed. While `npm install` should also install the typings, at times this does not happen. +> If the typing installation throws error try to upgrade the typing global installation with command `npm install typings -g` and then run the command `npm run typings install` again.~~ + +> The old approach of using the `typings` tool to install typings has been abandoned in favour of **npm** based typing supported by new versions of **TypeScript** compiler. Take latest of the code and upgrade to latest version of TypeScript compiler. `npm install` should now install all typings. + +> **Note**: The book content still show use of `typings`, you can disregard it. diff --git a/trainer/gulpfile.js b/trainer/gulpfile.js index c5de7e8..d0e205d 100644 --- a/trainer/gulpfile.js +++ b/trainer/gulpfile.js @@ -1,45 +1,56 @@ var gulp = require('gulp'); +var connect = require('gulp-connect'); var PATHS = { - src: 'src/**/*.ts' + src: 'src/**/*.ts', + html: 'src/**/*.html', + css: 'src/**/*.css' }; -gulp.task('clean', function (done) { - var del = require('del'); - del(['dist'], done); +gulp.task('clean', function(done) { + var del = require('del'); + del(['dist'], done); }); -gulp.task('ts2js', function () { - var typescript = require('gulp-typescript'); - var sourcemaps = require('gulp-sourcemaps'); - - var tsResult = gulp.src(PATHS.src) - .pipe(sourcemaps.init()) - .pipe(typescript({ - noImplicitAny: true, - module: 'system', - target: 'ES5', - moduleResolution: 'node', - emitDecoratorMetadata: true, - experimentalDecorators: true - })); - - return tsResult.js - .pipe(sourcemaps.write()) - .pipe(gulp.dest('dist')); +gulp.task('ts2js', function() { + var typescript = require('gulp-typescript'); + var sourcemaps = require('gulp-sourcemaps'); + + var tsResult = gulp.src(PATHS.src) + .pipe(sourcemaps.init()) + .pipe(typescript({ + noImplicitAny: true, + module: 'system', + target: 'ES5', + moduleResolution: 'node', + emitDecoratorMetadata: true, + experimentalDecorators: true + })); + + return tsResult.js + .pipe(sourcemaps.write()) + .pipe(gulp.dest('dist')) + .pipe(connect.reload()); }); -gulp.task('play', ['ts2js'], function () { - var http = require('http'); - var connect = require('connect'); - var serveStatic = require('serve-static'); - var open = require('open'); +gulp.task('play', ['ts2js'], function() { + var http = require('http'); + var open = require('open'); + var watch = require('gulp-watch'); - var port = 9000, app; - gulp.watch(PATHS.src, ['ts2js']); - app = connect().use(serveStatic(__dirname)); - http.createServer(app).listen(port, function () { - open('http://localhost:' + port); - }); + var port = 9000, + app; + + connect.server({ + root: __dirname, + port: port, + livereload: true, + fallback: 'index.html' + }); + open('http://localhost:' + port + '/index.html'); + + gulp.watch(PATHS.src, ['ts2js']); + watch(PATHS.html).pipe(connect.reload()); + watch(PATHS.css).pipe(connect.reload()); }); diff --git a/trainer/index.html b/trainer/index.html index 174563f..eb3d0b2 100644 --- a/trainer/index.html +++ b/trainer/index.html @@ -8,24 +8,27 @@ - + + - Loading... + Loading... - - + + + + + + + + - - - + diff --git a/trainer/package.json b/trainer/package.json index 09888b3..f47ff36 100644 --- a/trainer/package.json +++ b/trainer/package.json @@ -4,24 +4,38 @@ "description": "Angular 2 implementation of Personal Trainer in TypeScript", "repository": { "type": "git", - "url": "git+https://github.com/chandermani/angularjsbyexample.git" + "url": "git+https://github.com/chandermani/angular2byexample.git" }, "bugs": { - "url": "https://github.com/chandermani/angularjsbyexample/issues" + "url": "https://github.com/chandermani/angular2byexample/issues" }, - "homepage": "https://github.com/chandermani/angularjsbyexample#readme", + "homepage": "https://github.com/chandermani/angular2byexample.git#readme", "devDependencies": { - "connect": "^3.4.0", + "@types/core-js": "0.9.36", "del": "^1.2.0", "gulp": "^3.9.0", - "gulp-typescript": "^2.8.0", + "gulp-connect": "^3.1.0", "gulp-sourcemaps": "^1.6.0", + "gulp-typescript": "^3.1.5", + "gulp-watch": "^4.3.5", + "gulp-webserver": "^0.9.1", "open": "0.0.5", - "serve-static": "^1.10.0" + "typescript": "^2.2.1" }, "dependencies": { - "angular2": "^2.0.0-alpha.46", - "es6-shim": "^0.33.6", - "systemjs": "0.18.4" - } -} + "@angular/common": "2.0.0", + "@angular/compiler": "2.0.0", + "@angular/core": "2.0.0", + "@angular/forms": "2.0.0", + "@angular/http": "2.0.0", + "@angular/platform-browser": "2.0.0", + "@angular/platform-browser-dynamic": "2.0.0", + "@angular/router": "3.0.0", + "core-js": "^2.4.1", + "reflect-metadata": "0.1.3", + "rxjs": "5.0.0-beta.12", + "systemjs": "0.19.27", + "zone.js": "^0.6.23" + }, + "scripts": {} +} \ No newline at end of file diff --git a/trainer/src/bootstrap.ts b/trainer/src/bootstrap.ts index d56ec6d..0ec15a1 100644 --- a/trainer/src/bootstrap.ts +++ b/trainer/src/bootstrap.ts @@ -1,3 +1,3 @@ -import {bootstrap} from 'angular2/angular2'; -import {TrainerApp} from './components/app/app'; -bootstrap(TrainerApp); +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './components/app/app.module'; +platformBrowserDynamic().bootstrapModule(AppModule); \ No newline at end of file diff --git a/trainer/src/components/app/app.component.ts b/trainer/src/components/app/app.component.ts new file mode 100644 index 0000000..5effd23 --- /dev/null +++ b/trainer/src/components/app/app.component.ts @@ -0,0 +1,20 @@ +import {Component} from '@angular/core'; + +@Component({ + selector: 'trainer-app', + template: ` +
+ +
` +}) +export class TrainerAppComponent { + constructor() { + + } +} diff --git a/trainer/src/components/app/app.module.ts b/trainer/src/components/app/app.module.ts new file mode 100644 index 0000000..2893f81 --- /dev/null +++ b/trainer/src/components/app/app.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { TrainerAppComponent } from './app.component'; +import {WorkoutRunnerModule} from '../workout-runner/workout-runner.module'; +import {StartModule} from '../start/start.module'; +import {FinishModule} from '../finish/finish.module'; + +import {routing} from './app.routes'; + +@NgModule({ + imports: [ + BrowserModule, + WorkoutRunnerModule, + StartModule, + FinishModule, + routing], + declarations: [TrainerAppComponent], + bootstrap: [TrainerAppComponent] +}) +export class AppModule { } \ No newline at end of file diff --git a/trainer/src/components/app/app.routes.ts b/trainer/src/components/app/app.routes.ts new file mode 100644 index 0000000..18edf7d --- /dev/null +++ b/trainer/src/components/app/app.routes.ts @@ -0,0 +1,14 @@ +import { ModuleWithProviders } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import {WorkoutRunnerComponent} from '../workout-runner/workout-runner.component'; +import {StartComponent} from '../start/start.component'; +import {FinishComponent} from '../finish/finish.component'; + +export const routes: Routes = [ + { path: 'start', component: StartComponent }, + { path: 'workout', component: WorkoutRunnerComponent }, + { path: 'finish', component: FinishComponent }, + { path: '**', redirectTo: '/start' } +]; + +export const routing: ModuleWithProviders = RouterModule.forRoot(routes); \ No newline at end of file diff --git a/trainer/src/components/app/app.ts b/trainer/src/components/app/app.ts deleted file mode 100644 index 8165035..0000000 --- a/trainer/src/components/app/app.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {Component} from 'angular2/angular2'; -import {WorkoutRunner} from '../workout-runner/workout-runner'; -@Component({ - selector: 'trainer-app', - directives:[WorkoutRunner], - template: `` -}) -export class TrainerApp { -} diff --git a/trainer/src/components/finish/finish.component.ts b/trainer/src/components/finish/finish.component.ts new file mode 100644 index 0000000..bcba3d0 --- /dev/null +++ b/trainer/src/components/finish/finish.component.ts @@ -0,0 +1,8 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'finish', + templateUrl: '/src/components/finish/finish.html', +}) +export class FinishComponent { +} diff --git a/trainer/src/components/finish/finish.html b/trainer/src/components/finish/finish.html new file mode 100644 index 0000000..ca71873 --- /dev/null +++ b/trainer/src/components/finish/finish.html @@ -0,0 +1,16 @@ +
+
+
+

Well Done!

+
+ +
+ +
+
+
diff --git a/trainer/src/components/finish/finish.module.ts b/trainer/src/components/finish/finish.module.ts new file mode 100644 index 0000000..b3aa4fe --- /dev/null +++ b/trainer/src/components/finish/finish.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { FinishComponent } from './finish.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule], + declarations: [FinishComponent], + exports: [FinishComponent], +}) +export class FinishModule { } \ No newline at end of file diff --git a/trainer/src/components/start/start.component.ts b/trainer/src/components/start/start.component.ts new file mode 100644 index 0000000..e48ed55 --- /dev/null +++ b/trainer/src/components/start/start.component.ts @@ -0,0 +1,8 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'start', + templateUrl: '/src/components/start/start.html', +}) +export class StartComponent { +} diff --git a/trainer/src/components/start/start.html b/trainer/src/components/start/start.html new file mode 100644 index 0000000..6eeeb70 --- /dev/null +++ b/trainer/src/components/start/start.html @@ -0,0 +1,16 @@ +
+
+
+

Ready for a Workout?

+
+ +
+ +
+
+
diff --git a/trainer/src/components/start/start.module.ts b/trainer/src/components/start/start.module.ts new file mode 100644 index 0000000..9441ca1 --- /dev/null +++ b/trainer/src/components/start/start.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { StartComponent } from './start.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule], + declarations: [StartComponent], + exports: [StartComponent], +}) +export class StartModule { } \ No newline at end of file diff --git a/trainer/src/components/workout-runner/exercise-description.ts b/trainer/src/components/workout-runner/exercise-description/exercise-description.component.ts similarity index 58% rename from trainer/src/components/workout-runner/exercise-description.ts rename to trainer/src/components/workout-runner/exercise-description/exercise-description.component.ts index 37cf05f..c6e1084 100644 --- a/trainer/src/components/workout-runner/exercise-description.ts +++ b/trainer/src/components/workout-runner/exercise-description/exercise-description.component.ts @@ -1,10 +1,10 @@ -import {Component, Input} from 'angular2/angular2'; +import {Component, Input} from '@angular/core'; @Component({ selector: 'exercise-description', - templateUrl: '/src/components/workout-runner/exercise-description.tpl.html', + templateUrl: '/src/components/workout-runner/exercise-description/exercise-description.html', }) -export class ExerciseDescription { +export class ExerciseDescriptionComponent { @Input() description: string; @Input() steps: string; } diff --git a/trainer/src/components/workout-runner/exercise-description.tpl.html b/trainer/src/components/workout-runner/exercise-description/exercise-description.html similarity index 88% rename from trainer/src/components/workout-runner/exercise-description.tpl.html rename to trainer/src/components/workout-runner/exercise-description/exercise-description.html index a777e35..22c45c0 100644 --- a/trainer/src/components/workout-runner/exercise-description.tpl.html +++ b/trainer/src/components/workout-runner/exercise-description/exercise-description.html @@ -11,7 +11,7 @@

Description

Steps

-
+
diff --git a/trainer/src/components/workout-runner/my-audio.ts b/trainer/src/components/workout-runner/my-audio.ts deleted file mode 100644 index 981188f..0000000 --- a/trainer/src/components/workout-runner/my-audio.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {Directive, Input, ElementRef} from 'angular2/angular2'; - -@Directive({ - selector: 'audio', - exportAs: 'MyAudio' -}) -export class MyAudio { - private audioPlayer: HTMLAudioElement; - constructor(element: ElementRef) { - this.audioPlayer = element.nativeElement; - } - - stop() { - this.audioPlayer.pause(); - } - start() { - this.audioPlayer.play(); - } - currentTime(): number { - return this.audioPlayer.currentTime; - } - duration(): number { - return this.audioPlayer.duration; - } - playbackComplete() { - return this.duration() == this.currentTime(); - } - -} diff --git a/trainer/src/components/workout-runner/pipes.ts b/trainer/src/components/workout-runner/seconds-to-time.pipe.ts similarity index 72% rename from trainer/src/components/workout-runner/pipes.ts rename to trainer/src/components/workout-runner/seconds-to-time.pipe.ts index e12686d..d5e7279 100644 --- a/trainer/src/components/workout-runner/pipes.ts +++ b/trainer/src/components/workout-runner/seconds-to-time.pipe.ts @@ -1,10 +1,10 @@ -import {Pipe} from 'angular2/angular2'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ name: 'secondsToTime' }) -export class SecondsToTime { - transform(value: number, args: any[]): any { +export class SecondsToTimePipe implements PipeTransform { + transform(value: number): any { if (!isNaN(value)) { var hours = Math.floor(value / 3600); var minutes = Math.floor((value - (hours * 3600)) / 60); diff --git a/trainer/src/components/workout-runner/video-player.ts b/trainer/src/components/workout-runner/video-player.ts deleted file mode 100644 index 35b2377..0000000 --- a/trainer/src/components/workout-runner/video-player.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {Component, Input} from 'angular2/angular2'; - -@Component({ - selector: 'video-player', - templateUrl: '/src/components/workout-runner/video-player.tpl.html' -}) -export class VideoPlayer { - @Input() videos: Array; -} diff --git a/trainer/src/components/workout-runner/video-player/video-player.component.ts b/trainer/src/components/workout-runner/video-player/video-player.component.ts new file mode 100644 index 0000000..967befa --- /dev/null +++ b/trainer/src/components/workout-runner/video-player/video-player.component.ts @@ -0,0 +1,21 @@ +import {Component, Input, OnChanges} from '@angular/core'; +import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; + +@Component({ + selector: 'video-player', + templateUrl: '/src/components/workout-runner/video-player/video-player.html' +}) +export class VideoPlayerComponent implements OnChanges { + private youtubeUrlPrefix = '//www.youtube.com/embed/'; + + @Input() videos: Array; + safeVideoUrls: Array; + + constructor(private sanitizer: DomSanitizer) { } + + ngOnChanges() { + this.safeVideoUrls = this.videos ? + this.videos.map(v => this.sanitizer.bypassSecurityTrustResourceUrl(this.youtubeUrlPrefix + v)) + : this.videos; + } +} diff --git a/trainer/src/components/workout-runner/video-player.tpl.html b/trainer/src/components/workout-runner/video-player/video-player.html similarity index 50% rename from trainer/src/components/workout-runner/video-player.tpl.html rename to trainer/src/components/workout-runner/video-player/video-player.html index 132f8e2..5640f74 100644 --- a/trainer/src/components/workout-runner/video-player.tpl.html +++ b/trainer/src/components/workout-runner/video-player/video-player.html @@ -3,8 +3,8 @@

Videos

-
- +
+
diff --git a/trainer/src/components/workout-runner/workout-audio.tpl.html b/trainer/src/components/workout-runner/workout-audio.tpl.html deleted file mode 100644 index e7a5f2f..0000000 --- a/trainer/src/components/workout-runner/workout-audio.tpl.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/trainer/src/components/workout-runner/workout-audio.ts b/trainer/src/components/workout-runner/workout-audio.ts deleted file mode 100644 index 71150fc..0000000 --- a/trainer/src/components/workout-runner/workout-audio.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {Component, ContentChild, ViewChild, ViewChildren, ElementRef, QueryList, Host, Injector} from 'angular2/angular2'; -import {MyAudio} from './my-audio' -import {WorkoutRunner} from './workout-runner' -import {WorkoutPlan, ExercisePlan} from './model'; - -@Component({ - selector: 'workout-audio', - templateUrl: '/src/components/workout-runner/workout-audio.tpl.html', - directives: [MyAudio] -}) -export class WorkoutAudio { - @ViewChild('ticks') ticks: MyAudio; - @ViewChild('nextUp') nextUp: MyAudio; - @ViewChild('nextUpExercise') nextUpExercise: MyAudio; - @ViewChild('halfway') halfway: MyAudio; - @ViewChild('aboutToComplete') aboutToComplete: MyAudio; - private runner: WorkoutRunner; - private nameSounds: Array; - private nextupSound: string; - - constructor(public injector: Injector) { - this.runner = this.injector.get(WorkoutRunner); - - this.runner.exercisePaused.subscribe((exercise: ExercisePlan) => this.stop()); - this.runner.workoutComplete.subscribe((exercise: ExercisePlan) => this.stop()); - this.runner.exerciseResumed.subscribe((exercise: ExercisePlan) => this.resume()); - this.runner.exerciseProgress.subscribe((progress: any) => this.onExerciseProgress(progress)); - this.runner.exerciseChanged.subscribe((state: any) => this.onExerciseChanged(state)); - - } - - /*afterViewInit() { - console.log(this.ticks); - }*/ - - stop() { - this.ticks.stop(); - this.nextUp.stop(); - this.halfway.stop(); - this.aboutToComplete.stop(); - this.nextUpExercise.stop(); - } - - resume() { - this.ticks.start(); - console.log(this.nextUp.currentTime()); - console.log(this.nextUpExercise.currentTime()); - console.log(this.halfway.currentTime()); - console.log(this.aboutToComplete.currentTime()); - - if (this.nextUp.currentTime() > 0 && !this.nextUp.playbackComplete()) this.nextUp.start(); - else if (this.nextUpExercise.currentTime() > 0 && !this.nextUpExercise.playbackComplete()) this.nextUpExercise.start(); - else if (this.halfway.currentTime() > 0 && !this.halfway.playbackComplete()) this.halfway.start(); - else if (this.aboutToComplete.currentTime() > 0 && !this.aboutToComplete.playbackComplete()) this.aboutToComplete.start(); - } - - private onExerciseProgress(progress: any) { - if (progress.runningFor == Math.floor(progress.exercise.duration / 2) - && progress.exercise.exercise.name != "rest") { - this.halfway.start(); - } - else if (progress.timeRemaining == 3) { - this.aboutToComplete.start(); - } - } - - private onExerciseChanged(state: any) { - if (state.current.exercise.name == "rest") { - this.nextupSound = state.next.exercise.nameSound; - setTimeout(() => this.nextUp.start(), 2000); - setTimeout(() => this.nextUpExercise.start(), 3000); - } - } - - private onWorkoutStarted(workout: WorkoutPlan) { - - } -} diff --git a/trainer/src/components/workout-runner/workout-runner.ts b/trainer/src/components/workout-runner/workout-runner.component.ts similarity index 81% rename from trainer/src/components/workout-runner/workout-runner.ts rename to trainer/src/components/workout-runner/workout-runner.component.ts index f838ebd..25566ca 100644 --- a/trainer/src/components/workout-runner/workout-runner.ts +++ b/trainer/src/components/workout-runner/workout-runner.component.ts @@ -1,17 +1,12 @@ -import {Component, ViewChild, EventEmitter, Output} from 'angular2/angular2'; +import {Component,OnInit} from '@angular/core'; import {WorkoutPlan, ExercisePlan, Exercise} from './model'; -import {ExerciseDescription} from './exercise-description'; -import {VideoPlayer} from './video-player'; -import {WorkoutAudio} from './workout-audio'; -import {SecondsToTime} from './pipes'; +import {Router} from '@angular/router'; @Component({ selector: 'workout-runner', - templateUrl: '/src/components/workout-runner/workout-runner.tpl.html', - directives: [ExerciseDescription, VideoPlayer, WorkoutAudio], - pipes: [SecondsToTime] + templateUrl: '/src/components/workout-runner/workout-runner.html' }) -export class WorkoutRunner { +export class WorkoutRunnerComponent implements OnInit { workoutPlan: WorkoutPlan; workoutTimeRemaining: number; restExercise: ExercisePlan; @@ -20,20 +15,12 @@ export class WorkoutRunner { exerciseRunningDuration: number; exerciseTrackingInterval: number; workoutPaused: boolean; - @ViewChild(WorkoutAudio) workoutAudioPlayer: WorkoutAudio; - @Output() exercisePaused: EventEmitter = new EventEmitter(); - @Output() exerciseResumed: EventEmitter = new EventEmitter(); - @Output() exerciseProgress: EventEmitter = new EventEmitter(); - @Output() exerciseChanged: EventEmitter = new EventEmitter(); - @Output() workoutStarted: EventEmitter = new EventEmitter(); - @Output() workoutComplete: EventEmitter = new EventEmitter(); - - constructor() { + constructor(private router: Router) { this.workoutPlan = this.buildWorkout(); this.restExercise = new ExercisePlan(new Exercise("rest", "Relax!", "Relax a bit", "rest.png"), this.workoutPlan.restBetweenExercise); } - onInit() { + ngOnInit() { this.start(); } @@ -41,25 +28,16 @@ export class WorkoutRunner { this.workoutTimeRemaining = this.workoutPlan.totalWorkoutDuration(); this.currentExerciseIndex = 0; this.startExercise(this.workoutPlan.exercises[this.currentExerciseIndex]); - this.workoutStarted.next(this.workoutPlan); - /*let intervalId = setInterval(() => { - --this.workoutTimeRemaining; - if (this.workoutTimeRemaining == 0) clearInterval(intervalId); - }, 1000, this.workoutTimeRemaining);*/ } pause() { clearInterval(this.exerciseTrackingInterval); this.workoutPaused = true; - this.workoutAudioPlayer.stop(); - this.exercisePaused.next(this.currentExerciseIndex); } resume() { this.startExerciseTimeTracking(); this.workoutPaused = false; - this.workoutAudioPlayer.resume(); - this.exerciseResumed.next(this.currentExerciseIndex); } pauseResumeToggle() { @@ -70,7 +48,7 @@ export class WorkoutRunner { this.pause(); } } - onKeyPressed = function(event:KeyboardEvent) { + onKeyPressed = function(event: KeyboardEvent) { if (event.which == 80 || event.which == 112) { // 'p' or 'P' key to toggle pause and resume. this.pauseResumeToggle(); } @@ -79,21 +57,6 @@ export class WorkoutRunner { this.currentExercise = exercisePlan; this.exerciseRunningDuration = 0; this.startExerciseTimeTracking(); - /*let intervalId = setInterval(() => { - if (this.exerciseRunningDuration >= this.currentExercise.duration) { - clearInterval(intervalId); - let next: ExercisePlan = this.getNextExercise(); - if (next) { - this.startExercise(next); - } - else { - console.log("Workout complete!"); - } - } - else { - this.exerciseRunningDuration++; - } - }, 1000, this.currentExercise.duration);*/ } getNextExercise(): ExercisePlan { @@ -108,7 +71,7 @@ export class WorkoutRunner { } startExerciseTimeTracking() { - this.exerciseTrackingInterval = setInterval(() => { + this.exerciseTrackingInterval = window.setInterval(() => { if (this.exerciseRunningDuration >= this.currentExercise.duration) { clearInterval(this.exerciseTrackingInterval); let next: ExercisePlan = this.getNextExercise(); @@ -117,22 +80,14 @@ export class WorkoutRunner { this.currentExerciseIndex++; } this.startExercise(next); - this.exerciseChanged.next({ current: next, next: this.getNextExercise() }); } else { - this.workoutComplete.next(this.workoutPlan); - console.log("Workout complete!"); + this.router.navigate( ['/finish'] ); } return; } ++this.exerciseRunningDuration; --this.workoutTimeRemaining; - this.exerciseProgress.next({ - exercise: this.currentExercise, - runningFor: this.exerciseRunningDuration, - timeRemaining: this.currentExercise.duration - this.exerciseRunningDuration, - workoutTimeRemaining: this.workoutTimeRemaining - }); }, 1000); } diff --git a/trainer/src/components/workout-runner/workout-runner.tpl.html b/trainer/src/components/workout-runner/workout-runner.html similarity index 78% rename from trainer/src/components/workout-runner/workout-runner.tpl.html rename to trainer/src/components/workout-runner/workout-runner.html index d91a950..35cd6f3 100644 --- a/trainer/src/components/workout-runner/workout-runner.tpl.html +++ b/trainer/src/components/workout-runner/workout-runner.html @@ -4,7 +4,7 @@
- +
@@ -14,14 +14,14 @@

{{currentExercise.exercise.title}}

+ [ngStyle]="{'width':(exerciseRunningDuration/currentExercise.duration) * 100 + '%'}">

Time Remaining: {{currentExercise.duration-exerciseRunningDuration}}

-

Next up: +

Next up: {{workoutPlan.exercises[currentExerciseIndex + 1].exercise.title}}

@@ -31,5 +31,4 @@

N
-

diff --git a/trainer/src/components/workout-runner/workout-runner.module.ts b/trainer/src/components/workout-runner/workout-runner.module.ts new file mode 100644 index 0000000..cf81218 --- /dev/null +++ b/trainer/src/components/workout-runner/workout-runner.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { WorkoutRunnerComponent } from './workout-runner.component'; +import {ExerciseDescriptionComponent} from './exercise-description/exercise-description.component'; +import {VideoPlayerComponent} from './video-player/video-player.component'; +import {SecondsToTimePipe} from './seconds-to-time.pipe'; + +@NgModule({ + imports: [BrowserModule], + declarations: [ + WorkoutRunnerComponent, + ExerciseDescriptionComponent, + VideoPlayerComponent, + SecondsToTimePipe], + exports: [WorkoutRunnerComponent], +}) +export class WorkoutRunnerModule { } \ No newline at end of file diff --git a/trainer/src/tsconfig.json b/trainer/src/tsconfig.json index 8e04818..b3f6106 100644 --- a/trainer/src/tsconfig.json +++ b/trainer/src/tsconfig.json @@ -20,14 +20,6 @@ "!node_modules/**" ], "files": [ - "bootstrap.ts", - "components/app/app.ts", - "components/workout-runner/exercise-description.ts", - "components/workout-runner/model.ts", - "components/workout-runner/my-audio.ts", - "components/workout-runner/pipes.ts", - "components/workout-runner/video-player.ts", - "components/workout-runner/workout-audio.ts", - "components/workout-runner/workout-runner.ts" + "bootstrap.ts" ] } diff --git a/trainer/static/audio/15seconds.wav b/trainer/static/audio/15seconds.wav deleted file mode 100644 index c7a0329..0000000 Binary files a/trainer/static/audio/15seconds.wav and /dev/null differ diff --git a/trainer/static/audio/321.wav b/trainer/static/audio/321.wav deleted file mode 100644 index e9a807d..0000000 Binary files a/trainer/static/audio/321.wav and /dev/null differ diff --git a/trainer/static/audio/crunches.wav b/trainer/static/audio/crunches.wav deleted file mode 100644 index 0a5d40a..0000000 Binary files a/trainer/static/audio/crunches.wav and /dev/null differ diff --git a/trainer/static/audio/highknees.wav b/trainer/static/audio/highknees.wav deleted file mode 100644 index f9530dd..0000000 Binary files a/trainer/static/audio/highknees.wav and /dev/null differ diff --git a/trainer/static/audio/jumpingjacks.wav b/trainer/static/audio/jumpingjacks.wav deleted file mode 100644 index 43682af..0000000 Binary files a/trainer/static/audio/jumpingjacks.wav and /dev/null differ diff --git a/trainer/static/audio/lunge.wav b/trainer/static/audio/lunge.wav deleted file mode 100644 index fc20d9c..0000000 Binary files a/trainer/static/audio/lunge.wav and /dev/null differ diff --git a/trainer/static/audio/nextup.mp3 b/trainer/static/audio/nextup.mp3 deleted file mode 100644 index b6f76ca..0000000 Binary files a/trainer/static/audio/nextup.mp3 and /dev/null differ diff --git a/trainer/static/audio/nextup.wav b/trainer/static/audio/nextup.wav deleted file mode 100644 index fb96f74..0000000 Binary files a/trainer/static/audio/nextup.wav and /dev/null differ diff --git a/trainer/static/audio/plank.wav b/trainer/static/audio/plank.wav deleted file mode 100644 index d04f808..0000000 Binary files a/trainer/static/audio/plank.wav and /dev/null differ diff --git a/trainer/static/audio/pushupandrotate.wav b/trainer/static/audio/pushupandrotate.wav deleted file mode 100644 index 9c613c3..0000000 Binary files a/trainer/static/audio/pushupandrotate.wav and /dev/null differ diff --git a/trainer/static/audio/pushups.wav b/trainer/static/audio/pushups.wav deleted file mode 100644 index 9b34f19..0000000 Binary files a/trainer/static/audio/pushups.wav and /dev/null differ diff --git a/trainer/static/audio/sideplank.wav b/trainer/static/audio/sideplank.wav deleted file mode 100644 index e361611..0000000 Binary files a/trainer/static/audio/sideplank.wav and /dev/null differ diff --git a/trainer/static/audio/squats.wav b/trainer/static/audio/squats.wav deleted file mode 100644 index 4531335..0000000 Binary files a/trainer/static/audio/squats.wav and /dev/null differ diff --git a/trainer/static/audio/stepup.wav b/trainer/static/audio/stepup.wav deleted file mode 100644 index f5ec2c6..0000000 Binary files a/trainer/static/audio/stepup.wav and /dev/null differ diff --git a/trainer/static/audio/tick.mp3 b/trainer/static/audio/tick.mp3 deleted file mode 100644 index 5e71431..0000000 Binary files a/trainer/static/audio/tick.mp3 and /dev/null differ diff --git a/trainer/static/audio/tick10s.mp3 b/trainer/static/audio/tick10s.mp3 deleted file mode 100644 index b8811c8..0000000 Binary files a/trainer/static/audio/tick10s.mp3 and /dev/null differ diff --git a/trainer/static/audio/tricepdips.wav b/trainer/static/audio/tricepdips.wav deleted file mode 100644 index 7d7c9e8..0000000 Binary files a/trainer/static/audio/tricepdips.wav and /dev/null differ diff --git a/trainer/static/audio/wallsit.wav b/trainer/static/audio/wallsit.wav deleted file mode 100644 index 23ff40b..0000000 Binary files a/trainer/static/audio/wallsit.wav and /dev/null differ diff --git a/trainer/static/css/app.css b/trainer/static/css/app.css index 3324018..d2a0954 100644 --- a/trainer/static/css/app.css +++ b/trainer/static/css/app.css @@ -81,6 +81,10 @@ input[type="checkbox"].input-validation-error { /*styles for left nav bar - end*/ /*styles for container - start*/ +.container.app-container{ + width:100%; + max-width:100%; +} .workout-display-div { text-align: center; padding: 40px; @@ -132,13 +136,13 @@ input[type="checkbox"].input-validation-error { width:100%; height:100%; opacity:0; /*Comment this line to try our mouse event based pause and resume. */ - z-index:10; - + z-index:10; + } /*Comment this style to try our mouse event based pause and resume. */ #pause-overlay:hover { - opacity:.8; + opacity:.8; } #pause-overlay .pause{ font-size:120pt; @@ -153,16 +157,16 @@ input[type="checkbox"].input-validation-error { } #play-video-overlay { - position:absolute; + position:absolute; top:0px; width:100%; height:100%; opacity:0; - z-index:10; - + z-index:10; + } #play-video-overlay:hover { - opacity:.6; + opacity:.6; } #play-video-overlay .video { font-size:80pt; diff --git a/trainer/systemjs.config.js b/trainer/systemjs.config.js new file mode 100644 index 0000000..d0c7b0c --- /dev/null +++ b/trainer/systemjs.config.js @@ -0,0 +1,54 @@ +(function (global) { + + // map tells the System loader where to look for things + var map = { + 'app': 'dist', // 'dist', + 'rxjs': 'node_modules/rxjs', + '@angular': 'node_modules/@angular' + }; + + // packages tells the System loader how to load when no filename and/or no extension + var packages = { + 'app': { main: 'bootstrap.js', defaultExtension: 'js' }, + 'rxjs': { defaultExtension: 'js' } + }; + + var ngPackageNames = [ + 'common', + 'compiler', + 'core', + 'http', + 'platform-browser', + 'platform-browser-dynamic', + 'router', + 'testing' + ]; + + // Individual files (~300 requests): + function packIndex(pkgName) { + packages['@angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' }; + } + + // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' } + // Bundled (~40 requests): + function packUmd(pkgName) { + packages['@angular/' + pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; + } + + // Most environments should use UMD; some (Karma) need the individual index files + var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; + + // Add package entries for angular packages + ngPackageNames.forEach(setPackageConfig); + + var config = { + map: map, + packages: packages + } + + // filterSystemConfig - index.html's chance to modify config before we register it. + if (global.filterSystemConfig) { global.filterSystemConfig(config); } + + System.config(config); + +})(this); \ No newline at end of file