├── app
├── vendor-platform.ts
├── vendor-platform.ios.ts
├── models
│ ├── index.ts
│ └── Task.ts
├── store
│ ├── reducers
│ │ ├── index.ts
│ │ └── task.reducer.ts
│ ├── states
│ │ ├── index.ts
│ │ └── task.state.ts
│ ├── store.module.ts
│ ├── app.state.ts
│ ├── effects
│ │ └── task.effects.ts
│ ├── actions
│ │ └── task.actions.ts
│ └── services
│ │ └── task.service.ts
├── +task
│ ├── components
│ │ ├── task-banner
│ │ │ ├── task-banner.component.css
│ │ │ ├── task-banner.component.android.css
│ │ │ ├── task-banner.component.html
│ │ │ ├── task-banner.common.css
│ │ │ └── task-banner.component.ts
│ │ ├── task-form
│ │ │ ├── task-form.component.android.css
│ │ │ ├── task-form.component.ios.css
│ │ │ ├── task-form.common.css
│ │ │ ├── task-form.component.html
│ │ │ └── task-form.component.ts
│ │ ├── task-count
│ │ │ ├── task-count.component.html
│ │ │ ├── task-count.component.css
│ │ │ ├── task-count.component.android.css
│ │ │ └── task-count.component.ts
│ │ └── task-list
│ │ │ ├── task-list.component.css
│ │ │ ├── task-list.component.html
│ │ │ └── task-list.component.ts
│ ├── task.routing.ts
│ └── task.module.ts
├── App_Resources
│ ├── iOS
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── icon-29.png
│ │ │ │ ├── icon-40.png
│ │ │ │ ├── icon-76.png
│ │ │ │ ├── icon-29@2x.png
│ │ │ │ ├── icon-29@3x.png
│ │ │ │ ├── icon-40@2x.png
│ │ │ │ ├── icon-40@3x.png
│ │ │ │ ├── icon-60@2x.png
│ │ │ │ ├── icon-60@3x.png
│ │ │ │ ├── icon-76@2x.png
│ │ │ │ ├── icon-83.5@2x.png
│ │ │ │ └── Contents.json
│ │ │ ├── LaunchImage.launchimage
│ │ │ │ ├── Default.png
│ │ │ │ ├── Default@2x.png
│ │ │ │ ├── Default-568h@2x.png
│ │ │ │ ├── Default-667h@2x.png
│ │ │ │ ├── Default-736h@3x.png
│ │ │ │ ├── Default-Landscape.png
│ │ │ │ ├── Default-Portrait.png
│ │ │ │ ├── Default-Landscape@2x.png
│ │ │ │ ├── Default-Landscape@3x.png
│ │ │ │ ├── Default-Portrait@2x.png
│ │ │ │ └── Contents.json
│ │ │ ├── LaunchScreen.Center.imageset
│ │ │ │ ├── LaunchScreen-Center.png
│ │ │ │ ├── LaunchScreen-Center@2x.png
│ │ │ │ └── Contents.json
│ │ │ └── LaunchScreen.AspectFill.imageset
│ │ │ │ ├── LaunchScreen-AspectFill.png
│ │ │ │ ├── LaunchScreen-AspectFill@2x.png
│ │ │ │ └── Contents.json
│ │ ├── app_bg_day.jpg
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ ├── tasks_complete_night.png
│ │ ├── build.xcconfig
│ │ ├── Info.plist
│ │ └── LaunchScreen.storyboard
│ └── Android
│ │ ├── values-v21
│ │ ├── colors.xml
│ │ └── styles.xml
│ │ ├── drawable-hdpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── background.png
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-ldpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── background.png
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-mdpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── background.png
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-xhdpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── background.png
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-xxhdpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── background.png
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-xxxhdpi
│ │ ├── icon.png
│ │ ├── logo.png
│ │ ├── app_bg_day.jpg
│ │ ├── app_bg_night.jpg
│ │ ├── background.png
│ │ ├── tasks_complete_day.png
│ │ └── tasks_complete_night.png
│ │ ├── drawable-nodpi
│ │ ├── app_bg_day.jpg
│ │ ├── app_bg_night.jpg
│ │ ├── tasks_complete_day.png
│ │ ├── tasks_complete_night.png
│ │ └── splash_screen.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ └── styles.xml
│ │ ├── app.gradle
│ │ └── AndroidManifest.xml
├── app.component.html
├── package.json
├── utils
│ ├── Date.ts
│ └── Guid.ts
├── main.aot.ts
├── vendor.ts
├── vendor-platform.android.ts
├── app.css
├── app.routing.ts
├── operators.ts
├── main.ts
├── app.component.ts
└── app.module.ts
├── .gitignore
├── .vscode
└── settings.json
├── tsconfig.json
├── tsconfig.aot.json
├── package.json
├── README.md
└── webpack.config.js
/app/vendor-platform.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/vendor-platform.ios.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Task';
2 |
--------------------------------------------------------------------------------
/app/store/reducers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './task.reducer';
2 |
--------------------------------------------------------------------------------
/app/store/states/index.ts:
--------------------------------------------------------------------------------
1 | export * from './task.state';
2 |
--------------------------------------------------------------------------------
/app/+task/components/task-banner/task-banner.component.css:
--------------------------------------------------------------------------------
1 | @import 'task-banner.common.css';
2 |
--------------------------------------------------------------------------------
/app/+task/components/task-form/task-form.component.android.css:
--------------------------------------------------------------------------------
1 | @import 'task-form.common.css';
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | hooks/
2 | node_modules/
3 | platforms/
4 | report/
5 | .nsbuildinfo
6 | app/**/*.js
7 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/app/App_Resources/iOS/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/iOS/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/+task/components/task-banner/task-banner.component.android.css:
--------------------------------------------------------------------------------
1 | @import 'task-banner.common.css';
2 |
3 | .banner {
4 | margin-top: 20;
5 | }
6 |
--------------------------------------------------------------------------------
/app/+task/components/task-form/task-form.component.ios.css:
--------------------------------------------------------------------------------
1 | @import 'task-form.common.css';
2 |
3 | .action-bar {
4 | padding-bottom: 20;
5 | }
6 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/values-v21/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3d5afe
4 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/logo.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/background.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/background.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/background.png
--------------------------------------------------------------------------------
/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-nodpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-nodpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/background.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/background.png
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "android": {
3 | "v8Flags": "--expose_gc"
4 | },
5 | "main": "main.js",
6 | "name": "tns-template-hello-world-ng",
7 | "version": "3.1.2"
8 | }
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-nodpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-nodpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/app_bg_day.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/app_bg_day.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/app_bg_night.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/app_bg_night.jpg
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/background.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-hdpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-hdpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-ldpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-ldpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-mdpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-mdpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-nodpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-nodpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-nodpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-nodpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xhdpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xhdpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxhdpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxhdpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/tasks_complete_day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/tasks_complete_day.png
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-xxxhdpi/tasks_complete_night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/Android/drawable-xxxhdpi/tasks_complete_night.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
--------------------------------------------------------------------------------
/app/utils/Date.ts:
--------------------------------------------------------------------------------
1 |
2 | export class NSDate {
3 |
4 | static isDayTime(today = new Date()): boolean {
5 | const hours = today.getHours();
6 | return hours > 8 && hours < 17;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/+task/components/task-count/task-count.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sean-perkins/nativescript-task-app/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png
--------------------------------------------------------------------------------
/app/+task/components/task-count/task-count.component.css:
--------------------------------------------------------------------------------
1 | .count {
2 | padding-bottom: 20;
3 | font-size: 22;
4 | text-align: center;
5 | }
6 |
7 | .count-label {
8 | text-align: center;
9 | padding-top: 20;
10 | font-size: 12;
11 | color: #9b8e94;
12 | }
13 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F5F5F5
4 | #757575
5 | #33B5E5
6 | #272734
7 |
--------------------------------------------------------------------------------
/app/utils/Guid.ts:
--------------------------------------------------------------------------------
1 | export class Guid {
2 |
3 | static next() {
4 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
5 | const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
6 | return v.toString(16);
7 | });
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/+task/components/task-count/task-count.component.android.css:
--------------------------------------------------------------------------------
1 | .count {
2 | padding-bottom: 10;
3 | font-size: 20;
4 | margin-top:5;
5 | text-align: center;
6 | }
7 |
8 | .count-label {
9 | text-align: center;
10 | padding-top: 25;
11 | margin-top:5;
12 | font-size: 10;
13 | color: #9b8e94;
14 | }
15 |
--------------------------------------------------------------------------------
/app/main.aot.ts:
--------------------------------------------------------------------------------
1 | // this import should be first in order to load some required settings (like globals and reflect-metadata)
2 | import { platformNativeScript } from "nativescript-angular/platform-static";
3 |
4 | import { AppModuleNgFactory } from "./app.module.ngfactory";
5 |
6 | platformNativeScript().bootstrapModuleFactory(AppModuleNgFactory);
7 |
--------------------------------------------------------------------------------
/app/+task/components/task-banner/task-banner.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/drawable-nodpi/splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 | -
3 |
4 |
5 | -
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/vendor.ts:
--------------------------------------------------------------------------------
1 | require("./vendor-platform");
2 |
3 | require("reflect-metadata");
4 | require("@angular/platform-browser");
5 | require("@angular/core");
6 | require("@angular/common");
7 | require("@angular/forms");
8 | require("@angular/http");
9 | require("@angular/router");
10 |
11 | require("nativescript-angular/platform-static");
12 | require("nativescript-angular/forms");
13 | require("nativescript-angular/router");
14 |
--------------------------------------------------------------------------------
/app/vendor-platform.android.ts:
--------------------------------------------------------------------------------
1 | require("application");
2 | if (!global["__snapshot"]) {
3 | /*
4 | In case snapshot generation is enabled these modules will get into the bundle but will not be required/evaluated.
5 | The snapshot webpack plugin will add them to the tns-java-classes.js bundle file. This way, they will be evaluated on app start as early as possible.
6 | */
7 | require("ui/frame");
8 | require("ui/frame/activity");
9 | }
10 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/app.gradle:
--------------------------------------------------------------------------------
1 | // Add your native dependencies here:
2 |
3 | // Uncomment to add recyclerview-v7 dependency
4 | //dependencies {
5 | // compile 'com.android.support:recyclerview-v7:+'
6 | //}
7 |
8 | android {
9 | defaultConfig {
10 | generatedDensities = []
11 | applicationId = "org.nativescript.nativescripteventapp"
12 | }
13 | aaptOptions {
14 | additionalParameters "--no-version-vectors"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchScreen-Center.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchScreen-Center@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchScreen-AspectFill.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchScreen-AspectFill@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/app/App_Resources/iOS/build.xcconfig:
--------------------------------------------------------------------------------
1 | // You can add custom settings here
2 | // for example you can uncomment the following line to force distribution code signing
3 | // CODE_SIGN_IDENTITY = iPhone Distribution
4 | // To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
5 | // DEVELOPMENT_TEAM = YOUR_TEAM_ID;
6 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
7 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
8 |
--------------------------------------------------------------------------------
/app/store/store.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
2 | import { HttpModule } from '@angular/http';
3 | import { TaskService } from './services/task.service';
4 | import { EffectsModule } from '@ngrx/effects';
5 | import { TaskEffects } from './effects/task.effects';
6 |
7 | @NgModule({
8 | imports: [
9 | HttpModule,
10 | EffectsModule.run(TaskEffects)
11 | ],
12 | providers: [
13 | TaskService
14 | ],
15 | schemas: [NO_ERRORS_SCHEMA]
16 | })
17 | export class AppStoreModule { }
18 |
--------------------------------------------------------------------------------
/app/app.css:
--------------------------------------------------------------------------------
1 | /*
2 | In NativeScript, the app.css file is where you place CSS rules that
3 | you would like to apply to your entire application. Check out
4 | http://docs.nativescript.org/ui/styling for a full list of the CSS
5 | selectors and properties you can use to style UI components.
6 |
7 | /*
8 | In many cases you may want to use the NativeScript core theme instead
9 | of writing your own CSS rules. For a full list of class names in the theme
10 | refer to http://docs.nativescript.org/ui/theme.
11 | */
12 | @import 'nativescript-theme-core/css/core.light.css';
13 |
--------------------------------------------------------------------------------
/app/app.routing.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { NativeScriptRouterModule } from 'nativescript-angular/router';
3 | import { Routes } from '@angular/router';
4 |
5 | const routes: Routes = [
6 | { path: '', redirectTo: '/tasks', pathMatch: 'full' },
7 | {
8 | path: 'tasks',
9 | loadChildren: './+task/task.module#TaskModule'
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [NativeScriptRouterModule.forRoot(routes)],
15 | exports: [NativeScriptRouterModule]
16 | })
17 | export class AppRoutingModule { }
18 |
--------------------------------------------------------------------------------
/app/store/app.state.ts:
--------------------------------------------------------------------------------
1 | import { ActionReducer } from '@ngrx/store';
2 | import { compose } from '@ngrx/core/compose';
3 | import { combineReducers } from '@ngrx/store';
4 | import * as appReducers from './reducers/index';
5 | import * as appStates from './states/index';
6 |
7 | export interface IAppState {
8 | tasks: appStates.TaskState;
9 | };
10 |
11 | const reducers = {
12 | tasks: appReducers.taskReducer
13 | };
14 |
15 | export function AppReducer(state: any, action: any) {
16 | return combineReducers(reducers)(state, action);
17 | }
18 |
19 | export * from './states/index';
20 |
--------------------------------------------------------------------------------
/app/+task/task.routing.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { NativeScriptRouterModule } from 'nativescript-angular/router';
3 | import { Routes } from '@angular/router';
4 | import { TaskListComponent } from './components/task-list/task-list.component';
5 |
6 | const routes: Routes = [
7 | { path: '', pathMatch: 'full', component: TaskListComponent },
8 | ];
9 |
10 | @NgModule({
11 | imports: [
12 | NativeScriptRouterModule.forChild(routes)
13 | ],
14 | exports: [
15 | NativeScriptRouterModule
16 | ]
17 | })
18 | export class TaskRoutingModule { }
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.watcherExclude": {
3 | "hooks/*/**": true,
4 | "node_modules/*/**": true,
5 | "platforms/*/**": true
6 | },
7 | "search.exclude": {
8 | "platforms": true,
9 | "node_modules": true,
10 | "hooks": true
11 | },
12 | "[typescript]": {
13 | "editor.formatOnSave": true
14 | },
15 | "files.trimTrailingWhitespace": true,
16 | "files.insertFinalNewline": true,
17 | "editor.trimAutoWhitespace": true,
18 | "editor.formatOnPaste": true,
19 | "autoimport.filesToScan": "src/app/*.{ts,tsx}"
20 | }
21 |
--------------------------------------------------------------------------------
/app/operators.ts:
--------------------------------------------------------------------------------
1 | // rxjs
2 | import 'rxjs/add/observable/throw';
3 | import 'rxjs/add/operator/map';
4 | import 'rxjs/add/operator/do';
5 | import 'rxjs/add/operator/startWith';
6 | import 'rxjs/add/operator/switchMap';
7 | import 'rxjs/add/operator/mergeMap';
8 | import 'rxjs/add/operator/combineLatest';
9 | import 'rxjs/add/operator/catch';
10 | import 'rxjs/add/operator/take';
11 | import 'rxjs/add/operator/let';
12 | import 'rxjs/add/operator/withLatestFrom';
13 | import 'rxjs/add/operator/takeUntil';
14 | import 'rxjs/add/observable/combineLatest';
15 | import 'rxjs/add/observable/fromPromise';
16 |
17 | // ngrx
18 | import '@ngrx/core/add/operator/select';
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "experimentalDecorators": true,
6 | "emitDecoratorMetadata": true,
7 | "noEmitHelpers": true,
8 | "noEmitOnError": true,
9 | "lib": [
10 | "es6",
11 | "dom",
12 | "es2015.iterable"
13 | ],
14 | "baseUrl": ".",
15 | "paths": {
16 | "*": [
17 | "./node_modules/tns-core-modules/*",
18 | "./node_modules/*"
19 | ]
20 | }
21 | },
22 | "exclude": [
23 | "node_modules",
24 | "platforms",
25 | "**/*.aot.ts"
26 | ]
27 | }
--------------------------------------------------------------------------------
/app/main.ts:
--------------------------------------------------------------------------------
1 | // this import should be first in order to load some required settings (like globals and reflect-metadata)
2 | import { platformNativeScriptDynamic } from "nativescript-angular/platform";
3 |
4 | import { AppModule } from "./app.module";
5 |
6 | // A traditional NativeScript application starts by initializing global objects, setting up global CSS rules, creating, and navigating to the main page.
7 | // Angular applications need to take care of their own initialization: modules, components, directives, routes, DI providers.
8 | // A NativeScript Angular app needs to make both paradigms work together, so we provide a wrapper platform object, platformNativeScriptDynamic,
9 | // that sets up a NativeScript application and can bootstrap the Angular framework.
10 | platformNativeScriptDynamic().bootstrapModule(AppModule);
11 |
--------------------------------------------------------------------------------
/app/+task/components/task-count/task-count.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from '@angular/core';
2 | /**
3 | * Task Count Component
4 | * Displays a styled number with a label below it
5 | */
6 | @Component({
7 | moduleId: module.id,
8 | selector: 'ns-task-count',
9 | templateUrl: './task-count.component.html',
10 | styleUrls: ['./task-count.component.css']
11 | })
12 | export class TaskCountComponent {
13 | // The number of items
14 | @Input() count: number;
15 | // The description of the type of number being displayed (i.e. All)
16 | @Input() label: string;
17 |
18 | @Output() onPress: EventEmitter = new EventEmitter();
19 | // Bind to the NS input to control display of this element on the parent view
20 | @Input() col = 0;
21 |
22 | press(): void {
23 | this.onPress.emit(true);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/+task/components/task-banner/task-banner.common.css:
--------------------------------------------------------------------------------
1 | .banner {
2 | background-repeat: no-repeat;
3 | background-position: center;
4 | background-size: cover;
5 | }
6 |
7 | .banner .title {
8 | horizontal-align: right;
9 | text-align: right;
10 | vertical-align: top;
11 | color: #fff;
12 | width: 100%;
13 | font-size: 22;
14 | font-weight: bold;
15 | padding: 20;
16 | }
17 |
18 | .banner .today {
19 | horizontal-align: right;
20 | text-align: right;
21 | vertical-align: top;
22 | color: #fff;
23 | width: 100%;
24 | font-size: 15;
25 | padding: 20;
26 | margin-top: 30;
27 | }
28 |
29 | .banner .btn-clear {
30 | horizontal-align: left;
31 | text-align: left;
32 | vertical-align: bottom;
33 | padding: 10 20;
34 | font-size: 10;
35 | font-weight: bold;
36 | color: #fff;
37 | text-transform: uppercase;
38 | background-color: transparent;
39 | border-color: transparent;
40 | border-width: 1;
41 | }
42 |
--------------------------------------------------------------------------------
/app/store/reducers/task.reducer.ts:
--------------------------------------------------------------------------------
1 | import { TaskState } from './../states/task.state';
2 | import { Action } from '@ngrx/store';
3 |
4 | export function taskReducer(
5 | state: TaskState = new TaskState,
6 | action: Action) {
7 | switch (action.type) {
8 | case TaskState.ActionTypes.CLEAR:
9 | return Object.assign({}, state, {
10 | tasks: []
11 | });
12 | case TaskState.ActionTypes.FETCH:
13 | return Object.assign({}, state, {
14 | loading: true
15 | });
16 | case TaskState.ActionTypes.FETCH_SUCCESS:
17 | return Object.assign({}, state, {
18 | tasks: action.payload,
19 | loading: false
20 | });
21 | case TaskState.ActionTypes.FETCH_FAILED:
22 | return Object.assign({}, state, {
23 | task: [],
24 | loading: false
25 | });
26 | default:
27 | return state;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
14 |
15 |
16 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation } from '@angular/core';
2 | import './operators';
3 | import * as app from 'tns-core-modules/application';
4 | import { NSDate } from './utils/Date';
5 | import { isAndroid } from 'tns-core-modules/platform';
6 |
7 | @Component({
8 | selector: 'ns-app',
9 | templateUrl: 'app.component.html',
10 | encapsulation: ViewEncapsulation.Native
11 | })
12 |
13 | export class AppComponent {
14 |
15 | constructor() {
16 | app.addCss(this.getStyles(NSDate.isDayTime() ? '#ff9d6e' : '#0061ef'));
17 | }
18 |
19 | private getStyles(accentColor: string): any {
20 | return `
21 | .count, .input, .textarea {
22 | color: ${accentColor};
23 | }
24 | .banner {
25 | background-image: url('res://app_bg_${NSDate.isDayTime() ? 'day' : 'night'}');
26 | }
27 | .action-bar, .btn-delete {
28 | background-color: ${accentColor}
29 | }
30 | .fab {
31 | background-color: ${NSDate.isDayTime() ? '#FF482F' : '#0061ef'};
32 | border-color: ${NSDate.isDayTime() ? '#ef432c' : '#035bdd'};
33 | }
34 | `;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, NgModuleFactoryLoader, NO_ERRORS_SCHEMA } from '@angular/core';
2 | import { NSModuleFactoryLoader } from 'nativescript-angular/router';
3 | import { NativeScriptModule } from 'nativescript-angular/nativescript.module';
4 | import { AppRoutingModule } from './app.routing';
5 | import { AppComponent } from './app.component';
6 |
7 | import { StoreModule } from '@ngrx/store';
8 | import { AppStoreModule } from './store/store.module';
9 | import { AppReducer } from './store/app.state';
10 |
11 | // Uncomment and add to NgModule imports if you need to use two-way binding
12 | // import { NativeScriptFormsModule } from 'nativescript-angular/forms';
13 |
14 | // Uncomment and add to NgModule imports if you need to use the HTTP wrapper
15 | // import { NativeScriptHttpModule } from 'nativescript-angular/http';
16 |
17 | @NgModule({
18 | bootstrap: [
19 | AppComponent
20 | ],
21 | imports: [
22 | NativeScriptModule,
23 | AppRoutingModule,
24 | AppStoreModule,
25 | StoreModule.provideStore(AppReducer),
26 | ],
27 | declarations: [
28 | AppComponent
29 | ],
30 | providers: [
31 | { provide: NgModuleFactoryLoader, useClass: NSModuleFactoryLoader },
32 | ],
33 | schemas: [
34 | NO_ERRORS_SCHEMA
35 | ]
36 | })
37 | export class AppModule { }
38 |
--------------------------------------------------------------------------------
/app/+task/components/task-form/task-form.common.css:
--------------------------------------------------------------------------------
1 | .action-bar {
2 | orientation: horizontal;
3 | margin-top: 20;
4 | }
5 |
6 | .night .action-bar {
7 | background-color: #0061ef;
8 | }
9 |
10 | .form-container {
11 | background-color: #fff;
12 | padding: 20;
13 | }
14 |
15 | .btn-cancel {
16 | text-align: left;
17 | width: 50%;
18 | padding-left: 20;
19 | color: #fff;
20 | background-color: transparent;
21 | border-color: transparent;
22 | border-width: 1;
23 | text-transform: capitalize;
24 | }
25 |
26 | .btn-save {
27 | text-align: right;
28 | width: 50%;
29 | padding-right: 20;
30 | color: #fff;
31 | font-weight: bold;
32 | border-color: transparent;
33 | border-width: 1;
34 | background-color: transparent;
35 | text-transform: capitalize;
36 | }
37 |
38 | .label {
39 | font-size: 12;
40 | color: #9b8e94;
41 | }
42 |
43 | .createdAt {
44 | border-top-width: 1;
45 | border-top-color: #FBF8F8;
46 | padding-top: 10;
47 | }
48 |
49 | .label.error {
50 | color: #ff9d6e;
51 | }
52 |
53 | .night .label.error {
54 | color: #0061ef;
55 | }
56 |
57 | .input {
58 | border-bottom-width: 1;
59 | border-bottom-color: #FBF8F8;
60 | margin-top: 5;
61 | padding-bottom: 5;
62 | font-size: 13;
63 | }
64 |
65 | .textarea {
66 | height: 60;
67 | }
68 |
--------------------------------------------------------------------------------
/app/+task/components/task-banner/task-banner.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from '@angular/core';
2 | import { NSDate } from '../../../utils/Date';
3 | import * as dialogs from 'tns-core-modules/ui/dialogs';
4 | /**
5 | * Styled Banner Header
6 | * Displays personalized background graphic with todays date and
7 | * an action to clear existing tasks from the app.
8 | */
9 | @Component({
10 | moduleId: module.id,
11 | selector: 'ns-task-banner',
12 | templateUrl: './task-banner.component.html',
13 | styleUrls: ['./task-banner.component.css']
14 | })
15 | export class TaskBannerComponent {
16 |
17 | /**
18 | * Output event when a Label is tapped
19 | */
20 | @Output() onClear: EventEmitter = new EventEmitter();
21 | /**
22 | * Todays' date object
23 | */
24 | today = new Date();
25 |
26 | /**
27 | * Returns a different heading label based on if it is daytime or nighttime
28 | */
29 | get todayLabel(): string {
30 | return NSDate.isDayTime(this.today) ? 'Today' : 'Tonight';
31 | }
32 |
33 | clearTask(): void {
34 | // Prompts the user to confirm before clearing all tasks
35 | dialogs.confirm('Are you sure you want to clear all tasks?')
36 | .then(confirmed => {
37 | if (confirmed) {
38 | this.onClear.next(true);
39 | }
40 | });
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/+task/task.module.ts:
--------------------------------------------------------------------------------
1 | import { TaskListComponent } from './components/task-list/task-list.component';
2 | import { TaskFormComponent } from './components/task-form/task-form.component';
3 | import { TaskCountComponent } from './components/task-count/task-count.component';
4 | import { TaskBannerComponent } from './components/task-banner/task-banner.component';
5 | import { TaskRoutingModule } from './task.routing';
6 | import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
7 | import { CommonModule } from '@angular/common';
8 | import { NativeScriptUIListViewModule } from 'nativescript-telerik-ui/listview/angular';
9 | import { ModalDialogService } from 'nativescript-angular/modal-dialog';
10 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
11 | import { NativeScriptFormsModule } from 'nativescript-angular/forms';
12 |
13 | @NgModule({
14 | imports: [
15 | CommonModule,
16 | TaskRoutingModule,
17 | NativeScriptUIListViewModule,
18 | NativeScriptFormsModule,
19 | FormsModule,
20 | ReactiveFormsModule
21 | ],
22 | declarations: [
23 | TaskListComponent,
24 | TaskFormComponent,
25 | TaskCountComponent,
26 | TaskBannerComponent
27 | ],
28 | exports: [],
29 | entryComponents: [
30 | TaskFormComponent
31 | ],
32 | providers: [
33 | ModalDialogService
34 | ],
35 | schemas: [NO_ERRORS_SCHEMA]
36 | })
37 | export class TaskModule { }
38 |
--------------------------------------------------------------------------------
/app/+task/components/task-list/task-list.component.css:
--------------------------------------------------------------------------------
1 | .placeholder {
2 | height: 100%;
3 | }
4 |
5 | .placeholder Label {
6 | color: #87797f;
7 | text-align: center;
8 | vertical-align: middle;
9 | margin-top: 15;
10 | }
11 |
12 | .placeholder Image {
13 | text-align: center;
14 | vertical-align: center;
15 | width: 72;
16 | height: 72;
17 | }
18 |
19 | .count-bar {
20 | background-color: #fff;
21 | border-bottom-width: 1;
22 | border-bottom-color: #FBF8F8;
23 | }
24 |
25 | .btn-complete {
26 | background-color: #03dd79;
27 | }
28 |
29 | .btn-swipe {
30 | padding: 0 16;
31 | orientation: horizontal;
32 | }
33 |
34 | .btn-swipe Label {
35 | color: #fff;
36 | font-size: 20;
37 | horizontal-align: center;
38 | }
39 |
40 | .fab {
41 | horizontal-align: right;
42 | vertical-align: bottom;
43 | text-align: center;
44 | margin: 0 20 20 0;
45 | font-size: 22;
46 | padding: 0;
47 | border-width: 1;
48 | color: #fff;
49 | border-radius: 50;
50 | width: 50;
51 | height: 50;
52 | }
53 |
54 | .list-item {
55 | padding: 10 15;
56 | background-color: #fff;
57 | border-bottom-width: 1;
58 | border-bottom-color: #FBF8F8;
59 | }
60 |
61 | .list-item.complete Label {
62 | opacity: 0.1;
63 | }
64 |
65 | .list-item .title {
66 | color: #a3979e;
67 | font-weight: 400;
68 | font-size: 18;
69 | }
70 |
71 | .list-item .description {
72 | color: #87797f;
73 | font-size: 14;
74 | }
75 |
--------------------------------------------------------------------------------
/app/App_Resources/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/models/Task.ts:
--------------------------------------------------------------------------------
1 |
2 | import { Guid } from '../utils/Guid';
3 |
4 | export class Task {
5 | /**
6 | * The unique id of the event
7 | */
8 | id: string;
9 | /**
10 | * The event name
11 | */
12 | name: string;
13 | /**
14 | * The description of the event
15 | */
16 | description: string;
17 | /**
18 | * The start time of the event
19 | */
20 | startTime: any;
21 | /**
22 | * The end time of the event
23 | */
24 | endTime: any;
25 | /**
26 | * The created timestamp of the event
27 | */
28 | createdAt: number;
29 | /**
30 | * The updated timestamp of the event
31 | */
32 | updatedAt: number;
33 | /**
34 | * The timestamp the event was completed
35 | */
36 | completedAt: number;
37 |
38 | constructor(options: Task = {}) {
39 | this.id = options.id || null;
40 | this.name = options.name || null;
41 | this.description = options.description || null;
42 | this.startTime = options.startTime || null;
43 | this.endTime = options.endTime || null;
44 | this.createdAt = options.createdAt || null;
45 | this.updatedAt = options.updatedAt || null;
46 | this.completedAt = options.completedAt || null;
47 | }
48 |
49 | initalize(): void {
50 | this.id = Guid.next();
51 | this.createdAt = Date.now();
52 | this.update();
53 | }
54 |
55 | update(): void {
56 | this.updatedAt = Date.now();
57 | }
58 |
59 | complete(): void {
60 | this.completedAt = Date.now();
61 | }
62 |
63 | get completed(): boolean {
64 | return this.completedAt !== null;
65 | }
66 |
67 | toString = (): string => {
68 | return JSON.stringify(this);
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/tsconfig.aot.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig",
3 | "compilerOptions": {
4 | "baseUrl": ".",
5 | "paths": {
6 | "application": ["node_modules/tns-core-modules/application"],
7 | "application-settings": ["node_modules/tns-core-modules/application-settings"],
8 | "camera": ["node_modules/tns-core-modules/camera"],
9 | "color": ["node_modules/tns-core-modules/color"],
10 | "connectivity": ["node_modules/tns-core-modules/connectivity"],
11 | "console": ["node_modules/tns-core-modules/console"],
12 | "data/*": ["node_modules/tns-core-modules/data/*"],
13 | "fetch": ["node_modules/tns-core-modules/fetch"],
14 | "file-system": ["node_modules/tns-core-modules/file-system"],
15 | "fps-meter": ["node_modules/tns-core-modules/fps-meter"],
16 | "globals": ["node_modules/tns-core-modules/globals"],
17 | "http": ["node_modules/tns-core-modules/http"],
18 | "image-asset": ["node_modules/tns-core-modules/image-asset"],
19 | "image-source": ["node_modules/tns-core-modules/image-source"],
20 | "location": ["node_modules/tns-core-modules/location"],
21 | "platform": ["node_modules/tns-core-modules/platform"],
22 | "text": ["node_modules/tns-core-modules/text"],
23 | "timer": ["node_modules/tns-core-modules/timer"],
24 | "trace": ["node_modules/tns-core-modules/trace"],
25 | "ui/*": ["node_modules/tns-core-modules/ui/*"],
26 | "utils/*": ["node_modules/tns-core-modules/utils/*"],
27 | "xhr": ["node_modules/tns-core-modules/xhr"],
28 | "xml": ["node_modules/tns-core-modules/xml"]
29 | },
30 | "skipLibCheck": true
31 | },
32 | "exclude": [
33 | "node_modules",
34 | "platforms"
35 | ],
36 | "angularCompilerOptions": {
37 | "skipMetadataEmit": true,
38 | "genDir": "./"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiresFullScreen
28 |
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UIStatusBarStyle
47 | UIStatusBarStyleLightContent
48 | UIViewControllerBasedStatusBarAppearance
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/+task/components/task-form/task-form.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
9 |
10 |
12 |
17 |
18 |
19 |
20 |
23 |
24 |
26 |
29 |
30 |
31 |
33 |
35 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "icon-29.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "icon-29@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "icon-29@3x.png",
19 | "scale" : "3x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "icon-40@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "icon-40@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon-60@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon-60@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "icon-29.png",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "29x29",
53 | "idiom" : "ipad",
54 | "filename" : "icon-29@2x.png",
55 | "scale" : "2x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "icon-40.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "40x40",
65 | "idiom" : "ipad",
66 | "filename" : "icon-40@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "icon-76.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "76x76",
77 | "idiom" : "ipad",
78 | "filename" : "icon-76@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "83.5x83.5",
83 | "idiom" : "ipad",
84 | "filename" : "icon-83.5@2x.png",
85 | "scale" : "2x"
86 | }
87 | ],
88 | "info" : {
89 | "version" : 1,
90 | "author" : "xcode"
91 | }
92 | }
--------------------------------------------------------------------------------
/app/App_Resources/Android/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
21 |
22 |
23 |
37 |
38 |
40 |
41 |
42 |
47 |
48 |
50 |
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "NativeScript Application",
3 | "license": "SEE LICENSE IN ",
4 | "readme": "NativeScript Application",
5 | "repository": "",
6 | "nativescript": {
7 | "id": "org.nativescript.nativescripteventapp",
8 | "tns-ios": {
9 | "version": "3.2.0-2017-8-25-1"
10 | },
11 | "tns-android": {
12 | "version": "3.2.0-next-2017-06-28-1901"
13 | }
14 | },
15 | "dependencies": {
16 | "@angular/animations": "~4.2.0",
17 | "@angular/common": "~4.2.0",
18 | "@angular/compiler": "~4.2.0",
19 | "@angular/core": "~4.2.0",
20 | "@angular/forms": "~4.2.0",
21 | "@angular/http": "~4.2.0",
22 | "@angular/platform-browser": "~4.2.0",
23 | "@angular/router": "~4.2.0",
24 | "@ngrx/core": "^1.2.0",
25 | "@ngrx/effects": "^2.0.2",
26 | "@ngrx/store": "^2.2.1",
27 | "nativescript-angular": "~4.2.0",
28 | "nativescript-telerik-ui": "^3.0.4",
29 | "nativescript-theme-core": "~1.0.2",
30 | "ngrx-store-freeze": "0.1.9",
31 | "reflect-metadata": "~0.1.8",
32 | "rxjs": "~5.4.2",
33 | "tns-core-modules": "~3.2.0",
34 | "zone.js": "~0.8.2"
35 | },
36 | "devDependencies": {
37 | "@angular/compiler-cli": "~4.2.0",
38 | "@ngtools/webpack": "~1.5.0",
39 | "babel-traverse": "6.26.0",
40 | "babel-types": "6.26.0",
41 | "babylon": "6.18.0",
42 | "copy-webpack-plugin": "~4.0.1",
43 | "extract-text-webpack-plugin": "~3.0.0",
44 | "lazy": "1.0.11",
45 | "nativescript-css-loader": "~0.26.0",
46 | "nativescript-dev-typescript": "~0.5.0",
47 | "nativescript-dev-webpack": "^0.7.3",
48 | "raw-loader": "~0.5.1",
49 | "resolve-url-loader": "~2.1.0",
50 | "typescript": "~2.4.2",
51 | "webpack": "~3.2.0",
52 | "webpack-bundle-analyzer": "^2.8.2",
53 | "webpack-sources": "~1.0.1"
54 | },
55 | "scripts": {
56 | "ns-bundle": "ns-bundle",
57 | "publish-ios-bundle": "npm run ns-bundle --ios --publish-app",
58 | "generate-android-snapshot": "generate-android-snapshot --targetArchs arm,arm64,ia32 --install",
59 | "start-android-bundle": "npm run ns-bundle --android --run-app",
60 | "start-ios-bundle": "npm run ns-bundle --ios --run-app",
61 | "build-android-bundle": "npm run ns-bundle --android --build-app",
62 | "build-ios-bundle": "npm run ns-bundle --ios --build-app"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/+task/components/task-list/task-list.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
8 |
10 |
11 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
31 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
53 |
--------------------------------------------------------------------------------
/app/store/effects/task.effects.ts:
--------------------------------------------------------------------------------
1 |
2 | import { Injectable } from '@angular/core';
3 | import { Action } from '@ngrx/store';
4 | import { Actions, Effect } from '@ngrx/effects';
5 | import { Observable } from 'rxjs/Observable';
6 | import { of } from 'rxjs/observable/of';
7 | import { TaskState } from '../states/task.state';
8 | import { TaskService } from '../services/task.service';
9 |
10 | import { default as taskActions } from '../actions/task.actions';
11 | import { empty } from 'rxjs/observable/empty';
12 |
13 | @Injectable()
14 | export class TaskEffects {
15 |
16 | @Effect() create$: Observable = this.actions$
17 | .ofType(TaskState.ActionTypes.CREATE)
18 | .switchMap(({ payload }) =>
19 | this.taskService.create(payload)
20 | .map(() => new taskActions.CreateSuccessAction)
21 | .catch(error => of(new taskActions.CreateFailedAction(error)))
22 | );
23 |
24 | @Effect() update$: Observable = this.actions$
25 | .ofType(TaskState.ActionTypes.UPDATE)
26 | .switchMap(({ payload }) =>
27 | this.taskService.update(payload)
28 | .map(() => new taskActions.UpdateSuccessAction)
29 | .catch(error => of(new taskActions.UpdateFailedAction(error)))
30 | );
31 |
32 | @Effect() complete$: Observable = this.actions$
33 | .ofType(TaskState.ActionTypes.COMPLETE)
34 | .switchMap(({ payload }) =>
35 | this.taskService.complete(payload)
36 | .map(() => new taskActions.CompleteSuccessAction)
37 | .catch(error => of(new taskActions.CompleteFailedAction(error)))
38 | );
39 |
40 | @Effect() delete$: Observable = this.actions$
41 | .ofType(TaskState.ActionTypes.DELETE)
42 | .switchMap(({ payload }) =>
43 | this.taskService.remove(payload)
44 | .map(() => new taskActions.DeleteSuccessAction)
45 | .catch(error => of(new taskActions.DeleteFailedAction(error)))
46 | );
47 |
48 | @Effect() fetch$: Observable = this.actions$
49 | .ofType(TaskState.ActionTypes.FETCH)
50 | .switchMap(({ payload }) =>
51 | this.taskService.fetch
52 | .map(res => new taskActions.FetchSuccessAction(res))
53 | .catch(error => of(new taskActions.FetchFailedAction(error)))
54 | );
55 |
56 | @Effect() clear$: Observable = this.actions$
57 | .ofType(TaskState.ActionTypes.CLEAR)
58 | .switchMap(() => {
59 | this.taskService.clear();
60 | return empty();
61 | });
62 |
63 | constructor(
64 | private actions$: Actions,
65 | private taskService: TaskService
66 | ) { }
67 | }
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NativeScript Task App
2 | This repository demonstrates an example task management application built with NativeScript Angular.
3 |
4 | #### Technologies
5 | - NativeScript Angular
6 | - RxJS / NgRx (State / Effects / Actions / Reducers)
7 | - Model-Driven Objects
8 | - Lazy-Loading Modules
9 | - Offline Mode (Persistent Storage / App Settings)
10 | - Angular Reactive Forms
11 | - TypeScript Static Sub-classing for NgRx Actions
12 |
13 | #### Feature List
14 | - Ability to create, update and delete tasks
15 | - Complete task by swiping in from the left.
16 | - Delete tasks by swiping in from the right.
17 | - Update tasks by longpressing on the list item
18 | - Tap "Clear Tasks" to clear all tasks.
19 | - Tap "+" FAB to open modal form for creating tasks.
20 | - All tasks are saved local to the device for persistent storage.
21 | - App branding will change from daytime mode at 8am to nighttime mode at 7pm.
22 | - Filter between complete, incomplete and all tasks by tapping the statistic bar sections.
23 |
24 | ## Getting Started
25 | 1. Download or clone this repository.
26 | 2. Install dependencies `npm i` or `npm install`.
27 | 3. Install and run your desired runtime `tns run ios` or `tns run android`.
28 |
29 |
30 | ### App Images
31 |
32 | |iOS|Android|
33 | |:---:|:---:|
34 | |
|
|
35 | |
|
|
36 | |
|
|
37 |
|
|
38 |
39 | ## Credits / References
40 | * [Zoeyshen](https://dribbble.com/zoeyshen) for the initial graphics. Show her some love on Dribbble.
41 | * [MadebyOliver](https://www.flaticon.com/authors/madebyoliver) for the initial references for the task icons.
42 |
43 | # Contributors
44 |
45 | [
](https://github.com/sean-perkins) |
46 | :---:
47 | |[Sean Perkins](https://github.com/sean-perkins)|
48 |
--------------------------------------------------------------------------------
/app/store/states/task.state.ts:
--------------------------------------------------------------------------------
1 | import { Task } from './../../models/Task';
2 | import { IAppState } from './../app.state';
3 | import { Observable } from 'rxjs/Observable';
4 | import { compose } from '@ngrx/core/compose';
5 |
6 | export class TaskState {
7 |
8 | static NAMESPACE = 'TaskState';
9 |
10 | static ActionTypes = {
11 | CLEAR: `${TaskState.NAMESPACE} Clear`,
12 | CREATE: `${TaskState.NAMESPACE} Create Task`,
13 | CREATE_SUCCESS: `${TaskState.NAMESPACE} Create Task Success`,
14 | CREATE_FAILED: `${TaskState.NAMESPACE} Create Task Failed`,
15 | UPDATE: `${TaskState.NAMESPACE} Update Task`,
16 | UPDATE_SUCCESS: `${TaskState.NAMESPACE} Update Task Success`,
17 | UPDATE_FAILED: `${TaskState.NAMESPACE} Update Task Failed`,
18 | DELETE: `${TaskState.NAMESPACE} Delete Task`,
19 | DELETE_SUCCESS: `${TaskState.NAMESPACE} Delete Task Success`,
20 | DELETE_FAILED: `${TaskState.NAMESPACE} Delete Task Failed`,
21 | FETCH: `${TaskState.NAMESPACE} Fetch`,
22 | FETCH_SUCCESS: `${TaskState.NAMESPACE} Fetch Success`,
23 | FETCH_FAILED: `${TaskState.NAMESPACE} Fetch Failed`,
24 | COMPLETE: `${TaskState.NAMESPACE} Complete`,
25 | COMPLETE_SUCCESS: `${TaskState.NAMESPACE} Complete Success`,
26 | COMPleTE_FAILED: `${TaskState.NAMESPACE} Complete Failed`
27 | };
28 | /**
29 | * The collection of tasks loaded
30 | */
31 | tasks: Task[];
32 | /**
33 | * The detail view of a task
34 | */
35 | task: Task;
36 | /**
37 | * The loading state of the tasks
38 | */
39 | loading: boolean;
40 |
41 | static state$(state$: Observable): Observable {
42 | return state$.select(state => state.tasks);
43 | }
44 |
45 | static getTasks(state$: Observable) {
46 | return state$.select(state => state.tasks);
47 | }
48 |
49 | static getCompletedTasks(state$: Observable) {
50 | return state$.select(state => state.tasks.filter(res => res.completed));
51 | }
52 |
53 | static getPendingTasks(state$: Observable) {
54 | return state$.select(state => state.tasks.filter(res => !res.completed));
55 | }
56 |
57 | static getTaskDetail(state$: Observable) {
58 | return state$.select(state => state.task);
59 | }
60 |
61 | static isTasksLoading(state$: Observable) {
62 | return state$.select(state => state.loading);
63 | }
64 |
65 | constructor(options: TaskState = {}) {
66 | this.tasks = Array.isArray(options.tasks) ?
67 | options.tasks : [];
68 | this.task = options.task || null;
69 | }
70 |
71 | }
72 |
73 | export const getTasks: any = compose(TaskState.getTasks, TaskState.state$);
74 | export const getCompletedTasks: any = compose(TaskState.getCompletedTasks, TaskState.state$);
75 | export const getPendingTasks: any = compose(TaskState.getPendingTasks, TaskState.state$);
76 | export const getTaskDetail: any = compose(TaskState.getTaskDetail, TaskState.state$);
77 |
--------------------------------------------------------------------------------
/app/store/actions/task.actions.ts:
--------------------------------------------------------------------------------
1 | import { Task } from './../../models/Task';
2 | import { TaskState } from './../states/task.state';
3 | import { Action } from '@ngrx/store';
4 |
5 | export default class TaskActions {
6 |
7 | // Clear Actions
8 |
9 | static ClearAction = class implements Action {
10 | readonly type = TaskState.ActionTypes.CLEAR;
11 | payload = null;
12 | }
13 |
14 | // Create Actions
15 |
16 | static CreateAction = class implements Action {
17 | readonly type = TaskState.ActionTypes.CREATE;
18 | constructor(public payload: Task) { }
19 | }
20 |
21 | static CreateSuccessAction = class implements Action {
22 | readonly type = TaskState.ActionTypes.CREATE_SUCCESS;
23 | payload = null;
24 | }
25 |
26 | static CreateFailedAction = class implements Action {
27 | readonly type = TaskState.ActionTypes.CREATE_FAILED;
28 | constructor(public payload?: any) { }
29 | }
30 |
31 | // Update Actions
32 |
33 | static UpdateAction = class implements Action {
34 | readonly type = TaskState.ActionTypes.UPDATE;
35 | constructor(public payload: Task) { }
36 | }
37 |
38 | static UpdateSuccessAction = class implements Action {
39 | readonly type = TaskState.ActionTypes.UPDATE_SUCCESS;
40 | payload = null;
41 | }
42 |
43 | static UpdateFailedAction = class implements Action {
44 | readonly type = TaskState.ActionTypes.UPDATE_FAILED;
45 | constructor(public payload?: any) { }
46 | }
47 |
48 | // Delete Actions
49 |
50 | static DeleteAction = class implements Action {
51 | readonly type = TaskState.ActionTypes.DELETE;
52 | constructor(public payload: string) { }
53 | }
54 |
55 | static DeleteSuccessAction = class implements Action {
56 | readonly type = TaskState.ActionTypes.DELETE_SUCCESS;
57 | payload = null;
58 | }
59 |
60 | static DeleteFailedAction = class implements Action {
61 | readonly type = TaskState.ActionTypes.DELETE_FAILED;
62 | constructor(public payload?: any) { }
63 | }
64 |
65 | // Fetch Actions
66 |
67 | static FetchAction = class implements Action {
68 | readonly type = TaskState.ActionTypes.FETCH;
69 | payload = null;
70 | }
71 |
72 | static FetchSuccessAction = class implements Action {
73 | readonly type = TaskState.ActionTypes.FETCH_SUCCESS;
74 | constructor(public payload: any[]) { }
75 | }
76 |
77 | static FetchFailedAction = class implements Action {
78 | readonly type = TaskState.ActionTypes.FETCH_FAILED;
79 | constructor(public payload?: any) { }
80 | }
81 |
82 | // Complete Actions
83 |
84 | static CompleteAction = class implements Action {
85 | readonly type = TaskState.ActionTypes.COMPLETE;
86 | constructor(public payload: Task) { }
87 | }
88 |
89 | static CompleteSuccessAction = class implements Action {
90 | readonly type = TaskState.ActionTypes.COMPLETE_SUCCESS;
91 | payload = null;
92 | }
93 |
94 | static CompleteFailedAction = class implements Action {
95 | readonly type = TaskState.ActionTypes.COMPleTE_FAILED;
96 | constructor(public payload?: any) { }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/+task/components/task-form/task-form.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Page } from 'tns-core-modules/ui/page';
3 | import { ModalDialogParams } from 'nativescript-angular/modal-dialog';
4 | import { Color } from 'tns-core-modules/color';
5 | import { FormGroup, FormBuilder, Validators } from '@angular/forms';
6 | import { Task } from '../../../models/Task';
7 | import { NSDate } from '../../../utils/Date';
8 | /**
9 | * Task Form Component
10 | * Modal page that allows a user to create a new task or update an existing one
11 | */
12 | @Component({
13 | moduleId: module.id,
14 | selector: 'ns-task-form',
15 | templateUrl: './task-form.component.html',
16 | styleUrls: ['./task-form.component.css']
17 | })
18 | export class TaskFormComponent {
19 |
20 | /**
21 | * The collection of form inputs and validation states
22 | */
23 | form: FormGroup;
24 | /**
25 | * The submitted state of the form (default: false)
26 | */
27 | submitted = false;
28 | /**
29 | * Referece to the passed in task (if updating)
30 | */
31 | task: Task;
32 | /**
33 | * Determines if the form is creating or updating a record
34 | */
35 | isCreate = true;
36 |
37 | constructor(
38 | private params: ModalDialogParams,
39 | private page: Page,
40 | private fb: FormBuilder) {
41 | this.page.backgroundSpanUnderStatusBar = true;
42 | this.page.backgroundColor = new Color(this.isDayTime ? '#ff9d6e' : '#0061ef');
43 |
44 | this.initFormGroup(params.context);
45 |
46 | this.page.on('unloaded', () => {
47 | this.params.closeCallback();
48 | });
49 | }
50 |
51 | /**
52 | * Initializes the form group and sets existing field values
53 | * @param task The existing task (if updating)
54 | */
55 | private initFormGroup(task?: any) {
56 | this.task = task.id ? new Task(task) : null;
57 | this.isCreate = !task.id;
58 | this.form = this.fb.group({
59 | id: [task.id],
60 | name: [task.name, Validators.required],
61 | description: [task.description],
62 | complete: [false]
63 | });
64 |
65 | if (this.task && this.task.completed) {
66 | this.form.get('complete').setValue(true);
67 | }
68 | }
69 |
70 | /**
71 | * Helper function to get access to the isDayTime in the view
72 | */
73 | get isDayTime(): boolean {
74 | return NSDate.isDayTime();
75 | }
76 |
77 | /**
78 | * The cancel action of the dialog - dismisses the modal
79 | */
80 | cancel(): void {
81 | this.params.closeCallback();
82 | }
83 |
84 | /**
85 | * The save action of the dialog
86 | * Checks if the form is valid before dismissing
87 | */
88 | save(value = this.form.value): void {
89 | this.submitted = true;
90 | if (this.form.valid) {
91 | if (value.complete) {
92 | if (!this.task.completedAt) {
93 | value.completedAt = Date.now();
94 | }
95 | }
96 | else {
97 | value.completedAt = null;
98 | }
99 | this.params.closeCallback(value);
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/app/store/services/task.service.ts:
--------------------------------------------------------------------------------
1 | import { Task } from './../../models/Task';
2 | import { Injectable } from '@angular/core';
3 | import { Observable } from 'rxjs/Observable';
4 | import { Observer } from 'rxjs/Observer';
5 | import { of } from 'rxjs/observable/of';
6 |
7 | import * as appSettings from 'tns-core-modules/application-settings';
8 |
9 | @Injectable()
10 | export class TaskService {
11 |
12 | private static NAMESPACE = 'TASKS';
13 |
14 | get fetch(): Observable {
15 | return of(
16 | this.tasks
17 | );
18 | }
19 |
20 | create(task: Task): Observable {
21 | return Observable.create((observer: Observer) => {
22 | if (this.hasTask(task.id)) {
23 | observer.error(`Error: Task already exists with id: ${task.id}.`);
24 | }
25 | else {
26 | this.upsert(task);
27 | observer.next(true);
28 | observer.complete();
29 | }
30 | return observer;
31 | });
32 | }
33 |
34 | update(task: Task): Observable {
35 | return Observable.create((observer: Observer) => {
36 | if (this.hasTask(task.id)) {
37 | this.upsert(task);
38 | observer.next(true);
39 | observer.complete();
40 | }
41 | else {
42 | observer.error(`Error: Could not find task with id: ${task.id}.`);
43 | }
44 | return observer;
45 | });
46 | }
47 |
48 | remove(taskId: string): Observable {
49 | return Observable.create((observer: Observer) => {
50 | if (this.hasTask(taskId)) {
51 | this.delete(taskId);
52 | observer.next(true);
53 | observer.complete();
54 | }
55 | else {
56 | observer.error(`Error: Could not find task with id: ${taskId}`);
57 | }
58 | });
59 | }
60 |
61 | complete(task: Task): Observable {
62 | task.complete();
63 | return this.update(task);
64 | }
65 |
66 | clear() {
67 | appSettings.remove(TaskService.NAMESPACE);
68 | }
69 |
70 | private indexOfTask(taskId: string): number {
71 | return this.tasks.findIndex(res => res.id === taskId)
72 | }
73 |
74 | private hasTask(id: string): boolean {
75 | return this.tasks
76 | .filter(res => res.id === id).length > 0;
77 | }
78 |
79 | private upsert(task: Task) {
80 | let tasks = this.tasks;
81 | if (this.hasTask(task.id)) {
82 | tasks[this.indexOfTask(task.id)] = task;
83 | }
84 | else {
85 | tasks.push(task);
86 | }
87 | appSettings.setString(TaskService.NAMESPACE, JSON.stringify(tasks));
88 | }
89 |
90 | private delete(taskId: string) {
91 | let tasks: any[] = this.tasks;
92 | tasks = tasks.filter(res => res.id !== taskId);
93 | appSettings.setString(TaskService.NAMESPACE, JSON.stringify(tasks));
94 | }
95 |
96 | private get tasks(): any[] {
97 | const items: any = appSettings.getString(TaskService.NAMESPACE);
98 | if (items) {
99 | let tasks = JSON.parse(items);
100 | return tasks
101 | .map(res => new Task(res));
102 | }
103 | return [];
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "extent" : "full-screen",
5 | "idiom" : "iphone",
6 | "subtype" : "736h",
7 | "filename" : "Default-736h@3x.png",
8 | "minimum-system-version" : "8.0",
9 | "orientation" : "portrait",
10 | "scale" : "3x"
11 | },
12 | {
13 | "extent" : "full-screen",
14 | "idiom" : "iphone",
15 | "subtype" : "736h",
16 | "filename" : "Default-Landscape@3x.png",
17 | "minimum-system-version" : "8.0",
18 | "orientation" : "landscape",
19 | "scale" : "3x"
20 | },
21 | {
22 | "extent" : "full-screen",
23 | "idiom" : "iphone",
24 | "subtype" : "667h",
25 | "filename" : "Default-667h@2x.png",
26 | "minimum-system-version" : "8.0",
27 | "orientation" : "portrait",
28 | "scale" : "2x"
29 | },
30 | {
31 | "orientation" : "portrait",
32 | "idiom" : "iphone",
33 | "filename" : "Default@2x.png",
34 | "extent" : "full-screen",
35 | "minimum-system-version" : "7.0",
36 | "scale" : "2x"
37 | },
38 | {
39 | "extent" : "full-screen",
40 | "idiom" : "iphone",
41 | "subtype" : "retina4",
42 | "filename" : "Default-568h@2x.png",
43 | "minimum-system-version" : "7.0",
44 | "orientation" : "portrait",
45 | "scale" : "2x"
46 | },
47 | {
48 | "orientation" : "portrait",
49 | "idiom" : "ipad",
50 | "filename" : "Default-Portrait.png",
51 | "extent" : "full-screen",
52 | "minimum-system-version" : "7.0",
53 | "scale" : "1x"
54 | },
55 | {
56 | "orientation" : "landscape",
57 | "idiom" : "ipad",
58 | "filename" : "Default-Landscape.png",
59 | "extent" : "full-screen",
60 | "minimum-system-version" : "7.0",
61 | "scale" : "1x"
62 | },
63 | {
64 | "orientation" : "portrait",
65 | "idiom" : "ipad",
66 | "filename" : "Default-Portrait@2x.png",
67 | "extent" : "full-screen",
68 | "minimum-system-version" : "7.0",
69 | "scale" : "2x"
70 | },
71 | {
72 | "orientation" : "landscape",
73 | "idiom" : "ipad",
74 | "filename" : "Default-Landscape@2x.png",
75 | "extent" : "full-screen",
76 | "minimum-system-version" : "7.0",
77 | "scale" : "2x"
78 | },
79 | {
80 | "orientation" : "portrait",
81 | "idiom" : "iphone",
82 | "filename" : "Default.png",
83 | "extent" : "full-screen",
84 | "scale" : "1x"
85 | },
86 | {
87 | "orientation" : "portrait",
88 | "idiom" : "iphone",
89 | "filename" : "Default@2x.png",
90 | "extent" : "full-screen",
91 | "scale" : "2x"
92 | },
93 | {
94 | "orientation" : "portrait",
95 | "idiom" : "iphone",
96 | "filename" : "Default-568h@2x.png",
97 | "extent" : "full-screen",
98 | "subtype" : "retina4",
99 | "scale" : "2x"
100 | },
101 | {
102 | "orientation" : "portrait",
103 | "idiom" : "ipad",
104 | "extent" : "to-status-bar",
105 | "scale" : "1x"
106 | },
107 | {
108 | "orientation" : "portrait",
109 | "idiom" : "ipad",
110 | "filename" : "Default-Portrait.png",
111 | "extent" : "full-screen",
112 | "scale" : "1x"
113 | },
114 | {
115 | "orientation" : "landscape",
116 | "idiom" : "ipad",
117 | "extent" : "to-status-bar",
118 | "scale" : "1x"
119 | },
120 | {
121 | "orientation" : "landscape",
122 | "idiom" : "ipad",
123 | "filename" : "Default-Landscape.png",
124 | "extent" : "full-screen",
125 | "scale" : "1x"
126 | },
127 | {
128 | "orientation" : "portrait",
129 | "idiom" : "ipad",
130 | "extent" : "to-status-bar",
131 | "scale" : "2x"
132 | },
133 | {
134 | "orientation" : "portrait",
135 | "idiom" : "ipad",
136 | "filename" : "Default-Portrait@2x.png",
137 | "extent" : "full-screen",
138 | "scale" : "2x"
139 | },
140 | {
141 | "orientation" : "landscape",
142 | "idiom" : "ipad",
143 | "extent" : "to-status-bar",
144 | "scale" : "2x"
145 | },
146 | {
147 | "orientation" : "landscape",
148 | "idiom" : "ipad",
149 | "filename" : "Default-Landscape@2x.png",
150 | "extent" : "full-screen",
151 | "scale" : "2x"
152 | }
153 | ],
154 | "info" : {
155 | "version" : 1,
156 | "author" : "xcode"
157 | }
158 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve, join } = require("path");
2 |
3 | const webpack = require("webpack");
4 | const nsWebpack = require("nativescript-dev-webpack");
5 | const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
6 | const CopyWebpackPlugin = require("copy-webpack-plugin");
7 | const ExtractTextPlugin = require("extract-text-webpack-plugin");
8 | const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
9 |
10 | const { AotPlugin } = require("@ngtools/webpack");
11 |
12 | const mainSheet = `app.css`;
13 |
14 | module.exports = env => {
15 | const platform = getPlatform(env);
16 |
17 | // Default destination inside platforms//...
18 | const path = resolve(nsWebpack.getAppPath(platform));
19 |
20 | const entry = {
21 | // Discover entry module from package.json
22 | bundle: `./${nsWebpack.getEntryModule()}`,
23 |
24 | // Vendor entry with third-party libraries
25 | vendor: `./vendor`,
26 |
27 | // Entry for stylesheet with global application styles
28 | [mainSheet]: `./${mainSheet}`,
29 | };
30 |
31 | const rules = getRules();
32 | const plugins = getPlugins(platform, env);
33 | const extensions = getExtensions(platform);
34 |
35 | const config = {
36 | context: resolve("./app"),
37 | target: nativescriptTarget,
38 | entry,
39 | output: {
40 | pathinfo: true,
41 | path,
42 | libraryTarget: "commonjs2",
43 | filename: "[name].js",
44 | },
45 | resolve: {
46 | extensions,
47 |
48 | // Resolve {N} system modules from tns-core-modules
49 | modules: [
50 | "node_modules/tns-core-modules",
51 | "node_modules",
52 | ],
53 |
54 | alias: {
55 | '~': resolve("./app")
56 | },
57 | },
58 | node: {
59 | // Disable node shims that conflict with NativeScript
60 | "http": false,
61 | "timers": false,
62 | "setImmediate": false,
63 | "fs": "empty",
64 | },
65 | module: { rules },
66 | plugins,
67 | };
68 |
69 | if (env.snapshot) {
70 | plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
71 | chunk: "vendor",
72 | projectRoot: __dirname,
73 | webpackConfig: config,
74 | targetArchs: ["arm", "arm64", "ia32"],
75 | tnsJavaClassesOptions: { packages: ["tns-core-modules" ] },
76 | useLibs: false
77 | }));
78 | }
79 |
80 | return config;
81 | };
82 |
83 |
84 | function getPlatform(env) {
85 | return env.android ? "android" :
86 | env.ios ? "ios" :
87 | () => { throw new Error("You need to provide a target platform!") };
88 | }
89 |
90 | function getRules() {
91 | return [
92 | {
93 | test: /\.html$|\.xml$/,
94 | use: [
95 | "raw-loader",
96 | ]
97 | },
98 | // Root stylesheet gets extracted with bundled dependencies
99 | {
100 | test: new RegExp(mainSheet),
101 | use: ExtractTextPlugin.extract([
102 | {
103 | loader: "resolve-url-loader",
104 | options: { silent: true },
105 | },
106 | {
107 | loader: "nativescript-css-loader",
108 | options: { minimize: false }
109 | },
110 | "nativescript-dev-webpack/platform-css-loader",
111 | ]),
112 | },
113 | // Other CSS files get bundled using the raw loader
114 | {
115 | test: /\.css$/,
116 | exclude: new RegExp(mainSheet),
117 | use: [
118 | "raw-loader",
119 | ]
120 | },
121 | // SASS support
122 | {
123 | test: /\.scss$/,
124 | use: [
125 | "raw-loader",
126 | "resolve-url-loader",
127 | "sass-loader",
128 | ]
129 | },
130 |
131 |
132 | // Compile TypeScript files with ahead-of-time compiler.
133 | {
134 | test: /\.ts$/,
135 | loaders: [
136 | "nativescript-dev-webpack/tns-aot-loader",
137 | "@ngtools/webpack",
138 | ]
139 | }
140 |
141 | ];
142 | }
143 |
144 | function getPlugins(platform, env) {
145 | let plugins = [
146 | new ExtractTextPlugin(mainSheet),
147 |
148 | // Vendor libs go to the vendor.js chunk
149 | new webpack.optimize.CommonsChunkPlugin({
150 | name: ["vendor"],
151 | }),
152 |
153 | // Define useful constants like TNS_WEBPACK
154 | new webpack.DefinePlugin({
155 | "global.TNS_WEBPACK": "true",
156 | }),
157 |
158 | // Copy assets to out dir. Add your own globs as needed.
159 | new CopyWebpackPlugin([
160 | { from: mainSheet },
161 | { from: "css/**" },
162 | { from: "fonts/**" },
163 | { from: "**/*.jpg" },
164 | { from: "**/*.png" },
165 | { from: "**/*.xml" },
166 | ], { ignore: ["App_Resources/**"] }),
167 |
168 | // Generate a bundle starter script and activate it in package.json
169 | new nsWebpack.GenerateBundleStarterPlugin([
170 | "./vendor",
171 | "./bundle",
172 | ]),
173 |
174 | // Generate report files for bundles content
175 | new BundleAnalyzerPlugin({
176 | analyzerMode: "static",
177 | openAnalyzer: false,
178 | generateStatsFile: true,
179 | reportFilename: join(__dirname, "report", `report.html`),
180 | statsFilename: join(__dirname, "report", `stats.json`),
181 | }),
182 |
183 | // Angular AOT compiler
184 | new AotPlugin({
185 | tsConfigPath: "tsconfig.aot.json",
186 | entryModule: resolve(__dirname, "app/app.module#AppModule"),
187 | typeChecking: false
188 | }),
189 |
190 | // Resolve .ios.css and .android.css component stylesheets, and .ios.html and .android component views
191 | new nsWebpack.UrlResolvePlugin({
192 | platform: platform,
193 | resolveStylesUrls: true,
194 | resolveTemplateUrl: true
195 | }),
196 |
197 | ];
198 |
199 | if (env.uglify) {
200 | plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));
201 |
202 | // Work around an Android issue by setting compress = false
203 | const compress = platform !== "android";
204 | plugins.push(new webpack.optimize.UglifyJsPlugin({
205 | mangle: { except: nsWebpack.uglifyMangleExcludes },
206 | compress,
207 | }));
208 | }
209 |
210 | return plugins;
211 | }
212 |
213 | // Resolve platform-specific modules like module.android.js
214 | function getExtensions(platform) {
215 | return Object.freeze([
216 | `.${platform}.ts`,
217 | `.${platform}.js`,
218 | ".aot.ts",
219 | ".ts",
220 | ".js",
221 | ".css",
222 | `.${platform}.css`,
223 | ]);
224 | }
225 |
--------------------------------------------------------------------------------
/app/+task/components/task-list/task-list.component.ts:
--------------------------------------------------------------------------------
1 | import { Task } from './../../../models/Task';
2 | import { Observable } from 'rxjs/Observable';
3 | import { Component, OnInit, ViewContainerRef } from '@angular/core';
4 | import { Color } from 'tns-core-modules/color';
5 | import { Store } from '@ngrx/store';
6 | import { IAppState, getTasks, getCompletedTasks, getPendingTasks, TaskState } from '../../../store/app.state';
7 | import { Page } from 'tns-core-modules/ui/page';
8 | import { View, layout } from 'tns-core-modules/ui/core/view';
9 | import { ListViewEventData, RadListView, SwipeActionsEventData } from 'nativescript-telerik-ui/listview';
10 | import { Actions } from '@ngrx/effects';
11 |
12 | import { isAndroid } from 'tns-core-modules/platform';
13 |
14 | import { NSDate } from '../../../utils/Date';
15 |
16 | import { default as taskActions } from '../../../store/actions/task.actions';
17 | import { ModalDialogService, ModalDialogOptions } from 'nativescript-angular/modal-dialog';
18 | import { TaskFormComponent } from '../task-form/task-form.component';
19 |
20 | export type SupportedFilters = 'all' | 'completed' | 'pending';
21 |
22 | @Component({
23 | moduleId: module.id,
24 | selector: 'ns-task-list',
25 | templateUrl: './task-list.component.html',
26 | styleUrls: ['./task-list.component.css']
27 | })
28 | export class TaskListComponent implements OnInit {
29 | // The collection to hold all tasks
30 | tasks$: Observable;
31 | // The collection to hold pending tasks test
32 | completedTasks$: Observable;
33 | // The collection to hold pending (incomplete) tasks
34 | pendingTasks$: Observable;
35 |
36 | leftThresholdPassed = false;
37 | rightThresholdPassed = false;
38 |
39 | private activeFilter: SupportedFilters = 'all';
40 |
41 | constructor(
42 | private page: Page,
43 | private vcRef: ViewContainerRef,
44 | private modalService: ModalDialogService,
45 | private actions$: Actions,
46 | private store$: Store) { }
47 |
48 | ngOnInit(): void {
49 | this.page.backgroundSpanUnderStatusBar = true;
50 | this.page.actionBarHidden = true;
51 | this.page.backgroundColor = new Color(NSDate.isDayTime() ? '#ff9d6e' : '#0061ef');
52 |
53 | this.tasks$ = this.store$.let(getTasks);
54 | this.completedTasks$ = this.store$.let(getCompletedTasks);
55 | this.pendingTasks$ = this.store$.let(getPendingTasks);
56 |
57 | this.store$.dispatch(new taskActions.FetchAction);
58 |
59 | this.onTaskDeleteSuccess();
60 | this.onTaskCompleteSuccess();
61 | }
62 |
63 | /**
64 | * Gets the collection to be displayed based on the active filter
65 | */
66 | get displayedTasks$(): Observable {
67 | return this.activeFilter === 'all' ?
68 | this.tasks$ : (this.activeFilter === 'completed' ? this.completedTasks$ : this.pendingTasks$);
69 | }
70 |
71 | /**
72 | * Sets the active filter for displaying segmented results
73 | * @param newFilter The new filter mode
74 | */
75 | setFilter(newFilter: SupportedFilters = 'all') {
76 | this.activeFilter = newFilter;
77 | }
78 |
79 | /**
80 | * Displays the modal for creating or updating a task
81 | * @param existingTask The task to update (optional)
82 | */
83 | displayForm(args?: ListViewEventData): void {
84 | this.displayedTasks$.take(1)
85 | .subscribe(tasks => {
86 | const existingTask = args ? tasks[args.index] : undefined;
87 | const options: ModalDialogOptions = {
88 | viewContainerRef: this.vcRef,
89 | context: existingTask,
90 | fullscreen: false, // defaults true on Phone
91 | };
92 | this.modalService.showModal(TaskFormComponent, options)
93 | .then(formData => {
94 | if (formData) {
95 | const task = new Task((Object).assign({}, existingTask, formData));
96 | // If the task has an id, update the task
97 | if (task.id !== null) {
98 | console.log('the task', task);
99 | task.update();
100 | this.store$.dispatch(new taskActions.UpdateAction(task));
101 | this.onTaskUpdateSuccess();
102 | }
103 | else {
104 | // otherwise initialize a new task
105 | task.initalize();
106 | this.store$.dispatch(new taskActions.CreateAction(task));
107 | this.onTaskCreateSuccess();
108 | }
109 | }
110 | });
111 | });
112 | }
113 |
114 | onLeftSwipeClick(args: ListViewEventData) {
115 | const listView: RadListView = args.object;
116 | listView.notifySwipeToExecuteFinished();
117 | }
118 |
119 | onRightSwipeClick(args: ListViewEventData) {
120 | const listView = args.object
121 | listView.notifySwipeToExecuteFinished();
122 | }
123 |
124 | onSwipeCellStarted(args: SwipeActionsEventData) {
125 | var swipeLimits = args.data.swipeLimits;
126 | var swipeView = args.swipeView;
127 | var leftItem = swipeView.getViewById('mark-view');
128 | var rightItem = swipeView.getViewById('delete-view');
129 | swipeLimits.left = swipeLimits.right = args.data.x > 0 ? swipeView.getMeasuredWidth() / 2 : swipeView.getMeasuredWidth() / 2;
130 | swipeLimits.threshold = swipeView.getMeasuredWidth();
131 | }
132 |
133 | onCellSwiping(args: SwipeActionsEventData) {
134 | var swipeLimits = args.data.swipeLimits;
135 | var swipeView = args.swipeView;
136 | var mainView = args.mainView;
137 | var leftItem: View = swipeView.getViewById('mark-view');
138 | var rightItem: View = swipeView.getViewById('delete-view');
139 |
140 | if (args.data.x > swipeView.getMeasuredWidth() / 4 && !this.leftThresholdPassed) {
141 | var markLabel = leftItem.getViewById('mark-text');
142 | this.leftThresholdPassed = true;
143 | } else if (args.data.x < -swipeView.getMeasuredWidth() / 4 && !this.rightThresholdPassed) {
144 | var deleteLabel = rightItem.getViewById('delete-text');
145 | this.rightThresholdPassed = true;
146 | }
147 | if (args.data.x > 0) {
148 | var leftDimensions = View.measureChild(
149 | leftItem.parent,
150 | leftItem,
151 | layout.makeMeasureSpec(Math.abs(args.data.x), layout.EXACTLY),
152 | layout.makeMeasureSpec(mainView.getMeasuredHeight(), layout.EXACTLY));
153 | View.layoutChild(leftItem.parent, leftItem, 0, 0, leftDimensions.measuredWidth, leftDimensions.measuredHeight);
154 | } else {
155 | var rightDimensions = View.measureChild(
156 | rightItem.parent,
157 | rightItem,
158 | layout.makeMeasureSpec(Math.abs(args.data.x), layout.EXACTLY),
159 | layout.makeMeasureSpec(mainView.getMeasuredHeight(), layout.EXACTLY));
160 |
161 | View.layoutChild(rightItem.parent, rightItem, mainView.getMeasuredWidth() - rightDimensions.measuredWidth, 0, mainView.getMeasuredWidth(), rightDimensions.measuredHeight);
162 | }
163 | }
164 |
165 | onSwipeCellFinished(args: SwipeActionsEventData) {
166 | const task: Task = new Task(args.swipeView.bindingContext);
167 | if (this.leftThresholdPassed) {
168 | if (!task.completed) {
169 | this.store$.dispatch(new taskActions.CompleteAction(task));
170 | }
171 | } else if (this.rightThresholdPassed) {
172 | this.store$.dispatch(new taskActions.DeleteAction(task.id));
173 | }
174 | this.leftThresholdPassed = false;
175 | this.rightThresholdPassed = false;
176 | }
177 |
178 | /**
179 | * Dispatches an action to clear all existing tasks
180 | * Reloads tasks on completion
181 | */
182 | clearTask(): void {
183 | this.store$.dispatch(new taskActions.ClearAction);
184 | this.reloadTasks();
185 | }
186 |
187 | get placeholderImage(): string {
188 | return `res://tasks_complete_${NSDate.isDayTime() ? 'day' : 'night'}`;
189 | }
190 |
191 | private onTaskUpdateSuccess(): void {
192 | this.actions$
193 | .ofType(TaskState.ActionTypes.UPDATE_SUCCESS)
194 | .take(1)
195 | .do(() => {
196 | this.reloadTasks();
197 | })
198 | .subscribe();
199 | }
200 |
201 | private onTaskCompleteSuccess(): void {
202 | this.actions$
203 | .ofType(TaskState.ActionTypes.COMPLETE_SUCCESS)
204 | .do(() => {
205 | this.reloadTasks();
206 | })
207 | .subscribe();
208 | }
209 |
210 | private onTaskCreateSuccess(): void {
211 | this.actions$
212 | .ofType(TaskState.ActionTypes.CREATE_SUCCESS)
213 | .take(1)
214 | .do(() => {
215 | this.reloadTasks();
216 | })
217 | .subscribe();
218 | }
219 |
220 | private onTaskDeleteSuccess(): void {
221 | this.actions$
222 | .ofType(TaskState.ActionTypes.DELETE_SUCCESS)
223 | .do(() => {
224 | console.log('delete success');
225 | this.reloadTasks();
226 | })
227 | .subscribe();
228 | }
229 |
230 | private reloadTasks(): void {
231 | this.store$.dispatch(new taskActions.FetchAction);
232 | }
233 | }
234 |
--------------------------------------------------------------------------------