18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/theme/global.scss:
--------------------------------------------------------------------------------
1 | // http://ionicframework.com/docs/v2/theming/
2 |
3 |
4 | // Global CSS
5 | // --------------------------------------------------
6 | // Put CSS rules here that you want to apply globally.
7 | //
8 | // To declare rules for a specific mode, create a child rule
9 | // for the .md, .ios, or .wp mode classes. The mode class is
10 | // automatically applied to the
element in the app.
11 | //
12 | // App Shared Sass variables belong in app.variables.scss.
13 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "declaration": true,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": [
8 | "dom",
9 | "es2015"
10 | ],
11 | "module": "es2015",
12 | "moduleResolution": "node",
13 | "target": "es5"
14 | },
15 | "exclude": [
16 | "node_modules"
17 | ],
18 | "compileOnSave": false,
19 | "atom": {
20 | "rewriteTsconfig": false
21 | }
22 | }
--------------------------------------------------------------------------------
/src/pages/tabs/tabs.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | import { HomePage } from '../home/home';
4 | import { AboutPage } from '../about/about';
5 | import { ContactPage } from '../contact/contact';
6 |
7 | @Component({
8 | templateUrl: 'tabs.html'
9 | })
10 | export class TabsPage {
11 | // this tells the tabs component which Pages
12 | // should be each tab's root Page
13 | tab1Root: any = HomePage;
14 | tab2Root: any = AboutPage;
15 | tab3Root: any = ContactPage;
16 |
17 | constructor() {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | *~
5 | *.sw[mnpcod]
6 | *.log
7 | *.tmp
8 | *.tmp.*
9 | log.txt
10 | *.sublime-project
11 | *.sublime-workspace
12 | .vscode/
13 | npm-debug.log*
14 |
15 | .idea/
16 | .sass-cache/
17 | .tmp/
18 | .versions/
19 | coverage/
20 | dist/
21 | node_modules/
22 | tmp/
23 | temp/
24 | hooks/
25 | platforms/
26 | plugins/
27 | plugins/android.json
28 | plugins/ios.json
29 | www/
30 | $RECYCLE.BIN/
31 |
32 | .DS_Store
33 | Thumbs.db
34 | UserInterfaceState.xcuserstate
35 |
--------------------------------------------------------------------------------
/src/global/components/lazy-img/lazy-img.component.scss:
--------------------------------------------------------------------------------
1 | lazy-img {
2 | div {
3 | align-items: center;
4 | display: flex;
5 | justify-content: center;
6 | height: inherit;
7 | min-width: inherit;
8 | min-height: inherit;
9 | width: 100%;
10 |
11 | &.placeholder {
12 | background-color: grey;
13 | color: $color-grey;
14 | font-family: $font-icons;
15 | font-size: inherit;
16 | &:before {
17 | content: "\f30e";
18 | position: absolute;
19 | }
20 | }
21 |
22 | }
23 |
24 | img {
25 | display: block;
26 | height: inherit;
27 | opacity: 0;
28 | transition: opacity 2s;
29 | width: 100%;
30 | &.active {
31 | opacity: 1;
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { IonicApp, IonicModule } from 'ionic-angular';
3 |
4 | import { OfflineApp } from './app.component';
5 |
6 | import { LazyImgComponent } from '../global/components/';
7 |
8 | import { AboutPage,
9 | ContactPage,
10 | HomePage,
11 | TabsPage } from '../pages/';
12 |
13 | const pages = [ AboutPage,
14 | ContactPage,
15 | HomePage,
16 | TabsPage ];
17 |
18 | const components = [ LazyImgComponent ];
19 |
20 | @NgModule({
21 | declarations: [
22 | OfflineApp,
23 | pages,
24 | components
25 | ],
26 | imports: [
27 | IonicModule.forRoot(OfflineApp)
28 | ],
29 | bootstrap: [IonicApp],
30 | entryComponents: [
31 | OfflineApp,
32 | pages,
33 | components
34 | ],
35 | providers: []
36 | })
37 | export class AppModule { }
38 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild } from '@angular/core';
2 | import { Platform, Nav } from 'ionic-angular';
3 | import { StatusBar } from 'ionic-native';
4 |
5 | import { TabsPage } from '../pages/';
6 |
7 | import ImgCache from 'imgcache.js';
8 |
9 | @Component({
10 | template: ``
11 | })
12 | export class OfflineApp {
13 |
14 | @ViewChild('nav') nav: Nav;
15 |
16 | constructor(platform: Platform) {
17 | platform.ready().then(() => {
18 | // Okay, so the platform is ready and our plugins are available.
19 | // Here you can do any higher level native things you might need.
20 | StatusBar.styleDefault();
21 |
22 | // activated debug mode
23 | ImgCache.options.debug = true;
24 | // page is set until img cache has started
25 | ImgCache.init(()=>{ this.nav.setRoot(TabsPage); },
26 | ()=>{ console.error('ImgCache init: error! Check the log for errors');});
27 |
28 | });
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-hello-world",
3 | "author": "Ionic Framework",
4 | "homepage": "http://ionicframework.com/",
5 | "private": true,
6 | "scripts": {
7 | "build": "ionic-app-scripts build",
8 | "watch": "ionic-app-scripts watch",
9 | "serve:before": "watch",
10 | "emulate:before": "build",
11 | "deploy:before": "build",
12 | "build:before": "build",
13 | "run:before": "build"
14 | },
15 | "dependencies": {
16 | "@ionic/storage": "^1.0.3",
17 | "imgcache.js": "^1.0.0",
18 | "ionic-angular": "^2.0.0-rc.0",
19 | "ionic-native": "^2.0.3",
20 | "ionicons": "^3.0.0"
21 | },
22 | "devDependencies": {
23 | "@ionic/app-scripts": "^0.0.23",
24 | "typescript": "^2.0.3"
25 | },
26 | "cordovaPlugins": [
27 | "cordova-plugin-whitelist",
28 | "cordova-plugin-statusbar",
29 | "cordova-plugin-console",
30 | "cordova-plugin-device",
31 | "cordova-plugin-splashscreen",
32 | "ionic-plugin-keyboard"
33 | ],
34 | "cordovaPlatforms": [
35 | "ios",
36 | {
37 | "platform": "ios",
38 | "version": "",
39 | "locator": "ios"
40 | }
41 | ],
42 | "description": "offline: An Ionic project"
43 | }
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Offline App
2 | [](http://ninjadevs.io/)
3 |
4 | This is an example of how to cache image in Ionic 2.RC0 using ImgCache.js
5 |
6 | ## Getting Started
7 | * Install Ionic CLI `npm install ionic -g --save`
8 | * Install Cordova `npm install -g cordova`
9 |
10 | ## Run it on the browser
11 | * Run `ionic serve` in a terminal from the project root.
12 |
13 | ## Before run it on devices
14 | * Install iOS Sim (npm install -g ios-sim)
15 | * Install iOS Deploy (npm install -g ios-deploy)
16 | * Add Android platform `ionic platform add android`
17 | * Add iOS platform after `ionic platform add ios`
18 |
19 | ## Before run it on android
20 | * Install [Android Studio](http://developer.android.com/intl/es/sdk/index.html)
21 | * Open Android SDK Manager and install:
22 | * Android SDK Tools
23 | * Android SDK Platform-tools
24 | * Android SDK Build-tools
25 | * System images (in case you need to use Android Emulator)
26 | * Android Support Repository
27 | * Android Support Library
28 | * Google Play services
29 | * Google Repository
30 | * Intel x86 Emulator Accelerator (in case you need to use Android Emulator)
31 |
32 | ## Build and Run
33 | * ionic build ios/android
34 | * ionic run ios/android --emulator --devices
35 |
--------------------------------------------------------------------------------
/src/pages/contact/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Contact
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Find us
13 |
14 |
15 | Website
16 |
17 |
18 |
19 | Facebook Page
20 |
21 |
22 |
23 | Facebook Group
24 |
25 |
26 |
27 | Twitter
28 |
29 |
30 |
31 | Instagram
32 |
33 |
34 |
35 | GitHub
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Offline App
4 | This is an ionic 2 project with offline support
5 | Mariano Alvarez
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/global/components/lazy-img/lazy-img.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ElementRef, Input, OnInit } from '@angular/core';
2 |
3 | import ImgCache from 'imgcache.js';
4 |
5 | /**
6 | * This component will be in charge of caching images and use them when the app is offline
7 | */
8 | @Component({
9 | selector: 'lazy-img',
10 | template: `
11 |
The image above has been cached. Try turning on the airplane mode and let Imgcache.js do the magic!
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/theme/variables.scss:
--------------------------------------------------------------------------------
1 | // Ionic Variables and Theming. For more info, please see:
2 | // http://ionicframework.com/docs/v2/theming/
3 | @import "ionic.globals";
4 |
5 |
6 |
7 | // Shared Variables
8 | // --------------------------------------------------
9 | // To customize the look and feel of this app, you can override
10 | // the Sass variables found in Ionic's source scss files.
11 | // To view all the possible Ionic variables, see:
12 | // http://ionicframework.com/docs/v2/theming/overriding-ionic-variables/
13 |
14 | $text-color: #000;
15 | $background-color: #fff;
16 |
17 |
18 | // Named Color Variables
19 | // --------------------------------------------------
20 | // Named colors makes it easy to reuse colors on various components.
21 | // It's highly recommended to change the default colors
22 | // to match your app's branding. Ionic uses a Sass map of
23 | // colors so you can add, rename and remove colors as needed.
24 | // The "primary" color is the only required color in the map.
25 |
26 | $colors: (
27 | primary: #387ef5,
28 | secondary: #32db64,
29 | danger: #f53d3d,
30 | light: #f4f4f4,
31 | dark: #222,
32 | favorite: #69BB7B
33 | );
34 |
35 |
36 | // App Theme
37 | // --------------------------------------------------
38 | // Ionic apps can have different themes applied, which can
39 | // then be future customized. This import comes last
40 | // so that the above variables are used and Ionic's
41 | // default are overridden.
42 |
43 | @import "ionic.theme.default";
44 |
45 |
46 | // Ionicons
47 | // --------------------------------------------------
48 | // The premium icon font for Ionic. For more info, please see:
49 | // http://ionicframework.com/docs/v2/ionicons/
50 |
51 | $ionicons-font-path: "../assets/fonts";
52 | @import "ionicons";
53 |
54 | // color palette
55 | $color-orange: #f1af67;
56 | $color-dark-orange: #e0831d;
57 | $color-white: #fff;
58 | $color-grey: #666;
59 | $color-ligth-grey: #fbf9f9;
60 |
61 | $font-icons: "Ionicons";
62 |
63 | // Ovewrite ionic variables
64 | $toolbar-background: #373a3c;
65 | $toolbar-active-color: $color-orange;
66 | $toolbar-inactive-color: $color-white;
67 | $toolbar-ios-title-text-color: $color-orange;
68 | $toolbar-md-title-text-color: $color-orange;
69 |
70 | $list-background-color: transparent;
71 |
72 | //general styles - global file not working
73 | ion-content {
74 | background-color: $color-ligth-grey !important;
75 |
76 | h2, a {
77 | color: $color-orange;
78 | }
79 |
80 | p {
81 | color: $color-grey;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | // tick this to make the cache invalidate and update
2 | const CACHE_VERSION = 1;
3 | const CURRENT_CACHES = {
4 | 'read-through': 'read-through-cache-v' + CACHE_VERSION
5 | };
6 |
7 | self.addEventListener('activate', (event) => {
8 | // Delete all caches that aren't named in CURRENT_CACHES.
9 | // While there is only one cache in this example, the same logic will handle the case where
10 | // there are multiple versioned caches.
11 | const expectedCacheNames = Object.keys(CURRENT_CACHES).map((key) => {
12 | return CURRENT_CACHES[key];
13 | });
14 |
15 | event.waitUntil(
16 | caches.keys().then((cacheNames) => {
17 | return Promise.all(
18 | cacheNames.map((cacheName) => {
19 | if (expectedCacheNames.indexOf(cacheName) === -1) {
20 | // If this cache name isn't present in the array of "expected" cache names, then delete it.
21 | console.log('Deleting out of date cache:', cacheName);
22 | return caches.delete(cacheName);
23 | }
24 | })
25 | );
26 | })
27 | );
28 | });
29 |
30 | // This sample illustrates an aggressive approach to caching, in which every valid response is
31 | // cached and every request is first checked against the cache.
32 | // This may not be an appropriate approach if your web application makes requests for
33 | // arbitrary URLs as part of its normal operation (e.g. a RSS client or a news aggregator),
34 | // as the cache could end up containing large responses that might not end up ever being accessed.
35 | // Other approaches, like selectively caching based on response headers or only caching
36 | // responses served from a specific domain, might be more appropriate for those use cases.
37 | self.addEventListener('fetch', (event) => {
38 |
39 | event.respondWith(
40 | caches.open(CURRENT_CACHES['read-through']).then((cache) => {
41 | return cache.match(event.request).then((response) => {
42 | if (response) {
43 | // If there is an entry in the cache for event.request, then response will be defined
44 | // and we can just return it.
45 |
46 | return response;
47 | }
48 |
49 | // Otherwise, if there is no entry in the cache for event.request, response will be
50 | // undefined, and we need to fetch() the resource.
51 | console.log(' No response for %s found in cache. ' +
52 | 'About to fetch from network...', event.request.url);
53 |
54 | // We call .clone() on the request since we might use it in the call to cache.put() later on.
55 | // Both fetch() and cache.put() "consume" the request, so we need to make a copy.
56 | // (see https://fetch.spec.whatwg.org/#dom-request-clone)
57 | return fetch(event.request.clone()).then((response) => {
58 |
59 | // Optional: add in extra conditions here, e.g. response.type == 'basic' to only cache
60 | // responses from the same domain. See https://fetch.spec.whatwg.org/#concept-response-type
61 | if (response.status < 400 && response.type === 'basic') {
62 | // We need to call .clone() on the response object to save a copy of it to the cache.
63 | // (https://fetch.spec.whatwg.org/#dom-request-clone)
64 | cache.put(event.request, response.clone());
65 | }
66 |
67 | // Return the original response object, which will be used to fulfill the resource request.
68 | return response;
69 | });
70 | }).catch((error) => {
71 | // This catch() will handle exceptions that arise from the match() or fetch() operations.
72 | // Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
73 | // It will return a normal response object that has the appropriate error code set.
74 | console.error(' Read-through caching failed:', error);
75 |
76 | throw error;
77 | });
78 | })
79 | );
80 | });
--------------------------------------------------------------------------------