浏览代码

Add Ionic App with Spring Boot API

Matt Raible 7 年前
父节点
当前提交
0a0f154bf1
共有 100 个文件被更改,包括 464 次插入3571 次删除
  1. 2
    7
      README.md
  2. 246
    324
      TUTORIAL.md
  3. 0
    40
      client/config.xml
  4. 0
    29
      client/src/app/app.component.ts
  5. 0
    56
      client/src/app/app.module.ts
  6. 二进制
      client/src/assets/imgs/logo.png
  7. 二进制
      client/src/assets/imgs/stormpath-sdks.jpg
  8. 0
    18
      client/src/pages/about/about.html
  9. 0
    20
      client/src/pages/home/home.ts
  10. 0
    2971
      client/yarn.lock
  11. 3
    9
      deploy.sh
  12. 0
    0
      ionic-beer/.editorconfig
  13. 0
    0
      ionic-beer/.gitignore
  14. 39
    0
      ionic-beer/config.xml
  15. 0
    0
      ionic-beer/ionic.config.json
  16. 18
    18
      ionic-beer/package.json
  17. 二进制
      ionic-beer/resources/android/icon/drawable-hdpi-icon.png
  18. 二进制
      ionic-beer/resources/android/icon/drawable-ldpi-icon.png
  19. 二进制
      ionic-beer/resources/android/icon/drawable-mdpi-icon.png
  20. 二进制
      ionic-beer/resources/android/icon/drawable-xhdpi-icon.png
  21. 二进制
      ionic-beer/resources/android/icon/drawable-xxhdpi-icon.png
  22. 二进制
      ionic-beer/resources/android/icon/drawable-xxxhdpi-icon.png
  23. 0
    0
      ionic-beer/resources/android/splash/drawable-land-hdpi-screen.png
  24. 0
    0
      ionic-beer/resources/android/splash/drawable-land-ldpi-screen.png
  25. 0
    0
      ionic-beer/resources/android/splash/drawable-land-mdpi-screen.png
  26. 0
    0
      ionic-beer/resources/android/splash/drawable-land-xhdpi-screen.png
  27. 0
    0
      ionic-beer/resources/android/splash/drawable-land-xxhdpi-screen.png
  28. 0
    0
      ionic-beer/resources/android/splash/drawable-land-xxxhdpi-screen.png
  29. 0
    0
      ionic-beer/resources/android/splash/drawable-port-hdpi-screen.png
  30. 0
    0
      ionic-beer/resources/android/splash/drawable-port-ldpi-screen.png
  31. 0
    0
      ionic-beer/resources/android/splash/drawable-port-mdpi-screen.png
  32. 0
    0
      ionic-beer/resources/android/splash/drawable-port-xhdpi-screen.png
  33. 0
    0
      ionic-beer/resources/android/splash/drawable-port-xxhdpi-screen.png
  34. 0
    0
      ionic-beer/resources/android/splash/drawable-port-xxxhdpi-screen.png
  35. 0
    0
      ionic-beer/resources/icon.png
  36. 二进制
      ionic-beer/resources/ios/icon/icon-40.png
  37. 二进制
      ionic-beer/resources/ios/icon/icon-40@2x.png
  38. 二进制
      ionic-beer/resources/ios/icon/icon-40@3x.png
  39. 二进制
      ionic-beer/resources/ios/icon/icon-50.png
  40. 二进制
      ionic-beer/resources/ios/icon/icon-50@2x.png
  41. 二进制
      ionic-beer/resources/ios/icon/icon-60.png
  42. 二进制
      ionic-beer/resources/ios/icon/icon-60@2x.png
  43. 二进制
      ionic-beer/resources/ios/icon/icon-60@3x.png
  44. 二进制
      ionic-beer/resources/ios/icon/icon-72.png
  45. 二进制
      ionic-beer/resources/ios/icon/icon-72@2x.png
  46. 二进制
      ionic-beer/resources/ios/icon/icon-76.png
  47. 二进制
      ionic-beer/resources/ios/icon/icon-76@2x.png
  48. 二进制
      ionic-beer/resources/ios/icon/icon-83.5@2x.png
  49. 二进制
      ionic-beer/resources/ios/icon/icon-small.png
  50. 二进制
      ionic-beer/resources/ios/icon/icon-small@2x.png
  51. 二进制
      ionic-beer/resources/ios/icon/icon-small@3x.png
  52. 二进制
      ionic-beer/resources/ios/icon/icon.png
  53. 二进制
      ionic-beer/resources/ios/icon/icon@2x.png
  54. 0
    0
      ionic-beer/resources/ios/splash/Default-568h@2x~iphone.png
  55. 0
    0
      ionic-beer/resources/ios/splash/Default-667h.png
  56. 0
    0
      ionic-beer/resources/ios/splash/Default-736h.png
  57. 0
    0
      ionic-beer/resources/ios/splash/Default-Landscape-736h.png
  58. 0
    0
      ionic-beer/resources/ios/splash/Default-Landscape@2x~ipad.png
  59. 0
    0
      ionic-beer/resources/ios/splash/Default-Landscape~ipad.png
  60. 0
    0
      ionic-beer/resources/ios/splash/Default-Portrait@2x~ipad.png
  61. 0
    0
      ionic-beer/resources/ios/splash/Default-Portrait~ipad.png
  62. 0
    0
      ionic-beer/resources/ios/splash/Default@2x~iphone.png
  63. 0
    0
      ionic-beer/resources/ios/splash/Default~iphone.png
  64. 0
    0
      ionic-beer/resources/splash.png
  65. 22
    0
      ionic-beer/src/app/app.component.ts
  66. 0
    0
      ionic-beer/src/app/app.html
  67. 46
    0
      ionic-beer/src/app/app.module.ts
  68. 0
    18
      ionic-beer/src/app/app.scss
  69. 0
    0
      ionic-beer/src/app/main.ts
  70. 二进制
      ionic-beer/src/assets/icon/favicon.ico
  71. 二进制
      ionic-beer/src/assets/imgs/logo.png
  72. 0
    0
      ionic-beer/src/declarations.d.ts
  73. 3
    3
      ionic-beer/src/index.html
  74. 2
    2
      ionic-beer/src/manifest.json
  75. 11
    0
      ionic-beer/src/pages/about/about.html
  76. 0
    0
      ionic-beer/src/pages/about/about.scss
  77. 0
    1
      ionic-beer/src/pages/about/about.ts
  78. 0
    0
      ionic-beer/src/pages/beer/beer-modal.html
  79. 0
    0
      ionic-beer/src/pages/beer/beer-modal.ts
  80. 1
    1
      ionic-beer/src/pages/beer/beer.html
  81. 25
    0
      ionic-beer/src/pages/beer/beer.module.ts
  82. 0
    0
      ionic-beer/src/pages/beer/beer.scss
  83. 7
    6
      ionic-beer/src/pages/beer/beer.ts
  84. 1
    5
      ionic-beer/src/pages/contact/contact.html
  85. 0
    0
      ionic-beer/src/pages/contact/contact.scss
  86. 0
    1
      ionic-beer/src/pages/contact/contact.ts
  87. 0
    8
      ionic-beer/src/pages/home/home.html
  88. 0
    0
      ionic-beer/src/pages/home/home.scss
  89. 14
    0
      ionic-beer/src/pages/home/home.ts
  90. 0
    0
      ionic-beer/src/pages/tabs/tabs.html
  91. 2
    6
      ionic-beer/src/pages/tabs/tabs.ts
  92. 8
    12
      ionic-beer/src/providers/beer-service.ts
  93. 1
    0
      ionic-beer/src/providers/giphy-service.ts
  94. 0
    0
      ionic-beer/src/service-worker.js
  95. 1
    1
      ionic-beer/src/theme/variables.scss
  96. 0
    0
      ionic-beer/tsconfig.json
  97. 0
    0
      ionic-beer/tslint.json
  98. 1
    1
      server/.mvn/wrapper/maven-wrapper.properties
  99. 11
    14
      server/mvnw
  100. 0
    0
      server/mvnw.cmd

+ 2
- 7
README.md 查看文件

