├── platforms
└── .gitignore
├── src
├── pages
│ ├── help
│ │ ├── help.scss
│ │ ├── index.ts
│ │ ├── help.module.ts
│ │ ├── help.html
│ │ └── help.ts
│ ├── about
│ │ ├── about.scss
│ │ ├── index.ts
│ │ ├── about.module.ts
│ │ ├── about.html
│ │ └── about.ts
│ ├── login
│ │ ├── login.scss
│ │ ├── index.ts
│ │ ├── login.module.ts
│ │ ├── login.html
│ │ └── login.ts
│ ├── logout
│ │ ├── logout.scss
│ │ ├── index.ts
│ │ ├── logout.module.ts
│ │ ├── logout.html
│ │ └── logout.ts
│ ├── status
│ │ ├── status.scss
│ │ ├── index.ts
│ │ ├── status.module.ts
│ │ ├── status.html
│ │ └── status.ts
│ ├── unlock
│ │ ├── unlock.scss
│ │ ├── index.ts
│ │ ├── unlock.module.ts
│ │ ├── unlock.ts
│ │ └── unlock.html
│ ├── feedback
│ │ ├── feedback.scss
│ │ ├── index.ts
│ │ ├── feedback.module.ts
│ │ ├── feedback.ts
│ │ └── feedback.html
│ ├── setting
│ │ ├── setting.scss
│ │ ├── index.ts
│ │ ├── setting.module.ts
│ │ ├── setting.html
│ │ └── setting.ts
│ ├── dashboard
│ │ ├── dashboard.scss
│ │ ├── index.ts
│ │ ├── dashboard.module.ts
│ │ ├── dashboard.html
│ │ └── dashboard.ts
│ ├── botie-list
│ │ ├── botie-list.scss
│ │ ├── index.ts
│ │ ├── botie-list.module.ts
│ │ ├── botie-list.html
│ │ └── botie-list.ts
│ ├── giftie-list
│ │ ├── giftie-list.scss
│ │ ├── index.ts
│ │ ├── giftie-list.module.ts
│ │ ├── giftie-list.html
│ │ └── giftie-list.ts
│ ├── hostie-edit
│ │ ├── hostie-edit.scss
│ │ ├── index.ts
│ │ ├── hostie-edit.module.ts
│ │ ├── hostie-edit.html
│ │ └── hostie-edit.ts
│ ├── hostie-list
│ │ ├── hostie-list.scss
│ │ ├── index.ts
│ │ ├── hostie-list.module.ts
│ │ ├── hostie-list.html
│ │ └── hostie-list.ts
│ ├── botie-create
│ │ ├── botie-create.scss
│ │ ├── index.ts
│ │ ├── botie-create.module.ts
│ │ ├── botie-create.ts
│ │ └── botie-create.html
│ ├── botie-details
│ │ ├── botie-details.scss
│ │ ├── index.ts
│ │ ├── botie-details.module.ts
│ │ ├── botie-details.html
│ │ └── botie-details.ts
│ ├── hostie-create
│ │ ├── hostie-create.scss
│ │ ├── index.ts
│ │ ├── hostie-create.module.ts
│ │ ├── hostie-create.ts
│ │ └── hostie-create.html
│ ├── hostie-details
│ │ ├── hostie-details.scss
│ │ ├── index.ts
│ │ ├── hostie-details.module.ts
│ │ ├── hostie-details.html
│ │ └── hostie-details.ts
│ └── welcome
│ │ ├── index.ts
│ │ ├── welcome.scss
│ │ ├── welcome.module.ts
│ │ ├── welcome.html
│ │ └── welcome.ts
├── assets
│ ├── imgs
│ │ └── logo.png
│ └── icon
│ │ └── favicon.ico
├── app
│ ├── main.ts
│ ├── app.html
│ ├── app.scss
│ ├── app.component.ts
│ └── app.module.ts
├── config.ts
├── manifest.json
├── service-worker.js
├── index.html
└── theme
│ └── variables.scss
├── resources
├── .gitignore
├── icon.png
└── README.md
├── chatie.app.json
├── scripts
├── prepare-linux.sh
├── ios.sh
├── prepare-osx.sh
├── deploy-surge.sh
├── sync-version.sh
├── android.sh
├── ios-pro.sh
└── pre-push.sh
├── docs
└── images
│ └── ionic-angular-bot.jpg
├── bs-config.json
├── ionic.config.json
├── .editorconfig
├── .gitignore
├── tsconfig.json
├── .vscode
└── settings.json
├── .travis.yml
├── tslint.json
├── package.json
├── config.xml
├── LICENSE
└── README.md
/platforms/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !platforms.json
3 |
--------------------------------------------------------------------------------
/src/pages/help/help.scss:
--------------------------------------------------------------------------------
1 | page-help {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/about/about.scss:
--------------------------------------------------------------------------------
1 | page-about {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/login/login.scss:
--------------------------------------------------------------------------------
1 | page-login {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/logout/logout.scss:
--------------------------------------------------------------------------------
1 | page-logout {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/status/status.scss:
--------------------------------------------------------------------------------
1 | page-status {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/unlock/unlock.scss:
--------------------------------------------------------------------------------
1 | page-unlock {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/feedback/feedback.scss:
--------------------------------------------------------------------------------
1 | page-feedback {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/setting/setting.scss:
--------------------------------------------------------------------------------
1 | page-setting {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/dashboard/dashboard.scss:
--------------------------------------------------------------------------------
1 | page-dashboard {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/botie-list/botie-list.scss:
--------------------------------------------------------------------------------
1 | page-botie-list {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/giftie-list/giftie-list.scss:
--------------------------------------------------------------------------------
1 | page-giftie-list {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/hostie-edit/hostie-edit.scss:
--------------------------------------------------------------------------------
1 | page-hostie-edit {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/hostie-list/hostie-list.scss:
--------------------------------------------------------------------------------
1 | page-hostie-list {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/resources/.gitignore:
--------------------------------------------------------------------------------
1 | android/
2 | ios/
3 | wp8/
4 | splash.*
5 | *.md5
6 |
--------------------------------------------------------------------------------
/src/pages/botie-create/botie-create.scss:
--------------------------------------------------------------------------------
1 | page-botie-create {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/botie-details/botie-details.scss:
--------------------------------------------------------------------------------
1 | page-botie-details {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/hostie-create/hostie-create.scss:
--------------------------------------------------------------------------------
1 | page-hostie-create {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/chatie.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Chatie App",
3 | "baseref": "master"
4 | }
5 |
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chatie/app/HEAD/resources/icon.png
--------------------------------------------------------------------------------
/src/pages/hostie-details/hostie-details.scss:
--------------------------------------------------------------------------------
1 | page-hostie-details {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/about/index.ts:
--------------------------------------------------------------------------------
1 | export * from './about'
2 | export * from './about.module'
3 |
--------------------------------------------------------------------------------
/src/pages/help/index.ts:
--------------------------------------------------------------------------------
1 | export * from './help'
2 | export * from './help.module'
3 |
--------------------------------------------------------------------------------
/src/pages/login/index.ts:
--------------------------------------------------------------------------------
1 | export * from './login'
2 | export * from './login.module'
3 |
--------------------------------------------------------------------------------
/src/pages/logout/index.ts:
--------------------------------------------------------------------------------
1 | export * from './logout'
2 | export * from './logout.module'
3 |
--------------------------------------------------------------------------------
/src/pages/setting/index.ts:
--------------------------------------------------------------------------------
1 | export * from './setting'
2 | export * from './setting.module'
3 |
--------------------------------------------------------------------------------
/src/pages/status/index.ts:
--------------------------------------------------------------------------------
1 | export * from './status'
2 | export * from './status.module'
3 |
--------------------------------------------------------------------------------
/src/pages/unlock/index.ts:
--------------------------------------------------------------------------------
1 | export * from './unlock'
2 | export * from './unlock.module'
3 |
--------------------------------------------------------------------------------
/src/pages/welcome/index.ts:
--------------------------------------------------------------------------------
1 | export * from './welcome'
2 | export * from './welcome.module'
3 |
--------------------------------------------------------------------------------
/src/assets/imgs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chatie/app/HEAD/src/assets/imgs/logo.png
--------------------------------------------------------------------------------
/src/pages/feedback/index.ts:
--------------------------------------------------------------------------------
1 | export * from './feedback'
2 | export * from './feedback.module'
3 |
--------------------------------------------------------------------------------
/scripts/prepare-linux.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | echo "pretend to be prepared..."
5 |
--------------------------------------------------------------------------------
/src/assets/icon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chatie/app/HEAD/src/assets/icon/favicon.ico
--------------------------------------------------------------------------------
/src/pages/botie-list/index.ts:
--------------------------------------------------------------------------------
1 | export * from './botie-list'
2 | export * from './botie-list.module'
3 |
--------------------------------------------------------------------------------
/src/pages/dashboard/index.ts:
--------------------------------------------------------------------------------
1 | export * from './dashboard'
2 | export * from './dashboard.module'
3 |
--------------------------------------------------------------------------------
/src/pages/botie-create/index.ts:
--------------------------------------------------------------------------------
1 | export * from './botie-create'
2 | export * from './botie-create.module'
3 |
--------------------------------------------------------------------------------
/src/pages/giftie-list/index.ts:
--------------------------------------------------------------------------------
1 | export * from './giftie-list'
2 | export * from './giftie-list.module'
3 |
--------------------------------------------------------------------------------
/src/pages/hostie-edit/index.ts:
--------------------------------------------------------------------------------
1 | export * from './hostie-edit'
2 | export * from './hostie-edit.module'
3 |
--------------------------------------------------------------------------------
/src/pages/hostie-list/index.ts:
--------------------------------------------------------------------------------
1 | export * from './hostie-list'
2 | export * from './hostie-list.module'
3 |
--------------------------------------------------------------------------------
/docs/images/ionic-angular-bot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chatie/app/HEAD/docs/images/ionic-angular-bot.jpg
--------------------------------------------------------------------------------
/src/pages/botie-details/index.ts:
--------------------------------------------------------------------------------
1 | export * from './botie-details'
2 | export * from './botie-details.module'
3 |
--------------------------------------------------------------------------------
/src/pages/hostie-create/index.ts:
--------------------------------------------------------------------------------
1 | export * from './hostie-create'
2 | export * from './hostie-create.module'
3 |
--------------------------------------------------------------------------------
/src/pages/hostie-details/index.ts:
--------------------------------------------------------------------------------
1 | export * from './hostie-details'
2 | export * from './hostie-details.module'
3 |
--------------------------------------------------------------------------------
/src/pages/welcome/welcome.scss:
--------------------------------------------------------------------------------
1 | page-welcome {
2 | ion-slide {
3 | background-color: #32db64;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": 8100,
3 | "files": ["./www/**/*.{html,htm,css,js}"],
4 | "server": { "baseDir": "./www" }
5 | }
6 |
--------------------------------------------------------------------------------
/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Chatie",
3 | "app_id": "053e819b",
4 | "type": "ionic-angular",
5 | "integrations": {
6 | "cordova": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/scripts/ios.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | ionic cordova build ios \
5 | --aot \
6 | --minifyjs \
7 | --minifycss \
8 | --optimizejs \
9 | --prod \
10 | --release
11 |
--------------------------------------------------------------------------------
/scripts/prepare-osx.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | brew update
5 | brew cleanup
6 | brew cask cleanup
7 |
8 | brew install \
9 | moreutils \
10 | jq \
11 | shellcheck
12 |
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
2 |
3 | import { AppModule } from './app.module'
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule)
6 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | const pkg = require('../package.json')
2 | export const VERSION: string = pkg.version
3 |
4 | /**
5 | * Auth0 API Configuration
6 | */
7 | export const AUTH0_SETTINGS = {
8 | CLIENT_ID: 'kW2jmKVAO6xMY9H4fYPUtFJSSRJbe3sz',
9 | DOMAIN: 'zixia.auth0.com',
10 | }
11 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Chatie",
3 | "short_name": "Chatie",
4 | "start_url": "index.html",
5 | "display": "standalone",
6 | "icons": [{
7 | "src": "assets/imgs/logo.png",
8 | "sizes": "512x512",
9 | "type": "image/png"
10 | }],
11 | "background_color": "#4e8ef7",
12 | "theme_color": "#4e8ef7"
13 | }
14 |
--------------------------------------------------------------------------------
/src/pages/help/help.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { HelpPage } from './help'
4 |
5 | @NgModule({
6 | declarations: [
7 | HelpPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(HelpPage),
11 | ],
12 | })
13 | export class HelpPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/login/login.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { LoginPage } from './login'
4 |
5 | @NgModule({
6 | declarations: [
7 | LoginPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(LoginPage),
11 | ],
12 | })
13 | export class LoginPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/logout/logout.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { LogoutPage } from './logout'
4 |
5 | @NgModule({
6 | declarations: [
7 | LogoutPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(LogoutPage),
11 | ],
12 | })
13 | export class LogoutPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/unlock/unlock.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { UnlockPage } from './unlock'
4 |
5 | @NgModule({
6 | declarations: [
7 | UnlockPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(UnlockPage),
11 | ],
12 | })
13 | export class UnlockPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/about/about.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { AboutPage } from './about'
4 |
5 | @NgModule({
6 | declarations: [
7 | AboutPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(AboutPage),
11 | ],
12 | })
13 | export class AboutPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/setting/setting.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { SettingPage } from './setting'
4 |
5 | @NgModule({
6 | declarations: [
7 | SettingPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(SettingPage),
11 | ],
12 | })
13 | export class SettingPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/welcome/welcome.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { WelcomePage } from './welcome'
4 |
5 | @NgModule({
6 | declarations: [
7 | WelcomePage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(WelcomePage),
11 | ],
12 | })
13 | export class WelcomePageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/feedback/feedback.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { FeedbackPage } from './feedback'
4 |
5 | @NgModule({
6 | declarations: [
7 | FeedbackPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(FeedbackPage),
11 | ],
12 | })
13 | export class FeedbackPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/status/status.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { StatusPage } from './status'
4 |
5 | @NgModule({
6 | declarations: [
7 | StatusPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(StatusPage),
11 | ],
12 | })
13 | export class StatusPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/botie-list/botie-list.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { BotieListPage } from './botie-list'
4 |
5 | @NgModule({
6 | declarations: [
7 | BotieListPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(BotieListPage),
11 | ],
12 | })
13 | export class BotieListPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/dashboard/dashboard.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { DashboardPage } from './dashboard'
4 |
5 | @NgModule({
6 | declarations: [
7 | DashboardPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(DashboardPage),
11 | ],
12 | })
13 | export class DashboardPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/giftie-list/giftie-list.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { GiftieListPage } from './giftie-list'
4 |
5 | @NgModule({
6 | declarations: [
7 | GiftieListPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(GiftieListPage),
11 | ],
12 | })
13 | export class GiftieListPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/hostie-edit/hostie-edit.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { HostieEditPage } from './hostie-edit'
4 |
5 | @NgModule({
6 | declarations: [
7 | HostieEditPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(HostieEditPage),
11 | ],
12 | })
13 | export class HostieEditPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/hostie-list/hostie-list.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { HostieListPage } from './hostie-list'
4 |
5 | @NgModule({
6 | declarations: [
7 | HostieListPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(HostieListPage),
11 | ],
12 | })
13 | export class HostieListPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/botie-create/botie-create.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { BotieCreatePage } from './botie-create'
4 |
5 | @NgModule({
6 | declarations: [
7 | BotieCreatePage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(BotieCreatePage),
11 | ],
12 | })
13 | export class BotieCreatePageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/hostie-create/hostie-create.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { HostieCreatePage } from './hostie-create'
4 |
5 | @NgModule({
6 | declarations: [
7 | HostieCreatePage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(HostieCreatePage),
11 | ],
12 | })
13 | export class HostieCreatePageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/hostie-details/hostie-details.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 | import { HostieDetailsPage } from './hostie-details'
4 |
5 | @NgModule({
6 | declarations: [
7 | HostieDetailsPage,
8 | ],
9 | imports: [
10 | IonicPageModule.forChild(HostieDetailsPage),
11 | ],
12 | })
13 | export class HostieDetailsPageModule {}
14 |
--------------------------------------------------------------------------------
/src/pages/help/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Help
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Chatie is ChatBot manager in your pocket.
14 |
15 |
16 |
17 | Please learn more from
18 | https://www.chatie.io
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 2
9 |
10 | # We recommend you to keep these unchanged
11 | end_of_line = lf
12 | charset = utf-8
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/resources/README.md:
--------------------------------------------------------------------------------
1 | These are Cordova resources. You can replace icon.png and splash.png and run
2 | `ionic cordova resources` to generate custom icons and splash screens for your
3 | app. See `ionic cordova resources --help` for details.
4 |
5 | Cordova reference documentation:
6 |
7 | - Icons: https://cordova.apache.org/docs/en/latest/config_ref/images.html
8 | - Splash Screens: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/
9 |
--------------------------------------------------------------------------------
/scripts/deploy-surge.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | npm version
5 |
6 | npm run build:browser:prod
7 |
8 | echo app.chatie.io | tee www/CNAME
9 |
10 | cp -v resources/icon.png www/assets/imgs/logo.png
11 |
12 | #
13 | # NOTICE: we keep the domain chatie.surge.sh just for the CNAME alias of app.chatie.io.
14 | # chatie.surge.sh is a totally different site from app.chatie.io,
15 | # which means we should keep those two sites on surge.sh.
16 | #
17 | surge www/ app.chatie.io
18 |
--------------------------------------------------------------------------------
/src/pages/botie-details/botie-details.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core'
2 | import { IonicPageModule } from 'ionic-angular'
3 |
4 | import { QRCodeModule } from 'angularx-qrcode'
5 | import { WechatyModule } from '@chatie/angular'
6 |
7 | import { BotieDetailsPage } from './botie-details'
8 |
9 | @NgModule({
10 | declarations: [
11 | BotieDetailsPage,
12 | ],
13 | imports: [
14 | IonicPageModule.forChild(BotieDetailsPage),
15 | QRCodeModule,
16 | WechatyModule,
17 | ],
18 | })
19 | export class BotieDetailsPageModule {}
20 |
--------------------------------------------------------------------------------
/src/pages/welcome/welcome.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | slide1
5 |
6 |
7 |
8 |
9 | slide2
10 |
11 |
12 |
13 | slide3
14 |
15 |
16 |
17 |
18 |
19 | slide4/row
20 |
21 |
22 |
23 |
24 | Start Using My App
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/pages/status/status.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Status
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Web Socket API
16 |
17 |
18 |
19 |
20 | REST API
21 |
22 |
23 |
24 |
25 | Database
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/pages/help/help.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import { Brolog } from 'brolog'
9 |
10 | @IonicPage()
11 | @Component({
12 | selector: 'page-help',
13 | templateUrl: 'help.html',
14 | })
15 | export class HelpPage {
16 |
17 | constructor(
18 | public log: Brolog,
19 | public navCtrl: NavController,
20 | public navParams: NavParams,
21 | ) {
22 | this.log.verbose('HelpPage', 'constructor()')
23 | }
24 |
25 | public ionViewDidLoad() {
26 | this.log.verbose('HelpPage', 'ionViewDidLoad()')
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Menu
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 | {{ p.title }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/pages/status/status.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import { Brolog } from 'brolog'
9 |
10 | @IonicPage()
11 | @Component({
12 | selector: 'page-status',
13 | templateUrl: 'status.html',
14 | })
15 | export class StatusPage {
16 |
17 | constructor(
18 | public log: Brolog,
19 | public navCtrl: NavController,
20 | public navParams: NavParams,
21 | ) {
22 | this.log.verbose('StatusPage', 'constructor()')
23 | }
24 |
25 | public ionViewDidLoad() {
26 | this.log.verbose('StatusPage', 'ionViewDidLoad()')
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/feedback/feedback.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import { Brolog } from 'brolog'
9 |
10 | @IonicPage()
11 | @Component({
12 | selector: 'page-feedback',
13 | templateUrl: 'feedback.html',
14 | })
15 | export class FeedbackPage {
16 |
17 | constructor(
18 | public log: Brolog,
19 | public navCtrl: NavController,
20 | public navParams: NavParams,
21 | ) {
22 | this.log.verbose('FeedbackPage', 'constructor()')
23 | }
24 |
25 | public ionViewDidLoad() {
26 | this.log.verbose('FeedbackPage', 'ionViewDidLoad()')
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/logout/logout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Logout
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{ (auth.profile | async).nickname }}
18 | {{ (auth.profile | async).email }}
19 |
20 |
21 |
22 |
27 | Logout
28 |
29 |
30 |
31 | {{ auth.profile | async | json }}
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/app/app.scss:
--------------------------------------------------------------------------------
1 | // http://ionicframework.com/docs/theming/
2 |
3 |
4 | // App Global Sass
5 | // --------------------------------------------------
6 | // Put style rules here that you want to apply globally. These
7 | // styles are for the entire app and not just one component.
8 | // Additionally, this file can be also used as an entry point
9 | // to import other Sass files to be included in the output CSS.
10 | //
11 | // Shared Sass variables, which can be used to adjust Ionic's
12 | // default Sass variables, belong in "theme/variables.scss".
13 | //
14 | // To declare rules for a specific mode, create a child rule
15 | // for the .md, .ios, or .wp mode classes. The mode class is
16 | // automatically applied to the
element in the app.
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | *~
5 | *.sw[mnpcod]
6 | *.log
7 | *.tmp
8 | *.tmp.*
9 | log.txt
10 | *.sublime-project
11 | *.sublime-workspace
12 | npm-debug.log*
13 |
14 | .idea/
15 | .sourcemaps/
16 | .sass-cache/
17 | .tmp/
18 | .versions/
19 | coverage/
20 | dist/
21 | node_modules/
22 | tmp/
23 | temp/
24 | hooks/
25 | platforms/
26 | plugins/
27 | plugins/android.json
28 | plugins/ios.json
29 | www/
30 | $RECYCLE.BIN/
31 |
32 | .DS_Store
33 | Thumbs.db
34 | UserInterfaceState.xcuserstate
35 | yarn.lock
36 | t.*
37 | www.zip
38 | .io-config.json
39 | *.bak
40 | *.keystore
41 | project.zip
42 | Chatie*.apk
43 | Chatie*.ipa
44 | package-lock.json
45 | /res/
46 |
--------------------------------------------------------------------------------
/scripts/sync-version.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | VERSION=$(jq -r .version < package.json)
5 |
6 | MAJOR_MINOR=${VERSION%.*}
7 | PATCH=${VERSION##*.}
8 | PATCH_NEXT=$((PATCH+1))
9 |
10 | VERSION_NEXT="$MAJOR_MINOR.$PATCH_NEXT"
11 |
12 | #
13 | # Sync the App version to package.json
14 | #
15 | sed -i.bak \
16 | '/"io.chatie.app" version="/s/version="[^"]*"/version="'"$VERSION_NEXT"'"/' \
17 | config.xml
18 |
19 | rm -f config.xml.bak
20 |
21 | MSG="bumping $VERSION -> $VERSION_NEXT"
22 | echo
23 | echo "$MSG"
24 | echo
25 |
26 | git add config.xml
27 |
28 | if git status | grep "nothing to commit" > /dev/null 2>&1; then
29 | echo 'Clean repository - nothing to commit.'
30 | else
31 | echo 'Prepareing to commit...'
32 | git commit -m "$MSG"
33 | fi
34 |
--------------------------------------------------------------------------------
/src/pages/feedback/feedback.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Feedback
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Join Wechaty Developers' Community
17 |
18 |
19 |
20 | Wechaty is used in many ChatBot projects by hundreds of developers. If you want to talk with other developers, just scan the following QR Code in WeChat with secret code **wechaty**, you can join our Wechaty Developers' Home at once.
21 |
22 |
23 |
24 |
25 |
26 | Scan now, because other Wechaty developers want to talk with you too! (secret code: _wechaty_)
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check out https://googlechromelabs.github.io/sw-toolbox/ for
3 | * more info on how to use sw-toolbox to custom configure your service worker.
4 | */
5 |
6 |
7 | 'use strict';
8 | importScripts('./build/sw-toolbox.js');
9 |
10 | self.toolbox.options.cache = {
11 | name: 'ionic-cache'
12 | };
13 |
14 | // pre-cache our key assets
15 | self.toolbox.precache(
16 | [
17 | './build/main.js',
18 | './build/vendor.js',
19 | './build/main.css',
20 | './build/polyfills.js',
21 | 'index.html',
22 | 'manifest.json'
23 | ]
24 | );
25 |
26 | // dynamically cache any other local assets
27 | self.toolbox.router.any('/*', self.toolbox.fastest);
28 |
29 | // for any other requests go to the network, cache,
30 | // and then only use that cached resource if your user goes offline
31 | self.toolbox.router.default = self.toolbox.networkFirst;
32 |
--------------------------------------------------------------------------------
/scripts/android.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | VERSION=$(jq -r .version < package.json)
5 |
6 | KEYSTORE='akamobi.keystore'
7 | [ -e "$KEYSTORE" ] || {
8 | >&2 echo "ERROR: Keystore $KEYSTORE not found."
9 | exit 1
10 | }
11 |
12 | APK_RELEASE_UNSIGNED='platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk'
13 | APK_RELEASE_SIGNED="Chatie-$VERSION.apk"
14 |
15 | # rm before re-build
16 | rm -f "$APK_RELEASE_UNSIGNED"
17 | ionic cordova build android --release
18 |
19 | jarsigner -verbose \
20 | -sigalg SHA1withRSA \
21 | -digestalg SHA1 \
22 | -keystore "$KEYSTORE" \
23 | -storepass "$ANDROID_SDK_KEYSTORE_PASSWORD_CHATIE" \
24 | "$APK_RELEASE_UNSIGNED" \
25 | release
26 |
27 | # rm before re-generate
28 | rm -f "$APK_RELEASE_SIGNED"
29 | /usr/lib/android-sdk/build-tools/*/zipalign -v 4 \
30 | "$APK_RELEASE_UNSIGNED" \
31 | "$APK_RELEASE_SIGNED" \
32 |
--------------------------------------------------------------------------------
/scripts/ios-pro.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | figlet 'ionic package build ios'
5 | buildId=$(ionic package build ios --release --profile prod | grep 'Build ID:' | awk '{print $3}') || buildId=-1
6 |
7 | if [ "$buildId" == "-1" ]; then
8 | >&2 echo 'ERROR: ionic build failed'
9 | fi
10 |
11 | ttl=10
12 | figlet "ionic package info $buildId"
13 | status=$(ionic package info "$buildId" | grep status | awk '{print $3}')
14 | while [ "$status" != "SUCCESS" -a "$ttl" -gt 0 ]; do
15 | sleep 10
16 | ((ttl--))
17 | echo "ionic package info $buildId: status=$status, ttl=$ttl"
18 | status=$(ionic package info "$buildId" | grep status | awk '{print $3}')
19 | done
20 |
21 | figlet "ionic package download $buildId"
22 | ionic package download "$buildId"
23 |
24 | version=$(jq -r .version < package.json)
25 | # mv "Chatie-$buildId.ipa" "Chatie-$version.ipa"
26 | mv "Chatie.ipa" "Chatie-$version.ipa"
27 |
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "noUnusedLocals": true
8 | , "noImplicitReturns": true
9 | , "noFallthroughCasesInSwitch": true
10 | , "strictNullChecks": true
11 | , "alwaysStrict": true
12 | , "noImplicitAny": false
13 | , "noImplicitThis": true,
14 | "lib": [
15 | "dom",
16 | "es2015",
17 | "esnext"
18 | ],
19 | "module": "es2015",
20 | "moduleResolution": "node",
21 | "sourceMap": true,
22 | "target": "es6"
23 | },
24 | "include": [
25 | "src/**/*.ts"
26 | ],
27 | "exclude": [
28 | "node_modules",
29 | "src/**/*.spec.ts",
30 | "src/**/__tests__/*.ts"
31 | ],
32 | "compileOnSave": false,
33 | "atom": {
34 | "rewriteTsconfig": false
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/pages/hostie-edit/hostie-edit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hostie Edit
5 |
6 |
7 |
11 | Save
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Name
26 |
30 |
31 |
32 |
33 | Note
34 |
38 |
39 |
40 |
41 |
42 |
43 | TOKEN: {{ hostie.token }}
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/pages/login/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Login
5 |
6 |
7 |
11 | Sign In
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Currently we are in Alpha stage, login will only support login via Github.
24 | If you want to join Chatie, please login by authorize your Github account.
25 |
26 |
27 |
28 |
33 |
34 |
35 | Login
36 |
37 |
38 |
39 |
40 |
41 |
42 | Chatie v{{ version }}
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/pages/hostie-details/hostie-details.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hostie Details
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ hostie.name }}
19 |
20 |
21 |
22 | {{ hostie.note }}
23 |
24 |
25 |
26 |
27 |
Hostie environment:
28 |
29 | Wechaty v{{ hostie.version }}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 | {{ hostie.token }}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "typescript.tsdk": "node_modules/typescript/lib",
4 | "editor.tabSize": 2,
5 | "window.zoomLevel": 0,
6 | "editor.minimap.enabled": true,
7 | "files.exclude": {
8 | ".sourcemaps/": true
9 | , "node_modules/": true
10 | , "www/": true
11 | , "platforms/": true
12 | , "hooks/": true
13 | , "res/": true
14 | , "resources/": true
15 | , "plugins": true
16 | }
17 | , "alignment": {
18 | "operatorPadding": "right"
19 | , "indentBase": "firstline"
20 | , "surroundSpace": {
21 | "colon": [1, 1], // The first number specify how much space to add to the left, can be negative. The second number is how much space to the right, can be negative.
22 | "assignment": [1, 1], // The same as above.
23 | "arrow": [1, 1], // The same as above.
24 | "comment": 2 // Special how much space to add between the trailing comment and the code.
25 | // If this value is negative, it means don't align the trailing comment.
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/unlock/unlock.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import { Brolog } from 'brolog'
9 |
10 | @IonicPage()
11 | @Component({
12 | selector: 'page-unlock',
13 | templateUrl: 'unlock.html',
14 | })
15 | export class UnlockPage {
16 |
17 | constructor(
18 | public log: Brolog,
19 | public navCtrl: NavController,
20 | public navParams: NavParams,
21 | ) {
22 | this.log.verbose('UnlockPage', 'constructor()')
23 | }
24 |
25 | public ionViewDidLoad() {
26 | this.log.verbose('UnlockPage', 'ionViewDidLoad()')
27 | }
28 |
29 | public securedPing() {
30 | // Here we use authHttp to make an authenticated
31 | // request to the server. Change the endpoint up for
32 | // one that points to your own server.
33 |
34 | // this.authHttp.get('http://localhost:3001/secured/ping')
35 | // .map(res => res.json())
36 | // .subscribe(
37 | // data => this.log.verbose('UnlockPage', 'securePing() data: %s', data.text),
38 | // err => this.log.verbose('UnlockPage', 'securePing() err: %s', err),
39 | // )
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/pages/setting/setting.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Setting
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Notification
18 |
21 |
22 |
23 |
27 | About
28 |
29 |
30 |
34 | Help
35 |
36 |
37 |
41 | Test Monitoring(Exception)
42 |
43 |
44 | I'm connected to the {{ deployChannel }}.
45 |
46 | Download Progress {{ downloadProgress }} / 100
47 |
48 |
49 | Opt in to Beta Features
50 |
51 |
52 |
53 |
57 | Logout
58 |
59 |
60 |
61 |
62 | {{ notificate }}
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/pages/welcome/welcome.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & SPA
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 | import { Component } from '@angular/core'
10 | import {
11 | IonicPage,
12 | NavController,
13 | NavParams,
14 | } from 'ionic-angular'
15 |
16 | import { Brolog } from 'brolog'
17 | import { DashboardPage } from '../dashboard/'
18 | // import { LoginPage } from '../login/'
19 |
20 | @IonicPage()
21 | @Component({
22 | selector: 'page-welcome',
23 | templateUrl: 'welcome.html',
24 | })
25 |
26 | export class WelcomePage {
27 |
28 | constructor(
29 | public log: Brolog,
30 | public navCtrl: NavController,
31 | public navParams: NavParams,
32 | ) {
33 | this.log.verbose('WelcomePage', 'constructor()')
34 | }
35 |
36 | public ionViewDidLoad() {
37 | this.log.verbose('WelcomePage', 'ionViewDidLoad()')
38 | }
39 |
40 | public async goToDashboard() {
41 | this.log.verbose('WelcomePage', 'goToDashboard()')
42 |
43 | try {
44 | await this.navCtrl.setRoot(DashboardPage)
45 | } catch (e) {
46 | this.log.warn('WelcomePage', 'goToDashboard() exception:%s', e.message)
47 | // await this.navCtrl.push(LoginPage)
48 | }
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/pages/dashboard/dashboard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dashboard
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 | Boties
19 |
20 | {{ botieOnlineNum }} / {{ botieList.length }}
21 |
22 |
23 |
24 |
28 | Hosties
29 |
32 | {{ hostieOnlineNum }} / {{ hostieList.length }}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | News
42 |
43 |
44 |
45 | Wechaty APP Published, Cheers!
46 | Thanks Ionic Creator, We can build
47 | Wechaty APP in a week.
48 |
49 |
50 |
51 |
52 |
55 | Read more ...
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/pages/unlock/unlock.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Unlock Pro Features
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Our goal has always been to create the best free ChatBot manager. To help support the ongoing development of Wechaty, we also offer an optional upgrade with some advanced features that will appreciate.
13 |
14 |
15 |
16 |
17 |
18 | Free
19 |
20 |
21 | Pro
22 |
23 |
24 |
25 |
26 |
27 | Realtime Notification
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Unlimited Hosties
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 | ALREADY PURCHASED
54 |
55 |
56 |
60 | PURCHASE($4.99)
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/scripts/pre-push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # An example hook script to verify what is about to be committed.
4 | # Called by "git commit" with no arguments. The hook should
5 | # exit with non-zero status after issuing an appropriate message if
6 | # it wants to stop the commit.
7 | #
8 | # To enable this hook, rename this file to "pre-commit".
9 | set -e
10 |
11 | [ -n "$NO_HOOK" ] && exit 0
12 |
13 | [ -n "$GIT_INNER_PRE_HOOK" ] && {
14 | # http://stackoverflow.com/a/21334985/1123955
15 | exit 0
16 | }
17 |
18 | npm run lint
19 |
20 | [ -z "$CYGWIN" ] && {
21 | # git rebase
22 |
23 | scripts/sync-version.sh
24 |
25 | rm -f package-lock.json
26 | npm version patch --no-package-lock
27 | GIT_INNER_PRE_HOOK=1 git push
28 |
29 | cat <<'_STR_'
30 | ____ _ _ ____ _
31 | / ___(_) |_ | _ \ _ _ ___| |__
32 | | | _| | __| | |_) | | | / __| '_ \
33 | | |_| | | |_ | __/| |_| \__ \ | | |
34 | \____|_|\__| |_| \__,_|___/_| |_|
35 |
36 | ____ _ _
37 | / ___| _ _ ___ ___ ___ ___ __| | |
38 | \___ \| | | |/ __/ __/ _ \/ _ \/ _` | |
39 | ___) | |_| | (_| (_| __/ __/ (_| |_|
40 | |____/ \__,_|\___\___\___|\___|\__,_(_)
41 |
42 | _STR_
43 |
44 | echo
45 | echo
46 | echo
47 | echo " ### Npm verion bumped and pushed by inner push inside hook pre-push ###"
48 | echo " ------- vvvvvvv outer push will be canceled, never mind vvvvvvv -------"
49 | echo
50 | echo
51 | exit 127
52 | }
53 |
54 | # must run this after the above `test` ([ -z ...]),
55 | # or will whow a error: error: failed to push some refs to 'git@github.com:wechaty/wechaty.git'
56 | echo "PRE-PUSH HOOK PASSED"
57 | echo
58 |
--------------------------------------------------------------------------------
/src/pages/botie-list/botie-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Botie List
8 |
9 |
10 | 3"
14 | >
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
31 |
32 |
35 |
36 |
39 |
40 | {{ botie.name || 'Unnamed Botie' }}
41 |
42 |
43 | {{botie.note}}
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 | Trash
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Notice: we only support 4 Botie in Alpha stage for testing.
64 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/pages/botie-create/botie-create.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | } from 'ionic-angular'
6 |
7 | import { Brolog } from 'brolog'
8 | import cuid from 'cuid'
9 |
10 | import {
11 | Botie,
12 | BotieStore,
13 | Status,
14 | } from '@chatie/db'
15 |
16 | @IonicPage()
17 | @Component({
18 | selector: 'page-botie-create',
19 | templateUrl: 'botie-create.html',
20 | })
21 | export class BotieCreatePage {
22 | private token: string
23 | private name: string
24 | private note: string
25 |
26 | public loading: boolean
27 |
28 | constructor(
29 | public log: Brolog,
30 | public botieStore: BotieStore,
31 | public navCtrl: NavController,
32 | ) {
33 | this.log.verbose('BotieCreatePage', 'constructor()')
34 |
35 | this.token = cuid()
36 | this.name = 'Botie #' + this.token.substr(-2, 2)
37 | this.note = ''
38 |
39 | this.loading = false
40 | }
41 |
42 | public ionViewDidLoad() {
43 | this.log.verbose('BotieCreatePage', 'ionViewDidLoad()')
44 | }
45 |
46 | public async save() {
47 | this.log.verbose('BotieCreatePage', 'save()')
48 | this.loading = true
49 |
50 | const newBotie: Botie = {
51 | token: this.token,
52 | name: this.name,
53 | note: this.note,
54 | status: Status.OFF,
55 | }
56 |
57 | this.log.silly('BotieCreatePage', 'save() newBotie: %s', JSON.stringify(newBotie))
58 |
59 | this.botieStore.create({
60 | name: this.name,
61 | token: this.token,
62 | }).then(() => {
63 | this.navCtrl.pop()
64 | })
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/pages/hostie-list/hostie-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hostie List
8 |
9 |
10 | 3"
14 | >
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
31 |
32 |
35 |
36 |
39 |
40 | {{ hostie.name || 'Unnamed Hostie' }}
41 |
42 |
43 | {{hostie.note}}
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 | Trash
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Notice: we only support 4 Hostie in Alpha stage for testing.
64 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/pages/hostie-create/hostie-create.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | } from 'ionic-angular'
6 |
7 | import { Brolog } from 'brolog'
8 | import cuid from 'cuid'
9 |
10 | import {
11 | Hostie,
12 | HostieStore,
13 | Status,
14 | } from '@chatie/db'
15 |
16 | @IonicPage()
17 | @Component({
18 | selector: 'page-hostie-create',
19 | templateUrl: 'hostie-create.html',
20 | })
21 | export class HostieCreatePage {
22 | private token: string
23 | private name: string
24 | private note: string
25 |
26 | public loading: boolean
27 |
28 | constructor(
29 | public log: Brolog,
30 | public hostieStore: HostieStore,
31 | public navCtrl: NavController,
32 | ) {
33 | this.log.verbose('HostieCreatePage', 'constructor()')
34 |
35 | this.token = cuid()
36 | this.name = 'Hostie #' + this.token.substr(-2, 2)
37 | this.note = ''
38 |
39 | this.loading = false
40 | }
41 |
42 | public ionViewDidLoad() {
43 | this.log.verbose('HostieCreatePage', 'ionViewDidLoad()')
44 | }
45 |
46 | public async save() {
47 | this.log.verbose('HostieCreatePage', 'save()')
48 | this.loading = true
49 |
50 | const newHostie: Hostie = {
51 | token: this.token,
52 | name: this.name,
53 | note: this.note,
54 | status: Status.OFF,
55 | }
56 |
57 | this.log.silly('HostieCreatePage', 'save() newHostie: %s', JSON.stringify(newHostie))
58 |
59 | this.hostieStore.create({
60 | name: this.name,
61 | token: this.token,
62 | }).then(() => {
63 | this.navCtrl.pop()
64 | })
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/pages/hostie-create/hostie-create.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | New Hostie
5 |
6 |
7 |
11 | Save
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
29 |
30 | Hostie
31 |
32 |
33 | The place where bot lives in.
34 |
35 |
36 |
37 |
38 | Token
39 |
43 |
44 |
45 |
46 | Name
47 |
51 |
52 |
53 |
54 | Note
55 |
58 |
59 |
60 |
61 |
62 |
63 |
What is a Hostie?
64 |
65 |
66 | Hostie is the home for Botie. In order to make a Botie work, you need a Hostie to run Botie.
67 |
68 |
69 |
More technic:
70 |
71 |
72 |
73 | Hostie is a Wechaty Runtime with CPU & Memory & Network resources.
74 |
75 | Botie is a group of Functions(Gifties) that you want your bot behavior.
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 10
4 |
5 | os:
6 | - linux
7 | - osx
8 |
9 | cache:
10 | directories:
11 | - node_modules
12 |
13 | before_install:
14 | - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then travis_retry scripts/prepare-linux.sh; fi
15 | - if [ "$TRAVIS_OS_NAME" == 'osx' ]; then travis_retry scripts/prepare-osx.sh; fi
16 |
17 | install: travis_retry npm install
18 |
19 | script:
20 | - echo $TRAVIS_OS_NAME
21 | - npm version
22 | - ionic --version
23 | - cordova --version
24 | - ng --version
25 | - npm test
26 |
27 | after_success:
28 | - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then echo 'TODO update coverage'; fi
29 |
30 | stages:
31 | - test
32 | - pack
33 | - name: deploy
34 | if: (type = push) AND branch =~ ^(master|v\d+\.\d+)$
35 |
36 | jobs:
37 | include:
38 |
39 | - stage: pack
40 | script:
41 | - npm run test:pack && echo 'Npm pack testing is passed'
42 |
43 | - stage: deploy
44 | script:
45 | - echo "Building Web Pages ..."
46 | - npm run build:browser:prod
47 | - echo 'app.chatie.io' | tee www/CNAME
48 | - cp resources/icon.png www/assets/imgs/logo.png
49 | - echo "Deploying to Surge.sh ..."
50 |
51 | deploy:
52 | provider: surge
53 | project: www/
54 | domain: app.chatie.io
55 | skip_cleanup: true
56 | on:
57 | all_branches: true
58 |
59 | notifications:
60 | webhooks:
61 | urls:
62 | - https://webhooks.gitter.im/e/41a19fbf1d54a04e5217
63 | on_success: always # options: [always|never|change] default: always
64 | on_failure: always # options: [always|never|change] default: always
65 | on_start: never # options: [always|never|change] default: always
66 | email:
67 | on_success: change
68 | on_failure: change
69 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chatie
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/pages/botie-create/botie-create.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | New Botie
5 |
6 |
7 |
11 | Save
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
29 |
30 | Botie
31 |
32 |
33 | The place where bot lives in.
34 |
35 |
36 |
37 |
38 | Token
39 |
43 |
44 |
45 |
46 | Name
47 |
51 |
52 |
53 |
54 | Note
55 |
58 |
59 |
60 |
61 |
62 |
63 |
What is a Botie?
64 |
65 |
66 | A Botie is the configuration for your ChatBot. It's the right place to setup what your bot say when it receives new message, and what Giftie you want to install.
67 |
68 |
69 |
More technic:
70 |
71 |
72 |
73 | Botie is like package.json for NPM.
74 |
75 | Botie can install many Gifties and put them together as a group. Those Gifties is the Functions that you want your bot behavior.
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/pages/logout/logout.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Component,
3 | OnInit,
4 | } from '@angular/core'
5 | import {
6 | IonicPage,
7 | Loading,
8 | LoadingController,
9 | NavController,
10 | NavParams,
11 | } from 'ionic-angular'
12 |
13 | import { Auth } from 'auth-angular'
14 | import { Brolog } from 'brolog'
15 |
16 | import { LoginPage } from '../login/'
17 |
18 | @IonicPage()
19 | @Component({
20 | selector: 'page-logout',
21 | templateUrl: 'logout.html',
22 | })
23 | export class LogoutPage implements OnInit {
24 | public loading?: Loading
25 |
26 | constructor(
27 | public auth: Auth,
28 | public log: Brolog,
29 | public loadingCtrl: LoadingController,
30 | public navCtrl: NavController,
31 | public navParams: NavParams,
32 | ) {
33 | this.log.verbose('LogoutPage', 'constructor()')
34 | }
35 |
36 | public ngOnInit() {
37 | this.log.verbose('LogoutPage', 'ngOnInit()')
38 |
39 | this.auth.valid.first().toPromise().then(valid => {
40 | if (!valid) {
41 | this.logout()
42 | }
43 | })
44 | }
45 |
46 | public ionViewDidLoad() {
47 | this.log.verbose('LogoutPage', 'ionViewDidLoad()')
48 | }
49 |
50 | public async showLoader(): Promise {
51 | this.log.verbose('LogoutPage', 'showLoader()')
52 |
53 | if (this.loading) {
54 | await this.loading.dismissAll()
55 | }
56 | this.loading = this.loadingCtrl.create({
57 | content: 'Loading...',
58 | })
59 | await this.loading.present()
60 | }
61 |
62 | public hideLoader(): void {
63 | this.log.verbose('LogoutPage', 'hideLoader()')
64 |
65 | if (!this.loading) {
66 | return
67 | }
68 | this.loading.dismissAll()
69 | this.loading = undefined
70 | }
71 |
72 | public async logout() {
73 | this.log.verbose('LogoutPage', 'logout()')
74 |
75 | await this.showLoader()
76 | await this.auth.logout()
77 | await this.navCtrl.setRoot(LoginPage)
78 | await this.hideLoader()
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/pages/giftie-list/giftie-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Giftie List
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Giftie Management
17 |
18 |
19 |
20 |
21 |
22 | About
23 |
24 |
25 |
26 |
27 | Giftie are extensions of Wechaty functionality written by the community using our plugin development SDK.
28 |
29 |
30 | Are you interested in creating a Wechaty plugin? Check out our SDK and documentation to see exactly what plugins can do, how they work and how easy plugin development can be.
31 |
32 |
33 |
34 |
35 |
36 | VIEW DOCUMENTATION
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | {{ giftie.title }}
46 |
51 |
52 |
53 |
54 | {{ giftie.description }}
55 |
56 |
57 |
58 | 222 Installs
59 | 18 Stars
60 |
61 |
62 |
63 | Install
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
Giftie Management is part of our Pro pack.
72 |
73 |
Click below for a full list of all of the features included in out pro pack and to upgrade
74 |
75 |
76 |
82 |
83 | Unlock
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/pages/about/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | About
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 | Chatie v{{ version }}
18 |
19 |
20 |
25 |
26 | Rate Chatie
27 |
28 |
29 |
34 |
35 | Release Notes
36 |
37 |
38 |
43 |
44 | Feedback
45 |
46 |
47 |
52 |
53 | Status
54 |
55 |
56 |
61 |
62 | Help
63 |
64 |
65 |
70 |
71 | Check for Update
72 |
73 |
74 |
79 |
80 | Github
81 |
82 |
83 |
88 |
89 | Submit Issue
90 |
91 |
92 |
93 |
94 |
95 |
96 | Copyright © 2017-2018 ♥
97 | @zixia
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/pages/hostie-edit/hostie-edit.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | LoadingController,
5 | Loading,
6 | NavController,
7 | NavParams,
8 | } from 'ionic-angular'
9 |
10 | import { Brolog } from 'brolog'
11 |
12 | import {
13 | Hostie,
14 | HostieStore,
15 | } from '@chatie/db'
16 |
17 | @IonicPage()
18 | @Component({
19 | selector: 'page-hostie-edit',
20 | templateUrl: 'hostie-edit.html',
21 | })
22 | export class HostieEditPage {
23 | public hostie: Hostie
24 | public notify: (newHostie: Hostie) => Promise
25 |
26 | public loading: Loading | null
27 |
28 | constructor(
29 | public hostieStore: HostieStore,
30 | public log: Brolog,
31 | public loadingCtrl: LoadingController,
32 | public navCtrl: NavController,
33 | public navParams: NavParams,
34 | ) {
35 | this.log.verbose('HostieEditPage', 'constructor()')
36 |
37 | // XXX: why Object.assign ???
38 | this.hostie = Object.assign({}, navParams.get('hostie'))
39 | this.notify = navParams.get('notify')
40 | this.log.silly('HostieEditPage', 'constructor() hostie id:%s', this.hostie.id)
41 |
42 | }
43 |
44 | public ionViewDidLoad() {
45 | this.log.verbose('HostieEditPage', 'ionViewDidLoad()')
46 | }
47 |
48 | public async save() {
49 | this.log.verbose('HostieEditPage', 'save()')
50 |
51 | await this.showLoader()
52 | const ret = await this.hostieStore.update(
53 | this.hostie.id!,
54 | {
55 | name: this.hostie.name,
56 | note: this.hostie.note,
57 | },
58 | )
59 | await this.notify(this.hostie)
60 | this.hideLoader()
61 |
62 | this.log.silly('HostieEditPage', 'HostieStore.update() return: %s', JSON.stringify(ret))
63 |
64 | this.navCtrl.pop()
65 | }
66 |
67 | public showLoader() {
68 | this.log.verbose('HostieEditPage', 'showLoader()')
69 |
70 | this.loading = this.loadingCtrl.create({
71 | content: 'Loading...',
72 | })
73 | return this.loading.present()
74 | }
75 |
76 | public hideLoader() {
77 | this.log.verbose('HostieEditPage', 'hideLoader()')
78 |
79 | if (!this.loading) {
80 | return
81 | }
82 | this.loading.dismissAll()
83 | this.loading = null
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/pages/botie-list/botie-list.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeDetectionStrategy,
3 | Component,
4 | OnInit,
5 | OnDestroy,
6 | } from '@angular/core'
7 | import {
8 | IonicPage,
9 | NavController,
10 | NavParams,
11 | // reorderArray,
12 | } from 'ionic-angular'
13 | import {
14 | // Observable,
15 | Subscription,
16 | } from 'rxjs/Rx'
17 |
18 | import { Brolog } from 'brolog'
19 |
20 | import {
21 | Botie,
22 | BotieStore,
23 | } from '@chatie/db'
24 |
25 | import { BotieCreatePage } from '../botie-create/'
26 | import { BotieDetailsPage } from '../botie-details/'
27 |
28 | @IonicPage()
29 | @Component({
30 | selector: 'page-botie-list',
31 | templateUrl: 'botie-list.html',
32 | changeDetection: ChangeDetectionStrategy.OnPush,
33 | })
34 | export class BotieListPage implements OnInit, OnDestroy {
35 | private botieListSubscription?: Subscription
36 |
37 | public botieList: Botie[]
38 |
39 | constructor(
40 | public botieStore: BotieStore,
41 | public log: Brolog,
42 | public navCtrl: NavController,
43 | public navParams: NavParams,
44 | ) {
45 | this.log.verbose('BotieListPage', 'constructor()')
46 | }
47 |
48 | public ngOnInit() {
49 | this.log.verbose('BotieListPage', 'ngOnInit()')
50 |
51 | this.botieListSubscription = this.botieStore.itemList.subscribe(list => {
52 | this.log.silly('BotieListPage', 'ngOnInit() this.botieStore.itemList.subscript() list.length=%d', list.length)
53 | this.botieList = list
54 | })
55 | }
56 |
57 | public ngOnDestroy() {
58 | this.log.verbose('BotieListPage', 'ngOnDestroy()')
59 |
60 | if (this.botieListSubscription) {
61 | this.botieListSubscription.unsubscribe()
62 | this.botieListSubscription = undefined
63 | }
64 | }
65 |
66 | public ionViewDidLoad() {
67 | this.log.verbose('BotieListPage', 'ionViewDidLoad()')
68 | }
69 |
70 | public gotoBotieDetail(botie: Botie, event: any) {
71 | this.log.verbose('BotieListPage', 'gotoBotieDetail({id:%s}, %s)', botie.id, event)
72 |
73 | this.navCtrl.push(BotieDetailsPage, {
74 | token: botie.token,
75 | })
76 | }
77 |
78 | public async trash(botie: Botie): Promise {
79 | this.log.verbose('BotieListPage', 'trash(%s)', botie.id)
80 | if (!botie.id) {
81 | throw new Error('no botie id')
82 | }
83 | await this.botieStore.delete(botie.id)
84 | }
85 |
86 | public add() {
87 | this.navCtrl.push(BotieCreatePage)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/theme/variables.scss:
--------------------------------------------------------------------------------
1 | // Ionic Variables and Theming. For more info, please see:
2 | // http://ionicframework.com/docs/theming/
3 |
4 | // Font path is used to include ionicons,
5 | // roboto, and noto sans fonts
6 | $font-path: "../assets/fonts";
7 |
8 |
9 | // The app direction is used to include
10 | // rtl styles in your app. For more info, please see:
11 | // http://ionicframework.com/docs/theming/rtl-support/
12 | $app-direction: ltr;
13 |
14 |
15 | @import "ionic.globals";
16 |
17 |
18 | // Shared Variables
19 | // --------------------------------------------------
20 | // To customize the look and feel of this app, you can override
21 | // the Sass variables found in Ionic's source scss files.
22 | // To view all the possible Ionic variables, see:
23 | // http://ionicframework.com/docs/theming/overriding-ionic-variables/
24 |
25 |
26 |
27 |
28 | // Named Color Variables
29 | // --------------------------------------------------
30 | // Named colors makes it easy to reuse colors on various components.
31 | // It's highly recommended to change the default colors
32 | // to match your app's branding. Ionic uses a Sass map of
33 | // colors so you can add, rename and remove colors as needed.
34 | // The "primary" color is the only required color in the map.
35 |
36 | $colors: (
37 | primary: #488aff,
38 | secondary: #32db64,
39 | danger: #f53d3d,
40 | light: #f4f4f4,
41 | dark: #222
42 | );
43 |
44 |
45 | // App iOS Variables
46 | // --------------------------------------------------
47 | // iOS only Sass variables can go here
48 |
49 |
50 |
51 |
52 | // App Material Design Variables
53 | // --------------------------------------------------
54 | // Material Design only Sass variables can go here
55 |
56 |
57 |
58 |
59 | // App Windows Variables
60 | // --------------------------------------------------
61 | // Windows only Sass variables can go here
62 |
63 |
64 |
65 |
66 | // App Theme
67 | // --------------------------------------------------
68 | // Ionic apps can have different themes applied, which can
69 | // then be future customized. This import comes last
70 | // so that the above variables are used and Ionic's
71 | // default are overridden.
72 |
73 | @import "ionic.theme.default";
74 |
75 |
76 | // Ionicons
77 | // --------------------------------------------------
78 | // The premium icon font for Ionic. For more info, please see:
79 | // http://ionicframework.com/docs/ionicons/
80 |
81 | @import "ionic.ionicons";
82 |
83 |
84 | // Fonts
85 | // --------------------------------------------------
86 |
87 | @import "roboto";
88 | @import "noto-sans";
89 |
--------------------------------------------------------------------------------
/src/pages/botie-details/botie-details.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Botie Details
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {{ token }}
30 |
31 |
32 |
33 |
34 |
35 | Congratulations! Wechaty is on duty.
36 |
Logined with user {{ user.name }}
37 |
38 |
39 |
40 |
45 |
46 |
47 |
48 | Wechaty Initializing...
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Heartbeat #{{ counter }}
58 | {{ timestamp }}
59 |
60 |
61 |
64 |
65 |
66 | {{ event.type }}
67 |
68 | at {{ event.time }}
69 |
70 |
71 |
72 |
73 |
74 |
75 | {{ message }}
76 |
77 |
78 |
79 |
80 |
95 |
96 |
103 |
104 |
109 | Logout
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/pages/giftie-list/giftie-list.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import { Brolog } from 'brolog'
9 |
10 | import { UnlockPage } from '../unlock'
11 |
12 | interface Giftie {
13 | icon: string,
14 | title: string,
15 | description: string,
16 | }
17 |
18 | @IonicPage()
19 | @Component({
20 | selector: 'page-giftie-list',
21 | templateUrl: 'giftie-list.html',
22 | })
23 | export class GiftieListPage {
24 | public gifties: Giftie[] = [
25 | {
26 | icon: 'undo',
27 | title: 'Auto Reply',
28 | description: `Send canned reply automatically for **keywords** set by you.`,
29 | },
30 | {
31 | icon: 'people',
32 | title: 'Auto Accept Friend Request',
33 | description: `Accept friend request for you automatically. Can set **keywords** to only accept request with that.`,
34 | },
35 | {
36 | icon: 'key',
37 | title: 'Room Inviter',
38 | description: `Send a room invitation to friend if received the specified **keywords**.`,
39 | },
40 | {
41 | icon: 'eye',
42 | title: 'Room Guardian',
43 | description: `Protect your **room topic** form being changed by others.`,
44 | },
45 | {
46 | icon: 'megaphone',
47 | title: 'Mass Message Sender',
48 | description: `Send messages to multiple users at once.`,
49 | },
50 | {
51 | icon: 'swap',
52 | title: 'Interpreter',
53 | description: `Transpose messages from one language into another, instantly and accurately.
54 | Speaker can use Text or Audio, audience will get Text in the **Target Language**.`,
55 | },
56 | {
57 | icon: 'film',
58 | title: 'Film Maker',
59 | description: `Concatenate multiple Videos/Audios that received.`,
60 | },
61 | {
62 | icon: 'images',
63 | title: 'Image Digester',
64 | description: `Read photo and tell you what's it.`,
65 | },
66 | {
67 | icon: 'eye',
68 | title: 'Message Tracker',
69 | description: `Notice you if any new message matches the keywords you set.`,
70 | },
71 | {
72 | icon: 'microphone',
73 | title: 'Speech Recongnizer',
74 | description: `Write down the text message in a speech for you.`,
75 | },
76 | ]
77 |
78 | constructor(
79 | public log: Brolog,
80 | public navCtrl: NavController,
81 | public navParams: NavParams,
82 | ) {
83 | this.log.verbose('GiftieListPage', 'constructor()')
84 | }
85 |
86 | public ionViewDidLoad() {
87 | this.log.verbose('GiftieListPage', 'ionViewDidLoad()')
88 | }
89 |
90 | public unlock() {
91 | this.navCtrl.push(UnlockPage)
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/tslint-eslint-rules/dist/rules"
4 | ],
5 | "rules": {
6 | "align": [
7 | true,
8 | "parameters",
9 | // "arguments",
10 | "statements"
11 | ],
12 | "jsdoc-require": [
13 | false
14 | ],
15 | "ban": false,
16 | "class-name": true,
17 | "comment-format": [
18 | true,
19 | "check-space"
20 | ],
21 | "curly": false,
22 | "eofline": true,
23 | "forin": false,
24 | "indent": [
25 | true,
26 | "spaces"
27 | ],
28 | "interface-name": false,
29 | "jsdoc-format": true,
30 | "label-position": true,
31 | "max-line-length": [
32 | true,
33 | 180
34 | ],
35 | "callable-types": true,
36 | "import-blacklist": [true, "rxjs"],
37 | "interface-over-type-literal": true,
38 | "no-empty-interface": true,
39 | "no-string-throw": true,
40 | "prefer-const": true,
41 | "unified-signatures": false,
42 | "no-inferrable-types": [true, "ignore-params"],
43 | "member-access": true,
44 | "member-ordering": [false],
45 | "no-any": false,
46 | "no-arg": true,
47 | "no-bitwise": true,
48 | "no-conditional-assignment": true,
49 | "no-consecutive-blank-lines": true,
50 | "no-console": [false],
51 | "no-construct": false,
52 | "no-debugger": true,
53 | "no-duplicate-variable": true,
54 | "no-empty": true,
55 | "no-eval": true,
56 | "no-internal-module": true,
57 | "no-require-imports": false,
58 | "no-shadowed-variable": true,
59 | "no-string-literal": false,
60 | "no-switch-case-fall-through": true,
61 | "no-trailing-whitespace": true,
62 | "no-unused-expression": true,
63 | "no-unused-variable": [true],
64 | "no-use-before-declare": true,
65 | "no-var-keyword": true,
66 | "no-var-requires": false,
67 | "object-literal-sort-keys": false,
68 | "one-line": [
69 | true,
70 | "check-open-brace",
71 | "check-whitespace"
72 | ],
73 | "quotemark": [
74 | true,
75 | "single",
76 | "avoid-escape"
77 | ],
78 | "radix": false,
79 | "semicolon": [true, "never"],
80 | "switch-default": false,
81 | "trailing-comma": [
82 | true,
83 | {
84 | "multiline": "always",
85 | "singleline": "never"
86 | }
87 | ],
88 | "triple-equals": [true],
89 | "typedef": [false],
90 | "typedef-whitespace": [
91 | false,
92 | {
93 | "call-signature": "space",
94 | "index-signature": "nospace",
95 | "parameter": "nospace",
96 | "property-declaration": "nospace",
97 | "variable-declaration": "nospace"
98 | }
99 | ],
100 | "variable-name": [
101 | true,
102 | "check-format",
103 | "allow-leading-underscore",
104 | "ban-keywords"
105 | ],
106 | "whitespace": [
107 | true,
108 | "check-branch",
109 | "check-decl",
110 | "check-operator",
111 | "check-separator",
112 | "check-type"
113 | ]
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/pages/hostie-list/hostie-list.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & SPA
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 |
10 | /**
11 | * An Introduction to Lists in Ionic 2
12 | * http://www.joshmorony.com/an-introduction-to-lists-in-ionic-2/
13 | *
14 | */
15 | import {
16 | ChangeDetectionStrategy,
17 | Component,
18 | OnInit,
19 | OnDestroy,
20 | } from '@angular/core'
21 | import {
22 | IonicPage,
23 | NavController,
24 | NavParams,
25 | reorderArray,
26 | } from 'ionic-angular'
27 | import {
28 | // Observable,
29 | Subscription,
30 | } from 'rxjs/Subscription'
31 |
32 | import { Brolog } from 'brolog'
33 |
34 | import {
35 | Hostie,
36 | HostieStore,
37 | Status,
38 | } from '@chatie/db'
39 |
40 | import { HostieCreatePage } from '../hostie-create/'
41 | import { HostieDetailsPage } from '../hostie-details/'
42 |
43 | @IonicPage()
44 | @Component({
45 | selector: 'page-hostie-list',
46 | templateUrl: 'hostie-list.html',
47 | changeDetection: ChangeDetectionStrategy.OnPush,
48 | })
49 |
50 | export class HostieListPage implements OnInit, OnDestroy {
51 | public hostieList: Hostie[]
52 | public hostieListSubscription: Subscription
53 |
54 | public reordering = false
55 |
56 | constructor(
57 | public log: Brolog,
58 | public hostieStore: HostieStore,
59 | public navCtrl: NavController,
60 | public navParams: NavParams,
61 | ) {
62 | this.log.verbose('HostieListPage', 'constructor()')
63 | }
64 |
65 | public ngOnInit() {
66 | this.log.verbose('HostieListPage', 'ngOnInit()')
67 |
68 | this.hostieListSubscription = this.hostieStore.itemList.subscribe(list => {
69 | this.log.silly('HostieListPage', 'ngOnInit() subscript list.length=%d', list.length)
70 | this.hostieList = list
71 | })
72 | }
73 |
74 | public ngOnDestroy() {
75 | this.log.verbose('HostieListPage', 'ngOnDestroy()')
76 |
77 | if (this.hostieListSubscription) {
78 | this.hostieListSubscription.unsubscribe()
79 | }
80 | }
81 |
82 | public gotoHostieDetail(hostie: Hostie, event: any) {
83 | this.log.verbose('HostieListPage', 'select(%s, %s)', hostie.id, event)
84 | this.navCtrl.push(HostieDetailsPage, {
85 | hostie,
86 | })
87 | }
88 |
89 | public toggleReordering() {
90 | this.reordering = !this.reordering
91 | }
92 |
93 | public reorder(indexes: number[]) {
94 | this.hostieList = reorderArray(this.hostieList, {from: 0, to: 1})
95 | // TODO: save to backend
96 | }
97 |
98 | public hostieIcon(hostie: Hostie) {
99 | this.log.verbose('HostieListPage', 'hostieIcon()')
100 |
101 | if (hostie.status === Status.ON) {
102 | return 'ios-home'
103 | }
104 | return 'ios-home-outline'
105 | }
106 |
107 | public async trash(hostie: Hostie): Promise {
108 | this.log.verbose('HostieListPage', 'trash(%s)', hostie.id)
109 | if (!hostie.id) {
110 | throw new Error('no hostie id')
111 | }
112 | await this.hostieStore.delete(hostie.id)
113 | }
114 |
115 | public add() {
116 | this.navCtrl.push(HostieCreatePage)
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/pages/login/login.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Component,
3 | OnInit,
4 | OnDestroy,
5 | } from '@angular/core'
6 | import {
7 | AlertController,
8 | IonicPage,
9 | LoadingController,
10 | Loading,
11 | NavController,
12 | } from 'ionic-angular'
13 |
14 | import {
15 | Subscription,
16 | } from 'rxjs/Subscription'
17 |
18 | import { Auth } from 'auth-angular'
19 | import { Brolog } from 'brolog'
20 |
21 | import { VERSION } from '../../config'
22 |
23 | import { DashboardPage } from '../dashboard/'
24 |
25 | @IonicPage()
26 | @Component({
27 | selector: 'page-login',
28 | templateUrl: 'login.html',
29 | })
30 | export class LoginPage implements OnInit, OnDestroy {
31 | private validSub?: Subscription
32 | private loading?: Loading
33 |
34 | public email: string
35 | public password: string
36 |
37 | public version: string
38 |
39 | constructor(
40 | public alertCtrl: AlertController,
41 | public auth: Auth,
42 | public log: Brolog,
43 | public loadingCtrl: LoadingController,
44 | public navCtrl: NavController,
45 | ) {
46 | this.log.verbose('LoginPage', 'constructor()')
47 |
48 | this.version = VERSION
49 | }
50 |
51 | public ngOnInit() {
52 | this.log.verbose('LoginPage', 'ngOnInit()')
53 |
54 | this.validSub = this.auth.valid.subscribe(valid => {
55 | this.log.verbose('LoginPage', 'ngOnInit() this.auth.valid.subscribe(valid=%s)', valid)
56 | if (valid) {
57 | this.onLogin()
58 | }
59 | })
60 | }
61 |
62 | // https://webcake.co/page-lifecycle-hooks-in-ionic-2/
63 | public ngOnDestroy() {
64 | this.log.verbose('LoginPage', 'ngOnDestroy()')
65 |
66 | if (this.validSub) {
67 | this.validSub.unsubscribe()
68 | }
69 | }
70 |
71 | public ionViewDidLoad() {
72 | this.log.verbose('LoginPage', 'ionViewDidLoad()')
73 | }
74 |
75 | public onLogin(): void {
76 | this.log.verbose('LoginPage', 'onLogin()')
77 | this.gotoDashboardPage()
78 | }
79 |
80 | public async login(): Promise {
81 | this.log.verbose('LoginPage', 'login()')
82 |
83 | this.auth.login()
84 |
85 | // } catch (e) {
86 | // this.log.warn('LoginPage', 'login() exception: %s', e && e.message || e)
87 |
88 | // this.alertCtrl.create({
89 | // title: 'Login Error',
90 | // subTitle: 'Exception: ' + e.message,
91 | // buttons: ['OK'],
92 | // }).present()
93 | // }
94 |
95 | }
96 |
97 | public async logout(): Promise {
98 | this.log.verbose('LoginPage', 'logout()')
99 |
100 | await this.auth.logout()
101 | this.navCtrl.setRoot(LoginPage)
102 | }
103 |
104 | public showLoader(): void {
105 | this.log.verbose('LoginPage', 'showLoader()')
106 |
107 | this.loading = this.loadingCtrl.create({
108 | content: 'Loading...',
109 | })
110 | this.loading.present()
111 | }
112 |
113 | public hideLoader(): void {
114 | this.log.verbose('LoginPage', 'hideLoader()')
115 |
116 | if (!this.loading) {
117 | return
118 | }
119 | this.loading.dismissAll()
120 | this.loading = undefined
121 | }
122 |
123 | public async gotoDashboardPage(): Promise {
124 | this.log.verbose('LoginPage', 'gotoDashboardPage()')
125 | try {
126 | await this.navCtrl.setRoot(DashboardPage)
127 | } catch (e) {
128 | this.log.verbose('LoginPage', 'gotoDashboardPage() exception:%s', e.message)
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/pages/hostie-details/hostie-details.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & SPA
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 | import {
10 | ChangeDetectionStrategy,
11 | ChangeDetectorRef,
12 | Component,
13 | } from '@angular/core'
14 |
15 | import {
16 | AlertController,
17 | IonicPage,
18 | NavController,
19 | NavParams,
20 | } from 'ionic-angular'
21 |
22 | import { Brolog } from 'brolog'
23 |
24 | import {
25 | Hostie,
26 | HostieStore,
27 | Status,
28 | Platform,
29 | } from '@chatie/db'
30 |
31 | import { HostieEditPage } from '../hostie-edit/'
32 |
33 | @IonicPage()
34 | @Component({
35 | selector: 'page-hostie-details',
36 | templateUrl: 'hostie-details.html',
37 | /**
38 | * http://stackoverflow.com/questions/34375624/angular-2-one-time-binding
39 | * https://angular.io/docs/ts/latest/api/core/index/ChangeDetectionStrategy-enum.html#!#OnPush-anchor
40 | * http://www.syntaxsuccess.com/viewarticle/change-detection-in-angular-2.0
41 | */
42 | changeDetection: ChangeDetectionStrategy.OnPush,
43 | })
44 | export class HostieDetailsPage {
45 | public hostie: Hostie
46 | public hostieStore: HostieStore
47 |
48 | constructor(
49 | public alertCtrl: AlertController,
50 | public log: Brolog,
51 | public cdRef: ChangeDetectorRef,
52 | public navCtrl: NavController,
53 | public navParams: NavParams,
54 | ) {
55 | this.log.verbose('HostieDetailsPage', 'constructor()')
56 |
57 | // If we navigated to this page, we will have an item available as a nav param
58 | this.hostie = navParams.get('hostie')
59 | this.log.silly('HostieDetailsPage', 'constructor() hostie id:%s', this.hostie.id)
60 | }
61 |
62 | public online(): boolean {
63 | this.log.verbose('HostieDetailsPage', 'online()')
64 | return this.hostie.status === Status.ON
65 | }
66 |
67 | public uptime(): number {
68 | this.log.verbose('HostieDetailsPage', 'uptime()')
69 | return Date.now() - 0 // FIXME
70 | }
71 |
72 | /**
73 | * http://ionicframework.com/docs/ionicons/
74 | */
75 | public icon(): string {
76 | switch (this.hostie.platform) {
77 | case Platform.UNKNOWN: return 'help'
78 | case Platform.DOCKER: return 'cube'
79 | case Platform.LINUX: return 'logo-tux'
80 | case Platform.WIN32: return 'logo-windows'
81 | case Platform.DARWIN: return 'logo-apple'
82 | default: return 'help'
83 | }
84 | }
85 |
86 | public copy() {
87 | this.alertCtrl.create({
88 | title: 'Copy TOKEN',
89 | subTitle: 'Use this string as WECHATY_TOKEN',
90 | inputs: [
91 | {
92 | label: 'Token',
93 | name: 'TOKEN',
94 | placeholder: 'Token',
95 | value: this.hostie.token,
96 | disabled: true,
97 | },
98 | ],
99 | buttons: ['Done'],
100 | }).present()
101 | }
102 |
103 | public edit() {
104 | this.log.verbose('HostieDetailsPage', 'edit() hostie #%s', this.hostie.id)
105 |
106 | this.navCtrl.push(HostieEditPage, {
107 | hostie: this.hostie,
108 | /**
109 | * [SOLVED] Ionic2 navController pop with params
110 | * https://forum.ionicframework.com/t/solved-ionic2-navcontroller-pop-with-params/58104
111 | */
112 | notify: (savedHostie: Hostie) => {
113 | this.log.verbose('HostieDetailsPage', 'edit() done() %s',
114 | JSON.stringify(savedHostie),
115 | )
116 | this.hostie = savedHostie
117 | this.cdRef.markForCheck()
118 | },
119 | })
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@chatie/app",
3 | "description": "Chatie App",
4 | "version": "0.2.49",
5 | "author": "Huan LI ",
6 | "homepage": "https://github.com/chatie/app/",
7 | "license": "Apache-2.0",
8 | "bugs": {
9 | "url": "https://github.com/chatie/app/issues"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/chatie/app.git"
14 | },
15 | "private": true,
16 | "scripts": {
17 | "build": "ionic-app-scripts build",
18 | "build:browser:prod": "ionic-app-scripts build --prod --aot",
19 | "clean": "ionic-app-scripts clean",
20 | "deploy:browser:surge": "bash scripts/deploy-surge.sh",
21 | "ionic:build": "ionic-app-scripts build",
22 | "ionic:build:browser": "ionic cordova build browser --aot --prod",
23 | "ionic:monitoring:syncmaps": "(sleep 1 && echo \"y\n\" && sleep 1 && echo \"y\n\") | ionic monitoring syncmaps",
24 | "ionic:serve": "ionic-app-scripts serve",
25 | "lite:server": "lite-server",
26 | "lint": "npm run lint:ts && npm run lint:ionic",
27 | "lint:ts": "tslint --project tsconfig.json && tsc --noEmit",
28 | "lint:ionic": "ionic-app-scripts lint",
29 | "test": "npm run lint && echo To Be Test",
30 | "test:pack": "echo To Be Pack"
31 | },
32 | "dependencies": {
33 | "@angular/animations": "6.1.1",
34 | "@angular/common": "6.1.1",
35 | "@angular/compiler": "6.1.1",
36 | "@angular/compiler-cli": "6.1.1",
37 | "@angular/core": "6.1.1",
38 | "@angular/forms": "6.1.1",
39 | "@angular/http": "6.1.1",
40 | "@angular/platform-browser": "6.1.1",
41 | "@angular/platform-browser-dynamic": "6.1.1",
42 | "@auth0/angular-jwt": "^2.0.0",
43 | "@chatie/angular": "^0.4.8",
44 | "@chatie/db": "^0.8.21",
45 | "@chatie/graphql": "^0.6.7",
46 | "@ionic-native/core": "4.11.0",
47 | "@ionic-native/splash-screen": "4.11.0",
48 | "@ionic-native/status-bar": "4.11.0",
49 | "@ionic/pro": "^2.0.3",
50 | "@ionic/storage": "2.1.3",
51 | "angularx-qrcode": "^1.1.7",
52 | "auth-angular": "^0.4.5",
53 | "auth0-lock": "^11.5.1",
54 | "brolog": "^1.3.3",
55 | "cordova-android": "7.1.1",
56 | "cordova-browser": "5.0.3",
57 | "cordova-ios": "4.5.5",
58 | "cordova-plugin-device": "^2.0.1",
59 | "cordova-plugin-ionic": "^5.0.5",
60 | "cordova-plugin-ionic-keyboard": "^2.0.5",
61 | "cordova-plugin-ionic-webview": "^2.0.2",
62 | "cordova-plugin-splashscreen": "^5.0.2",
63 | "cordova-plugin-whitelist": "^1.3.3",
64 | "cuid": "^2.1.1",
65 | "graphql-tag": "^2.8.0",
66 | "ionic-angular": "3.9.2",
67 | "ionicons": "4.3.0",
68 | "jwt-decode": "^2.2.0",
69 | "moment": "^2.21.0",
70 | "rxjs": "6.2.2",
71 | "state-switch": "^0.6.2",
72 | "sw-toolbox": "3.6.0",
73 | "zone.js": "0.8.26"
74 | },
75 | "devDependencies": {
76 | "@angular/cli": "^6.1.2",
77 | "@ionic/app-scripts": "^3.1.8",
78 | "@types/auth0-lock": "^11.4.5",
79 | "@types/cuid": "^1.3.0",
80 | "@types/node": "^10.5.6",
81 | "babel-eslint": "^8.2.2",
82 | "cordova": "^8.0.0",
83 | "eslint": "^5.3.0",
84 | "git-scripts": "^0.2.1",
85 | "ionic": "^4.0.3",
86 | "lite-server": "^2.3.0",
87 | "surge": "^0.20.1",
88 | "typescript": "~3.0.1"
89 | },
90 | "cordova": {
91 | "plugins": {
92 | "cordova-plugin-whitelist": {},
93 | "cordova-plugin-device": {},
94 | "cordova-plugin-splashscreen": {},
95 | "cordova-plugin-ionic-webview": {},
96 | "cordova-plugin-ionic": {
97 | "APP_ID": "053e819b",
98 | "CHANNEL_NAME": "Master",
99 | "UPDATE_METHOD": "background",
100 | "WARN_DEBUG": "true",
101 | "UPDATE_API": "https://api.ionicjs.com",
102 | "MAX_STORE": "2"
103 | }
104 | },
105 | "platforms": [
106 | "ios",
107 | "browser"
108 | ]
109 | },
110 | "git": {
111 | "scripts": {
112 | "pre-push": "./scripts/pre-push.sh"
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/pages/dashboard/dashboard.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & SPA
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 | import {
10 | Component,
11 | OnInit,
12 | OnDestroy,
13 | } from '@angular/core'
14 | import {
15 | IonicPage,
16 | NavController,
17 | NavParams,
18 | } from 'ionic-angular'
19 | import {
20 | Subscription,
21 | } from 'rxjs/Rx'
22 |
23 | import { Auth } from 'auth-angular'
24 | import { Brolog } from 'brolog'
25 |
26 | import {
27 | Botie,
28 | BotieStore,
29 | // Giftie,
30 | GiftieStore,
31 | Status,
32 | Hostie,
33 | HostieStore,
34 | } from '@chatie/db'
35 |
36 | import { BotieListPage } from '../botie-list/'
37 | import { HostieListPage } from '../hostie-list/'
38 |
39 | @IonicPage()
40 | @Component({
41 | selector: 'page-dashboard',
42 | templateUrl: 'dashboard.html',
43 | })
44 | export class DashboardPage implements OnInit, OnDestroy {
45 | private hostieSubscription?: Subscription
46 | private botieSubscription?: Subscription
47 |
48 | public hostieList: Hostie[]
49 | public hostieOnlineNum: number
50 |
51 | public botieList: Botie[]
52 | public botieOnlineNum: number
53 |
54 | constructor(
55 | public auth: Auth,
56 | public botieStore: BotieStore,
57 | public hostieStore: HostieStore,
58 | public giftieStore: GiftieStore,
59 | public log: Brolog,
60 | public navCtrl: NavController,
61 | public navParams: NavParams,
62 | ) {
63 | this.log.verbose('DashboardPage', 'constructor()')
64 |
65 | this.hostieList = []
66 | this.hostieOnlineNum = 0
67 |
68 | this.botieList = []
69 | this.botieOnlineNum = 0
70 | }
71 |
72 | public ionViewDidLoad() {
73 | this.log.verbose('DashboardPage', 'ionViewDidLoad()')
74 | }
75 |
76 | // https://devdactic.com/ionic-auth-guards/
77 | public ionViewCanEnter() {
78 | this.log.verbose('DashboardPage', 'ionViewCanEnter()')
79 | return this.auth.valid.first().toPromise()
80 | }
81 |
82 | // https://webcake.co/page-lifecycle-hooks-in-ionic-2/
83 | public ngOnInit() {
84 | this.log.verbose('DashboardPage', 'ngOnInit()')
85 | // console.log(this.hostieStore)
86 | // console.log(this.hostieStore.itemList)
87 | // console.log(this.hostieStore.itemList.subscribe)
88 |
89 | this.botieSubscription = this.botieStore.itemList.subscribe(list => {
90 | this.log.verbose('DashboardPage', 'ngOnInit() botieStore.itemList.subscribe() list.length=%d', list.length)
91 | this.botieList = list
92 | this.botieOnlineNum = list
93 | .filter(item => item.status === Status.ON )
94 | .length
95 | })
96 |
97 | this.hostieSubscription = this.hostieStore.itemList.subscribe(list => {
98 | this.log.verbose('DashboardPage', 'ngOnInit() hostieStore.itemList.subscribe() list.length=%d', list.length)
99 | this.hostieList = list
100 | this.hostieOnlineNum = list
101 | .filter( item => item.status === Status.ON )
102 | .length
103 | })
104 |
105 | }
106 |
107 | public ngOnDestroy() {
108 | this.log.verbose('DashboardPage', 'ngOnDestroy()')
109 |
110 | if (this.botieSubscription) {
111 | this.botieSubscription.unsubscribe()
112 | this.botieSubscription = undefined
113 | }
114 |
115 | if (this.hostieSubscription) {
116 | this.hostieSubscription.unsubscribe()
117 | this.hostieSubscription = undefined
118 | }
119 |
120 | }
121 |
122 | public gotoHostieListPage() {
123 | this.log.verbose('DashboardPage', 'gotoHostieListPage()')
124 | this.navCtrl.push(HostieListPage)
125 | }
126 |
127 | public gotoBotieListPage() {
128 | this.log.verbose('DashboardPage', 'gotoBotieListPage()')
129 | this.navCtrl.push(BotieListPage)
130 | }
131 |
132 | // gotoBotieDetailsPage() {
133 | // this.log.verbose('DashboardPage', 'gotoBotieDetailsPage()')
134 | // this.navCtrl.push(BotieDetailsPage)
135 | // }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/src/pages/botie-details/botie-details.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 |
8 | import moment from 'moment'
9 |
10 | import { Brolog } from 'brolog'
11 |
12 | import {
13 | WechatyComponent,
14 | ScanInfo,
15 | UserInfo,
16 | } from '@chatie/angular'
17 |
18 | import {
19 | // Botie,
20 | } from '@chatie/db'
21 |
22 | interface WechatyEvent {
23 | type: 'scan' | 'login' | 'logout' | 'message' | 'error',
24 | time: string,
25 | data: string,
26 | }
27 |
28 | @IonicPage()
29 | @Component({
30 | selector: 'page-botie-details',
31 | templateUrl: 'botie-details.html',
32 | })
33 | export class BotieDetailsPage {
34 |
35 | public token: string
36 | public messageList: string[]
37 |
38 | public scanQrcodeValue: null | string
39 |
40 | public user: UserInfo | null
41 | public counter: number
42 |
43 | public timestamp: string
44 |
45 | public eventList: WechatyEvent[]
46 |
47 | // private botie: Botie
48 |
49 | constructor(
50 | public log: Brolog,
51 | public navCtrl: NavController,
52 | public navParams: NavParams,
53 | ) {
54 | this.token = navParams.get('token')
55 |
56 | this.log.verbose('BotieDetails', 'constructor() with token:%s', this.token)
57 | }
58 |
59 | public ionViewDidLoad() {
60 | this.log.verbose('BotieDetails', 'ionViewDidLoad()')
61 | }
62 |
63 | public ngOnInit() {
64 | this.log.verbose('BotieDetailsPage', 'ngOnInit()')
65 |
66 | this.eventList = []
67 | this.messageList = []
68 | this.counter = 0
69 | }
70 |
71 | public ngOnDestroy() {
72 | this.log.verbose('BotieDetailsPage', 'ngOnDestroy()')
73 | }
74 |
75 | public onMessage(msg: any) {
76 | this.log.verbose('BotieDetailsPage', 'onMessage(%s)', msg)
77 | this.messageList.push(msg)
78 | this.eventList.push({
79 | type: 'message',
80 | time: moment().format('LTS'),
81 | data: msg,
82 | })
83 | }
84 |
85 | public onHeartbeat(e: any) {
86 | this.log.silly('BotieDetailsPage', 'onHeartbeat(%s)', e)
87 | this.counter++
88 | this.timestamp = moment().format('LTS')
89 | }
90 |
91 | public onScan(scan: ScanInfo) {
92 | this.log.verbose('BotieDetailsPage', 'onScan(%s)', JSON.stringify(scan))
93 |
94 | this.scanQrcodeValue = scan.qrcode
95 |
96 | // console.log(scan)
97 |
98 | this.eventList.push({
99 | type: 'scan',
100 | time: moment().format('LTS'),
101 | data: scan.qrcode,
102 | })
103 | }
104 |
105 | public onLogin(user: UserInfo) {
106 | this.log.verbose('BotieDetailsPage', 'onLogin(%s)', user.name)
107 | this.user = user
108 | this.scanQrcodeValue = null
109 |
110 | console.log(user)
111 |
112 | this.eventList.push({
113 | type: 'login',
114 | time: moment().format('LTS'),
115 | data: user.name,
116 | })
117 | }
118 |
119 | public onLogout(e: UserInfo) {
120 | this.log.verbose('BotieDetailsPage', 'onLogout(%s)', e.name)
121 | this.user = null
122 | this.eventList.push({
123 | type: 'logout',
124 | time: moment().format('LTS'),
125 | data: e.name,
126 | })
127 | }
128 |
129 | public onError(e: any) {
130 | this.log.verbose('BotieDetailsPage', 'onError(%s)', e)
131 | this.eventList.push({
132 | type: 'error',
133 | time: moment().format('LTS'),
134 | data: e,
135 | })
136 | }
137 |
138 | public shutdown(wechaty: WechatyComponent) {
139 | this.log.verbose('BotieDetailsPage', 'shutdown()')
140 | this.scanQrcodeValue = this.user = null
141 | wechaty.shutdown('by web bot component')
142 | }
143 |
144 | public logout(wechaty: WechatyComponent) {
145 | this.log.verbose('BotieDetailsPage', 'logout()')
146 | this.scanQrcodeValue = this.user = null
147 | wechaty.logoff('from chatie app')
148 | }
149 |
150 | public eventToIcon(eventName: string): string {
151 | switch (eventName) {
152 | case 'scan': return 'qr-scanner'
153 | case 'login': return 'log-in'
154 | case 'logout': return 'log-out'
155 | case 'message': return 'chatboxes'
156 | case 'error': return 'alert'
157 | default: return 'help'
158 | }
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/src/pages/about/about.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | AlertController,
4 | Loading,
5 | LoadingController,
6 | IonicPage,
7 | NavController,
8 | NavParams,
9 | ToastController,
10 | } from 'ionic-angular'
11 |
12 | import { Brolog } from 'brolog'
13 |
14 | import { HelpPage } from '../help/'
15 | import { StatusPage } from '../status/'
16 |
17 | @IonicPage()
18 | @Component({
19 | selector: 'page-about',
20 | templateUrl: 'about.html',
21 | })
22 | export class AboutPage {
23 | private loading: Loading | null = null
24 | public version = '0.0.0'
25 | public clickCounter = 0
26 |
27 | constructor(
28 | public alertCtrl: AlertController,
29 | public log: Brolog,
30 | public loadingCtrl: LoadingController,
31 | public navCtrl: NavController,
32 | public navParams: NavParams,
33 | public toastCtrl: ToastController,
34 | ) {
35 | this.log.verbose('AboutPage', 'constructor()')
36 | this.initVersion()
37 | }
38 |
39 | public initVersion() {
40 | this.log.verbose('AboutPage', 'getVersion()')
41 |
42 | try {
43 | // FIXME
44 | const packageJson = require('../../../package.json')
45 | this.version = packageJson.version
46 | } catch (e) {
47 | this.log.warn('AboutPage', 'getVersion() exception: %s', e.message)
48 | }
49 | }
50 |
51 | public ionViewDidLoad() {
52 | this.log.verbose('AboutPage', 'ionViewDidLoad()')
53 | }
54 |
55 | public help() {
56 | this.navCtrl.push(HelpPage)
57 | }
58 |
59 | public status() {
60 | this.navCtrl.push(StatusPage)
61 | }
62 |
63 | // async checkDeploy() {
64 | // this.log.verbose('AboutPage', 'check() clickCounter=%s', this.clickCounter)
65 |
66 | // if (this.loading) {
67 | // return
68 | // }
69 |
70 | // const MAX_NUM = 7
71 | // if (this.clickCounter <= MAX_NUM) {
72 | // this.toastCtrl.create({
73 | // message: (MAX_NUM - this.clickCounter).toString(),
74 | // duration: 500,
75 | // position: 'middle',
76 | // }).present()
77 |
78 | // this.clickCounter++
79 | // return
80 | // }
81 |
82 | // this.deploy.channel = 'dev'
83 | // this.showLoader()
84 |
85 | // try {
86 | // const hasUpdate = await this.deploy.check()
87 |
88 | // if (!hasUpdate) {
89 | // this.hideLoader()
90 |
91 | // this.toastCtrl.create({
92 | // message: 'You are cool!',
93 | // duration: 1500,
94 | // position: 'middle',
95 | // })
96 | // .present()
97 |
98 | // return
99 |
100 | // }
101 |
102 | // this.log.silly('AboutPage', 'checkDeploy() found new update!')
103 |
104 | // const metaData = this.deploy.getMetadata()
105 | // this.log.silly('AboutPage', 'check() metaData of update: %s', JSON.stringify(metaData))
106 |
107 | // this.log.silly('AboutPage', 'check() downloading...')
108 | // await this.deploy.download()
109 |
110 | // this.log.silly('AboutPage', 'check() extracting...')
111 | // await this.deploy.extract()
112 |
113 | // const snapshotList = await this.deploy.getSnapshots() as string[]
114 | // this.log.silly('AboutPage', 'check() we has %s snapshots: %s',
115 | // snapshotList.length,
116 | // snapshotList.join(','),
117 | // )
118 |
119 | // this.hideLoader()
120 |
121 | // this.log.silly('AboutPage', 'check() loading...')
122 | // this.deploy.load()
123 |
124 | // } catch (e) {
125 | // this.log.warn('AboutPage', 'check() exception: %s', e.message)
126 |
127 | // this.hideLoader()
128 | // this.alertCtrl.create({
129 | // title: 'Check Error',
130 | // subTitle: 'Exception: ' + e.message,
131 | // buttons: ['OK'],
132 | // }).present()
133 | // }
134 | // }
135 |
136 | public showLoader(): void {
137 | this.log.verbose('AboutPage', 'showLoader()')
138 |
139 | this.loading = this.loadingCtrl.create({
140 | content: 'Loading...',
141 | })
142 | this.loading.present()
143 | }
144 |
145 | public hideLoader(): void {
146 | this.log.verbose('AboutPage', 'hideLoader()')
147 |
148 | if (!this.loading) {
149 | return
150 | }
151 | this.loading.dismissAll()
152 | this.loading = null
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/src/pages/setting/setting.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core'
2 | import {
3 | IonicPage,
4 | NavController,
5 | NavParams,
6 | } from 'ionic-angular'
7 | import {
8 | Pro,
9 | } from '@ionic/pro'
10 |
11 | import { Brolog } from 'brolog'
12 |
13 | import { AboutPage } from '../about/'
14 | import { HelpPage } from '../help/'
15 | import { LogoutPage } from '../logout/'
16 |
17 | @IonicPage()
18 | @Component({
19 | selector: 'page-setting',
20 | templateUrl: 'setting.html',
21 | })
22 | export class SettingPage {
23 | public notificate = true
24 |
25 | public deployChannel = ''
26 | public isBeta = false
27 | public downloadProgress = 0
28 |
29 | constructor(
30 | public log: Brolog,
31 | public navCtrl: NavController,
32 | public navParams: NavParams,
33 | ) {
34 | this.log.verbose('SettingPage', 'constructor()')
35 | this.checkChannel()
36 | }
37 |
38 | public ionViewDidLoad() {
39 | this.log.verbose('SettingPage', 'ionViewDidLoad()')
40 | }
41 |
42 | public about() {
43 | this.navCtrl.push(AboutPage)
44 | }
45 |
46 | public help() {
47 | this.navCtrl.push(HelpPage)
48 | }
49 |
50 | public gotoLogoutPage() {
51 | this.navCtrl.push(LogoutPage)
52 | }
53 |
54 | public testMonitoring() {
55 |
56 | Pro.monitoring.exception(new Error('test Pro.monitoring.exception()'))
57 | Pro.monitoring.log('test Pro.monitoring.log() This happens sometimes for level: error', { level: 'error' })
58 |
59 | try {
60 | Pro.monitoring.call(() => {
61 | throw new Error('test Pro.monitoring.call() error')
62 | })
63 | } catch (e) {
64 | console.log('call function exception still be throwed to outside')
65 | }
66 |
67 | const newFn = Pro.monitoring.wrap(() => {
68 | throw new Error('test Pro.monitoring.wrap newFn() error')
69 | })
70 | try {
71 | newFn()
72 | } catch (e) {
73 | console.log('call wrap func error still be throwed to outside')
74 | }
75 |
76 | }
77 |
78 | /**
79 | * https://ionicframework.com/docs/pro/deploy/plugin-api.html
80 | */
81 | public async checkChannel() {
82 | try {
83 | const res = await Pro.deploy.info()
84 | this.deployChannel = res.channel || 'unknown(web?)'
85 | this.isBeta = (this.deployChannel === 'Beta')
86 | } catch (err) {
87 | // We encountered an error.
88 | // Here's how we would log it to Ionic Pro Monitoring while also catching:
89 |
90 | Pro.monitoring.exception(err)
91 | }
92 | }
93 |
94 | public async toggleBeta() {
95 | const config = {
96 | channel: (this.isBeta ? 'Beta' : 'Production'),
97 | }
98 |
99 | try {
100 | await Pro.deploy.init(config)
101 | await this.checkChannel()
102 | await this.performAutomaticUpdate() // Alternatively, to customize how this works, use performManualUpdate()
103 | } catch (err) {
104 | // We encountered an error.
105 | // Here's how we would log it to Ionic Pro Monitoring while also catching:
106 |
107 | Pro.monitoring.exception(err)
108 | }
109 |
110 | }
111 |
112 | public async performAutomaticUpdate() {
113 |
114 | /*
115 | This code performs an entire Check, Download, Extract, Redirect flow for
116 | you so you don't have to program the entire flow yourself. This should
117 | work for a majority of use cases.
118 | */
119 |
120 | try {
121 | const resp = await Pro.deploy.checkAndApply(true, progress => {
122 | this.downloadProgress = progress
123 | })
124 |
125 | if (resp.update) {
126 | // We found an update, and are in process of redirecting you since you put true!
127 | } else {
128 | // No update available
129 | }
130 | } catch (err) {
131 | // We encountered an error.
132 | // Here's how we would log it to Ionic Pro Monitoring while also catching:
133 |
134 | Pro.monitoring.exception(err)
135 | }
136 | }
137 |
138 | public async performManualUpdate() {
139 |
140 | /*
141 | Here we are going through each manual step of the update process:
142 | Check, Download, Extract, and Redirect.
143 | This code is currently exactly the same as performAutomaticUpdate,
144 | but you could split it out to customize the flow.
145 |
146 | Ex: Check, Download, Extract when a user logs into your app,
147 | but Redirect when they logout for an app that is always running
148 | but used with multiple users (like at a doctors office).
149 | */
150 |
151 | try {
152 | const haveUpdate = await Pro.deploy.check()
153 |
154 | if (haveUpdate) {
155 | this.downloadProgress = 0
156 |
157 | await Pro.deploy.download(progress => {
158 | this.downloadProgress = progress
159 | })
160 | await Pro.deploy.extract()
161 | await Pro.deploy.redirect()
162 | }
163 | } catch (err) {
164 | // We encountered an error.
165 | // Here's how we would log it to Ionic Pro Monitoring while also catching:
166 |
167 | Pro.monitoring.exception(err)
168 | }
169 |
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & SPA
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 | import {
10 | Component,
11 | ViewChild,
12 | } from '@angular/core'
13 | import {
14 | Platform,
15 | MenuController,
16 | Nav,
17 | } from 'ionic-angular'
18 | import {
19 | StatusBar,
20 | } from '@ionic-native/status-bar'
21 | import {
22 | SplashScreen,
23 | } from '@ionic-native/splash-screen'
24 | import { Auth } from 'auth-angular'
25 | import { Brolog } from 'brolog'
26 |
27 | // import { BotieListPage } from '../pages/botie-list/'
28 | import { DashboardPage } from '../pages/dashboard/'
29 | // import { HostieListPage } from '../pages/hostie-list/'
30 | // import { FeedbackPage } from '../pages/feedback/'
31 | import { LoginPage } from '../pages/login/'
32 | // import { SettingPage } from '../pages/setting/'
33 | // import { WelcomePage } from '../pages/welcome/'
34 |
35 | // Week Type Detection of TypeScript 2.4
36 | // https://blog.mariusschulz.com/2017/12/01/typescript-2-4-weak-type-detection
37 |
38 | @Component({
39 | templateUrl: 'app.html',
40 | })
41 | export class ChatieApp {
42 | @ViewChild(Nav) private nav: Nav
43 |
44 | public rootPage: any = DashboardPage
45 |
46 | public pages: Array<{
47 | title: string,
48 | icon: string,
49 | component: any,
50 | }>
51 |
52 | constructor(
53 | public auth: Auth,
54 | public log: Brolog,
55 | public menu: MenuController,
56 | public platform: Platform,
57 | public statusBar: StatusBar,
58 | public splashScreen: SplashScreen,
59 | ) {
60 | this.log.verbose('ChatieApp', 'constructor()')
61 |
62 | this.initializeApp()
63 |
64 | // set our app's pages
65 | this.pages = [
66 | { title: 'Dashboard' , icon: 'speedometer' , component: DashboardPage },
67 | // { title: 'Gifties' , icon: 'school' , component: GiftieListPage },
68 | // { title: 'Gifties' , icon: 'flash' , component: GiftieListPage },
69 | { title: 'Boties' , icon: 'logo-android', component: 'BotieListPage' },
70 | { title: 'Hosties' , icon: 'home' , component: 'HostieListPage' },
71 | { title: 'Setting' , icon: 'cog' , component: 'SettingPage' },
72 | { title: 'Feedback' , icon: 'people' , component: 'FeedbackPage' },
73 | ]
74 | }
75 |
76 | public async initializeApp() {
77 | this.log.verbose('ChatieApp', 'initializeApp()')
78 |
79 | const readySource = await this.platform.ready()
80 |
81 | this.log.silly('ChatieApp', 'initializeApp() platform.ready() return %s', readySource)
82 |
83 | // Okay, so the platform is ready and our plugins are available.
84 | // Here you can do any higher level native things you might need.
85 |
86 | // this.auth.idToken.subscribe(token => {
87 | // this.setupPush(!!token)
88 | // })
89 |
90 | this.statusBar.styleDefault()
91 | this.splashScreen.hide()
92 | /**
93 | * https://www.raymondcamden.com/2016/11/04/an-example-of-the-ionic-auth-service-with-ionic-2
94 | */
95 | this.auth.valid.subscribe(valid => {
96 | if (valid) {
97 | this.rootPage = DashboardPage
98 | } else {
99 | this.rootPage = LoginPage
100 | }
101 | })
102 |
103 | return readySource
104 | }
105 |
106 | public openPage(page: any) {
107 | this.log.verbose('ChatieApp', 'openPage(%s)', page.title || page)
108 |
109 | // close the menu when clicking a link from the menu
110 | this.menu.close()
111 |
112 | // Reset the content nav to have just this page
113 | // we wouldn't want the back button to show in this scenario
114 | this.nav.setRoot(page.component)
115 | }
116 |
117 | // /**
118 | // * Setup Push Service
119 | // */
120 | // async setupPush(push = true): Promise {
121 | // this.log.verbose('ChatieApp', 'setupPush(%s)', push)
122 |
123 | // try {
124 | // if (push) {
125 | // const pushToken = await this.push.register()
126 | // await this.push.saveToken(pushToken)
127 | // this.log.silly('ChatieApp', 'setupPush() push token saved: %s', pushToken)
128 |
129 | // this.pushSubscription = this.push.rx.notification().subscribe(msg => {
130 | // this.onPush(msg)
131 | // })
132 | // } else {
133 | // if (this.pushSubscription) {
134 | // this.pushSubscription.unsubscribe()
135 | // this.pushSubscription = null
136 | // }
137 | // await this.push.unregister()
138 | // }
139 | // } catch (e) {
140 | // this.log.warn('AppComponent', 'setupPush() exception:%s', e.message)
141 | // }
142 |
143 | // // do something with the push data
144 | // // then call finish to let the OS know we are done
145 | // // push.finish(function() {
146 | // // console.log("processing of push data is finished");
147 | // // }, function() {
148 | // // console.log("something went wrong with push.finish for ID = " + data.additionalData.notId)
149 | // // }, data.additionalData.notId);
150 |
151 | // }
152 |
153 | // onPush(msg: IPushMessage): void {
154 | // this.log.verbose('ChatieApp', 'onPush({title:%s,...})', msg.title)
155 | // alert(msg.title + ': ' + msg.text)
156 | // }
157 | }
158 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Chatie
4 | Your Cloud Bot Manager
5 | Chatie Team
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 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Chatie APP for Android & Ios & Web
3 | * Your ChatBot Pocket Manager
4 | *
5 | * https://github.com/chatie/app
6 | * Huan LI
7 | * License Apache-2.0
8 | */
9 | import { BrowserModule } from '@angular/platform-browser'
10 | import {
11 | APP_INITIALIZER,
12 | ErrorHandler,
13 | Injectable,
14 | Injector,
15 | NgModule,
16 | } from '@angular/core'
17 | import {
18 | IonicStorageModule,
19 | // Storage,
20 | } from '@ionic/storage'
21 |
22 | import {
23 | IonicApp,
24 | IonicModule,
25 | IonicErrorHandler,
26 | } from 'ionic-angular'
27 |
28 | // These are all imports required for Pro Client with Monitoring & Deploy,
29 | // feel free to merge into existing imports above.
30 | import { Pro } from '@ionic/pro'
31 | import { StatusBar } from '@ionic-native/status-bar'
32 | import { SplashScreen } from '@ionic-native/splash-screen'
33 |
34 | import { HttpClientModule } from '@angular/common/http'
35 |
36 | import {
37 | Brolog,
38 | log,
39 | } from 'brolog'
40 |
41 | // import { WechatyModule } from '@chatie/angular'
42 | import {
43 | DbModule,
44 | } from '@chatie/db'
45 |
46 | import { AuthModule } from 'auth-angular'
47 |
48 | import {
49 | VERSION,
50 | } from '../config'
51 |
52 | import { ChatieApp } from './app.component'
53 |
54 | const { app_id } = require('../../ionic.config.json')
55 | Pro.init(app_id, {
56 | appVersion: VERSION,
57 | })
58 |
59 | log.info('ChatieApp', 'v%s', VERSION)
60 |
61 | @Injectable()
62 | export class ProErrorHandler implements ErrorHandler {
63 | private ionicErrorHandler: IonicErrorHandler
64 |
65 | constructor(injector: Injector) {
66 | try {
67 | this.ionicErrorHandler = injector.get(IonicErrorHandler)
68 | } catch (e) {
69 | // Unable to get the IonicErrorHandler provider, ensure
70 | // IonicErrorHandler has been added to the providers list below
71 | throw e
72 | }
73 | }
74 |
75 | public handleError(err: any): void {
76 | Pro.monitoring.handleNewError(err)
77 | // Remove this if you want to disable Ionic's auto exception handling
78 | // in development mode.
79 | this.ionicErrorHandler.handleError(err)
80 | }
81 | }
82 |
83 | // const cloudSettings: CloudSettings = {
84 | // core: {
85 | // app_id, // : ionicConfig['app_id'],
86 | // },
87 | // push: {
88 | // sender_id: '673602949542',
89 | // pluginConfig: {
90 | // ios: {
91 | // badge: true,
92 | // sound: true,
93 | // },
94 | // android: {
95 | // iconColor: '#343434',
96 | // },
97 | // },
98 | // },
99 | // // 'database': {
100 | // // 'authType': 'authenticated',
101 | // // },
102 | // }
103 |
104 | /**
105 | * << Pages >>
106 | */
107 | import { AboutPageModule } from '../pages/about/'
108 | import { BotieCreatePageModule } from '../pages/botie-create/'
109 | import { BotieListPageModule } from '../pages/botie-list/'
110 | import { BotieDetailsPageModule } from '../pages/botie-details/'
111 | import { DashboardPageModule } from '../pages/dashboard/'
112 | import { FeedbackPageModule } from '../pages/feedback/'
113 | import { GiftieListPageModule } from '../pages/giftie-list/'
114 | import { HelpPageModule } from '../pages/help/'
115 | import { HostieDetailsPageModule } from '../pages/hostie-details/'
116 | import { HostieEditPageModule } from '../pages/hostie-edit/'
117 | import { HostieListPageModule } from '../pages/hostie-list/'
118 | import { HostieCreatePageModule } from '../pages/hostie-create/'
119 | import { LoginPageModule } from '../pages/login/'
120 | import { LogoutPageModule } from '../pages/logout/'
121 | import { SettingPageModule } from '../pages/setting/'
122 | import { StatusPageModule } from '../pages/status/'
123 | import { UnlockPageModule } from '../pages/unlock/'
124 | import { WelcomePageModule } from '../pages/welcome/'
125 |
126 | export function appInitializerFactory() {
127 | log.verbose('AppModule', 'appInitializerFactory()')
128 | // Be careful: this will block the ui when starting the app
129 | return appInit
130 |
131 | async function appInit () {
132 | log.verbose('AppModule', 'appInitializerFactory() appInit()')
133 | // FIXME: Should not wait db open()
134 | // design better observable to chain the events.
135 | // await db.open()
136 | }
137 | }
138 |
139 | @NgModule({
140 | declarations: [
141 | ChatieApp,
142 | // << Pages >>
143 | // BotieListPage,
144 | // BotieDetailsPage,
145 | // DashboardPage,
146 | // FeedbackPage,
147 | // GiftieListPage,
148 | // HelpPage,
149 | // HostieCreatePage,
150 | // HostieDetailsPage,
151 | // HostieEditPage,
152 | // HostieListPage,
153 | // LoginPage,
154 | // LogoutPage,
155 | // SettingPage,
156 | // StatusPage,
157 | // UnlockPage,
158 | // WelcomePage,
159 | ],
160 | imports: [
161 |
162 | // << Page Modules >>
163 |
164 | AboutPageModule,
165 | BrowserModule,
166 | BotieCreatePageModule,
167 | BotieDetailsPageModule,
168 | BotieListPageModule,
169 | DashboardPageModule,
170 | FeedbackPageModule,
171 | GiftieListPageModule,
172 | HelpPageModule,
173 | HostieCreatePageModule,
174 | HostieDetailsPageModule,
175 | HostieEditPageModule,
176 | HostieListPageModule,
177 | LoginPageModule,
178 | LogoutPageModule,
179 | SettingPageModule,
180 | StatusPageModule,
181 | UnlockPageModule,
182 | WelcomePageModule,
183 |
184 | // Others
185 |
186 | AuthModule.forRoot(),
187 | DbModule.forRoot(),
188 | HttpClientModule,
189 | IonicModule.forRoot(ChatieApp),
190 | IonicStorageModule.forRoot(),
191 | // WechatyModule,
192 | ],
193 | bootstrap: [IonicApp],
194 | entryComponents: [
195 | ChatieApp,
196 | // << Pages >>
197 | // BotieDetailsPage,
198 | // BotieListPage,
199 | // DashboardPage,
200 | // FeedbackPage,
201 | // GiftieListPage,
202 | // HelpPage,
203 | // HostieCreatePage,
204 | // HostieDetailsPage,
205 | // HostieEditPage,
206 | // HostieListPage,
207 | // LoginPage,
208 | // LogoutPage,
209 | // SettingPage,
210 | // StatusPage,
211 | // UnlockPage,
212 | // WelcomePage,
213 | ],
214 | providers: [
215 | IonicErrorHandler,
216 | StatusBar,
217 | SplashScreen,
218 | {
219 | provide: Brolog,
220 | useValue: log,
221 | },
222 | {
223 | provide: ErrorHandler,
224 | useClass: ProErrorHandler,
225 | },
226 | {
227 | provide: APP_INITIALIZER,
228 | useFactory: appInitializerFactory,
229 | deps: [],
230 | multi: true,
231 | },
232 | ],
233 | })
234 |
235 | export class AppModule {}
236 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2016-2018 Huan LI
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CHATIE APP
2 |
3 |
4 |
5 | Chatie App for Android & Ios & Web
6 |
7 | Chatie.io - Make your own ChatBot in no language, in minutes.
8 |
9 | 
10 | > Picture Credit:
11 |
12 | ## FEATURES
13 |
14 | * Passwordless Auth
15 | * Serverless Deploy
16 | * Languageless Programing
17 |
18 | ## DEVELOPMENT
19 |
20 | ### Linux
21 |
22 | OS: Ubuntu 17.10
23 |
24 | #### Install Android SDK
25 |
26 | ```shell
27 | sudo apt install \
28 | adb \
29 | android-platform-tools-base \
30 | android-sdk \
31 | android-sdk-platform-23 \
32 | android-sdk \
33 | android-sdk-platform-tools
34 |
35 | cd $ANDROID_HOME
36 | # download link comes from https://developer.android.com/studio/index.html
37 | wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
38 | sudo unzip -n sdk-tools-linux-3859397.zip
39 | sudo chmod +x \
40 | tools/bin/sdkmanager \
41 | tools/bin/avdmanager
42 |
43 | # XXX: make sure the following line is required...?
44 | sudo ./tools/bin/sdkmanager "build-tools;27.0.3"
45 |
46 | # IMPORTANT: Accept all the licenses
47 | ./tools/bin/sdkmanager --licenses
48 |
49 | ```
50 |
51 | #### Build Android APK
52 |
53 | ```shell
54 | ./scripts/android.sh
55 | ```
56 |
57 | ### Mac
58 |
59 | #### Install ...
60 |
61 | ```shell
62 | # Ios: https://cocoapods.org/
63 | $ sudo gem install cocoapods
64 | ```
65 |
66 | #### Build iOS IPA
67 |
68 | ```shell
69 | ./scripts/ios.sh
70 | ```
71 |
72 | ### Browser
73 |
74 | #### Build
75 |
76 | ```shell
77 | ionic cordova platform add browser
78 | ionic cordova build browser --prod
79 | ```
80 |
81 | ## APP PUBLISHING
82 |
83 | ### Google Play
84 |
85 | *
86 |
87 | ### Apple Store
88 |
89 | *
90 | *
91 |
92 | 1. Xcode -> Product ->
93 | 1. Build
94 | 1. Archive
95 |
96 | ### Web
97 |
98 | #### Develop
99 |
100 | #### Debug Switch
101 |
102 | By adding `?BROLOG_LEVEL=silly` to URL, you can enable full debug output messages in the console.
103 |
104 | For example:
105 |
106 | * https://localhost:8100/?BROLOG_LEVEL=silly
107 | * https://app.chatie.io/?BROLOG_LEVEL=silly
108 |
109 | ### Learning Resources
110 |
111 | #### Copy Cat Clone
112 |
113 | * [Build a WhatsApp Clone with Ionic 2, Angular 2, and Meteor!](https://blog.ionicframework.com/build-a-whatsapp-clone-with-ionic-2-angular-2-and-meteor/)
114 |
115 | #### Angular
116 |
117 | * [Angular Package Format v6.0](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview), design document at Google Docs
118 | * [How to Build an Angular 5 Material App](https://coursetro.com/posts/code/113/How-to-Build-an-Angular-5-Material-App)
119 |
120 | #### Material
121 |
122 | * [Angular Material And Angular 6 — Material Design For Angular](https://medium.com/codingthesmartway-com-blog/angular-material-and-angular-6-material-design-for-angular-6b1a3ee476f0)
123 |
124 | #### Auth0
125 |
126 | * [OAuth 2.0](https://auth0.com/docs/protocols/oauth2)
127 | * [Silent Authentication](https://auth0.com/docs/api-auth/tutorials/silent-authentication)
128 | * [Doc for Get User Info](https://auth0.com/docs/api/authentication#get-user-info)
129 | * [Calling your APIs with Auth0 tokens](https://auth0.com/docs/api-auth/tutorials/adoption/api-tokens)
130 | * [User profile claims and scope](https://auth0.com/docs/api-auth/tutorials/adoption/scope-custom-claims)
131 | * [Tokens used by Auth0](https://auth0.com/docs/tokens)
132 | * [What is the right setup for Lock + SPA + Native + Rest API?](https://community.auth0.com/t/what-is-the-right-setup-for-lock-spa-native-rest-api/6316/2)
133 | * [Auth0 Ionic2 Quick Start](https://auth0.com/docs/quickstart/native/ionic2)
134 | * [Ionic 2 and Auth0(outdated: v0.9)](http://blog.ionic.io/ionic-2-and-auth0/)
135 | * [Experimenting With Auth0 Passwordless Email Authentication In Angular 2.4.1](https://www.bennadel.com/blog/3207-experimenting-with-auth0-passwordless-email-authentication-in-angular-2-4-1.htm)
136 | * [OpenID Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)
137 | * [Server + API Architecture Scenario](https://auth0.com/docs/architecture-scenarios/application/server-api)
138 | * [Verify Access Tokens](https://auth0.com/docs/api-auth/tutorials/verify-access-token)
139 | * [Auth0 + Scaphold](https://scaphold.io/community/questions/scaphold-social-login/)
140 |
141 | <<<<<<< HEAD
142 | ### RxJS
143 | =======
144 | #### Rxjs
145 | >>>>>>> ec6237233f54b2f152977a6b8964732ce6f054c4
146 |
147 | How to use Observable.
148 |
149 | * [Observables for ECMAScript](https://github.com/tc39/proposal-observable)
150 | * [Migrating from RxJS 4 to 5](https://github.com/ReactiveX/rxjs/blob/master/MIGRATION.md)
151 |
152 | ##### Build from Scratch
153 |
154 | * [Creating Observable From Scratch(Video)](https://egghead.io/lessons/rxjs-creating-observable-from-scratch)
155 | * [Learning Observable By Building Observable](https://medium.com/@benlesh/learning-observable-by-building-observable-d5da57405d87)
156 |
157 | #### Others
158 |
159 | * [Functional Programming in Javascript](http://reactivex.io/learnrx/)
160 | * [How to build Angular 2 apps using Observable Data Services - Pitfalls to avoid](http://blog.angular-university.io/how-to-build-angular2-apps-using-rxjs-observable-data-services-pitfalls-to-avoid/)
161 | * [3 Common Rxjs Pitfalls that you might find while building Angular 2 Applications](http://blog.angular-university.io/angular-2-rxjs-common-pitfalls/)
162 | * [10 Need-to-Know RxJS Functions with Examples](https://www.sitepoint.com/rxjs-functions-with-examples/)
163 | * [Asynchronous Programming at Netflix - @Scale 2014 - Web](https://www.youtube.com/watch?v=gawmdhCNy-A)
164 | * [RxJS, the smartest dumbest tool ever](https://www.christianalfoni.com/articles/2016_03_31_RxJs-the-smartest-dumbest-tool-ever)
165 | * [COLD VS HOT OBSERVABLES](https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html#caveat-http-with-observables)
166 | * [The Difference Between Throttling and Debouncing](https://css-tricks.com/the-difference-between-throttling-and-debouncing/)
167 | * [RxJS: Don’t Unsubscribe](https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87)
168 |
169 | #### Machine Learning
170 |
171 | * [architecture-free neural network library for node.js and the browser](http://caza.la/synaptic)
172 |
173 | ### Progressive Web Apps
174 |
175 | A Progressive Web App(PWA) uses modern web capabilities to deliver an app-like user experience.
176 |
177 | * [Ionic PWA Doc](http://ionicframework.com/docs/v2/resources/progressive-web-apps/)
178 | * [Ionic PWA Blog](http://blog.ionic.io/navigating-the-world-of-progressive-web-apps-with-ionic-2/)
179 | * [Creating (near) native mobile web app (aka progressive web app) for iOS with Ionic 2](https://technology.amis.nl/2016/08/16/creating-near-native-mobile-web-app-aka-progressive-web-app-for-ios-with-ionic-2/)
180 |
181 | ### Database
182 |
183 | #### 1. GraphQL
184 |
185 | * [Zero to GraphQL in 30 Minutes – Steven Luscher](https://www.youtube.com/watch?v=UBGzsb2UkeY)
186 | * [New features in GraphQL: Batch, defer, stream, live, and subscribe](https://dev-blog.apollodata.com/new-features-in-graphql-batch-defer-stream-live-and-subscribe-7585d0c28b07#.tzc669fjv)
187 | * [GraphQL(with Subscription) Backend As A Service](https://scaphold.io/)
188 |
189 | #### 2. PouchDB
190 |
191 | * [Offline Syncing in Ionic 2 with PouchDB & CouchDB](https://www.joshmorony.com/offline-syncing-in-ionic-2-with-pouchdb-couchdb/)
192 |
193 | ### Testing
194 |
195 | * [Writing Marble Tests](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md)
196 | * [Introduction to RxJS Marble Testing](https://egghead.io/lessons/rxjs-introduction-to-rxjs-marble-testing)
197 |
198 | ### Open API Specification
199 |
200 | * [Top Specification Formats for REST APIs](http://nordicapis.com/top-specification-formats-for-rest-apis/)
201 | * [Speed up your RESTful API development in Node.js with Swagger](https://scotch.io/tutorials/speed-up-your-restful-api-development-in-node-js-with-swagger)
202 | * [Medium.com API Specification](https://github.com/amardeshbd/medium-api-specification)
203 | * [Writing OpenAPI (Swagger) Specification Tutorial](https://apihandyman.io/writing-openapi-swagger-specification-tutorial-part-1-introduction/)
204 |
205 | ### Push
206 |
207 | * [PhoneGap Day US Push Workshop 2016 Build a Hybrid Mobile App with Push](http://macdonst.github.io/push-workshop/index.html)
208 |
209 | ### UI
210 |
211 | * https://vex.visurel.com/
212 |
213 | ## TODO
214 |
215 | 1. [Use Lighthouse to improve quality](https://developers.google.com/web/tools/lighthouse/)
216 | 1. GitHub:
217 | 1. Try:
218 |
219 | * [x] Hostie Event Page
220 | * [ ] Hostie QR Code Push
221 | * [ ] Store Publish
222 | * [ ] Other
223 | * [ ] Feedback enable Wilddog & Scrollglue
224 | * [ ] Gavatar in menu with Matrix CSS
225 |
226 | ## SEE ALSO
227 |
228 | * [Motion.AI - Chatbots made easy.](https://www.motion.ai)
229 | * [Static web publishing for Front-End Developers](https://surge.sh)
230 |
231 | ## CHANGELOG
232 |
233 | ### v0.3 (master) Apr, 2018
234 |
235 | 1. Promote `Auth` service as a solo npm package [auth-angular](https://github.com/zixia/auth-angular)
236 |
237 | ### v0.2 Feb, 2018
238 |
239 | 1. Upgrade to Ionic 3 & Angular 5
240 | 1. GraphQL DB Integration
241 |
242 | ### v0.1 Apri, 2017
243 |
244 | 1. Auth0 Integration
245 | 1. FastLane.tools Integration
246 | 1. Ionic DB Integration
247 |
248 | ### v0.0 Dec 16, 2016
249 |
250 | 1. Build with Ionic/Angular 2
251 | 1. Prototype with Ionic Creator
252 |
253 | ## AUTHOR
254 |
255 | [Huan LI](http://linkedin.com/in/zixia) \
256 |
257 |
258 |
259 |
260 |
261 | ## COPYRIGHT & LICENSE
262 |
263 | * Code & Docs © 2017-2018 Huan LI \
264 | * Code released under the Apache-2.0 License
265 | * Docs released under Creative Commons
266 |
267 | ## MEMO
268 |
269 | title: "Welcome to the Platform!",
270 | description: "The Ionic Component Documentation showcases a number of useful components that are included out of the box with Ionic.",
271 |
272 | title: "What is platform?",
273 | description: "Ionic Framework is an open source SDK that enables developers to build high quality mobile apps with web technologies like HTML, CSS, and JavaScript.",
274 |
275 | title: "What isPlatform?",
276 | description: "The Ionic Platform is a cloud platform for managing and scaling Ionic apps with integrated services like push notifications, native builds, user auth, and live updating.",
277 |
278 | ## ALPHA DESIGN
279 |
280 | ```ts
281 | import { Giftie } from '@chatie/giftie'
282 |
283 | ```
284 |
285 | ```ts
286 | import { Botie } from '@chatie/botie'
287 |
288 | const botie = new Botie()
289 |
290 | ```
291 |
292 | ```ts
293 | const botie = new Botie('token')
294 |
295 | try {
296 | await botie.init()
297 | await botie.test().pipe(
298 | tap(progress => {
299 | console.log('on progress...', progress)
300 | })
301 | ).toPromise()
302 | wechaty.addBotie(botie)
303 | } catch (e) {
304 | if ( e.instanceof(UnitTestingException )) {
305 | // botie test fail
306 | } else {
307 | // other exception
308 | }
309 | }
310 |
311 | function addBotie(botie: Botie): Promise {
312 | // const eventNameList = botie.eventNameList()
313 | // const eventListenerList = botie.eventListenerList()
314 |
315 | // for (const i in eventNameList) {
316 | // this.addListener(eventNameList[i], eventListenerList[i])
317 | // }
318 |
319 | botie.bind(this)
320 |
321 | botie.listener.subscribe.pipe(
322 | tap(
323 | (event, listener) => this.addListener(event, listener),
324 | ),
325 | ).toPromise()
326 | }
327 |
328 | function removeBotie(botie: Botie) Promise {
329 | botie.listener.subscribe.pipe(
330 | tap(
331 | (event, listener) => this.removeListener(event, listener),
332 | ),
333 | ).toPromise()
334 | }
335 |
336 | const wechaty = Wechaty.instance()
337 | wechaty.setPuppet(new HostiePuppet('token'))
338 | wechaty.start()
339 |
340 | ```
341 |
--------------------------------------------------------------------------------