@@ -1,15 +1,10 @@
1
-# Stormpath is Joining Okta
2
-We are incredibly excited to announce that [Stormpath is joining forces with Okta](https://stormpath.com/blog/stormpaths-new-path?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement). Please visit [the Migration FAQs](https://stormpath.com/oktaplusstormpath?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement) for a detailed look at what this means for Stormpath users.
3
-
4
-We're available to answer all questions at [support@stormpath.com](mailto:support@stormpath.com).
5
-
6
-# Spring Boot, Ionic, and Stormpath 🍻
1
+# Spring Boot + Ionic 🍻
7 2
 
8 3
 This project is an example application for a typical [Ionic](https://ionicframework.com/) app with a [Spring Boot](https://projects.spring.io/spring-boot/) backend.
9 4
 
10 5
 You can read about how this application was created in [this tutorial](./TUTORIAL.md). Feel free to copy any code in this project for your own use in accordance with the [MIT license](LICENSE).
11 6
 
12
-**Prerequisites**: Java 8, Node.js, Maven, a [Stormpath Account](https://api.stormpath.com/register), and an `apiKey.properties` file in `~/stormpath/`.
7
+**Prerequisites**: Java 8, Node.js, and Maven.
13 8
 
14 9
 To run the Spring Boot backend, cd into `server` and run `mvn spring-boot:run`.
15 10
 

+ 246
- 324
TUTORIAL.md 查看文件

@@ -1,93 +1,31 @@
1
-# Spring Boot, Ionic, and Stormpath
1
+# Tutorial: Develop a Mobile App with Ionic and Spring Boot
2 2
 
3
-This tutorial shows how to build a secure Spring Boot API with Stormpath. It also shows how to build an Ionic app that securely connects to this API and can be deployed to a mobile device.
3
+Ionic 3.0 was [recently released](http://blog.ionic.io/ionic-3-0-has-arrived/), with support for 
4
+Angular 4, TypeScript 2.2, and lazy loading. Ionic, often called Ionic framework, is an open source
5
+(MIT-licensed) project that simplifies building native and progressive web apps. When developing an Ionic app, you'll use Angular and have access to native APIs via [Ionic Native](https://ionicframework.com/docs/native/) and [Apache Cordova](https://cordova.apache.org/). This means you can develop slick-looking UIs using the technologies you know and love: HTML, CSS, and JavaScript/TypeScript.
4 6
 
5
-**Prerequisites**: Java 8, Node.js, Maven, a [Stormpath Account](https://api.stormpath.com/register), and an `apiKey.properties` file in `~/stormpath/`.
7
+This tutorial shows how to build a Spring Boot API, how to build an Ionic app, and how to deploy it to a mobile device.
6 8
 
7
-## Spring Boot API
8
-
9
-Create your Spring Boot API project using [start.spring.io](https://start.spring.io).
10
-
11
-```
12
-http https://start.spring.io/starter.zip \
13
-dependencies==data-jpa,data-rest,h2,web,devtools,security,stormpath -d
14
-```
15
-
16
-Run the application with `./mvnw spring-boot:run`.
17
-
18
-Create a `Beer` entity class in `src/main/java/com/example/beer`.
9
+**Prerequisites**: [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) and [Node.js](https://nodejs.org) installed.
19 10
 
20
-```java
21
-package com.example.beer;
22
-
23
-import javax.persistence.Entity;
24
-import javax.persistence.GeneratedValue;
25
-import javax.persistence.Id;
26
-
27
-@Entity
28
-public class Beer {
29
-
30
-    @Id
31
-    @GeneratedValue
32
-    private Long id;
33
-    private String name;
11
+## Create a Project
34 12
 
35
-    public Beer() {
36
-    }
37
-
38
-    public Beer(String name) {
39
-        this.name = name;
40
-    }
13
+To begin, create a directory on your hard drive called `spring-boot-ionic-example`. During this tutorial, you will create `server` and `ionic-beer` directories to hold the server and client applications, respectively.  
41 14
 
42
-    public Long getId() {
43
-        return id;
44
-    }
45
-
46
-    public void setId(Long id) {
47
-        this.id = id;
48
-    }
49
-
50
-    public String getName() {
51
-        return name;
52
-    }
15
+## Spring Boot API
53 16
 
54
-    public void setName(String name) {
55
-        this.name = name;
56
-    }
17
+I recently wrote about how to build a Spring Boot API in a [QuickStart Guide to Spring Boot with Angular]. Rather than covering that again, you can clone the existing project and copy the `server` directory into `spring-boot-ionic-example`.
57 18
 
58
-    @Override
59
-    public String toString() {
60
-        return "Beer{" +
61
-                "id=" + id +
62
-                ", name='" + name + '\'' +
63
-                '}';
64
-    }
65
-}
19
+```bash
20
+git clone https://github.com/oktadeveloper/spring-boot-angular-example.git
21
+cp -r spring-boot-angular-example/server ~/spring-boot-ionic-example/.
66 22
 ```
67 23
 
68
-Create a JPA Repository to manage the `Beer` entity.
69
-
70
-```java
71
-package com.example.beer;
72
-
73
-import org.springframework.data.jpa.repository.JpaRepository;
74
-import org.springframework.data.rest.core.annotation.RepositoryRestResource;
24
+This project contains a `beers` API that allows you to <abbr title="Create, Read, Update, and Delete">CRUD</abbr> a list of beer names. It also contains a `/good-beers` endpoint that filters out less-than-great beers.
75 25
 
76
-@RepositoryRestResource
77
-interface BeerRepository extends JpaRepository<Beer, Long> {
78
-}
79
-```
80
-
81
-Create a CommandLineRunner to populate the database.
26
+The default list of beers is created by a `BeerCommandLineRunner` class:
82 27
 
83 28
 ```java
84
-package com.example.beer;
85
-
86
-import org.springframework.boot.CommandLineRunner;
87
-import org.springframework.stereotype.Component;
88
-
89
-import java.util.stream.Stream;
90
-
91 29
 @Component
92 30
 class BeerCommandLineRunner implements CommandLineRunner {
93 31
     private final BeerRepository repository;
@@ -98,29 +36,26 @@ class BeerCommandLineRunner implements CommandLineRunner {
98 36
 
99 37
     @Override
100 38
     public void run(String... strings) throws Exception {
101
-        // top 5 beers from https://www.beeradvocate.com/lists/top/
102
-        Stream.of("Good Morning", "Kentucky Brunch Brand Stout", "ManBearPig", "King Julius",
103
-                "Very Hazy", "Budweiser", "Coors Light", "PBR").forEach(name ->
39
+        // Top beers from https://www.beeradvocate.com/lists/top/
40
+        Stream.of("Kentucky Brunch Brand Stout", "Good Morning", "Very Hazy", "King Julius",
41
+                "Budweiser", "Coors Light", "PBR").forEach(name ->
104 42
                 repository.save(new Beer(name))
105 43
         );
106
-        System.out.println(repository.findAll());
44
+        repository.findAll().forEach(System.out::println);
107 45
     }
108 46
 }
109 47
 ```
110 48
 
111
-Create a `BeerController` for your REST API. Add some business logic that results in a `/good-beers` endpoint.
49
+The `BeerRepository` interface is decorated with `@RepositoryRestResource` to expose CRUD endpoints for the `Beer` entity.
112 50
 
113 51
 ```java
114
-package com.example.beer;
115
-
116
-import org.springframework.web.bind.annotation.GetMapping;
117
-import org.springframework.web.bind.annotation.RestController;
52
+@RepositoryRestResource
53
+interface BeerRepository extends JpaRepository<Beer, Long> {}
54
+```
118 55
 
119
-import java.util.Collection;
120
-import java.util.HashMap;
121
-import java.util.Map;
122
-import java.util.stream.Collectors;
56
+The last piece of the API is the `BeerController` that exposes `/good-beers` and specifies cross-origin resource sharing (CORS) settings.
123 57
 
58
+```java
124 59
 @RestController
125 60
 public class BeerController {
126 61
     private BeerRepository repository;
@@ -130,6 +65,7 @@ public class BeerController {
130 65
     }
131 66
 
132 67
     @GetMapping("/good-beers")
68
+    @CrossOrigin(origins = "http://localhost:4200")
133 69
     public Collection<Map<String, String>> goodBeers() {
134 70
 
135 71
         return repository.findAll().stream()
@@ -148,251 +84,128 @@ public class BeerController {
148 84
                 !beer.getName().equals("PBR");
149 85
     }
150 86
 }
151
-
152 87
 ```
153 88
 
154
-Access the API using `http localhost:8080/good-beers --auth <user>:<password>`.
89
+You should be able to start the `server` application by running it in your favorite IDE or from the command line using `mvn spring-boot:run`. If you don't have Maven installed, you can use the Maven wrapper that's included in the project (`./mvnw spring-boot:run` on *nix, `\mvnw spring-boot:run` on Windows).
155 90
 
156
-## Create Ionic App
91
+After the app has started, navigate to <http://localhost:8080/good-beers>. You should see the list of good beers in your browser.
157 92
 
158
-Install Ionic and Cordova: `yarn global add cordova ionic`
93
+![Good Beers JSON](static/good-beers-json.png) 
159 94
 
160
-From a terminal window, create a new application using the following command:
95
+## Create Ionic App
161 96
 
97
+To create an Ionic app to display data from your API, you'll first need to install Ionic CLI and Cordova: 
98
+
99
+```bash
100
+npm install -g ionic cordova
162 101
 ```
102
+
103
+The [Ionic CLI](http://ionicframework.com/docs/cli/) is a command-line tool that greatly reduces the time it takes to develop an Ionic app. It’s like a Swiss Army Knife: It brings together a bunch of miscellaneous tools under a single interface. The CLI contains a number of useful commands for Ionic development, such as `start`, `build`, `generate`, `serve`, and `run`.
104
+
105
+After installation completes, create a new application using the following command:
106
+
107
+```bash
163 108
 ionic start ionic-beer --v2
164 109
 ```
165 110
 
166 111
 This may take a minute or two to complete, depending on your internet connection speed. In the same terminal window, change to be in your application’s directory and run it.
167 112
 
168
-```
113
+```bash
169 114
 cd ionic-beer
170 115
 ionic serve
171 116
 ```
172 117
 
173 118
 This will open your default browser on [http://localhost:8100](http://localhost:8100). You can click through the tabbed interface to see the default structure of the app.
174 119
 
175
-## Upgrade to Angular 2.3
120
+![Ionic shell with tabs](static/ionic-tabs.png)
176 121
 
177
-With Angular versions less than 2.3, you can’t extend components and override their templates. The Ionic pages for Stormpath module uses component extension to override the templates in its pages. Because of this, you have to upgrade your project to use Angular 2.3. The only downside to use Angular 2.3 with Ionic 2.0.0 is that you won’t be able to use the `--prod` build flag when compiling. This is because its compiler does not support Angular 2.3.
122
+## Create a Good Beers UI
178 123
 
179
-To begin, modify `package.json` so all the `angular` dependencies use version `2.3.1` rather than `2.2.1`.
124
+Run `ionic generate page beer` to create a component and a template to display the list of good beers. This creates a number of files in `src/app/pages/beer`:
180 125
 
181
-```json
182
-"dependencies": {
183
-  "@angular/common": "2.3.1",
184
-  "@angular/compiler": "2.3.1",
185
-  "@angular/compiler-cli": "2.3.1",
186
-  "@angular/core": "2.3.1",
187
-  "@angular/forms": "2.3.1",
188
-  "@angular/http": "2.3.1",
189
-  "@angular/platform-browser": "2.3.1",
190
-  "@angular/platform-browser-dynamic": "2.3.1",
191
-  "@angular/platform-server": "2.3.1",
126
+```
127
+beer.html
128
+beer.module.ts
129
+beer.scss
130
+beer.ts
192 131
 ```
193 132
 
194
-Run `yarn` to update to these versions.
133
+Open `beer.ts` and change the name of the class to be `BeerPage`.
195 134
 
196
-## Install Ionic Pages for Stormpath
135
+```typescript
136
+export class BeerPage {
197 137
 
198
-Install [Ionic pages for Stormpath](https://github.com/stormpath/stormpath-sdk-angular-ionic):
138
+  constructor(public navCtrl: NavController, public navParams: NavParams) {
139
+  }
199 140
 
200
-```
201
-yarn add angular-stormpath-ionic
141
+  ionViewDidLoad() {
142
+    console.log('ionViewDidLoad BeerPage');
143
+  }
144
+
145
+}
202 146
 ```
203 147
 
204
-Modify `src/app/app.module.ts` to define a `stormpathConfig` function. This function is used to configure the `endpointPrefix` to point to your Spring Boot API. Import `StormpathModule`, `StormpathIonicModule`, and override the provider of `StormpathConfiguration`. You’ll also need to append Stormpath's pre-built Ionic pages to `entryComponents`.
148
+Modify `beer.module.ts` to change the class name too.
205 149
 
206 150
 ```typescript
207
-import { StormpathConfiguration, StormpathModule } from 'angular-stormpath';
208
-import { StormpathIonicModule, LoginPage, ForgotPasswordPage, RegisterPage } from 'angular-stormpath-ionic';
209
-
210
-export function stormpathConfig(): StormpathConfiguration {
211
-  let spConfig: StormpathConfiguration = new StormpathConfiguration();
212
-  spConfig.endpointPrefix = 'http://localhost:8080';
213
-  return spConfig;
214
-}
151
+import { NgModule } from '@angular/core';
152
+import { IonicModule } from 'ionic-angular';
153
+import { BeerPage } from './beer';
215 154
 
216 155
 @NgModule({
217
-  ...
218
-  imports: [
219
-    IonicModule.forRoot(MyApp),
220
-    StormpathModule,
221
-    StormpathIonicModule
156
+  declarations: [
157
+    BeerPage
222 158
   ],
223
-  bootstrap: [IonicApp],
224
-  entryComponents: [
225
-    ...
226
-    LoginPage,
227
-    ForgotPasswordPage,
228
-    RegisterPage
159
+  imports: [
160
+    IonicModule.forRoot(BeerPage),
229 161
   ],
230
-  providers: [
231
-    {provide: ErrorHandler, useClass: IonicErrorHandler},
232
-    {provide: StormpathConfiguration, useFactory: stormpathConfig}
162
+  exports: [
163
+    BeerPage
233 164
   ]
234 165
 })
235
-export class AppModule {}
166
+export class BeerModule {}
236 167
 ```
237 168
 
238
-To render a login page before users can view the application, modify `src/app/app.component.ts` to use the `Stormpath` service and navigate to Stormpath's `LoginPage` if the user is not authenticated.
169
+Add `BeerModule` to the `imports` list in `app.module.ts`.
239 170
 
240 171
 ```typescript
241
-import { Component } from '@angular/core';
242
-import { Platform } from 'ionic-angular';
243
-import { StatusBar, Splashscreen } from 'ionic-native';
244
-import { TabsPage } from '../pages/tabs/tabs';
245
-import { Stormpath } from 'angular-stormpath';
246
-import { LoginPage } from 'angular-stormpath-ionic';
247
-
248
-@Component({
249
-  templateUrl: 'app.html'
250
-})
251
-export class MyApp {
252
-  rootPage;
253
-
254
-  constructor(platform: Platform, private stormpath: Stormpath) {
255
-    stormpath.user$.subscribe(user => {
256
-      if (!user) {
257
-        this.rootPage = LoginPage;
258
-      } else {
259
-        this.rootPage = TabsPage;
260
-      }
261
-    });
262
-
263
-    platform.ready().then(() => {
264
-      // Okay, so the platform is ready and our plugins are available.
265
-      // Here you can do any higher level native things you might need.
266
-      StatusBar.styleDefault();
267
-      Splashscreen.hide();
268
-    });
269
-  }
270
-}
271
-```
272
-
273
-If you run `ionic serve`, you’ll likely see something similar to the following error in your browser’s console.
274
-
275
-```
276
-XMLHttpRequest cannot load http://localhost:8080/me. Response to preflight request
277
-doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on
278
-the requested resource. Origin 'http://localhost:8100 is therefore not allowed access.
279
-The response had HTTP status code 403.
280
-```
172
+import { BeerModule } from '../pages/beer/beer.module';
281 173
 
282
-To fix this, open your Spring Boot application's `src/main/resources/application.properties` and add the following line. This enables cross-origin resource sharing (CORS) from both the browser and the mobile client.
283
-
284
-```
285
-stormpath.web.cors.allowed.originUris = http://localhost:8100,file://
286
-```
287
-
288
-Restart Spring Boot and your Ionic app. You should see a login screen when you run `ionic serve`.
289
-
290
-![Stormpath Login for Ionic](./static/ionic-login.png)
291
-
292
-In `src/pages/home.html`, add a logout link to the header and a paragraph in the content section that shows the currently logged in user.
293
-
294
-```html
295
-<ion-header>
296
-  <ion-navbar>
297
-    <ion-title>Home</ion-title>
298
-    <ion-buttons end>
299
-      <button ion-button icon-only (click)="logout()">
300
-        Logout
301
-      </button>
302
-    </ion-buttons>
303
-  </ion-navbar>
304
-</ion-header>
305
-
306
-<ion-content padding>
174
+@NgModule({
307 175
   ...
308
-  <p *ngIf="(user$ | async)">
309
-    You are logged in as: <b>{{ ( user$ | async ).fullName }}</b>
310
-  </p>
311
-</ion-content>
312
-```
313
-
314
-If you login, the “Logout” button will render, but won’t work because there’s no `logout()` method in `src/pages/home.ts`. Similarly, the “You are logged in” message won’t appear because there’s no `user$` variable defined. Change the body of `home.ts` to retrieve `user$` from the `Stormpath` service and define the `logout()` method.
315
-
316
-```typescript
317
-import { Account, Stormpath } from 'angular-stormpath';
318
-import { Observable } from 'rxjs';
319
-...
320
-export class HomePage {
321
-  user$: Observable<Account | boolean>;
322
-
323
-  constructor(private stormpath: Stormpath) {
324
-    this.user$ = this.stormpath.user$;
325
-  }
326
-
327
-  logout(): void {
328
-    this.stormpath.logout();
329
-  }
330
-}
331
-```
332
-
333
-If you’re logged in, you should see a screen with a logout button and the name of the currently logged in user.
334
-
335
-![Logged in as: Hip User](./static/ionic-home.png)
336
-
337
-The `LoginPage` tries to auto-focus onto the `email` field when it loads. To auto-activate the keyboard you'll need to tell Cordova it’s OK to display the keyboard without user interaction. You can do this by adding the following to `config.xml` in the root directory.
338
-
339
-```xml
340
-<preference name="KeyboardDisplayRequiresUserAction" value="false"/>
341
-```
342
-
343
-Check your changes into Git.
344
-
345
-```
346
-git add .
347
-git commit -m "Add Stormpath"
176
+  imports: [
177
+    BrowserModule,
178
+    IonicModule.forRoot(MyApp),
179
+    BeerModule
180
+  ],
181
+  ...
182
+})
348 183
 ```
349 184
 
350
-## Build a Good Beers UI
351
-
352
-Run `ionic generate page beer` to create a component and a template to display the list of good beers.
185
+Run `ionic g provider beer-service` to create a service to fetch the beer list from the Spring Boot API.
353 186
 
354
-Add `BeerPage` to the `declarations` and `entryComponent` lists in `app.module.ts`.
355
-
356
-Run `ionic generate provider beer-service` to create a service to fetch the beer list from the Spring Boot API.
357
-
358
-Change `src/providers/beer-service.ts` to use have a `getGoodBeers()` method.
187
+Change `src/providers/beer-service.ts` to have constants for the API path and add a `getGoodBeers()` method.
359 188
 
360 189
 ```typescript
361 190
 import { Injectable } from '@angular/core';
362
-import { Http, Response, RequestOptions } from '@angular/http';
191
+import { Http, Response } from '@angular/http';
363 192
 import 'rxjs/add/operator/map';
364 193
 import { Observable } from 'rxjs';
365
-import { StormpathConfiguration } from 'angular-stormpath';
366 194
 
367 195
 @Injectable()
368 196
 export class BeerService {
369
-  public API;
370
-  public BEER_API;
197
+  public API = 'http://localhost:8080';
198
+  public BEER_API = this.API + '/beers';
371 199
 
372
-  constructor(public http: Http, public config: StormpathConfiguration) {
373
-    this.API = config.endpointPrefix;
374
-    this.BEER_API = this.API + '/beers';
375
-  }
200
+  constructor(private http: Http) {}
376 201
 
377 202
   getGoodBeers(): Observable<any> {
378
-    let options = new RequestOptions({ withCredentials: true });
379
-    return this.http.get(this.API + '/good-beers', options)
203
+    return this.http.get(this.API + '/good-beers')
380 204
       .map((response: Response) => response.json());
381 205
   }
382 206
 }
383 207
 ```
384 208
 
385
-**TIP:** If you don’t want to pass in `withCredentials: true`, you can add the API URI as an `autoAuthorizeUri` in `StormpathConfiguration`.
386
-
387
-```typescript
388
-export function stormpathConfig(): StormpathConfiguration {
389
-  let spConfig: StormpathConfiguration = new StormpathConfiguration();
390
-  spConfig.endpointPrefix = 'http://localhost:8080';
391
-  spConfig.autoAuthorizedUris.push(new RegExp(spConfig.endpointPrefix + '/*'));
392
-  return spConfig;
393
-}
394
-```
395
-
396 209
 Modify `beer.html` to show the list of beers.
397 210
 
398 211
 ```html
@@ -405,28 +218,43 @@ Modify `beer.html` to show the list of beers.
405 218
 
406 219
 <ion-content padding>
407 220
   <ion-list>
408
-    <ion-item *ngFor="let beer of beers" >
221
+    <ion-item *ngFor="let beer of beers">
409 222
       <h2>{{beer.name}}</h2>
410 223
     </ion-item>
411 224
   </ion-list>
412 225
 </ion-content>
413 226
 ```
414 227
 
415
-Update `beer.ts` to import `BeerService` and add as a provider. Call the `getGoodBeers()` method in the `ionViewDidLoad()` lifecycle method.
228
+Modify `beer.module.ts` to import `BeerService` and add it as a provider. You could add it as a provider in each component, but adding it in the module allows all components to use it. 
229
+
230
+```typescript
231
+import { BeerService } from '../../providers/beer-service';
232
+
233
+@NgModule({
234
+  ...
235
+  providers: [
236
+    BeerService
237
+  ]
238
+})
239
+```
240
+
241
+Update `beer.ts` to import `BeerService` and add it as a dependency in the constructor. Call the `getGoodBeers()` method in the `ionViewDidLoad()` lifecycle method.
416 242
 
417 243
 ```typescript
418 244
 import { Component } from '@angular/core';
245
+import { IonicPage, NavController, NavParams } from 'ionic-angular';
419 246
 import { BeerService } from '../../providers/beer-service';
420 247
 
248
+@IonicPage()
421 249
 @Component({
422 250
   selector: 'page-beer',
423
-  templateUrl: 'beer.html',
424
-  providers: [BeerService]
251
+  templateUrl: 'beer.html'
425 252
 })
426 253
 export class BeerPage {
427 254
   private beers: Array<any>;
428 255
 
429
-  constructor(public beerService: BeerService) {
256
+  constructor(public navCtrl: NavController, public navParams: NavParams,
257
+              public beerService: BeerService) {
430 258
   }
431 259
 
432 260
   ionViewDidLoad() {
@@ -451,19 +279,16 @@ import { BeerPage } from '../beer/beer';
451 279
   templateUrl: 'tabs.html'
452 280
 })
453 281
 export class TabsPage {
454
-  // this tells the tabs component which Pages
455
-  // should be each tab's root Page
456 282
   tab1Root: any = HomePage;
457 283
   tab2Root: any = BeerPage;
458 284
   tab3Root: any = ContactPage;
459 285
   tab4Root: any = AboutPage;
460 286
 
461
-  constructor() {
462
-  }
287
+  constructor() {}
463 288
 }
464 289
 ```
465 290
 
466
-Update `tabs.html` too!
291
+You'll also need to update `tabs.html` to have the new tab order.
467 292
 
468 293
 ```html
469 294
 <ion-tabs>
@@ -474,7 +299,9 @@ Update `tabs.html` too!
474 299
 </ion-tabs>
475 300
 ```
476 301
 
477
-Add some fun with Giphy! Run `ionic generate provider giphy-service`. Replace the code in `src/providers/giphy-service.ts` with the following TypeScript:
302
+### Add Some Fun with Animated GIFs
303
+
304
+Run `ionic g provider giphy-service` to generate a `GiphyService` class. Replace the code in `src/providers/giphy-service.ts` with code that searches Giphy's API:
478 305
 
479 306
 ```typescript
480 307
 import { Injectable } from '@angular/core';
@@ -485,6 +312,7 @@ import { Observable } from 'rxjs';
485 312
 // http://tutorials.pluralsight.com/front-end-javascript/getting-started-with-angular-2-by-building-a-giphy-search-application
486 313
 export class GiphyService {
487 314
 
315
+  // Public beta key: https://github.com/Giphy/GiphyAPI#public-beta-key
488 316
   giphyApi = 'https://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';
489 317
 
490 318
   constructor(public http: Http) {
@@ -504,22 +332,38 @@ export class GiphyService {
504 332
 }
505 333
 ```
506 334
 
507
-Update `beer.ts` to take advantage of `GiphyService`:
335
+Update `beer.module.ts` to import `GiphyService` and include it is as a provider.
336
+
337
+```typescript
338
+import { GiphyService } from '../../providers/giphy-service';
339
+
340
+@NgModule({
341
+  ...
342
+  providers: [
343
+    BeerService,
344
+    GiphyService
345
+  ]
346
+})
347
+```
348
+
349
+Modify `beer.ts` to import `GiphyService` and set a `giphyUrl` on each beer.
508 350
 
509 351
 ```typescript
510 352
 import { Component } from '@angular/core';
353
+import { IonicPage, NavController, NavParams } from 'ionic-angular';
511 354
 import { BeerService } from '../../providers/beer-service';
512 355
 import { GiphyService } from '../../providers/giphy-service';
513 356
 
357
+@IonicPage()
514 358
 @Component({
515 359
   selector: 'page-beer',
516
-  templateUrl: 'beer.html',
517
-  providers: [BeerService, GiphyService]
360
+  templateUrl: 'beer.html'
518 361
 })
519 362
 export class BeerPage {
520 363
   private beers: Array<any>;
521 364
 
522
-  constructor(public beerService: BeerService, public giphyService: GiphyService) {
365
+  constructor(public navCtrl: NavController, public navParams: NavParams,
366
+              public beerService: BeerService, public giphyService: GiphyService) {
523 367
   }
524 368
 
525 369
   ionViewDidLoad() {
@@ -546,11 +390,49 @@ Update `beer.html` to display the image retrieved:
546 390
 </ion-item>
547 391
 ```
548 392
 
393
+Start the Spring Boot app in one terminal and run `ionic serve` in another. Open <http://localhost:8100> in your browser. Click on the Beer icon and you'll likely see an error in your browser.
394
+
395
+```
396
+Uncaught (in promise): Error: No provider for Http! 
397
+```
398
+
399
+![No provider for Http!](static/no-http-provider.png)
400
+
401
+This highlights one of the slick features of Ionic: errors are displayed in your browser, not just the browser's console. Add `HttpModule` to the list of imports in `src/app/app.module.ts` to solve this issue.
402
+
403
+```typescript
404
+import { HttpModule } from '@angular/http';
405
+
406
+@NgModule({
407
+  ...
408
+  imports: [
409
+    BrowserModule,
410
+    HttpModule,
411
+    IonicModule.forRoot(MyApp),
412
+    BeerModule
413
+  ],
414
+```
415
+
416
+After making this change, you’ll likely see the following error in your browser’s console.
417
+
418
+```
419
+XMLHttpRequest cannot load http://localhost:8080/good-beers. No 'Access-Control-Allow-Origin' 
420
+header is present on the requested resource. Origin 'http://localhost:8100' is therefore 
421
+not allowed access. The response had HTTP status code 401.
422
+```
423
+
424
+To fix this, open your Spring Boot application's `BeerController.java` class and change its `@CrossOrigin` annotation to allow `http://localhost:8100` and `file://`. This enables cross-origin resource sharing (CORS) from both the browser and the mobile client.
425
+
426
+```java
427
+@CrossOrigin(origins = {"http://localhost:8100","file://"})
428
+public Collection<Map<String, String>> goodBeers() {
429
+```
430
+
431
+Recompile this class and DevTools should restart the application.
432
+
549 433
 If everything works as expected, you should see a page similar to the one below in your browser.
550 434
 
551
-<p align="center">
552
-<img src="./static/good-beers-ui.png" width="600" alt="Good Beers UI">
553
-</p>
435
+![Good Beers UI](static/good-beers-ui.png)
554 436
 
555 437
 ### Add a Modal for Editing
556 438
 
@@ -578,12 +460,13 @@ In this same file, change `<ion-item>` to have a click handler for opening the m
578 460
 Add `ModalController` as a dependency in `BeerPage` and add an `openModal()` method.
579 461
 
580 462
 ```typescript
581
-import { ModalController } from 'ionic-angular';
463
+import { IonicPage, ModalController, NavController, NavParams } from 'ionic-angular';
582 464
 
583 465
 export class BeerPage {
584 466
   private beers: Array<any>;
585 467
 
586
-  constructor(public beerService: BeerService, public giphyService: GiphyService,
468
+  constructor(public navCtrl: NavController, public navParams: NavParams,
469
+              public beerService: BeerService, public giphyService: GiphyService,
587 470
               public modalCtrl: ModalController) {
588 471
   }
589 472
 
@@ -654,7 +537,7 @@ export class BeerModalPage {
654 537
 }
655 538
 ```
656 539
 
657
-Create `beer-modal.html` as a template for this page.
540
+Add the import for `BeerModalPage` to `beer.ts`, then create `beer-modal.html` as a template for this page.
658 541
 
659 542
 ```html
660 543
 <ion-header>
@@ -699,7 +582,7 @@ Create `beer-modal.html` as a template for this page.
699 582
 </ion-content>
700 583
 ```
701 584
 
702
-Add `BeerModalPage` to the `declarations` and `entryComponent` lists in `app.module.ts`.
585
+Add `BeerModalPage` to the `declarations` and `entryComponent` lists in `beer.module.ts`.
703 586
 
704 587
 You'll also need to modify `beer-service.ts` to have `get()` and `save()` methods.
705 588
 
@@ -721,6 +604,40 @@ save(beer: any): Observable<any> {
721 604
 }
722 605
 ```
723 606
 
607
+At this point, if you try to add or edit a beer name, you'll likely see an error in your browser's console.
608
+
609
+```
610
+ModalCmp ionViewPreLoad error: No component factory found for BeerModalPage. 
611
+Did you add it to @NgModule.entryComponents?
612
+```
613
+
614
+Add `BeerModalPage` to the list of `entryComponents` in `app.module.ts`. While you're in there, add `BeerService` to the list of global providers so you don't have to add it to each component that uses it.
615
+
616
+```typescript
617
+@NgModule({
618
+  ...
619
+  entryComponents: [
620
+    ...
621
+    BeerModalPage
622
+  ],
623
+  providers: [
624
+    BeerService,
625
+    ...
626
+  ]
627
+})
628
+```
629
+
630
+Now if you try to edit a beer's name, you'll see another CORS in your browser's console. Add a `@CrossOrigin` annotation to `BeerRepository.java` (in your Spring Boot project) that matches the one in `BeerController`.
631
+ 
632
+```java
633
+@RepositoryRestResource
634
+@CrossOrigin(origins = {"http://localhost:8100","file://"})
635
+```
636
+
637
+Re-compile and now everything should work as expected. For example, below is a screenshot that shows I added a new beer and what it looks like when editing it.
638
+ 
639
+![Mmmmm, Guinness](static/beer-modal.png)
640
+
724 641
 ### Add Swipe to Delete
725 642
 
726 643
 To add swipe-to-delete functionality on the list of beers, open `beer.html` and make it so `<ion-item-sliding>` wraps `<ion-item>` and contains the `*ngFor`. Add a delete button using `<ion-item-options>`.
@@ -766,7 +683,8 @@ remove(beer) {
766 683
 Add `toastCtrl` as a dependency in the constructor so everything compiles.
767 684
 
768 685
 ```typescript
769
-constructor(public beerService: BeerService, public giphyService: GiphyService,
686
+constructor(public navCtrl: NavController, public navParams: NavParams,
687
+          public beerService: BeerService, public giphyService: GiphyService,
770 688
           public modalCtrl: ModalController, public toastCtrl: ToastController) {
771 689
 }
772 690
 ```
@@ -780,37 +698,36 @@ remove(id: string) {
780 698
 }
781 699
 ```
782 700
 
783
-After making these additions, you should be able to add, edit and delete beers.
701
+After making these additions, you should be able to delete beer names. To emulate a left swipe in your browser, click on the item and drag it to the left.
784 702
 
785
-<p align="center">
786
-<img src="./static/beer-modal.png" width="350">&nbsp;&nbsp;
787
-<img src="./static/beer-delete.png" width="350">
788
-</p>
703
+![Left swipe](static/beer-delete.png)
789 704
 
790 705
 ## PWAs with Ionic
791 706
 
792
-Ionic 2 ships with support for creating progressive web apps (PWAs). If you’d like to learn more about what PWAs are, see [Navigating the World of Progressive Web Apps with Ionic 2](http://blog.ionic.io/navigating-the-world-of-progressive-web-apps-with-ionic-2/).
707
+Ionic ships with support for creating progressive web apps (PWAs). If you’d like to learn more about what PWAs are, see [Navigating the World of Progressive Web Apps with Ionic 2](http://blog.ionic.io/navigating-the-world-of-progressive-web-apps-with-ionic-2/). This blog post is still relevant for Ionic 3.
708
+
709
+If you run the [Lighthouse Chrome extension](https://developers.google.com/web/tools/lighthouse/) on this application, you’ll get a mediocre score (51/100).
793 710
 
794
-If you run the [Lighthouse Chrome extension](https://developers.google.com/web/tools/lighthouse/) on this application, you’ll get a mediocre score (54/100).
711
+![Lighthouse: 51](static/lighthouse-51.png)
795 712
 
796
-To register a service worker, and improve the app’s score, uncomment the following block in `index.html`.
713
+To register a service worker, and improve the app’s score, uncomment the following block in `src/index.html`.
797 714
 
798 715
 ```html
799 716
 <!-- un-comment this code to enable service worker
800 717
 <script>
801
-  if ('serviceWorker' in navigator) {
802
-    navigator.serviceWorker.register('service-worker.js')
803
-      .then(() => console.log('service worker installed'))
804
-      .catch(err => console.log('Error', err));
805
-  }
718
+if ('serviceWorker' in navigator) {
719
+  navigator.serviceWorker.register('service-worker.js')
720
+    .then(() => console.log('service worker installed'))
721
+    .catch(err => console.log('Error', err));
722
+}
806 723
 </script>-->
807 724
 ```
808 725
 
809
-After making this change, the score should improve. In my tests, it increased to 69/100. The remaining issues were:
726
+After making this change, the score should improve. In my tests, it increased to 66/100. The remaining issues were:
810 727
 
811
-* The page body should render some content if its scripts are not available. This could likely be solved with [Angular’s app-shell directives](https://www.npmjs.com/package/@angular/app-shell).
812
-* Site is not on HTTPS and does not redirect HTTP to HTTPS.
813 728
 * A couple -1’s in performance for "Cannot read property 'ts' of undefined”.
729
+* Site is not progressively enhanced (page should contain some content when JavaScript is not available). This could likely be solved with [Angular’s app-shell directives](https://www.npmjs.com/package/@angular/app-shell).
730
+* Site is not on HTTPS and does not redirect HTTP to HTTPS.
814 731
 
815 732
 If you refresh the app and Chrome doesn’t prompt you to install the app (a PWA feature), you probably need to turn on a couple of features. Copy and paste the following URLs into Chrome and enable each feature.
816 733
 
@@ -819,7 +736,7 @@ chrome://flags/#bypass-app-banner-engagement-checks
819 736
 chrome://flags/#enable-add-to-shelf
820 737
 ```
821 738
 
822
-After enabling these flags, you’ll see an error in your browser’s console about `assets/imgs/logo.png` not being found. This files is referenced in `src/manifest.json`. You can fix this by copying a 512x512 PNG into this location or by modifying `manifest.json` accordingly.
739
+After enabling these flags, you’ll see an error in your browser’s console about `assets/imgs/logo.png` not being found. This file is referenced in `src/manifest.json`. You can fix this by copying a 512x512 PNG ([like this one](http://www.iconsdb.com/orange-icons/beer-icon.html)) into this location or by modifying `manifest.json` accordingly. At the very least, you should modify `manifest.json` to have your app's name.
823 740
 
824 741
 ## Deploy to a Mobile Device
825 742
 
@@ -827,6 +744,8 @@ It’s pretty cool that you’re able to develop mobile apps with Ionic in your
827 744
 
828 745
 To see how your application will look on different devices you can run `ionic serve --lab`. The `--lab` flag opens opens a page in your browser that lets you see how your app looks on different devices.
829 746
 
747
+![Ionic Labs](static/ionic-labs.png)
748
+
830 749
 ### iOS
831 750
 
832 751
 To emulate or deploy to an iOS device, you’ll need a Mac and a fresh installation of [Xcode](https://developer.apple.com/xcode/). If you’d like to build iOS apps on Windows, Ionic offers an [Ionic Package](http://ionic.io/cloud#packaging) service.
@@ -854,7 +773,7 @@ open ionic-beer.xcodeproj
854 773
 
855 774
 Select your phone as the target in Xcode and click the play button to run your app. The first time you do this, Xcode may spin for a while with a “Processing symbol files” message at the top.
856 775
 
857
-Deploying to your phone will likely fail because it won't be able to connect to `http://localhost:8080`. To fix this, copy [this script](./deploy.sh) to your hard drive. It expects to be in a directory above your apps. It also expects your apps to be named `client` and `server`.
776
+Deploying to your phone will likely fail because it won't be able to connect to `http://localhost:8080`. To fix this, copy [this script](./deploy.sh) to your hard drive. It expects to be in a directory above your apps. It also expects your apps to be named `ionic-beer` and `server`.
858 777
 
859 778
 If you don't have a Cloud Foundry account, you'll need to [create one](https://account.run.pivotal.io/z/uaa/sign-up) and install its command line tools for this script to work.
860 779
 
@@ -862,13 +781,9 @@ If you don't have a Cloud Foundry account, you'll need to [create one](https://a
862 781
 brew tap cloudfoundry/tap && brew install cf-cli
863 782
 ```
864 783
 
865
-Once you’re configured your phone, computer, and Apple ID to work, you should be able to open the app and see all the screens you created. Below are the ones the ones I captured on my iPhone 6s Plus.
784
+Once you’re configured your phone, computer, and Apple ID to work, you should be able to open the app and see the beer list you created. Below is how it looks on my iPhone 6s Plus.
866 785
 
867
-<p align="center">
868
-<img src="./static/iphone-login.png" width="250">&nbsp;&nbsp;
869
-<img src="./static/iphone-register.png" width="250">&nbsp;&nbsp;
870
-<img src="./static/iphone-forgot-password.png" width="250">
871
-</p>
786
+![iPhone Beer List](static/iphone-beer-list.png)
872 787
 
873 788
 ### Android
874 789
 
@@ -903,11 +818,18 @@ Skin: Skin with dynamic hardware controls
903 818
 
904 819
 After performing these steps, you should be able to run `ionic emulate android` and see your app running in the AVD.
905 820
 
821
+![Android Beer List](static/android-beer-list.png)
822
+
906 823
 ## Learn More
907
-I hope you’ve enjoyed this tour of Ionic, Angular, and Stormpath. I like how Ionic takes your web development skills up a notch and allows you to create mobile applications that look and behave natively.
908 824
 
909
-To learn more about Ionic, Angular, or Stormpath, please see the following resources:
825
+I hope you’ve enjoyed this tour of Ionic and Angular. I like how Ionic takes your web development skills up a notch and allows you to create mobile applications that look and behave natively.
826
+
827
+You can find a completed version of the application created in this blog post [on GitHub](https://github.com/oktadeveloper/spring-boot-ionic-example).
828
+
829
+If you encountered issues, please [create an issue in GitHub](TODO) or hit me up on Twitter [@mraible](https://twitter.com/mraible).
830
+
831
+To learn more about Ionic or Angular, please see the following resources:
910 832
 
911 833
 * [Get started with Ionic Framework](http://ionicframework.com/getting-started/)
834
+* [Angular Authentication with OpenID Connect and Okta in 20 Minutes](http://developer.okta.com/blog/2017/04/17/angular-authentication-with-oidc)
912 835
 * [Getting Started with Angular](https://www.youtube.com/watch?v=Jq3szz2KOOs) A YouTube webinar by yours truly. ;)
913
-* [Stormpath Client API Guide](https://docs.stormpath.com/client-api/product-guide/latest/)

+ 0
- 40
client/config.xml 查看文件

@@ -1,40 +0,0 @@
1
-<?xml version='1.0' encoding='utf-8'?>
2
-<widget id="com.ionicframework.ionicauth613285" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
3
-    <name>ionic-beer</name>
4
-    <description>An awesome Ionic/Cordova app.</description>
5
-    <author email="matt.raible@stormpath.com" href="https://stormpath.com/">Matt Raible</author>
6
-    <content src="index.html" />
7
-    <access origin="*" />
8
-    <allow-navigation href="http://ionic.local/*" />
9
-    <allow-intent href="http://*/*" />
10
-    <allow-intent href="https://*/*" />
11
-    <allow-intent href="tel:*" />
12
-    <allow-intent href="sms:*" />
13
-    <allow-intent href="mailto:*" />
14
-    <allow-intent href="geo:*" />
15
-    <platform name="android">
16
-        <allow-intent href="market:*" />
17
-    </platform>
18
-    <platform name="ios">
19
-        <allow-intent href="itms:*" />
20
-        <allow-intent href="itms-apps:*" />
21
-    </platform>
22
-    <preference name="webviewbounce" value="false" />
23
-    <preference name="UIWebViewBounce" value="false" />
24
-    <preference name="DisallowOverscroll" value="true" />
25
-    <preference name="android-minSdkVersion" value="16" />
26
-    <preference name="BackupWebStorage" value="none" />
27
-    <preference name="SplashMaintainAspectRatio" value="true" />
28
-    <preference name="FadeSplashScreenDuration" value="300" />
29
-    <preference name="SplashShowOnlyFirstTime" value="false" />
30
-    <preference name="KeyboardDisplayRequiresUserAction" value="false" />
31
-    <feature name="StatusBar">
32
-        <param name="ios-package" onload="true" value="CDVStatusBar" />
33
-    </feature>
34
-    <plugin name="ionic-plugin-keyboard" spec="~2.2.1" />
35
-    <plugin name="cordova-plugin-whitelist" spec="~1.3.1" />
36
-    <plugin name="cordova-plugin-console" spec="~1.0.5" />
37
-    <plugin name="cordova-plugin-statusbar" spec="~2.2.1" />
38
-    <plugin name="cordova-plugin-device" spec="~1.1.4" />
39
-    <plugin name="cordova-plugin-splashscreen" spec="~4.0.1" />
40
-</widget>

+ 0
- 29
client/src/app/app.component.ts 查看文件

@@ -1,29 +0,0 @@
1
-import { Component } from '@angular/core';
2
-import { Platform } from 'ionic-angular';
3
-import { StatusBar, Splashscreen } from 'ionic-native';
4
-import { TabsPage } from '../pages/tabs/tabs';
5
-import { Stormpath, LoginPage } from 'angular-stormpath';
6
-
7
-@Component({
8
-  templateUrl: 'app.html'
9
-})
10
-export class MyApp {
11
-  rootPage;
12
-
13
-  constructor(platform: Platform, private stormpath: Stormpath) {
14
-    stormpath.user$.subscribe(user => {
15
-      if (!user) {
16
-        this.rootPage = LoginPage;
17
-      } else {
18
-        this.rootPage = TabsPage;
19
-      }
20
-    });
21
-
22
-    platform.ready().then(() => {
23
-      // Okay, so the platform is ready and our plugins are available.
24
-      // Here you can do any higher level native things you might need.
25
-      StatusBar.styleDefault();
26
-      Splashscreen.hide();
27
-    });
28
-  }
29
-}

+ 0
- 56
client/src/app/app.module.ts 查看文件

@@ -1,56 +0,0 @@
1
-import { NgModule, ErrorHandler } from '@angular/core';
2
-import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
3
-import { MyApp } from './app.component';
4
-import { AboutPage } from '../pages/about/about';
5
-import { ContactPage } from '../pages/contact/contact';
6
-import { HomePage } from '../pages/home/home';
7
-import { TabsPage } from '../pages/tabs/tabs';
8
-import { StormpathConfiguration, StormpathModule } from 'angular-stormpath';
9
-import { StormpathIonicModule, LoginPage, RegisterPage, ForgotPasswordPage } from 'angular-stormpath-ionic';
10
-import { BeerPage } from '../pages/beer/beer';
11
-import { BeerService } from '../providers/beer-service';
12
-import { GiphyService } from '../providers/giphy-service';
13
-import { BeerModalPage } from '../pages/beer/beer-modal';
14
-
15
-export function stormpathConfig(): StormpathConfiguration {
16
-  let spConfig: StormpathConfiguration = new StormpathConfiguration();
17
-  spConfig.endpointPrefix = 'http://localhost:8080';
18
-  spConfig.autoAuthorizedUris.push(new RegExp(spConfig.endpointPrefix + '/*'));
19
-  return spConfig;
20
-}
21
-
22
-@NgModule({
23
-  declarations: [
24
-    MyApp,
25
-    AboutPage,
26
-    ContactPage,
27
-    HomePage,
28
-    TabsPage,
29
-    BeerPage,
30
-    BeerModalPage
31
-  ],
32
-  imports: [
33
-    IonicModule.forRoot(MyApp),
34
-    StormpathModule,
35
-    StormpathIonicModule
36
-  ],
37
-  bootstrap: [IonicApp],
38
-  entryComponents: [
39
-    MyApp,
40
-    AboutPage,
41
-    ContactPage,
42
-    HomePage,
43
-    TabsPage,
44
-    LoginPage,
45
-    ForgotPasswordPage,
46
-    RegisterPage,
47
-    BeerPage,
48
-    BeerModalPage
49
-  ],
50
-  providers: [
51
-    {provide: ErrorHandler, useClass: IonicErrorHandler},
52
-    {provide: StormpathConfiguration, useFactory: stormpathConfig},
53
-    BeerService, GiphyService
54
-  ]
55
-})
56
-export class AppModule {}

二进制
client/src/assets/imgs/logo.png 查看文件


二进制
client/src/assets/imgs/stormpath-sdks.jpg 查看文件


+ 0
- 18
client/src/pages/about/about.html 查看文件

@@ -1,18 +0,0 @@
1
-<ion-header>
2
-  <ion-navbar>
3
-    <ion-title>
4
-      About
5
-    </ion-title>
6
-  </ion-navbar>
7
-</ion-header>
8
-
9
-<ion-content padding>
10
-  <p><a href="https://stormpath.com">Stormpath</a> is an API service that allows developers to create, edit, and
11
-    securely store user accounts and user account data, and connect them with one or multiple applications. We make user
12
-    account management a lot easier, more secure, and infinitely scalable.</p>
13
-
14
-  <p>
15
-    Click the image below to see all the language and framework integrations we provide.
16
-    <a href="https://docs.stormpath.com"><img src="assets/imgs/stormpath-sdks.jpg" alt="Stormpath SDKs"></a>
17
-  </p>
18
-</ion-content>

+ 0
- 20
client/src/pages/home/home.ts 查看文件

@@ -1,20 +0,0 @@
1
-import { Component } from '@angular/core';
2
-
3
-import { Account, Stormpath } from 'angular-stormpath';
4
-import { Observable } from 'rxjs';
5
-
6
-@Component({
7
-  selector: 'page-home',
8
-  templateUrl: 'home.html'
9
-})
10
-export class HomePage {
11
-  user$: Observable<Account | boolean>;
12
-
13
-  constructor(private stormpath: Stormpath) {
14
-    this.user$ = this.stormpath.user$;
15
-  }
16
-
17
-  logout(): void {
18
-    this.stormpath.logout();
19
-  }
20
-}

+ 0
- 2971
client/yarn.lock
文件差异内容过多而无法显示
查看文件


+ 3
- 9
deploy.sh 查看文件

@@ -36,16 +36,10 @@ cf d -f ionic-server
36 36
 
37 37
 cf a
38 38
 
39
-# Stormpath
40
-stormpathApiKeyId=`cat ~/.stormpath/apiKey.properties | grep apiKey.id | cut -f3 -d\ `
41
-stormpathApiKeySecret=`cat ~/.stormpath/apiKey.properties | grep apiKey.secret | cut -f3 -d\ `
42
-
43 39
 # Deploy the server
44 40
 cd $r/server
45 41
 mvn clean package
46 42
 cf push -p target/*jar ionic-server --no-start  --random-route
47
-cf set-env ionic-server STORMPATH_API_KEY_ID $stormpathApiKeyId
48
-cf set-env ionic-server STORMPATH_API_KEY_SECRET $stormpathApiKeySecret
49 43
 cf set-env ionic-server FORCE_HTTPS true
50 44
 cf start ionic-server
51 45
 
@@ -53,7 +47,7 @@ cf start ionic-server
53 47
 serverUri=https://`app_domain ionic-server`
54 48
 
55 49
 # Deploy the client
56
-cd $r/client
50
+cd $r/ionic-beer
57 51
 npm run clean
58 52
 # replace the server URL in the client
59 53
 sed -i -e "s|http://localhost:8080|$serverUri|g" src/app/app.module.ts
@@ -63,5 +57,5 @@ npm install && ionic build ios
63 57
 ionic run ios
64 58
 
65 59
 # cleanup changed files
66
-git checkout $r/client
67
-rm $r/client/src/app/app.module.ts-e
60
+git checkout $r/ionic-beer
61
+rm $r/ionic-beer/src/app/app.module.ts-e

client/.editorconfig → ionic-beer/.editorconfig 查看文件


client/.gitignore → ionic-beer/.gitignore 查看文件


+ 39
- 0
ionic-beer/config.xml 查看文件

@@ -0,0 +1,39 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+<widget id="com.ionicframework.ionicbeer926596" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
3
+  <name>ionic-beer</name>
4
+  <description>An awesome Ionic/Cordova app.</description>
5
+  <author email="hi@ionicframework" href="http://ionicframework.com/">Ionic Framework Team</author>
6
+  <content src="index.html"/>
7
+  <access origin="*"/>
8
+  <allow-navigation href="http://ionic.local/*"/>
9
+  <allow-intent href="http://*/*"/>
10
+  <allow-intent href="https://*/*"/>
11
+  <allow-intent href="tel:*"/>
12
+  <allow-intent href="sms:*"/>
13
+  <allow-intent href="mailto:*"/>
14
+  <allow-intent href="geo:*"/>
15
+  <platform name="android">
16
+    <allow-intent href="market:*"/>
17
+  </platform>
18
+  <platform name="ios">
19
+    <allow-intent href="itms:*"/>
20
+    <allow-intent href="itms-apps:*"/>
21
+  </platform>
22
+  <preference name="webviewbounce" value="false"/>
23
+  <preference name="UIWebViewBounce" value="false"/>
24
+  <preference name="DisallowOverscroll" value="true"/>
25
+  <preference name="android-minSdkVersion" value="16"/>
26
+  <preference name="BackupWebStorage" value="none"/>
27
+  <preference name="SplashMaintainAspectRatio" value="true"/>
28
+  <preference name="FadeSplashScreenDuration" value="300"/>
29
+  <preference name="SplashShowOnlyFirstTime" value="false"/>
30
+  <feature name="StatusBar">
31
+    <param name="ios-package" onload="true" value="CDVStatusBar"/>
32
+  </feature>
33
+  <plugin name="ionic-plugin-keyboard" spec="~2.2.1"/>
34
+  <plugin name="cordova-plugin-whitelist" spec="1.3.1"/>
35
+  <plugin name="cordova-plugin-console" spec="1.0.5"/>
36
+  <plugin name="cordova-plugin-statusbar" spec="2.2.1"/>
37
+  <plugin name="cordova-plugin-device" spec="1.1.4"/>
38
+  <plugin name="cordova-plugin-splashscreen" spec="~4.0.1"/>
39
+</widget>

client/ionic.config.json → ionic-beer/ionic.config.json 查看文件


client/package.json → ionic-beer/package.json 查看文件

@@ -10,32 +10,32 @@
10 10
     "ionic:serve": "ionic-app-scripts serve"
11 11
   },
12 12
   "dependencies": {
13
-    "@angular/common": "2.3.1",
14
-    "@angular/compiler": "2.3.1",
15
-    "@angular/compiler-cli": "2.3.1",
16
-    "@angular/core": "2.3.1",
17
-    "@angular/forms": "2.3.1",
18
-    "@angular/http": "2.3.1",
19
-    "@angular/platform-browser": "2.3.1",
20
-    "@angular/platform-browser-dynamic": "2.3.1",
21
-    "@angular/platform-server": "2.3.1",
22
-    "@ionic/storage": "1.1.7",
23
-    "angular-stormpath-ionic": "^0.0.3",
24
-    "ionic-angular": "2.0.0",
25
-    "ionic-native": "2.4.1",
13
+    "@angular/common": "4.0.0",
14
+    "@angular/compiler": "4.0.0",
15
+    "@angular/compiler-cli": "4.0.0",
16
+    "@angular/core": "4.0.0",
17
+    "@angular/forms": "4.0.0",
18
+    "@angular/http": "4.0.0",
19
+    "@angular/platform-browser": "4.0.0",
20
+    "@angular/platform-browser-dynamic": "4.0.0",
21
+    "@ionic-native/core": "3.4.2",
22
+    "@ionic-native/splash-screen": "3.4.2",
23
+    "@ionic-native/status-bar": "3.4.2",
24
+    "@ionic/storage": "2.0.1",
25
+    "ionic-angular": "3.0.1",
26 26
     "ionicons": "3.0.0",
27
-    "rxjs": "5.0.0-beta.12",
27
+    "rxjs": "5.1.1",
28 28
     "sw-toolbox": "3.4.0",
29
-    "zone.js": "0.6.26"
29
+    "zone.js": "^0.8.4"
30 30
   },
31 31
   "devDependencies": {
32
-    "@ionic/app-scripts": "1.0.0",
33
-    "typescript": "2.0.9"
32
+    "@ionic/app-scripts": "1.3.0",
33
+    "typescript": "~2.2.1"
34 34
   },
35 35
   "cordovaPlugins": [
36
+    "cordova-plugin-statusbar",
36 37
     "cordova-plugin-whitelist",
37 38
     "cordova-plugin-console",
38
-    "cordova-plugin-statusbar",
39 39
     "cordova-plugin-device",
40 40
     "cordova-plugin-splashscreen",
41 41
     "ionic-plugin-keyboard"

二进制
ionic-beer/resources/android/icon/drawable-hdpi-icon.png 查看文件


二进制
ionic-beer/resources/android/icon/drawable-ldpi-icon.png 查看文件


二进制
ionic-beer/resources/android/icon/drawable-mdpi-icon.png 查看文件


二进制
ionic-beer/resources/android/icon/drawable-xhdpi-icon.png 查看文件


二进制
ionic-beer/resources/android/icon/drawable-xxhdpi-icon.png 查看文件


二进制
ionic-beer/resources/android/icon/drawable-xxxhdpi-icon.png 查看文件


client/resources/android/splash/drawable-land-hdpi-screen.png → ionic-beer/resources/android/splash/drawable-land-hdpi-screen.png 查看文件


client/resources/android/splash/drawable-land-ldpi-screen.png → ionic-beer/resources/android/splash/drawable-land-ldpi-screen.png 查看文件


client/resources/android/splash/drawable-land-mdpi-screen.png → ionic-beer/resources/android/splash/drawable-land-mdpi-screen.png 查看文件


client/resources/android/splash/drawable-land-xhdpi-screen.png → ionic-beer/resources/android/splash/drawable-land-xhdpi-screen.png 查看文件


client/resources/android/splash/drawable-land-xxhdpi-screen.png → ionic-beer/resources/android/splash/drawable-land-xxhdpi-screen.png 查看文件


client/resources/android/splash/drawable-land-xxxhdpi-screen.png → ionic-beer/resources/android/splash/drawable-land-xxxhdpi-screen.png 查看文件


client/resources/android/splash/drawable-port-hdpi-screen.png → ionic-beer/resources/android/splash/drawable-port-hdpi-screen.png 查看文件


client/resources/android/splash/drawable-port-ldpi-screen.png → ionic-beer/resources/android/splash/drawable-port-ldpi-screen.png 查看文件


client/resources/android/splash/drawable-port-mdpi-screen.png → ionic-beer/resources/android/splash/drawable-port-mdpi-screen.png 查看文件


client/resources/android/splash/drawable-port-xhdpi-screen.png → ionic-beer/resources/android/splash/drawable-port-xhdpi-screen.png 查看文件


client/resources/android/splash/drawable-port-xxhdpi-screen.png → ionic-beer/resources/android/splash/drawable-port-xxhdpi-screen.png 查看文件


client/resources/android/splash/drawable-port-xxxhdpi-screen.png → ionic-beer/resources/android/splash/drawable-port-xxxhdpi-screen.png 查看文件


client/resources/icon.png → ionic-beer/resources/icon.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-40.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-40@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-40@3x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-50.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-50@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-60.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-60@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-60@3x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-72.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-72@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-76.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-76@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-83.5@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-small.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-small@2x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon-small@3x.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon.png 查看文件


二进制
ionic-beer/resources/ios/icon/icon@2x.png 查看文件


client/resources/ios/splash/Default-568h@2x~iphone.png → ionic-beer/resources/ios/splash/Default-568h@2x~iphone.png 查看文件


client/resources/ios/splash/Default-667h.png → ionic-beer/resources/ios/splash/Default-667h.png 查看文件


client/resources/ios/splash/Default-736h.png → ionic-beer/resources/ios/splash/Default-736h.png 查看文件


client/resources/ios/splash/Default-Landscape-736h.png → ionic-beer/resources/ios/splash/Default-Landscape-736h.png 查看文件


client/resources/ios/splash/Default-Landscape@2x~ipad.png → ionic-beer/resources/ios/splash/Default-Landscape@2x~ipad.png 查看文件


client/resources/ios/splash/Default-Landscape~ipad.png → ionic-beer/resources/ios/splash/Default-Landscape~ipad.png 查看文件


client/resources/ios/splash/Default-Portrait@2x~ipad.png → ionic-beer/resources/ios/splash/Default-Portrait@2x~ipad.png 查看文件


client/resources/ios/splash/Default-Portrait~ipad.png → ionic-beer/resources/ios/splash/Default-Portrait~ipad.png 查看文件


client/resources/ios/splash/Default@2x~iphone.png → ionic-beer/resources/ios/splash/Default@2x~iphone.png 查看文件


client/resources/ios/splash/Default~iphone.png → ionic-beer/resources/ios/splash/Default~iphone.png 查看文件


client/resources/splash.png → ionic-beer/resources/splash.png 查看文件


+ 22
- 0
ionic-beer/src/app/app.component.ts 查看文件

@@ -0,0 +1,22 @@
1
+import { Component } from '@angular/core';
2
+import { Platform } from 'ionic-angular';
3
+import { StatusBar } from '@ionic-native/status-bar';
4
+import { SplashScreen } from '@ionic-native/splash-screen';
5
+
6
+import { TabsPage } from '../pages/tabs/tabs';
7
+
8
+@Component({
9
+  templateUrl: 'app.html'
10
+})
11
+export class MyApp {
12
+  rootPage:any = TabsPage;
13
+
14
+  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
15
+    platform.ready().then(() => {
16
+      // Okay, so the platform is ready and our plugins are available.
17
+      // Here you can do any higher level native things you might need.
18
+      statusBar.styleDefault();
19
+      splashScreen.hide();
20
+    });
21
+  }
22
+}

client/src/app/app.html → ionic-beer/src/app/app.html 查看文件


+ 46
- 0
ionic-beer/src/app/app.module.ts 查看文件

@@ -0,0 +1,46 @@
1
+import { NgModule, ErrorHandler } from '@angular/core';
2
+import { BrowserModule } from '@angular/platform-browser';
3
+import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
4
+import { MyApp } from './app.component';
5
+
6
+import { AboutPage } from '../pages/about/about';
7
+import { ContactPage } from '../pages/contact/contact';
8
+import { HomePage } from '../pages/home/home';
9
+import { TabsPage } from '../pages/tabs/tabs';
10
+
11
+import { StatusBar } from '@ionic-native/status-bar';
12
+import { SplashScreen } from '@ionic-native/splash-screen';
13
+import { BeerModule } from '../pages/beer/beer.module';
14
+import { HttpModule } from '@angular/http';
15
+import { BeerModalPage } from '../pages/beer/beer-modal';
16
+
17
+@NgModule({
18
+  declarations: [
19
+    MyApp,
20
+    AboutPage,
21
+    ContactPage,
22
+    HomePage,
23
+    TabsPage
24
+  ],
25
+  imports: [
26
+    BrowserModule,
27
+    HttpModule,
28
+    IonicModule.forRoot(MyApp),
29
+    BeerModule
30
+  ],
31
+  bootstrap: [IonicApp],
32
+  entryComponents: [
33
+    MyApp,
34
+    AboutPage,
35
+    ContactPage,
36
+    HomePage,
37
+    TabsPage,
38
+    BeerModalPage
39
+  ],
40
+  providers: [
41
+    StatusBar,
42
+    SplashScreen,
43
+    {provide: ErrorHandler, useClass: IonicErrorHandler}
44
+  ]
45
+})
46
+export class AppModule {}

client/src/app/app.scss → ionic-beer/src/app/app.scss 查看文件

@@ -14,21 +14,3 @@
14 14
 // To declare rules for a specific mode, create a child rule
15 15
 // for the .md, .ios, or .wp mode classes. The mode class is
16 16
 // automatically applied to the <body> element in the app.
17
-
18
-.alert {
19
-  padding: 15px;
20
-  margin-bottom: 20px;
21
-  border: 1px solid transparent;
22
-}
23
-
24
-.alert-danger {
25
-  color: #a94442;
26
-  background-color: #f2dede;
27
-  border-color: #ebccd1;
28
-}
29
-
30
-.alert-success {
31
-  color: #3c763d;
32
-  background-color: #dff0d8;
33
-  border-color: #d6e9c6;
34
-}

client/src/app/main.ts → ionic-beer/src/app/main.ts 查看文件


二进制
ionic-beer/src/assets/icon/favicon.ico 查看文件


二进制
ionic-beer/src/assets/imgs/logo.png 查看文件


client/src/declarations.d.ts → ionic-beer/src/declarations.d.ts 查看文件


client/src/index.html → ionic-beer/src/index.html 查看文件

@@ -2,7 +2,7 @@
2 2
 <html lang="en" dir="ltr">
3 3
 <head>
4 4
   <meta charset="UTF-8">
5
-  <title>Ionic Beer</title>
5
+  <title>Ionic App</title>
6 6
   <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
7 7
   <meta name="format-detection" content="telephone=no">
8 8
   <meta name="msapplication-tap-highlight" content="no">
@@ -14,13 +14,13 @@
14 14
   <!-- cordova.js required for cordova apps -->
15 15
   <script src="cordova.js"></script>
16 16
 
17
-  <!--<script>
17
+  <script>
18 18
     if ('serviceWorker' in navigator) {
19 19
       navigator.serviceWorker.register('service-worker.js')
20 20
         .then(() => console.log('service worker installed'))
21 21
         .catch(err => console.log('Error', err));
22 22
     }
23
-  </script>-->
23
+  </script>
24 24
 
25 25
   <link href="build/main.css" rel="stylesheet">
26 26
 

client/src/manifest.json → ionic-beer/src/manifest.json 查看文件

@@ -1,6 +1,6 @@
1 1
 {
2
-  "name": "Ionic Beer",
3
-  "short_name": "Ionic Beer",
2
+  "name": "Ionic Beers",
3
+  "short_name": "Ionic Beers",
4 4
   "start_url": "index.html",
5 5
   "display": "standalone",
6 6
   "icons": [{

+ 11
- 0
ionic-beer/src/pages/about/about.html 查看文件

@@ -0,0 +1,11 @@
1
+<ion-header>
2
+  <ion-navbar>
3
+    <ion-title>
4
+      About
5
+    </ion-title>
6
+  </ion-navbar>
7
+</ion-header>
8
+
9
+<ion-content padding>
10
+
11
+</ion-content>

client/src/pages/about/about.scss → ionic-beer/src/pages/about/about.scss 查看文件


client/src/pages/about/about.ts → ionic-beer/src/pages/about/about.ts 查看文件

@@ -1,5 +1,4 @@
1 1
 import { Component } from '@angular/core';
2
-
3 2
 import { NavController } from 'ionic-angular';
4 3
 
5 4
 @Component({

client/src/pages/beer/beer-modal.html → ionic-beer/src/pages/beer/beer-modal.html 查看文件


client/src/pages/beer/beer-modal.ts → ionic-beer/src/pages/beer/beer-modal.ts 查看文件


client/src/pages/beer/beer.html → ionic-beer/src/pages/beer/beer.html 查看文件

@@ -13,7 +13,7 @@
13 13
 
14 14
 <ion-content padding>
15 15
   <ion-list>
16
-    <ion-item-sliding *ngFor="let beer of beers" >
16
+    <ion-item-sliding *ngFor="let beer of beers">
17 17
       <ion-item (click)="openModal({id: beer.id})">
18 18
         <ion-avatar item-left>
19 19
           <img src="{{beer.giphyUrl}}">

+ 25
- 0
ionic-beer/src/pages/beer/beer.module.ts 查看文件

@@ -0,0 +1,25 @@
1
+import { NgModule } from '@angular/core';
2
+import { IonicModule } from 'ionic-angular';
3
+import { BeerPage } from './beer';
4
+import { BeerModalPage } from './beer-modal';
5
+import { BeerService } from '../../providers/beer-service';
6
+import { GiphyService } from '../../providers/giphy-service';
7
+
8
+@NgModule({
9
+  declarations: [
10
+    BeerPage,
11
+    BeerModalPage
12
+  ],
13
+  imports: [
14
+    IonicModule.forRoot(BeerPage)
15
+  ],
16
+  exports: [
17
+    BeerPage,
18
+    BeerModalPage
19
+  ],
20
+  providers: [
21
+    BeerService,
22
+    GiphyService
23
+  ]
24
+})
25
+export class BeerModule {}

client/src/pages/beer/beer.scss → ionic-beer/src/pages/beer/beer.scss 查看文件


client/src/pages/beer/beer.ts → ionic-beer/src/pages/beer/beer.ts 查看文件

@@ -1,20 +1,21 @@
1 1
 import { Component } from '@angular/core';
2
-import { ModalController, ToastController } from 'ionic-angular';
2
+import { IonicPage, ModalController, NavController, NavParams, ToastController } from 'ionic-angular';
3 3
 import { BeerService } from '../../providers/beer-service';
4 4
 import { GiphyService } from '../../providers/giphy-service';
5 5
 import { BeerModalPage } from './beer-modal';
6 6
 
7
+@IonicPage()
7 8
 @Component({
8 9
   selector: 'page-beer',
9
-  templateUrl: 'beer.html',
10
-  providers: [BeerService, GiphyService]
10
+  templateUrl: 'beer.html'
11 11
 })
12 12
 export class BeerPage {
13 13
   private beers: Array<any>;
14 14
 
15
-  constructor(public beerService: BeerService, public giphyService: GiphyService,
16
-              public modalCtrl: ModalController, public toastCtrl: ToastController) {
17
-  }
15
+constructor(public navCtrl: NavController, public navParams: NavParams,
16
+          public beerService: BeerService, public giphyService: GiphyService,
17
+          public modalCtrl: ModalController, public toastCtrl: ToastController) {
18
+}
18 19
 
19 20
   ionViewDidLoad() {
20 21
     this.beerService.getGoodBeers().subscribe(beers => {

client/src/pages/contact/contact.html → ionic-beer/src/pages/contact/contact.html 查看文件

@@ -11,11 +11,7 @@
11 11
     <ion-list-header>Follow us on Twitter</ion-list-header>
12 12
     <ion-item>
13 13
       <ion-icon name="ionic" item-left></ion-icon>
14
-      <a href="https://twitter.com/ionicframework">@ionicframework</a>
15
-    </ion-item>
16
-    <ion-item>
17
-      <ion-icon item-left><img src="assets/imgs/logo.png" width="24"></ion-icon>
18
-      <a href="https://twitter.com/gostormpath">@goStormpath</a>
14
+      @ionicframework
19 15
     </ion-item>
20 16
   </ion-list>
21 17
 </ion-content>

client/src/pages/contact/contact.scss → ionic-beer/src/pages/contact/contact.scss 查看文件


client/src/pages/contact/contact.ts → ionic-beer/src/pages/contact/contact.ts 查看文件

@@ -1,5 +1,4 @@
1 1
 import { Component } from '@angular/core';
2
-
3 2
 import { NavController } from 'ionic-angular';
4 3
 
5 4
 @Component({

client/src/pages/home/home.html → ionic-beer/src/pages/home/home.html 查看文件

@@ -1,11 +1,6 @@
1 1
 <ion-header>
2 2
   <ion-navbar>
3 3
     <ion-title>Home</ion-title>
4
-    <ion-buttons end>
5
-      <button ion-button icon-only (click)="logout()">
6
-        Logout
7
-      </button>
8
-    </ion-buttons>
9 4
   </ion-navbar>
10 5
 </ion-header>
11 6
 
@@ -19,7 +14,4 @@
19 14
     Take a look at the <code>src/pages/</code> directory to add or change tabs,
20 15
     update any existing page or create new pages.
21 16
   </p>
22
-  <p *ngIf="(user$ | async)">
23
-    You are logged in as: <b>{{ ( user$ | async ).fullName }}</b>
24
-  </p>
25 17
 </ion-content>

client/src/pages/home/home.scss → ionic-beer/src/pages/home/home.scss 查看文件


+ 14
- 0
ionic-beer/src/pages/home/home.ts 查看文件

@@ -0,0 +1,14 @@
1
+import { Component } from '@angular/core';
2
+import { NavController } from 'ionic-angular';
3
+
4
+@Component({
5
+  selector: 'page-home',
6
+  templateUrl: 'home.html'
7
+})
8
+export class HomePage {
9
+
10
+  constructor(public navCtrl: NavController) {
11
+
12
+  }
13
+
14
+}

client/src/pages/tabs/tabs.html → ionic-beer/src/pages/tabs/tabs.html 查看文件


client/src/pages/tabs/tabs.ts → ionic-beer/src/pages/tabs/tabs.ts 查看文件

@@ -1,22 +1,18 @@
1 1
 import { Component } from '@angular/core';
2 2
 
3
-import { HomePage } from '../home/home';
4 3
 import { AboutPage } from '../about/about';
5 4
 import { ContactPage } from '../contact/contact';
5
+import { HomePage } from '../home/home';
6 6
 import { BeerPage } from '../beer/beer';
7 7
 
8 8
 @Component({
9 9
   templateUrl: 'tabs.html'
10 10
 })
11 11
 export class TabsPage {
12
-  // this tells the tabs component which Pages
13
-  // should be each tab's root Page
14 12
   tab1Root: any = HomePage;
15 13
   tab2Root: any = BeerPage;
16 14
   tab3Root: any = ContactPage;
17 15
   tab4Root: any = AboutPage;
18 16
 
19
-  constructor() {
20
-
21
-  }
17
+  constructor() {}
22 18
 }

client/src/providers/beer-service.ts → ionic-beer/src/providers/beer-service.ts 查看文件

@@ -2,17 +2,13 @@ import { Injectable } from '@angular/core';
2 2
 import { Http, Response } from '@angular/http';
3 3
 import 'rxjs/add/operator/map';
4 4
 import { Observable } from 'rxjs';
5
-import { StormpathConfiguration } from 'angular-stormpath';
6 5
 
7 6
 @Injectable()
8 7
 export class BeerService {
9
-  public API;
10
-  public BEER_API;
8
+  public API = 'http://localhost:8080';
9
+  public BEER_API = this.API + '/beers';
11 10
 
12
-  constructor(public http: Http, public config: StormpathConfiguration) {
13
-    this.API = config.endpointPrefix;
14
-    this.BEER_API = this.API + '/beers';
15
-  }
11
+  constructor(private http: Http) {}
16 12
 
17 13
   getGoodBeers(): Observable<any> {
18 14
     return this.http.get(this.API + '/good-beers')
@@ -24,11 +20,6 @@ export class BeerService {
24 20
       .map((response: Response) => response.json());
25 21
   }
26 22
 
27
-  remove(id: string) {
28
-    return this.http.delete(this.BEER_API + '/' + id)
29
-      .map((response: Response) => response.json());
30
-  }
31
-
32 23
   save(beer: any): Observable<any> {
33 24
     let result: Observable<Response>;
34 25
     if (beer['href']) {
@@ -39,4 +30,9 @@ export class BeerService {
39 30
     return result.map((response: Response) => response.json())
40 31
       .catch(error => Observable.throw(error));
41 32
   }
33
+
34
+  remove(id: string) {
35
+    return this.http.delete(this.BEER_API + '/' + id)
36
+      .map((response: Response) => response.json());
37
+  }
42 38
 }

client/src/providers/giphy-service.ts → ionic-beer/src/providers/giphy-service.ts 查看文件

@@ -6,6 +6,7 @@ import { Observable } from 'rxjs';
6 6
 // http://tutorials.pluralsight.com/front-end-javascript/getting-started-with-angular-2-by-building-a-giphy-search-application
7 7
 export class GiphyService {
8 8
 
9
+  // Public beta key: https://github.com/Giphy/GiphyAPI#public-beta-key
9 10
   giphyApi = 'https://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';
10 11
 
11 12
   constructor(public http: Http) {

client/src/service-worker.js → ionic-beer/src/service-worker.js 查看文件


client/src/theme/variables.scss → ionic-beer/src/theme/variables.scss 查看文件

@@ -24,7 +24,7 @@ $font-path: "../assets/fonts";
24 24
 // The "primary" color is the only required color in the map.
25 25
 
26 26
 $colors: (
27
-  primary:    #387ef5,
27
+  primary:    #488aff,
28 28
   secondary:  #32db64,
29 29
   danger:     #f53d3d,
30 30
   light:      #f4f4f4,

client/tsconfig.json → ionic-beer/tsconfig.json 查看文件


client/tslint.json → ionic-beer/tslint.json 查看文件


+ 1
- 1
server/.mvn/wrapper/maven-wrapper.properties 查看文件

@@ -1 +1 @@
1
-distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
1
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip

+ 11
- 14
server/mvnw 查看文件

@@ -184,6 +184,16 @@ fi
184 184
 
185 185
 CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
186 186
 
187
+# For Cygwin, switch paths to Windows format before running java
188
+if $cygwin; then
189
+  [ -n "$M2_HOME" ] &&
190
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
191
+  [ -n "$JAVA_HOME" ] &&
192
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
193
+  [ -n "$CLASSPATH" ] &&
194
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
195
+fi
196
+
187 197
 # traverses directory structure from process work directory to filesystem root
188 198
 # first directory with .mvn subdirectory is considered project base directory
189 199
 find_maven_basedir() {
@@ -209,18 +219,6 @@ concat_lines() {
209 219
 export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
210 220
 MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
211 221
 
212
-# For Cygwin, switch paths to Windows format before running java
213
-if $cygwin; then
214
-  [ -n "$M2_HOME" ] &&
215
-    M2_HOME=`cygpath --path --windows "$M2_HOME"`
216
-  [ -n "$JAVA_HOME" ] &&
217
-    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
218
-  [ -n "$CLASSPATH" ] &&
219
-    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
220
-  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
221
-    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
222
-fi
223
-
224 222
 # Provide a "standardized" way to retrieve the CLI args that will
225 223
 # work with both Windows and non-Windows executions.
226 224
 MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
@@ -228,9 +226,8 @@ export MAVEN_CMD_LINE_ARGS
228 226
 
229 227
 WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
230 228
 
231
-# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@
232 229
 exec "$JAVACMD" \
233 230
   $MAVEN_OPTS \
234 231
   -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
235 232
   "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
236
-  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
233
+  ${WRAPPER_LAUNCHER} "$@"

+ 0
- 0
server/mvnw.cmd 查看文件


部分文件因为文件数量过多而无法显示