"architect": { 13
+        "build": {
14
+          "builder": "@angular-devkit/build-angular:browser",
15
+          "options": {
16
+            "outputPath": "www",
17
+            "index": "src/index.html",
18
+            "main": "src/main.ts",
19
+            "polyfills": "src/polyfills.ts",
20
+            "tsConfig": "tsconfig.app.json",
21
+            "assets": [
22
+              {
23
+                "glob": "**/*",
24
+                "input": "src/assets",
25
+                "output": "assets"
26
+              },
27
+              {
28
+                "glob": "**/*.svg",
29
+                "input": "node_modules/ionicons/dist/ionicons/svg",
30
+                "output": "./svg"
31
+              }
32
+            ],
33
+            "styles": ["src/theme/variables.scss", "src/global.scss"],
34
+            "scripts": [],
35
+            "aot": false,
36
+            "vendorChunk": true,
37
+            "extractLicenses": false,
38
+            "buildOptimizer": false,
39
+            "sourceMap": true,
40
+            "optimization": false,
41
+            "namedChunks": true
42
+          },
43
+          "configurations": {
44
+            "production": {
45
+              "fileReplacements": [
46
+                {
47
+                  "replace": "src/environments/environment.ts",
48
+                  "with": "src/environments/environment.prod.ts"
49
+                }
50
+              ],
51
+              "optimization": true,
52
+              "outputHashing": "all",
53
+              "sourceMap": false,
54
+              "namedChunks": false,
55
+              "aot": true,
56
+              "extractLicenses": true,
57
+              "vendorChunk": false,
58
+              "buildOptimizer": true,
59
+              "budgets": [
60
+                {
61
+                  "type": "initial",
62
+                  "maximumWarning": "2mb",
63
+                  "maximumError": "5mb"
64
+                }
65
+              ]
66
+            },
67
+            "ci": {
68
+              "progress": false
69
+            }
70
+          }
71
+        },
72
+        "serve": {
73
+          "builder": "@angular-devkit/build-angular:dev-server",
74
+          "options": {
75
+            "browserTarget": "app:build"
76
+          },
77
+          "configurations": {
78
+            "production": {
79
+              "browserTarget": "app:build:production"
80
+            },
81
+            "ci": {
82
+              "progress": false
83
+            }
84
+          }
85
+        },
86
+        "extract-i18n": {
87
+          "builder": "@angular-devkit/build-angular:extract-i18n",
88
+          "options": {
89
+            "browserTarget": "app:build"
90
+          }
91
+        },
92
+        "test": {
93
+          "builder": "@angular-devkit/build-angular:karma",
94
+          "options": {
95
+            "main": "src/test.ts",
96
+            "polyfills": "src/polyfills.ts",
97
+            "tsConfig": "tsconfig.spec.json",
98
+            "karmaConfig": "karma.conf.js",
99
+            "styles": [],
100
+            "scripts": [],
101
+            "assets": [
102
+              {
103
+                "glob": "favicon.ico",
104
+                "input": "src/",
105
+                "output": "/"
106
+              },
107
+              {
108
+                "glob": "**/*",
109
+                "input": "src/assets",
110
+                "output": "/assets"
111
+              }
112
+            ]
113
+          },
114
+          "configurations": {
115
+            "ci": {
116
+              "progress": false,
117
+              "watch": false
118
+            }
119
+          }
120
+        },
121
+        "lint": {
122
+          "builder": "@angular-eslint/builder:lint",
123
+          "options": {
124
+            "lintFilePatterns": [
125
+              "src/**/*.ts",
126
+              "src/**/*.html"
127
+            ]
128
+          }
129
+        },
130
+        "e2e": {
131
+          "builder": "@angular-devkit/build-angular:protractor",
132
+          "options": {
133
+            "protractorConfig": "e2e/protractor.conf.js",
134
+            "devServerTarget": "app:serve"
135
+          },
136
+          "configurations": {
137
+            "production": {
138
+              "devServerTarget": "app:serve:production"
139
+            },
140
+            "ci": {
141
+              "devServerTarget": "app:serve:ci"
142
+            }
143
+          }
144
+        }
145
+      }
146
+    }
147
+  },
148
+  "cli": {
149
+    "schematicCollections": [
150
+      "@ionic/angular-toolkit"
151
+    ],
152
+    "analytics": false
153
+  },
154
+  "schematics": {
155
+    "@ionic/angular-toolkit:component": {
156
+      "styleext": "scss"
157
+    },
158
+    "@ionic/angular-toolkit:page": {
159
+      "styleext": "scss"
160
+    }
161
+  }
162
+}

+ 10 - 0
capacitor.config.ts

@@ -0,0 +1,10 @@
1
+import { CapacitorConfig } from '@capacitor/cli';
2
+
3
+const config: CapacitorConfig = {
4
+  appId: 'io.ionic.starter',
5
+  appName: 'ra100',
6
+  webDir: 'www',
7
+  bundledWebRuntime: false
8
+};
9
+
10
+export default config;

+ 37 - 0
e2e/protractor.conf.js

@@ -0,0 +1,37 @@
1
+// @ts-check
2
+// Protractor configuration file, see link for more information
3
+// https://github.com/angular/protractor/blob/master/lib/config.ts
4
+
5
+const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6
+
7
+/**
8
+ * @type { import("protractor").Config }
9
+ */
10
+exports.config = {
11
+  allScriptsTimeout: 11000,
12
+  specs: [
13
+    './src/**/*.e2e-spec.ts'
14
+  ],
15
+  capabilities: {
16
+    browserName: 'chrome'
17
+  },
18
+  directConnect: true,
19
+  SELENIUM_PROMISE_MANAGER: false,
20
+  baseUrl: 'http://localhost:4200/',
21
+  framework: 'jasmine',
22
+  jasmineNodeOpts: {
23
+    showColors: true,
24
+    defaultTimeoutInterval: 30000,
25
+    print: function() {}
26
+  },
27
+  onPrepare() {
28
+    require('ts-node').register({
29
+      project: require('path').join(__dirname, './tsconfig.json')
30
+    });
31
+    jasmine.getEnv().addReporter(new SpecReporter({
32
+      spec: {
33
+        displayStacktrace: StacktraceOption.PRETTY
34
+      }
35
+    }));
36
+  }
37
+};

+ 14 - 0
e2e/src/app.e2e-spec.ts

@@ -0,0 +1,14 @@
1
+import { AppPage } from './app.po';
2
+
3
+describe('new App', () => {
4
+  let page: AppPage;
5
+
6
+  beforeEach(() => {
7
+    page = new AppPage();
8
+  });
9
+
10
+  it('should be blank', () => {
11
+    page.navigateTo();
12
+    expect(page.getParagraphText()).toContain('Start with Ionic UI Components');
13
+  });
14
+});

+ 11 - 0
e2e/src/app.po.ts

@@ -0,0 +1,11 @@
1
+import { browser, by, element } from 'protractor';
2
+
3
+export class AppPage {
4
+  navigateTo() {
5
+    return browser.get('/');
6
+  }
7
+
8
+  getParagraphText() {
9
+    return element(by.deepCss('app-root ion-content')).getText();
10
+  }
11
+}

+ 12 - 0
e2e/tsconfig.json

@@ -0,0 +1,12 @@
1
+{
2
+  "extends": "../tsconfig.json",
3
+  "compilerOptions": {
4
+    "outDir": "../out-tsc/e2e",
5
+    "module": "commonjs",
6
+    "target": "es2018",
7
+    "types": [
8
+      "jasmine",
9
+      "node"
10
+    ]
11
+  }
12
+}

+ 7 - 0
ionic.config.json

@@ -0,0 +1,7 @@
1
+{
2
+  "name": "ra100",
3
+  "integrations": {
4
+    "capacitor": {}
5
+  },
6
+  "type": "angular"
7
+}

+ 44 - 0
karma.conf.js

@@ -0,0 +1,44 @@
1
+// Karma configuration file, see link for more information
2
+// https://karma-runner.github.io/1.0/config/configuration-file.html
3
+
4
+module.exports = function (config) {
5
+  config.set({
6
+    basePath: '',
7
+    frameworks: ['jasmine', '@angular-devkit/build-angular'],
8
+    plugins: [
9
+      require('karma-jasmine'),
10
+      require('karma-chrome-launcher'),
11
+      require('karma-jasmine-html-reporter'),
12
+      require('karma-coverage'),
13
+      require('@angular-devkit/build-angular/plugins/karma')
14
+    ],
15
+    client: {
16
+      jasmine: {
17
+        // you can add configuration options for Jasmine here
18
+        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19
+        // for example, you can disable the random execution with `random: false`
20
+        // or set a specific seed with `seed: 4321`
21
+      },
22
+      clearContext: false // leave Jasmine Spec Runner output visible in browser
23
+    },
24
+    jasmineHtmlReporter: {
25
+      suppressAll: true // removes the duplicated traces
26
+    },
27
+    coverageReporter: {
28
+      dir: require('path').join(__dirname, './coverage/ngv'),
29
+      subdir: '.',
30
+      reporters: [
31
+        { type: 'html' },
32
+        { type: 'text-summary' }
33
+      ]
34
+    },
35
+    reporters: ['progress', 'kjhtml'],
36
+    port: 9876,
37
+    colors: true,
38
+    logLevel: config.LOG_INFO,
39
+    autoWatch: true,
40
+    browsers: ['Chrome'],
41
+    singleRun: false,
42
+    restartOnFileChange: true
43
+  });
44
+};

Разлика између датотеке није приказан због своје велике величине
+ 29245 - 0
package-lock.json


+ 73 - 0
package.json

@@ -0,0 +1,73 @@
1
+{
2
+  "name": "ra100",
3
+  "version": "0.0.1",
4
+  "author": "Ionic Framework",
5
+  "homepage": "https://ionicframework.com/",
6
+  "scripts": {
7
+    "ng": "ng",
8
+    "start": "ng serve",
9
+    "build": "ng build",
10
+    "test": "ng test",
11
+    "lint": "ng lint",
12
+    "e2e": "ng e2e"
13
+  },
14
+  "private": true,
15
+  "dependencies": {
16
+    "@angular/common": "^14.0.0",
17
+    "@angular/core": "^14.0.0",
18
+    "@angular/forms": "^14.0.0",
19
+    "@angular/platform-browser": "^14.0.0",
20
+    "@angular/platform-browser-dynamic": "^14.0.0",
21
+    "@angular/router": "^14.0.0",
22
+    "@capacitor/app": "4.1.0",
23
+    "@capacitor/core": "4.4.0",
24
+    "@capacitor/haptics": "4.0.1",
25
+    "@capacitor/keyboard": "4.0.1",
26
+    "@capacitor/status-bar": "4.0.1",
27
+    "@fortawesome/angular-fontawesome": "^0.11.1",
28
+    "@fortawesome/fontawesome-svg-core": "^6.2.0",
29
+    "@fortawesome/free-brands-svg-icons": "^6.2.0",
30
+    "@fortawesome/free-regular-svg-icons": "^6.2.0",
31
+    "@fortawesome/free-solid-svg-icons": "^6.2.0",
32
+    "@ionic/angular": "^6.1.9",
33
+    "ionicons": "^6.0.3",
34
+    "rxjs": "~6.6.0",
35
+    "swiper": "^8.4.4",
36
+    "tslib": "^2.2.0",
37
+    "zone.js": "~0.11.4"
38
+  },
39
+  "devDependencies": {
40
+    "@angular-devkit/build-angular": "^14.0.0",
41
+    "@angular-eslint/builder": "~13.0.1",
42
+    "@angular-eslint/eslint-plugin": "~13.0.1",
43
+    "@angular-eslint/eslint-plugin-template": "~13.0.1",
44
+    "@angular-eslint/template-parser": "~13.0.1",
45
+    "@angular/cli": "^14.0.0",
46
+    "@angular/compiler": "^14.0.0",
47
+    "@angular/compiler-cli": "^14.0.0",
48
+    "@angular/language-service": "^14.0.0",
49
+    "@capacitor/cli": "4.4.0",
50
+    "@ionic/angular-toolkit": "^6.0.0",
51
+    "@types/jasmine": "~3.6.0",
52
+    "@types/jasminewd2": "~2.0.3",
53
+    "@types/node": "^12.11.1",
54
+    "@typescript-eslint/eslint-plugin": "5.3.0",
55
+    "@typescript-eslint/parser": "5.3.0",
56
+    "eslint": "^7.6.0",
57
+    "eslint-plugin-import": "2.22.1",
58
+    "eslint-plugin-jsdoc": "30.7.6",
59
+    "eslint-plugin-prefer-arrow": "1.2.2",
60
+    "jasmine-core": "~3.8.0",
61
+    "jasmine-spec-reporter": "~5.0.0",
62
+    "karma": "~6.3.2",
63
+    "karma-chrome-launcher": "~3.1.0",
64
+    "karma-coverage": "~2.0.3",
65
+    "karma-coverage-istanbul-reporter": "~3.0.2",
66
+    "karma-jasmine": "~4.0.0",
67
+    "karma-jasmine-html-reporter": "^1.5.0",
68
+    "protractor": "~7.0.0",
69
+    "ts-node": "~8.3.0",
70
+    "typescript": "~4.7.3"
71
+  },
72
+  "description": "An Ionic project"
73
+}

+ 42 - 0
src/app/app-routing.module.ts

@@ -0,0 +1,42 @@
1
+import { NgModule } from '@angular/core';
2
+import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
3
+
4
+const routes: Routes = [
5
+  // {
6
+  //   path: 'home',
7
+  //   loadChildren: () => import('./home/home.module').then( m => m.HomePageModule)
8
+  // },
9
+  // {
10
+  //   path: 'navtabs',
11
+  //   loadChildren: () => import('./navtabs/navtabs.module').then( m => m.NavtabsPageModule)
12
+  // },
13
+  {
14
+    path: '',
15
+    redirectTo: 'navtabs',
16
+    pathMatch: 'full'
17
+  },
18
+  {
19
+    path: 'navtabs',
20
+    loadChildren: () => import('./navtabs/navtabs.module').then( m => m.NavtabsPageModule)
21
+  },
22
+  // {
23
+  //   path: 'youtube',
24
+  //   loadChildren: () => import('./youtube/youtube.module').then( m => m.YoutubePageModule)
25
+  // },
26
+  // {
27
+  //   path: 'article',
28
+  //   loadChildren: () => import('./article/article.module').then( m => m.ArticlePageModule)
29
+  // },
30
+  // {
31
+  //   path: 'navtabs',
32
+  //   loadChildren: () => import('./navtabs/navtabs.module').then( m => m.NavtabsPageModule)
33
+  // },
34
+];
35
+
36
+@NgModule({
37
+  imports: [
38
+    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
39
+  ],
40
+  exports: [RouterModule]
41
+})
42
+export class AppRoutingModule { }

+ 25 - 0
src/app/app.component.html

@@ -0,0 +1,25 @@
1
+<ion-app>
2
+  <ion-menu side="start" contentId="content">
3
+    <ion-header>
4
+      <ion-toolbar>
5
+        <ion-title class="menu-title">Menu</ion-title>
6
+      </ion-toolbar>
7
+    </ion-header>
8
+    <ion-content>
9
+      <ion-list>
10
+        <ion-menu-toggle auto-hide="true">
11
+          <ion-item routerLink="/tabs/tab1" routerDirection="forward">
12
+            <ion-label>Tab 1</ion-label>
13
+          </ion-item>
14
+          <ion-item routerLink="/tabs/tab2" routerDirection="forward">
15
+            <ion-label>Tab 2</ion-label>
16
+          </ion-item>
17
+          <ion-item routerLink="/tabs/tab3" routerDirection="forward">
18
+            <ion-label>Tab 3</ion-label>
19
+          </ion-item>
20
+        </ion-menu-toggle>
21
+      </ion-list>
22
+    </ion-content>
23
+  </ion-menu>
24
+  <ion-router-outlet id="content"></ion-router-outlet>
25
+</ion-app>  

+ 0 - 0
src/app/app.component.scss


+ 23 - 0
src/app/app.component.spec.ts

@@ -0,0 +1,23 @@
1
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
+import { TestBed, waitForAsync } from '@angular/core/testing';
3
+
4
+import { AppComponent } from './app.component';
5
+
6
+describe('AppComponent', () => {
7
+
8
+  beforeEach(waitForAsync(() => {
9
+
10
+    TestBed.configureTestingModule({
11
+      declarations: [AppComponent],
12
+      schemas: [CUSTOM_ELEMENTS_SCHEMA],
13
+    }).compileComponents();
14
+  }));
15
+
16
+  it('should create the app', () => {
17
+    const fixture = TestBed.createComponent(AppComponent);
18
+    const app = fixture.debugElement.componentInstance;
19
+    expect(app).toBeTruthy();
20
+  });
21
+  // TODO: add more tests!
22
+
23
+});

+ 10 - 0
src/app/app.component.ts

@@ -0,0 +1,10 @@
1
+import { Component } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'app-root',
5
+  templateUrl: 'app.component.html',
6
+  styleUrls: ['app.component.scss'],
7
+})
8
+export class AppComponent {
9
+  constructor() {}
10
+}

+ 26 - 0
src/app/app.module.ts

@@ -0,0 +1,26 @@
1
+import { NgModule } from '@angular/core';
2
+import { BrowserModule } from '@angular/platform-browser';
3
+import { RouteReuseStrategy } from '@angular/router';
4
+
5
+import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
6
+
7
+import { AppComponent } from './app.component';
8
+import { AppRoutingModule } from './app-routing.module';
9
+import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
10
+import { fas } from '@fortawesome/free-solid-svg-icons'
11
+import { far } from '@fortawesome/free-regular-svg-icons'
12
+import { fab } from '@fortawesome/free-brands-svg-icons'
13
+
14
+@NgModule({
15
+  declarations: [AppComponent],
16
+  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, FontAwesomeModule],
17
+  providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
18
+  bootstrap: [AppComponent],
19
+})
20
+export class AppModule {
21
+
22
+  constructor(library: FaIconLibrary) { 
23
+		library.addIconPacks(fas, far, fab);
24
+	}
25
+  
26
+}

+ 17 - 0
src/app/article/article-routing.module.ts

@@ -0,0 +1,17 @@
1
+import { NgModule } from '@angular/core';
2
+import { Routes, RouterModule } from '@angular/router';
3
+
4
+import { ArticlePage } from './article.page';
5
+
6
+const routes: Routes = [
7
+  {
8
+    path: '',
9
+    component: ArticlePage
10
+  }
11
+];
12
+
13
+@NgModule({
14
+  imports: [RouterModule.forChild(routes)],
15
+  exports: [RouterModule],
16
+})
17
+export class ArticlePageRoutingModule {}

+ 20 - 0
src/app/article/article.module.ts

@@ -0,0 +1,20 @@
1
+import { NgModule } from '@angular/core';
2
+import { CommonModule } from '@angular/common';
3
+import { FormsModule } from '@angular/forms';
4
+
5
+import { IonicModule } from '@ionic/angular';
6
+
7
+import { ArticlePageRoutingModule } from './article-routing.module';
8
+
9
+import { ArticlePage } from './article.page';
10
+
11
+@NgModule({
12
+  imports: [
13
+    CommonModule,
14
+    FormsModule,
15
+    IonicModule,
16
+    ArticlePageRoutingModule
17
+  ],
18
+  declarations: [ArticlePage]
19
+})
20
+export class ArticlePageModule {}

+ 9 - 0
src/app/article/article.page.html

@@ -0,0 +1,9 @@
1
+<ion-header>
2
+  <ion-toolbar>
3
+    <ion-title>article</ion-title>
4
+  </ion-toolbar>
5
+</ion-header>
6
+
7
+<ion-content>
8
+
9
+</ion-content>

+ 0 - 0
src/app/article/article.page.scss


+ 24 - 0
src/app/article/article.page.spec.ts

@@ -0,0 +1,24 @@
1
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
+import { IonicModule } from '@ionic/angular';
3
+
4
+import { ArticlePage } from './article.page';
5
+
6
+describe('ArticlePage', () => {
7
+  let component: ArticlePage;
8
+  let fixture: ComponentFixture<ArticlePage>;
9
+
10
+  beforeEach(waitForAsync(() => {
11
+    TestBed.configureTestingModule({
12
+      declarations: [ ArticlePage ],
13
+      imports: [IonicModule.forRoot()]
14
+    }).compileComponents();
15
+
16
+    fixture = TestBed.createComponent(ArticlePage);
17
+    component = fixture.componentInstance;
18
+    fixture.detectChanges();
19
+  }));
20
+
21
+  it('should create', () => {
22
+    expect(component).toBeTruthy();
23
+  });
24
+});

+ 15 - 0
src/app/article/article.page.ts

@@ -0,0 +1,15 @@
1
+import { Component, OnInit } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'app-article',
5
+  templateUrl: './article.page.html',
6
+  styleUrls: ['./article.page.scss'],
7
+})
8
+export class ArticlePage implements OnInit {
9
+
10
+  constructor() { }
11
+
12
+  ngOnInit() {
13
+  }
14
+
15
+}

+ 16 - 0
src/app/home/home-routing.module.ts

@@ -0,0 +1,16 @@
1
+import { NgModule } from '@angular/core';
2
+import { RouterModule, Routes } from '@angular/router';
3
+import { HomePage } from './home.page';
4
+
5
+const routes: Routes = [
6
+  {
7
+    path: '',
8
+    component: HomePage,
9
+  }
10
+];
11
+
12
+@NgModule({
13
+  imports: [RouterModule.forChild(routes)],
14
+  exports: [RouterModule]
15
+})
16
+export class HomePageRoutingModule {}

+ 22 - 0
src/app/home/home.module.ts

@@ -0,0 +1,22 @@
1
+import { NgModule } from '@angular/core';
2
+import { CommonModule } from '@angular/common';
3
+import { IonicModule } from '@ionic/angular';
4
+import { FormsModule } from '@angular/forms';
5
+import { HomePage } from './home.page';
6
+
7
+import { HomePageRoutingModule } from './home-routing.module';
8
+import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
9
+import { SwiperModule } from 'swiper/angular';
10
+
11
+@NgModule({
12
+  imports: [
13
+    CommonModule,
14
+    FormsModule,
15
+    IonicModule,
16
+    HomePageRoutingModule,
17
+    FontAwesomeModule,
18
+    SwiperModule
19
+  ],
20
+  declarations: [HomePage]
21
+})
22
+export class HomePageModule {}

+ 86 - 0
src/app/home/home.page.html

@@ -0,0 +1,86 @@
1
+<ion-header [translucent]="true">
2
+  <ion-toolbar>
3
+    <ion-buttons slot="end">
4
+      <ion-menu-button></ion-menu-button>
5
+    </ion-buttons>
6
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7
+  </ion-toolbar>
8
+</ion-header>
9
+<ion-content>
10
+  <swiper #swiper [config]="config">
11
+    <ng-template swiperSlide><img src="../../../assets/img-static/fb-Ad-1.jpeg" alt=""></ng-template>
12
+    <ng-template swiperSlide><img src="../../../assets/img-static/fb-Ad-2.jpeg" alt=""></ng-template>
13
+    <ng-template swiperSlide><img src="../../../assets/img-static/fb-Ad-3.jpeg" alt=""></ng-template>
14
+  </swiper>
15
+  <!-- <div id="container">
16
+    <fa-icon [icon]="['fas', 'graduation-cap']"></fa-icon>
17
+    <hr>
18
+    <strong>Ready to create an app?</strong>
19
+    <p>Start with Ionic <a target="_blank" rel="noopener noreferrer"
20
+        href="https://ionicframework.com/docs/components">UI Components</a></p>
21
+  </div> -->
22
+  <ion-grid>
23
+    <ion-row>
24
+      <ion-col>
25
+        <h2>ข่าวกีฬา</h2>
26
+      </ion-col>
27
+    </ion-row>
28
+    <ion-row>
29
+      <ion-col size="5">
30
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
31
+      </ion-col>
32
+      <ion-col>“น้องเทนนิส” หวังคว้าแชมป์ในศึกชิงแชมป์โลก ต้นเดือนหน้า</ion-col>
33
+    </ion-row>
34
+    <ion-row>
35
+      <ion-col size="5">
36
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
37
+      </ion-col>
38
+      <ion-col>โรนัลโด กลับมาซ้อมกับทีม พร้อมปรับความเข้าใจกับ เทน ฮาก</ion-col>
39
+    </ion-row>
40
+    <ion-row>
41
+      <ion-col size="5">
42
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
43
+      </ion-col>
44
+      <ion-col>เตรียมหารือบอร์ดหาข้อสรุป รัฐ-เอกชน จับมือยิงสดฟุตบอลโลก</ion-col>
45
+    </ion-row>
46
+    <ion-row>
47
+      <ion-col size="5">
48
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
49
+      </ion-col>
50
+      <ion-col>บีจี แยกทางกับ “มาโกโตะ เทกุระโมริ” หลังผลงานไม่เป็นตามเป้า</ion-col>
51
+    </ion-row>
52
+    <ion-row>
53
+      <ion-col>
54
+        <img src="../../../assets/img-static/banner-320x50.jpeg" alt="">
55
+      </ion-col>
56
+    </ion-row>
57
+    <ion-row>
58
+      <ion-col>
59
+        <h2>รายการย้อนหลัง</h2>
60
+      </ion-col>
61
+    </ion-row>
62
+    <ion-row>
63
+      <ion-col size="5">
64
+        <img src="../../assets/img-static/mqdefault-1.jpg">
65
+      </ion-col>
66
+      <ion-col>Morning Talk [26-10-2022 l 07:30 - 09:00 น. ]</ion-col>
67
+    </ion-row>
68
+    <ion-row>
69
+      <ion-col size="5">
70
+        <img src="../../assets/img-static/mqdefault-2.jpg">
71
+      </ion-col>
72
+      <ion-col>Golf Trick [26-10-2022 l 09:00 - 10:00 น.]</ion-col>
73
+    </ion-row>
74
+    <ion-row>
75
+      <ion-col size="5">
76
+        <img src="../../assets/img-static/mqdefault-3.jpg">
77
+      </ion-col>
78
+      <ion-col>เจาะสนามบอลไทย [ 20-10-2022 l 20:00 - 21:30 น. ]</ion-col>
79
+    </ion-row>
80
+    <ion-row>
81
+      <ion-col>
82
+        <img src="../../../assets/img-static/banner-320x100.jpeg" alt="">
83
+      </ion-col>
84
+    </ion-row>
85
+  </ion-grid>
86
+</ion-content>

+ 39 - 0
src/app/home/home.page.scss

@@ -0,0 +1,39 @@
1
+
2
+// ion-title { text-align: center !important; }
3
+
4
+#container strong {
5
+  font-size: 20px;
6
+  line-height: 26px;
7
+}
8
+
9
+#container p {
10
+  font-size: 16px;
11
+  line-height: 22px;
12
+
13
+  color: #8c8c8c;
14
+
15
+  margin: 0;
16
+}
17
+
18
+#container a {
19
+  text-decoration: none;
20
+}
21
+
22
+// .swiper .swiper-slide {
23
+//   height: 100%;
24
+//   width: 100%;
25
+// }
26
+
27
+.swiper-slide {
28
+  // display: flex;
29
+  // flex-direction: column;
30
+  // align-items: center;
31
+  // justify-content: center;
32
+  background-color: blueviolet;
33
+}
34
+
35
+ion-content{ 
36
+  font-family:IBM Plex Sans Thai SemiBold !important;
37
+  font-size:1em;
38
+  line-height: 1.4em;
39
+}

+ 24 - 0
src/app/home/home.page.spec.ts

@@ -0,0 +1,24 @@
1
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
+import { IonicModule } from '@ionic/angular';
3
+
4
+import { HomePage } from './home.page';
5
+
6
+describe('HomePage', () => {
7
+  let component: HomePage;
8
+  let fixture: ComponentFixture<HomePage>;
9
+
10
+  beforeEach(waitForAsync(() => {
11
+    TestBed.configureTestingModule({
12
+      declarations: [ HomePage ],
13
+      imports: [IonicModule.forRoot()]
14
+    }).compileComponents();
15
+
16
+    fixture = TestBed.createComponent(HomePage);
17
+    component = fixture.componentInstance;
18
+    fixture.detectChanges();
19
+  }));
20
+
21
+  it('should create', () => {
22
+    expect(component).toBeTruthy();
23
+  });
24
+});

+ 36 - 0
src/app/home/home.page.ts

@@ -0,0 +1,36 @@
1
+import { AfterContentChecked, Component, ViewChild, ViewEncapsulation } from '@angular/core';
2
+import {SwiperComponent} from 'swiper/angular';
3
+import { SwiperOptions } from 'swiper';
4
+import SwiperCore, { Pagination,Autoplay,Navigation,Keyboard } from 'swiper';
5
+
6
+SwiperCore.use([Pagination, Autoplay, Navigation, Keyboard]);
7
+@Component({
8
+  selector: 'app-home',
9
+  templateUrl: 'home.page.html',
10
+  styleUrls: ['home.page.scss'],
11
+  encapsulation: ViewEncapsulation.None
12
+})
13
+export class HomePage implements AfterContentChecked {
14
+  
15
+  @ViewChild('swiper') swiper: SwiperComponent;
16
+
17
+  config: SwiperOptions = {
18
+    slidesPerView: 1,  
19
+    pagination: { clickable: true },
20
+    autoplay: {
21
+      delay: 200,
22
+      disableOnInteraction: false,
23
+    },
24
+    loop: true,
25
+    navigation: true,
26
+  }
27
+
28
+  constructor() {}
29
+
30
+  ngAfterContentChecked() {
31
+    if (this.swiper) {
32
+      this.swiper.updateSwiper({});
33
+    }    
34
+  }
35
+
36
+}

+ 45 - 0
src/app/navtabs/navtabs-routing.module.ts

@@ -0,0 +1,45 @@
1
+import { NgModule } from '@angular/core';
2
+import { Routes, RouterModule } from '@angular/router';
3
+
4
+import { NavtabsPage } from './navtabs.page';
5
+
6
+const routes: Routes = [
7
+  {
8
+    path: 'navtabsTab',
9
+    component: NavtabsPage,
10
+    children: [
11
+      {
12
+        path: 'home',
13
+        loadChildren: () => import('../home/home.module').then( m => m.HomePageModule)
14
+      },   
15
+      {
16
+        path: 'news',
17
+        loadChildren: () => import('../news/news.module').then( m => m.NewsPageModule)
18
+      },   
19
+      {
20
+        path: 'article',
21
+        loadChildren: () => import('../article/article.module').then( m => m.ArticlePageModule)
22
+      },   
23
+      {
24
+        path: 'youtube',
25
+        loadChildren: () => import('../youtube/youtube.module').then( m => m.YoutubePageModule)
26
+      }, 
27
+      {
28
+        path: '',
29
+        redirectTo: '/navtabs/navtabsTab/home',
30
+        pathMatch: 'full'
31
+      }
32
+    ]
33
+  },
34
+  {
35
+    path: '',
36
+    redirectTo: '/navtabs/navtabsTab/home',
37
+    pathMatch: 'full'    
38
+  }
39
+];
40
+
41
+@NgModule({
42
+  imports: [RouterModule.forChild(routes)],
43
+  exports: [RouterModule],
44
+})
45
+export class NavtabsPageRoutingModule {}

+ 20 - 0
src/app/navtabs/navtabs.module.ts

@@ -0,0 +1,20 @@
1
+import { NgModule } from '@angular/core';
2
+import { CommonModule } from '@angular/common';
3
+import { FormsModule } from '@angular/forms';
4
+
5
+import { IonicModule } from '@ionic/angular';
6
+
7
+import { NavtabsPageRoutingModule } from './navtabs-routing.module';
8
+
9
+import { NavtabsPage } from './navtabs.page';
10
+
11
+@NgModule({
12
+  imports: [
13
+    CommonModule,
14
+    FormsModule,
15
+    IonicModule,
16
+    NavtabsPageRoutingModule
17
+  ],
18
+  declarations: [NavtabsPage]
19
+})
20
+export class NavtabsPageModule {}

+ 25 - 0
src/app/navtabs/navtabs.page.html

@@ -0,0 +1,25 @@
1
+
2
+<ion-tabs>
3
+  <ion-tab-bar slot="bottom">
4
+    <ion-tab-button tab="home">
5
+      <ion-icon name="globe"></ion-icon>
6
+      <!-- <ion-label>Home</ion-label> -->      
7
+    </ion-tab-button>
8
+    <ion-tab-button tab="news">
9
+      <ion-icon name="football"></ion-icon>
10
+      <!-- <ion-label>News</ion-label> -->
11
+    </ion-tab-button>
12
+    <ion-tab-button tab="#">
13
+      <ion-icon name="play-circle"></ion-icon>
14
+      <!-- <ion-label>Audio</ion-label> -->
15
+    </ion-tab-button>  
16
+    <ion-tab-button tab="youtube">
17
+      <ion-icon name="logo-youtube"></ion-icon>
18
+      <!-- <ion-label>Youtube</ion-label> -->
19
+    </ion-tab-button>  
20
+    <ion-tab-button tab="#">
21
+      <ion-icon name="videocam"></ion-icon>
22
+      <!-- <ion-label>Video</ion-label> -->
23
+    </ion-tab-button>
24
+  </ion-tab-bar>
25
+</ion-tabs>

+ 98 - 0
src/app/navtabs/navtabs.page.scss

@@ -0,0 +1,98 @@
1
+// ::ng-deep ion-icon.icon-button {
2
+//     background: #3c457e !important;
3
+//     color: white !important;
4
+//     border-radius: 50%!important;
5
+// }
6
+
7
+// :host ::ng-deep .tabs-inner {
8
+//     position: unset!important;
9
+//     contain: size style!important;
10
+//   }
11
+  
12
+//   .bottom-tab-bar {
13
+//     --background: transparent;
14
+//     --border: 0;
15
+//   }
16
+  
17
+//   ion-tab-button {
18
+//     --background: #134d80;
19
+//     --color:white;
20
+//     --color-selected: red;
21
+//     --ripple-color: white;
22
+//   }
23
+  
24
+
25
+// .button-center {
26
+//     --background: transparent!important;
27
+//     ion-icon {
28
+//       height: 40px;
29
+//       width: 40px;
30
+//       font-size: 60px;
31
+//     }
32
+// }
33
+// ion-tab-bar {
34
+//     &:before {
35
+//       box-shadow: 0 387px 0 300px #3c457e;
36
+//       position: absolute;
37
+//       margin-top: -48px;
38
+//       padding: 56px;
39
+//       border-radius: 65%;
40
+//       content: '';
41
+//     }
42
+//   }
43
+  
44
+// .inner-left-btn {
45
+//     border-radius: 0 50% 0 0; 
46
+//     //create the curved style on the left side of the center
47
+// }
48
+
49
+
50
+// .inner-right-btn {
51
+//     border-radius: 50% 0 0 0; 
52
+//     // create the curved style on the right side of the center
53
+// }
54
+  
55
+// .inner-center-btn {
56
+//     position: absolute;
57
+//     left: calc(50% - 35px); // position your button in the center
58
+//     bottom: 20px; // position button slightly above the half
59
+//     font-size: 70px;
60
+//     --background: transparent;
61
+// }
62
+
63
+// ion-tab-bar {
64
+//     overflow-x: scroll;
65
+//     display: flex;    
66
+//     overflow-x: auto;
67
+//     ion-tab-button {
68
+//         display: inline-block;
69
+//         min-width: 100px;
70
+//         width: auto;
71
+//     }
72
+// }
73
+
74
+// ion-tab-bar {
75
+//   bottom: 20px;
76
+//   position: relative;
77
+//   border-radius: 16px;
78
+//   width: 92%;
79
+//   margin: 0 auto;
80
+// }
81
+
82
+// ion-tab-button {
83
+//   --color: var(--ion-color-medium);
84
+//   --color-selected: var(--ion-color-primary);
85
+
86
+//   &::before {
87
+//     background-color: transparent;
88
+//     display: block;
89
+//     content: "";
90
+//     margin: 0 auto;
91
+//     width: 20px;
92
+//     height: 2px;
93
+//   }
94
+
95
+//   &.tab-selected::before {
96
+//     background-color: var(--ion-color-primary);
97
+//   }
98
+// }

+ 24 - 0
src/app/navtabs/navtabs.page.spec.ts

@@ -0,0 +1,24 @@
1
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
+import { IonicModule } from '@ionic/angular';
3
+
4
+import { NavtabsPage } from './navtabs.page';
5
+
6
+describe('NavtabsPage', () => {
7
+  let component: NavtabsPage;
8
+  let fixture: ComponentFixture<NavtabsPage>;
9
+
10
+  beforeEach(waitForAsync(() => {
11
+    TestBed.configureTestingModule({
12
+      declarations: [ NavtabsPage ],
13
+      imports: [IonicModule.forRoot()]
14
+    }).compileComponents();
15
+
16
+    fixture = TestBed.createComponent(NavtabsPage);
17
+    component = fixture.componentInstance;
18
+    fixture.detectChanges();
19
+  }));
20
+
21
+  it('should create', () => {
22
+    expect(component).toBeTruthy();
23
+  });
24
+});

+ 15 - 0
src/app/navtabs/navtabs.page.ts

@@ -0,0 +1,15 @@
1
+import { Component, OnInit } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'app-navtabs',
5
+  templateUrl: './navtabs.page.html',
6
+  styleUrls: ['./navtabs.page.scss'],
7
+})
8
+export class NavtabsPage implements OnInit {
9
+
10
+  constructor() { }
11
+
12
+  ngOnInit() {
13
+  }
14
+
15
+}

+ 17 - 0
src/app/news/news-routing.module.ts

@@ -0,0 +1,17 @@
1
+import { NgModule } from '@angular/core';
2
+import { Routes, RouterModule } from '@angular/router';
3
+
4
+import { NewsPage } from './news.page';
5
+
6
+const routes: Routes = [
7
+  {
8
+    path: '',
9
+    component: NewsPage
10
+  }
11
+];
12
+
13
+@NgModule({
14
+  imports: [RouterModule.forChild(routes)],
15
+  exports: [RouterModule],
16
+})
17
+export class NewsPageRoutingModule {}

+ 22 - 0
src/app/news/news.module.ts

@@ -0,0 +1,22 @@
1
+import { NgModule } from '@angular/core';
2
+import { CommonModule } from '@angular/common';
3
+import { FormsModule } from '@angular/forms';
4
+
5
+import { IonicModule } from '@ionic/angular';
6
+
7
+import { NewsPageRoutingModule } from './news-routing.module';
8
+
9
+import { NewsPage } from './news.page';
10
+import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'
11
+
12
+@NgModule({
13
+  imports: [
14
+    CommonModule,
15
+    FormsModule,
16
+    IonicModule,
17
+    NewsPageRoutingModule,
18
+    FontAwesomeModule,
19
+  ],
20
+  declarations: [NewsPage]
21
+})
22
+export class NewsPageModule {}

+ 72 - 0
src/app/news/news.page.html

@@ -0,0 +1,72 @@
1
+<ion-header [translucent]="true">
2
+  <ion-toolbar>
3
+    <ion-buttons slot="end">
4
+      <ion-menu-button></ion-menu-button>
5
+    </ion-buttons>
6
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7
+  </ion-toolbar>
8
+</ion-header>
9
+
10
+<ion-content>
11
+  <img src="../../../assets/img-static/banner-320x50.jpeg" alt="">
12
+  <ion-grid>
13
+    <ion-row>
14
+      <ion-col>
15
+        <h2>ข่าวกีฬา</h2>
16
+      </ion-col>
17
+    </ion-row>
18
+    <ion-row>
19
+      <ion-col size="5">
20
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
21
+      </ion-col>
22
+      <ion-col>“น้องเทนนิส” หวังคว้าแชมป์ในศึกชิงแชมป์โลก ต้นเดือนหน้า</ion-col>
23
+    </ion-row>
24
+    <ion-row>
25
+      <ion-col size="5">
26
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
27
+      </ion-col>
28
+      <ion-col>โรนัลโด กลับมาซ้อมกับทีม พร้อมปรับความเข้าใจกับ เทน ฮาก</ion-col>
29
+    </ion-row>
30
+    <ion-row>
31
+      <ion-col size="5">
32
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
33
+      </ion-col>
34
+      <ion-col>เตรียมหารือบอร์ดหาข้อสรุป รัฐ-เอกชน จับมือยิงสดฟุตบอลโลก</ion-col>
35
+    </ion-row>
36
+    <ion-row>
37
+      <ion-col size="5">
38
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
39
+      </ion-col>
40
+      <ion-col>บีจี แยกทางกับ “มาโกโตะ เทกุระโมริ” หลังผลงานไม่เป็นตามเป้า</ion-col>
41
+    </ion-row>
42
+    <ion-row>
43
+      <ion-col size="5">
44
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
45
+      </ion-col>
46
+      <ion-col>“น้องเทนนิส” หวังคว้าแชมป์ในศึกชิงแชมป์โลก ต้นเดือนหน้า</ion-col>
47
+    </ion-row>
48
+    <ion-row>
49
+      <ion-col size="5">
50
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
51
+      </ion-col>
52
+      <ion-col>โรนัลโด กลับมาซ้อมกับทีม พร้อมปรับความเข้าใจกับ เทน ฮาก</ion-col>
53
+    </ion-row>
54
+    <ion-row>
55
+      <ion-col size="5">
56
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
57
+      </ion-col>
58
+      <ion-col>เตรียมหารือบอร์ดหาข้อสรุป รัฐ-เอกชน จับมือยิงสดฟุตบอลโลก</ion-col>
59
+    </ion-row>
60
+    <ion-row>
61
+      <ion-col size="5">
62
+        <img src="../../assets/img-static/SEI129887404-c4a9.jpg">
63
+      </ion-col>
64
+      <ion-col>บีจี แยกทางกับ “มาโกโตะ เทกุระโมริ” หลังผลงานไม่เป็นตามเป้า</ion-col>
65
+    </ion-row> 
66
+    <ion-row>
67
+      <ion-col>
68
+        <img src="../../../assets/img-static/banner-320x100.jpeg" alt="">
69
+      </ion-col>
70
+    </ion-row>
71
+  </ion-grid>
72
+</ion-content>

+ 0 - 0
src/app/news/news.page.scss


+ 24 - 0
src/app/news/news.page.spec.ts

@@ -0,0 +1,24 @@
1
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
+import { IonicModule } from '@ionic/angular';
3
+
4
+import { NewsPage } from './news.page';
5
+
6
+describe('NewsPage', () => {
7
+  let component: NewsPage;
8
+  let fixture: ComponentFixture<NewsPage>;
9
+
10
+  beforeEach(waitForAsync(() => {
11
+    TestBed.configureTestingModule({
12
+      declarations: [ NewsPage ],
13
+      imports: [IonicModule.forRoot()]
14
+    }).compileComponents();
15
+
16
+    fixture = TestBed.createComponent(NewsPage);
17
+    component = fixture.componentInstance;
18
+    fixture.detectChanges();
19
+  }));
20
+
21
+  it('should create', () => {
22
+    expect(component).toBeTruthy();
23
+  });
24
+});

+ 15 - 0
src/app/news/news.page.ts

@@ -0,0 +1,15 @@
1
+import { Component, OnInit } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'app-news',
5
+  templateUrl: './news.page.html',
6
+  styleUrls: ['./news.page.scss'],
7
+})
8
+export class NewsPage implements OnInit {
9
+
10
+  constructor() { }
11
+
12
+  ngOnInit() {
13
+  }
14
+
15
+}

+ 17 - 0
src/app/youtube/youtube-routing.module.ts

@@ -0,0 +1,17 @@
1
+import { NgModule } from '@angular/core';
2
+import { Routes, RouterModule } from '@angular/router';
3
+
4
+import { YoutubePage } from './youtube.page';
5
+
6
+const routes: Routes = [
7
+  {
8
+    path: '',
9
+    component: YoutubePage
10
+  }
11
+];
12
+
13
+@NgModule({
14
+  imports: [RouterModule.forChild(routes)],
15
+  exports: [RouterModule],
16
+})
17
+export class YoutubePageRoutingModule {}

+ 20 - 0
src/app/youtube/youtube.module.ts

@@ -0,0 +1,20 @@
1
+import { NgModule } from '@angular/core';
2
+import { CommonModule } from '@angular/common';
3
+import { FormsModule } from '@angular/forms';
4
+
5
+import { IonicModule } from '@ionic/angular';
6
+
7
+import { YoutubePageRoutingModule } from './youtube-routing.module';
8
+
9
+import { YoutubePage } from './youtube.page';
10
+
11
+@NgModule({
12
+  imports: [
13
+    CommonModule,
14
+    FormsModule,
15
+    IonicModule,
16
+    YoutubePageRoutingModule
17
+  ],
18
+  declarations: [YoutubePage]
19
+})
20
+export class YoutubePageModule {}

+ 42 - 0
src/app/youtube/youtube.page.html

@@ -0,0 +1,42 @@
1
+<ion-header [translucent]="true">
2
+  <ion-toolbar>
3
+    <ion-buttons slot="end">
4
+      <ion-menu-button></ion-menu-button>
5
+    </ion-buttons>
6
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7
+  </ion-toolbar>
8
+</ion-header>
9
+
10
+<ion-content>
11
+  <img src="../../../assets/img-static/banner-320x50.jpeg" alt="">
12
+  <ion-grid>
13
+    <ion-row>
14
+      <ion-col>
15
+        <h2>รายการย้อนหลัง</h2>
16
+      </ion-col>
17
+    </ion-row>
18
+    <ion-row>
19
+      <ion-col size="5">
20
+        <img src="../../assets/img-static/mqdefault-1.jpg">
21
+      </ion-col>
22
+      <ion-col>Morning Talk [26-10-2022 l 07:30 - 09:00 น. ]</ion-col>
23
+    </ion-row>
24
+    <ion-row>
25
+      <ion-col size="5">
26
+        <img src="../../assets/img-static/mqdefault-2.jpg">
27
+      </ion-col>
28
+      <ion-col>Golf Trick [26-10-2022 l 09:00 - 10:00 น.]</ion-col>
29
+    </ion-row>
30
+    <ion-row>
31
+      <ion-col size="5">
32
+        <img src="../../assets/img-static/mqdefault-3.jpg">
33
+      </ion-col>
34
+      <ion-col>เจาะสนามบอลไทย [ 20-10-2022 l 20:00 - 21:30 น. ]</ion-col>
35
+    </ion-row>
36
+    <ion-row>
37
+      <ion-col>
38
+        <img src="../../../assets/img-static/banner-320x100.jpeg" alt="">
39
+      </ion-col>
40
+    </ion-row>
41
+  </ion-grid>
42
+</ion-content>

+ 0 - 0
src/app/youtube/youtube.page.scss


+ 24 - 0
src/app/youtube/youtube.page.spec.ts

@@ -0,0 +1,24 @@
1
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
+import { IonicModule } from '@ionic/angular';
3
+
4
+import { YoutubePage } from './youtube.page';
5
+
6
+describe('YoutubePage', () => {
7
+  let component: YoutubePage;
8
+  let fixture: ComponentFixture<YoutubePage>;
9
+
10
+  beforeEach(waitForAsync(() => {
11
+    TestBed.configureTestingModule({
12
+      declarations: [ YoutubePage ],
13
+      imports: [IonicModule.forRoot()]
14
+    }).compileComponents();
15
+
16
+    fixture = TestBed.createComponent(YoutubePage);
17
+    component = fixture.componentInstance;
18
+    fixture.detectChanges();
19
+  }));
20
+
21
+  it('should create', () => {
22
+    expect(component).toBeTruthy();
23
+  });
24
+});

+ 15 - 0
src/app/youtube/youtube.page.ts

@@ -0,0 +1,15 @@
1
+import { Component, OnInit } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'app-youtube',
5
+  templateUrl: './youtube.page.html',
6
+  styleUrls: ['./youtube.page.scss'],
7
+})
8
+export class YoutubePage implements OnInit {
9
+
10
+  constructor() { }
11
+
12
+  ngOnInit() {
13
+  }
14
+
15
+}

BIN
src/assets/fonts/IBMPlexSansThai-Regular.ttf


BIN
src/assets/fonts/IBMPlexSansThai-SemiBold.ttf


BIN
src/assets/fonts/K2D-Light.ttf


BIN
src/assets/fonts/Montserrat-Medium.ttf


BIN
src/assets/fonts/Montserrat-SemiBold.ttf


BIN
src/assets/fonts/Prompt-Light.ttf


BIN
src/assets/fonts/Prompt-Medium.ttf


BIN
src/assets/icon/favicon.png


BIN
src/assets/icon/logo-fm99.png


BIN
src/assets/img-static/SEI129887404-c4a9.jpg


BIN
src/assets/img-static/banner-250x250.jpeg


BIN
src/assets/img-static/banner-320x100.jpeg


BIN
src/assets/img-static/banner-320x50.jpeg


BIN
src/assets/img-static/fb-Ad-1.jpeg


BIN
src/assets/img-static/fb-Ad-2.jpeg


BIN
src/assets/img-static/fb-Ad-3.jpeg


BIN
src/assets/img-static/mqdefault-1.jpg


BIN
src/assets/img-static/mqdefault-2.jpg


BIN
src/assets/img-static/mqdefault-3.jpg


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
src/assets/shapes.svg


+ 3 - 0
src/environments/environment.prod.ts

@@ -0,0 +1,3 @@
1
+export const environment = {
2
+  production: true
3
+};

+ 16 - 0
src/environments/environment.ts

@@ -0,0 +1,16 @@
1
+// This file can be replaced during build by using the `fileReplacements` array.
2
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3
+// The list of file replacements can be found in `angular.json`.
4
+
5
+export const environment = {
6
+  production: false
7
+};
8
+
9
+/*
10
+ * For easier debugging in development mode, you can import the following file
11
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12
+ *
13
+ * This import should be commented out in production mode because it will have a negative impact
14
+ * on performance if an error is thrown.
15
+ */
16
+// import 'zone.js/dist/zone-error';  // Included with Angular CLI.

+ 106 - 0
src/global.scss

@@ -0,0 +1,106 @@
1
+/*
2
+ * App Global CSS
3
+ * ----------------------------------------------------------------------------
4
+ * Put style rules here that you want to apply globally. These styles are for
5
+ * the entire app and not just one component. Additionally, this file can be
6
+ * used as an entry point to import other CSS/Sass files to be included in the
7
+ * output CSS.
8
+ * For more information on global stylesheets, visit the documentation:
9
+ * https://ionicframework.com/docs/layout/global-stylesheets
10
+ */
11
+
12
+/* Core CSS required for Ionic components to work properly */
13
+@import "~@ionic/angular/css/core.css";
14
+
15
+/* Basic CSS for apps built with Ionic */
16
+@import "~@ionic/angular/css/normalize.css";
17
+@import "~@ionic/angular/css/structure.css";
18
+@import "~@ionic/angular/css/typography.css";
19
+@import '~@ionic/angular/css/display.css';
20
+
21
+/* Optional CSS utils that can be commented out */
22
+@import "~@ionic/angular/css/padding.css";
23
+@import "~@ionic/angular/css/float-elements.css";
24
+@import "~@ionic/angular/css/text-alignment.css";
25
+@import "~@ionic/angular/css/text-transformation.css";
26
+@import "~@ionic/angular/css/flex-utils.css";
27
+
28
+// @import "swiper/scss";
29
+// @import "swiper/scss/navigation.css";
30
+// @import "swiper/scss/autoplay";
31
+@import "@ionic/angular/css/ionic-swiper";
32
+@import "swiper/scss";
33
+@import "swiper/scss/navigation";
34
+@import "swiper/scss/pagination";
35
+@import "swiper/scss/autoplay";
36
+// @import "swiper/css/bundle";
37
+// @import "swiper/css/autoplay";
38
+// @import "~swiper/swiper-bundle";
39
+// @import "swiper/scss";
40
+// @import "swiper/scss/autoplay";
41
+// @import "swiper/scss/keyboard";
42
+// @import "swiper/scss/pagination";
43
+// @import "swiper/scss/scrollbar";
44
+// @import "swiper/scss/zoom";
45
+
46
+
47
+
48
+@font-face {
49
+    font-family: "IBM Plex Sans Thai";
50
+    font-style: normal;
51
+    font-weight: normal;
52
+    src: url("./assets/fonts/IBMPlexSansThai-Regular.ttf");
53
+  }
54
+
55
+  @font-face {
56
+    font-family: "IBM Plex Sans Thai SemiBold";
57
+    font-style: normal;
58
+    font-weight: normal;
59
+    src: url("./assets/fonts/IBMPlexSansThai-SemiBold.ttf");
60
+  }  
61
+  @font-face {
62
+    font-family: "Prompt";
63
+    font-style: normal;
64
+    font-weight: normal;
65
+    src: url("./assets/fonts/Prompt-Medium.ttf");
66
+  }  
67
+  @font-face {
68
+    font-family: "Montserrat";
69
+    font-style: normal;
70
+    font-weight: normal;
71
+    src: url("./assets/fonts/Montserrat-Medium.ttf");
72
+  }   
73
+
74
+  @font-face {
75
+    font-family: "K2D";
76
+    font-style: normal;
77
+    font-weight: normal;
78
+    src: url("./assets/fonts/K2D-Light.ttf");
79
+  }  
80
+
81
+
82
+ion-title {
83
+    font-family:Montserrat !important;
84
+    font-size:1.4em;    
85
+}
86
+
87
+
88
+h2{
89
+    font-family:Prompt !important;
90
+    font-size:1.3em;
91
+    margin-top: 5px;
92
+    margin-bottom: 0px;
93
+
94
+}
95
+
96
+h3{
97
+    font-family:IBM Plex Sans Thai SemiBold !important;
98
+    font-size:1.3em;    
99
+}
100
+
101
+.head-img {
102
+  width: 15%;
103
+  display: flex;
104
+  margin-left:10px;
105
+  margin-top:5px;
106
+}

+ 26 - 0
src/index.html

@@ -0,0 +1,26 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+
4
+<head>
5
+  <meta charset="utf-8" />
6
+  <title>Ionic App</title>
7
+
8
+  <base href="/" />
9
+
10
+  <meta name="color-scheme" content="light dark" />
11
+  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
12
+  <meta name="format-detection" content="telephone=no" />
13
+  <meta name="msapplication-tap-highlight" content="no" />
14
+
15
+  <link rel="icon" type="image/png" href="assets/icon/favicon.png" />
16
+
17
+  <!-- add to homescreen for ios -->
18
+  <meta name="apple-mobile-web-app-capable" content="yes" />
19
+  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
20
+</head>
21
+
22
+<body>
23
+  <app-root></app-root>
24
+</body>
25
+
26
+</html>

+ 12 - 0
src/main.ts

@@ -0,0 +1,12 @@
1
+import { enableProdMode } from '@angular/core';
2
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3
+
4
+import { AppModule } from './app/app.module';
5
+import { environment } from './environments/environment';
6
+
7
+if (environment.production) {
8
+  enableProdMode();
9
+}
10
+
11
+platformBrowserDynamic().bootstrapModule(AppModule)
12
+  .catch(err => console.log(err));

+ 65 - 0
src/polyfills.ts

@@ -0,0 +1,65 @@
1
+/**
2
+ * This file includes polyfills needed by Angular and is loaded before the app.
3
+ * You can add your own extra polyfills to this file.
4
+ *
5
+ * This file is divided into 2 sections:
6
+ *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7
+ *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
8
+ *      file.
9
+ *
10
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13
+ *
14
+ * Learn more in https://angular.io/guide/browser-support
15
+ */
16
+
17
+/***************************************************************************************************
18
+ * BROWSER POLYFILLS
19
+ */
20
+
21
+/** IE11 requires the following for NgClass support on SVG elements */
22
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
23
+
24
+/**
25
+ * Web Animations `@angular/platform-browser/animations`
26
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28
+ */
29
+// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
30
+
31
+/**
32
+ * By default, zone.js will patch all possible macroTask and DomEvents
33
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
34
+ * because those flags need to be set before `zone.js` being loaded, and webpack
35
+ * will put import in the top of bundle, so user need to create a separate file
36
+ * in this directory (for example: zone-flags.ts), and put the following flags
37
+ * into that file, and then add the following code before importing zone.js.
38
+ * import './zone-flags';
39
+ *
40
+ * The flags allowed in zone-flags.ts are listed here.
41
+ *
42
+ * The following flags will work for all browsers.
43
+ *
44
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46
+ * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47
+ *
48
+ *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49
+ *  with the following flag, it will bypass `zone.js` patch for IE/Edge
50
+ *
51
+ *  (window as any).__Zone_enable_cross_context_check = true;
52
+ *
53
+ */
54
+
55
+import './zone-flags';
56
+
57
+/***************************************************************************************************
58
+ * Zone JS is required by default for Angular itself.
59
+ */
60
+import 'zone.js/dist/zone';  // Included with Angular CLI.
61
+
62
+
63
+/***************************************************************************************************
64
+ * APPLICATION IMPORTS
65
+ */

+ 25 - 0
src/test.ts

@@ -0,0 +1,25 @@
1
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
2
+
3
+import 'zone.js/dist/zone-testing';
4
+import { getTestBed } from '@angular/core/testing';
5
+import {
6
+  BrowserDynamicTestingModule,
7
+  platformBrowserDynamicTesting
8
+} from '@angular/platform-browser-dynamic/testing';
9
+
10
+declare const require: {
11
+  context(path: string, deep?: boolean, filter?: RegExp): {
12
+    <T>(id: string): T;
13
+    keys(): string[];
14
+  };
15
+};
16
+
17
+// First, initialize the Angular testing environment.
18
+getTestBed().initTestEnvironment(
19
+  BrowserDynamicTestingModule,
20
+  platformBrowserDynamicTesting()
21
+);
22
+// Then we find all the tests.
23
+const context = require.context('./', true, /\.spec\.ts$/);
24
+// And load the modules.
25
+context.keys().map(context);

+ 236 - 0
src/theme/variables.scss

@@ -0,0 +1,236 @@
1
+// Ionic Variables and Theming. For more info, please see:
2
+// http://ionicframework.com/docs/theming/
3
+
4
+/** Ionic CSS Variables **/
5
+:root {
6
+  /** primary **/
7
+  --ion-color-primary: #3880ff;
8
+  --ion-color-primary-rgb: 56, 128, 255;
9
+  --ion-color-primary-contrast: #ffffff;
10
+  --ion-color-primary-contrast-rgb: 255, 255, 255;
11
+  --ion-color-primary-shade: #3171e0;
12
+  --ion-color-primary-tint: #4c8dff;
13
+
14
+  /** secondary **/
15
+  --ion-color-secondary: #3dc2ff;
16
+  --ion-color-secondary-rgb: 61, 194, 255;
17
+  --ion-color-secondary-contrast: #ffffff;
18
+  --ion-color-secondary-contrast-rgb: 255, 255, 255;
19
+  --ion-color-secondary-shade: #36abe0;
20
+  --ion-color-secondary-tint: #50c8ff;
21
+
22
+  /** tertiary **/
23
+  --ion-color-tertiary: #5260ff;
24
+  --ion-color-tertiary-rgb: 82, 96, 255;
25
+  --ion-color-tertiary-contrast: #ffffff;
26
+  --ion-color-tertiary-contrast-rgb: 255, 255, 255;
27
+  --ion-color-tertiary-shade: #4854e0;
28
+  --ion-color-tertiary-tint: #6370ff;
29
+
30
+  /** success **/
31
+  --ion-color-success: #2dd36f;
32
+  --ion-color-success-rgb: 45, 211, 111;
33
+  --ion-color-success-contrast: #ffffff;
34
+  --ion-color-success-contrast-rgb: 255, 255, 255;
35
+  --ion-color-success-shade: #28ba62;
36
+  --ion-color-success-tint: #42d77d;
37
+
38
+  /** warning **/
39
+  --ion-color-warning: #ffc409;
40
+  --ion-color-warning-rgb: 255, 196, 9;
41
+  --ion-color-warning-contrast: #000000;
42
+  --ion-color-warning-contrast-rgb: 0, 0, 0;
43
+  --ion-color-warning-shade: #e0ac08;
44
+  --ion-color-warning-tint: #ffca22;
45
+
46
+  /** danger **/
47
+  --ion-color-danger: #eb445a;
48
+  --ion-color-danger-rgb: 235, 68, 90;
49
+  --ion-color-danger-contrast: #ffffff;
50
+  --ion-color-danger-contrast-rgb: 255, 255, 255;
51
+  --ion-color-danger-shade: #cf3c4f;
52
+  --ion-color-danger-tint: #ed576b;
53
+
54
+  /** dark **/
55
+  --ion-color-dark: #222428;
56
+  --ion-color-dark-rgb: 34, 36, 40;
57
+  --ion-color-dark-contrast: #ffffff;
58
+  --ion-color-dark-contrast-rgb: 255, 255, 255;
59
+  --ion-color-dark-shade: #1e2023;
60
+  --ion-color-dark-tint: #383a3e;
61
+
62
+  /** medium **/
63
+  --ion-color-medium: #92949c;
64
+  --ion-color-medium-rgb: 146, 148, 156;
65
+  --ion-color-medium-contrast: #ffffff;
66
+  --ion-color-medium-contrast-rgb: 255, 255, 255;
67
+  --ion-color-medium-shade: #808289;
68
+  --ion-color-medium-tint: #9d9fa6;
69
+
70
+  /** light **/
71
+  --ion-color-light: #f4f5f8;
72
+  --ion-color-light-rgb: 244, 245, 248;
73
+  --ion-color-light-contrast: #000000;
74
+  --ion-color-light-contrast-rgb: 0, 0, 0;
75
+  --ion-color-light-shade: #d7d8da;
76
+  --ion-color-light-tint: #f5f6f9;
77
+}
78
+
79
+@media (prefers-color-scheme: dark) {
80
+  /*
81
+   * Dark Colors
82
+   * -------------------------------------------
83
+   */
84
+
85
+  body {
86
+    --ion-color-primary: #428cff;
87
+    --ion-color-primary-rgb: 66,140,255;
88
+    --ion-color-primary-contrast: #ffffff;
89
+    --ion-color-primary-contrast-rgb: 255,255,255;
90
+    --ion-color-primary-shade: #3a7be0;
91
+    --ion-color-primary-tint: #5598ff;
92
+
93
+    --ion-color-secondary: #50c8ff;
94
+    --ion-color-secondary-rgb: 80,200,255;
95
+    --ion-color-secondary-contrast: #ffffff;
96
+    --ion-color-secondary-contrast-rgb: 255,255,255;
97
+    --ion-color-secondary-shade: #46b0e0;
98
+    --ion-color-secondary-tint: #62ceff;
99
+
100
+    --ion-color-tertiary: #6a64ff;
101
+    --ion-color-tertiary-rgb: 106,100,255;
102
+    --ion-color-tertiary-contrast: #ffffff;
103
+    --ion-color-tertiary-contrast-rgb: 255,255,255;
104
+    --ion-color-tertiary-shade: #5d58e0;
105
+    --ion-color-tertiary-tint: #7974ff;
106
+
107
+    --ion-color-success: #2fdf75;
108
+    --ion-color-success-rgb: 47,223,117;
109
+    --ion-color-success-contrast: #000000;
110
+    --ion-color-success-contrast-rgb: 0,0,0;
111
+    --ion-color-success-shade: #29c467;
112
+    --ion-color-success-tint: #44e283;
113
+
114
+    --ion-color-warning: #ffd534;
115
+    --ion-color-warning-rgb: 255,213,52;
116
+    --ion-color-warning-contrast: #000000;
117
+    --ion-color-warning-contrast-rgb: 0,0,0;
118
+    --ion-color-warning-shade: #e0bb2e;
119
+    --ion-color-warning-tint: #ffd948;
120
+
121
+    --ion-color-danger: #ff4961;
122
+    --ion-color-danger-rgb: 255,73,97;
123
+    --ion-color-danger-contrast: #ffffff;
124
+    --ion-color-danger-contrast-rgb: 255,255,255;
125
+    --ion-color-danger-shade: #e04055;
126
+    --ion-color-danger-tint: #ff5b71;
127
+
128
+    --ion-color-dark: #f4f5f8;
129
+    --ion-color-dark-rgb: 244,245,248;
130
+    --ion-color-dark-contrast: #000000;
131
+    --ion-color-dark-contrast-rgb: 0,0,0;
132
+    --ion-color-dark-shade: #d7d8da;
133
+    --ion-color-dark-tint: #f5f6f9;
134
+
135
+    --ion-color-medium: #989aa2;
136
+    --ion-color-medium-rgb: 152,154,162;
137
+    --ion-color-medium-contrast: #000000;
138
+    --ion-color-medium-contrast-rgb: 0,0,0;
139
+    --ion-color-medium-shade: #86888f;
140
+    --ion-color-medium-tint: #a2a4ab;
141
+
142
+    --ion-color-light: #222428;
143
+    --ion-color-light-rgb: 34,36,40;
144
+    --ion-color-light-contrast: #ffffff;
145
+    --ion-color-light-contrast-rgb: 255,255,255;
146
+    --ion-color-light-shade: #1e2023;
147
+    --ion-color-light-tint: #383a3e;
148
+  }
149
+
150
+  /*
151
+   * iOS Dark Theme
152
+   * -------------------------------------------
153
+   */
154
+
155
+  .ios body {
156
+    --ion-background-color: #000000;
157
+    --ion-background-color-rgb: 0,0,0;
158
+
159
+    --ion-text-color: #ffffff;
160
+    --ion-text-color-rgb: 255,255,255;
161
+
162
+    --ion-color-step-50: #0d0d0d;
163
+    --ion-color-step-100: #1a1a1a;
164
+    --ion-color-step-150: #262626;
165
+    --ion-color-step-200: #333333;
166
+    --ion-color-step-250: #404040;
167
+    --ion-color-step-300: #4d4d4d;
168
+    --ion-color-step-350: #595959;
169
+    --ion-color-step-400: #666666;
170
+    --ion-color-step-450: #737373;
171
+    --ion-color-step-500: #808080;
172
+    --ion-color-step-550: #8c8c8c;
173
+    --ion-color-step-600: #999999;
174
+    --ion-color-step-650: #a6a6a6;
175
+    --ion-color-step-700: #b3b3b3;
176
+    --ion-color-step-750: #bfbfbf;
177
+    --ion-color-step-800: #cccccc;
178
+    --ion-color-step-850: #d9d9d9;
179
+    --ion-color-step-900: #e6e6e6;
180
+    --ion-color-step-950: #f2f2f2;
181
+
182
+    --ion-item-background: #000000;
183
+
184
+    --ion-card-background: #1c1c1d;
185
+  }
186
+
187
+  .ios ion-modal {
188
+    --ion-background-color: var(--ion-color-step-100);
189
+    --ion-toolbar-background: var(--ion-color-step-150);
190
+    --ion-toolbar-border-color: var(--ion-color-step-250);
191
+  }
192
+
193
+
194
+  /*
195
+   * Material Design Dark Theme
196
+   * -------------------------------------------
197
+   */
198
+
199
+  .md body {
200
+    --ion-background-color: #121212;
201
+    --ion-background-color-rgb: 18,18,18;
202
+
203
+    --ion-text-color: #ffffff;
204
+    --ion-text-color-rgb: 255,255,255;
205
+
206
+    --ion-border-color: #222222;
207
+
208
+    --ion-color-step-50: #1e1e1e;
209
+    --ion-color-step-100: #2a2a2a;
210
+    --ion-color-step-150: #363636;
211
+    --ion-color-step-200: #414141;
212
+    --ion-color-step-250: #4d4d4d;
213
+    --ion-color-step-300: #595959;
214
+    --ion-color-step-350: #656565;
215
+    --ion-color-step-400: #717171;
216
+    --ion-color-step-450: #7d7d7d;
217
+    --ion-color-step-500: #898989;
218
+    --ion-color-step-550: #949494;
219
+    --ion-color-step-600: #a0a0a0;
220
+    --ion-color-step-650: #acacac;
221
+    --ion-color-step-700: #b8b8b8;
222
+    --ion-color-step-750: #c4c4c4;
223
+    --ion-color-step-800: #d0d0d0;
224
+    --ion-color-step-850: #dbdbdb;
225
+    --ion-color-step-900: #e7e7e7;
226
+    --ion-color-step-950: #f3f3f3;
227
+
228
+    --ion-item-background: #1e1e1e;
229
+
230
+    --ion-toolbar-background: #1f1f1f;
231
+
232
+    --ion-tab-bar-background: #1f1f1f;
233
+
234
+    --ion-card-background: #1e1e1e;
235
+  }
236
+}

+ 6 - 0
src/zone-flags.ts

@@ -0,0 +1,6 @@
1
+/**
2
+ * Prevents Angular change detection from
3
+ * running with certain Web Component callbacks
4
+ */
5
+// eslint-disable-next-line no-underscore-dangle
6
+(window as any).__Zone_disable_customElements = true;

+ 15 - 0
tsconfig.app.json

@@ -0,0 +1,15 @@
1
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+{
3
+  "extends": "./tsconfig.json",
4
+  "compilerOptions": {
5
+    "outDir": "./out-tsc/app",
6
+    "types": []
7
+  },
8
+  "files": [
9
+    "src/main.ts",
10
+    "src/polyfills.ts"
11
+  ],
12
+  "include": [
13
+    "src/**/*.d.ts"
14
+  ]
15
+}

+ 23 - 0
tsconfig.json

@@ -0,0 +1,23 @@
1
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+{
3
+  "compileOnSave": false,
4
+  "compilerOptions": {
5
+    "baseUrl": "./",
6
+    "outDir": "./dist/out-tsc",
7
+    "sourceMap": true,
8
+    "declaration": false,
9
+    "downlevelIteration": true,
10
+    "experimentalDecorators": true,
11
+    "moduleResolution": "node",
12
+    "importHelpers": true,
13
+    "target": "es2015",
14
+    "module": "es2020",
15
+    "lib": ["es2018", "dom"]
16
+  },
17
+  "angularCompilerOptions": {
18
+    "enableI18nLegacyMessageIdFormat": false,
19
+    "strictInjectionParameters": true,
20
+    "strictInputAccessModifiers": true,
21
+    "strictTemplates": true
22
+  }
23
+}

+ 18 - 0
tsconfig.spec.json

@@ -0,0 +1,18 @@
1
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+{
3
+  "extends": "./tsconfig.json",
4
+  "compilerOptions": {
5
+    "outDir": "./out-tsc/spec",
6
+    "types": [
7
+      "jasmine"
8
+    ]
9
+  },
10
+  "files": [
11
+    "src/test.ts",
12
+    "src/polyfills.ts"
13
+  ],
14
+  "include": [
15
+    "src/**/*.spec.ts",
16
+    "src/**/*.d.ts"
17
+  ]
18
+}

push message · 663a230fdb - Gogs: Simplico Git Service
tum %!s(int64=2) %!d(string=hace) años
padre
commit
663a230fdb

+ 1 - 1
capacitor.config.ts

@@ -10,7 +10,7 @@ const config: CapacitorConfig = {
10 10
   plugins: {
11 11
     CapacitorHttp: {
12 12
       enabled: true
13
-    }
13
+    },
14 14
   }
15 15
 };
16 16
 

+ 33 - 5
ios/App/App.xcodeproj/project.pbxproj

@@ -3,10 +3,12 @@
3 3
 	archiveVersion = 1;
4 4
 	classes = {
5 5
 	};
6
-	objectVersion = 48;
6
+	objectVersion = 54;
7 7
 	objects = {
8 8
 
9 9
 /* Begin PBXBuildFile section */
10
+		1EF387912AF6160200F60A08 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1EF387902AF6160200F60A08 /* GoogleService-Info.plist */; };
11
+		1EF387942AF7EEBF00F60A08 /* google-services.json in Resources */ = {isa = PBXBuildFile; fileRef = 1EF387932AF7EEBE00F60A08 /* google-services.json */; };
10 12
 		2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
11 13
 		50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
12 14
 		504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
@@ -18,6 +20,9 @@
18 20
 /* End PBXBuildFile section */
19 21
 
20 22
 /* Begin PBXFileReference section */
23
+		1EF387902AF6160200F60A08 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
24
+		1EF387922AF6201900F60A08 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
25
+		1EF387932AF7EEBE00F60A08 /* google-services.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "google-services.json"; sourceTree = "<group>"; };
21 26
 		2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
22 27
 		50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
23 28
 		504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -73,6 +78,9 @@
73 78
 		504EC3061FED79650016851F /* App */ = {
74 79
 			isa = PBXGroup;
75 80
 			children = (
81
+				1EF387932AF7EEBE00F60A08 /* google-services.json */,
82
+				1EF387922AF6201900F60A08 /* App.entitlements */,
83
+				1EF387902AF6160200F60A08 /* GoogleService-Info.plist */,
76 84
 				50379B222058CBB4000EE86E /* capacitor.config.json */,
77 85
 				504EC3071FED79650016851F /* AppDelegate.swift */,
78 86
 				504EC30B1FED79650016851F /* Main.storyboard */,
@@ -122,8 +130,9 @@
122 130
 		504EC2FC1FED79650016851F /* Project object */ = {
123 131
 			isa = PBXProject;
124 132
 			attributes = {
133
+				BuildIndependentTargetsInParallel = YES;
125 134
 				LastSwiftUpdateCheck = 0920;
126
-				LastUpgradeCheck = 0920;
135
+				LastUpgradeCheck = 1500;
127 136
 				TargetAttributes = {
128 137
 					504EC3031FED79650016851F = {
129 138
 						CreatedOnToolsVersion = 9.2;
@@ -157,10 +166,12 @@
157 166
 			files = (
158 167
 				504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
159 168
 				50B271D11FEDC1A000F3C39B /* public in Resources */,
169
+				1EF387942AF7EEBF00F60A08 /* google-services.json in Resources */,
160 170
 				504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
161 171
 				50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
162 172
 				504EC30D1FED79650016851F /* Main.storyboard in Resources */,
163 173
 				2FAD9763203C412B000D30F8 /* config.xml in Resources */,
174
+				1EF387912AF6160200F60A08 /* GoogleService-Info.plist in Resources */,
164 175
 			);
165 176
 			runOnlyForDeploymentPostprocessing = 0;
166 177
 		};
@@ -247,6 +258,7 @@
247 258
 				CLANG_WARN_BOOL_CONVERSION = YES;
248 259
 				CLANG_WARN_COMMA = YES;
249 260
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
261
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
250 262
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251 263
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
252 264
 				CLANG_WARN_EMPTY_BODY = YES;
@@ -254,8 +266,10 @@
254 266
 				CLANG_WARN_INFINITE_RECURSION = YES;
255 267
 				CLANG_WARN_INT_CONVERSION = YES;
256 268
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
269
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
257 270
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
258 271
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
272
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
259 273
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
260 274
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
261 275
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -267,6 +281,7 @@
267 281
 				DEBUG_INFORMATION_FORMAT = dwarf;
268 282
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
269 283
 				ENABLE_TESTABILITY = YES;
284
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
270 285
 				GCC_C_LANGUAGE_STANDARD = gnu11;
271 286
 				GCC_DYNAMIC_NO_PIC = NO;
272 287
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -304,6 +319,7 @@
304 319
 				CLANG_WARN_BOOL_CONVERSION = YES;
305 320
 				CLANG_WARN_COMMA = YES;
306 321
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
322
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
307 323
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
308 324
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
309 325
 				CLANG_WARN_EMPTY_BODY = YES;
@@ -311,8 +327,10 @@
311 327
 				CLANG_WARN_INFINITE_RECURSION = YES;
312 328
 				CLANG_WARN_INT_CONVERSION = YES;
313 329
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
330
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
314 331
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
315 332
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
333
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
316 334
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
317 335
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
318 336
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -324,6 +342,7 @@
324 342
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
325 343
 				ENABLE_NS_ASSERTIONS = NO;
326 344
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
345
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
327 346
 				GCC_C_LANGUAGE_STANDARD = gnu11;
328 347
 				GCC_NO_COMMON_BLOCKS = YES;
329 348
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -335,7 +354,8 @@
335 354
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
336 355
 				MTL_ENABLE_DEBUG_INFO = NO;
337 356
 				SDKROOT = iphoneos;
338
-				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
357
+				SWIFT_COMPILATION_MODE = wholemodule;
358
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
339 359
 				VALIDATE_PRODUCT = YES;
340 360
 			};
341 361
 			name = Release;
@@ -345,12 +365,16 @@
345 365
 			baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
346 366
 			buildSettings = {
347 367
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368
+				CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
348 369
 				CODE_SIGN_STYLE = Automatic;
349 370
 				CURRENT_PROJECT_VERSION = 1;
350 371
 				DEVELOPMENT_TEAM = 5QTJEGL2H2;
351 372
 				INFOPLIST_FILE = App/Info.plist;
352 373
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
353
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
374
+				LD_RUNPATH_SEARCH_PATHS = (
375
+					"$(inherited)",
376
+					"@executable_path/Frameworks",
377
+				);
354 378
 				MARKETING_VERSION = 1.0;
355 379
 				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
356 380
 				PRODUCT_BUNDLE_IDENTIFIER = net.simplico.tmtlive;
@@ -366,12 +390,16 @@
366 390
 			baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
367 391
 			buildSettings = {
368 392
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
393
+				CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
369 394
 				CODE_SIGN_STYLE = Automatic;
370 395
 				CURRENT_PROJECT_VERSION = 1;
371 396
 				DEVELOPMENT_TEAM = 5QTJEGL2H2;
372 397
 				INFOPLIST_FILE = App/Info.plist;
373 398
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
374
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
399
+				LD_RUNPATH_SEARCH_PATHS = (
400
+					"$(inherited)",
401
+					"@executable_path/Frameworks",
402
+				);
375 403
 				MARKETING_VERSION = 1.0;
376 404
 				PRODUCT_BUNDLE_IDENTIFIER = net.simplico.tmtlive;
377 405
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 8 - 0
ios/App/App/App.entitlements

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>aps-environment</key>
6
+	<string>development</string>
7
+</dict>
8
+</plist>

+ 18 - 1
ios/App/App/AppDelegate.swift

@@ -1,7 +1,7 @@
1 1
 import UIKit
2 2
 import Capacitor
3 3
 import FBSDKCoreKit
4
-
4
+import Firebase
5 5
 
6 6
 @UIApplicationMain
7 7
 class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -11,6 +11,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
11 11
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
12 12
         // Override point for customization after application launch.
13 13
         FBSDKCoreKit.ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
14
+        FirebaseApp.configure()
14 15
         return true
15 16
     }
16 17
 
@@ -59,5 +60,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
59 60
         // tracking app url opens, make sure to keep this call
60 61
         return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
61 62
     }
63
+    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
64
+      NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
65
+        Messaging.messaging().apnsToken = deviceToken
66
+        Messaging.messaging().token(completion: { (token, error) in
67
+             if let error = error {
68
+                 NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
69
+             } else if let token = token {
70
+                 NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: token)
71
+             }
72
+        })
73
+    }
74
+
75
+    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
76
+      NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
77
+    
78
+    }
62 79
 
63 80
 }

+ 38 - 0
ios/App/App/GoogleService-Info.plist

@@ -0,0 +1,38 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CLIENT_ID</key>
6
+	<string>496323526366-khm7rkn7rthnauaailuth9sdid4of8d8.apps.googleusercontent.com</string>
7
+	<key>REVERSED_CLIENT_ID</key>
8
+	<string>com.googleusercontent.apps.496323526366-khm7rkn7rthnauaailuth9sdid4of8d8</string>
9
+	<key>PLIST_VERSION</key>
10
+	<string>1</string>
11
+	<key>BUNDLE_ID</key>
12
+	<string>net.simplico.tmtlive</string>
13
+    <key>API_KEY</key>
14
+    <string>AIzaSyCEy_bLCJITwxRi-5vsiyArQM5oow5NAgk</string>
15
+    <key>GCM_SENDER_ID</key>
16
+    <string>214019008700</string>
17
+    <key>PLIST_VERSION</key>
18
+    <string>1</string>
19
+    <key>BUNDLE_ID</key>
20
+    <string>net.simplico.tmtlive</string>
21
+    <key>PROJECT_ID</key>
22
+    <string>tmtlive-557ac</string>
23
+    <key>STORAGE_BUCKET</key>
24
+    <string>tmtlive-557ac.appspot.com</string>
25
+    <key>IS_ADS_ENABLED</key>
26
+    <false></false>
27
+    <key>IS_ANALYTICS_ENABLED</key>
28
+    <false></false>
29
+    <key>IS_APPINVITE_ENABLED</key>
30
+    <true></true>
31
+    <key>IS_GCM_ENABLED</key>
32
+    <true></true>
33
+    <key>IS_SIGNIN_ENABLED</key>
34
+    <true></true>
35
+    <key>GOOGLE_APP_ID</key>
36
+    <string>1:214019008700:ios:be7fb5f07aeed695c088b9</string>
37
+</dict>
38
+</plist>

+ 42 - 33
ios/App/App/Info.plist

@@ -45,38 +45,47 @@
45 45
 	</array>
46 46
 	<key>UIViewControllerBasedStatusBarAppearance</key>
47 47
 	<true/>
48
-    <key>CFBundleURLTypes</key>
49
-        <array>
50
-        <dict>
51
-            <key>CFBundleURLSchemes</key>
52
-            <array>
53
-            <string>fb200395709360570</string>
54
-            </array>
55
-        </dict>
56
-        </array>
57
-        <key>FacebookAppID</key>
58
-        <string>200395709360570</string>
59
-        <key>FacebookClientToken</key>
60
-        <string>a3ae16e80d605bab9483feaa4c523e84</string>
61
-        <key>FacebookDisplayName</key>
62
-        <string>tigermuaythai.live</string>
63
-        <key>LSApplicationQueriesSchemes</key>
64
-        <array>
65
-            <string>fbapi</string>
66
-            <string>fbapi20130214</string>
67
-            <string>fbapi20130410</string>
68
-            <string>fbapi20130702</string>
69
-            <string>fbapi20131010</string>
70
-            <string>fbapi20131219</string>
71
-            <string>fbapi20140410</string>
72
-            <string>fbapi20140116</string>
73
-            <string>fbapi20150313</string>
74
-            <string>fbapi20150629</string>
75
-            <string>fbapi20160328</string>
76
-            <string>fbauth</string>
77
-            <string>fb-messenger-share-api</string>
78
-            <string>fbauth2</string>
79
-            <string>fbshareextension</string>
80
-        </array>
48
+  <key>CFBundleURLTypes</key>
49
+  <array>
50
+    <dict>
51
+      <key>CFBundleURLSchemes</key>
52
+      <array>
53
+        <string>fb200395709360570</string>
54
+      </array>
55
+    </dict>
56
+    <dict>
57
+			<key>CFBundleURLName</key>
58
+			<string>net.simplico.tmtlive</string>
59
+			<key>CFBundleURLSchemes</key>
60
+			<array>
61
+				<string>tmtlive</string>
62
+				<string>com.googleusercontent.apps.496323526366-khm7rkn7rthnauaailuth9sdid4of8d8</string>
63
+			</array>
64
+		</dict>
65
+  </array>
66
+  <key>FacebookAppID</key>
67
+  <string>200395709360570</string>
68
+  <key>FacebookClientToken</key>
69
+  <string>a3ae16e80d605bab9483feaa4c523e84</string>
70
+  <key>FacebookDisplayName</key>
71
+  <string>tigermuaythai.live</string>
72
+  <key>LSApplicationQueriesSchemes</key>
73
+  <array>
74
+    <string>fbapi</string>
75
+    <string>fbapi20130214</string>
76
+    <string>fbapi20130410</string>
77
+    <string>fbapi20130702</string>
78
+    <string>fbapi20131010</string>
79
+    <string>fbapi20131219</string>
80
+    <string>fbapi20140410</string>
81
+    <string>fbapi20140116</string>
82
+    <string>fbapi20150313</string>
83
+    <string>fbapi20150629</string>
84
+    <string>fbapi20160328</string>
85
+    <string>fbauth</string>
86
+    <string>fb-messenger-share-api</string>
87
+    <string>fbauth2</string>
88
+    <string>fbshareextension</string>
89
+  </array>
81 90
 </dict>
82 91
 </plist>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 13 - 0
ios/App/App/google-services.json


+ 3 - 0
ios/App/Podfile

@@ -16,12 +16,15 @@ def capacitor_pods
16 16
   pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
17 17
   pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
18 18
   pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
19
+  pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
19 20
   pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
21
+  pod 'CodetrixStudioCapacitorGoogleAuth', :path => '../../node_modules/@codetrix-studio/capacitor-google-auth'
20 22
 end
21 23
 
22 24
 target 'App' do
23 25
   capacitor_pods
24 26
   # Add your Pods here
27
+  pod 'Firebase/Messaging' # Add this line
25 28
 end
26 29
 
27 30
 post_install do |installer|

+ 107 - 1
ios/App/Podfile.lock

@@ -1,4 +1,10 @@
1 1
 PODS:
2
+  - AppAuth (1.6.2):
3
+    - AppAuth/Core (= 1.6.2)
4
+    - AppAuth/ExternalUserAgent (= 1.6.2)
5
+  - AppAuth/Core (1.6.2)
6
+  - AppAuth/ExternalUserAgent (1.6.2):
7
+    - AppAuth/Core
2 8
   - Capacitor (5.5.0):
3 9
     - CapacitorCordova
4 10
   - CapacitorApp (5.0.6):
@@ -14,8 +20,13 @@ PODS:
14 20
     - Capacitor
15 21
   - CapacitorPreferences (5.0.6):
16 22
     - Capacitor
23
+  - CapacitorPushNotifications (5.1.0):
24
+    - Capacitor
17 25
   - CapacitorStatusBar (5.0.6):
18 26
     - Capacitor
27
+  - CodetrixStudioCapacitorGoogleAuth (0.0.1):
28
+    - Capacitor
29
+    - GoogleSignIn (~> 6.2.4)
19 30
   - FBAEMKit (16.1.3):
20 31
     - FBSDKCoreKit_Basics (= 16.1.3)
21 32
   - FBSDKCoreKit (16.1.3):
@@ -24,6 +35,66 @@ PODS:
24 35
   - FBSDKCoreKit_Basics (16.1.3)
25 36
   - FBSDKLoginKit (16.1.3):
26 37
     - FBSDKCoreKit (= 16.1.3)
38
+  - Firebase/CoreOnly (10.17.0):
39
+    - FirebaseCore (= 10.17.0)
40
+  - Firebase/Messaging (10.17.0):
41
+    - Firebase/CoreOnly
42
+    - FirebaseMessaging (~> 10.17.0)
43
+  - FirebaseCore (10.17.0):
44
+    - FirebaseCoreInternal (~> 10.0)
45
+    - GoogleUtilities/Environment (~> 7.8)
46
+    - GoogleUtilities/Logger (~> 7.8)
47
+  - FirebaseCoreInternal (10.17.0):
48
+    - "GoogleUtilities/NSData+zlib (~> 7.8)"
49
+  - FirebaseInstallations (10.17.0):
50
+    - FirebaseCore (~> 10.0)
51
+    - GoogleUtilities/Environment (~> 7.8)
52
+    - GoogleUtilities/UserDefaults (~> 7.8)
53
+    - PromisesObjC (~> 2.1)
54
+  - FirebaseMessaging (10.17.0):
55
+    - FirebaseCore (~> 10.0)
56
+    - FirebaseInstallations (~> 10.0)
57
+    - GoogleDataTransport (~> 9.2)
58
+    - GoogleUtilities/AppDelegateSwizzler (~> 7.8)
59
+    - GoogleUtilities/Environment (~> 7.8)
60
+    - GoogleUtilities/Reachability (~> 7.8)
61
+    - GoogleUtilities/UserDefaults (~> 7.8)
62
+    - nanopb (< 2.30910.0, >= 2.30908.0)
63
+  - GoogleDataTransport (9.2.5):
64
+    - GoogleUtilities/Environment (~> 7.7)
65
+    - nanopb (< 2.30910.0, >= 2.30908.0)
66
+    - PromisesObjC (< 3.0, >= 1.2)
67
+  - GoogleSignIn (6.2.4):
68
+    - AppAuth (~> 1.5)
69
+    - GTMAppAuth (~> 1.3)
70
+    - GTMSessionFetcher/Core (< 3.0, >= 1.1)
71
+  - GoogleUtilities/AppDelegateSwizzler (7.11.6):
72
+    - GoogleUtilities/Environment
73
+    - GoogleUtilities/Logger
74
+    - GoogleUtilities/Network
75
+  - GoogleUtilities/Environment (7.11.6):
76
+    - PromisesObjC (< 3.0, >= 1.2)
77
+  - GoogleUtilities/Logger (7.11.6):
78
+    - GoogleUtilities/Environment
79
+  - GoogleUtilities/Network (7.11.6):
80
+    - GoogleUtilities/Logger
81
+    - "GoogleUtilities/NSData+zlib"
82
+    - GoogleUtilities/Reachability
83
+  - "GoogleUtilities/NSData+zlib (7.11.6)"
84
+  - GoogleUtilities/Reachability (7.11.6):
85
+    - GoogleUtilities/Logger
86
+  - GoogleUtilities/UserDefaults (7.11.6):
87
+    - GoogleUtilities/Logger
88
+  - GTMAppAuth (1.3.1):
89
+    - AppAuth/Core (~> 1.6)
90
+    - GTMSessionFetcher/Core (< 3.0, >= 1.5)
91
+  - GTMSessionFetcher/Core (2.3.0)
92
+  - nanopb (2.30909.1):
93
+    - nanopb/decode (= 2.30909.1)
94
+    - nanopb/encode (= 2.30909.1)
95
+  - nanopb/decode (2.30909.1)
96
+  - nanopb/encode (2.30909.1)
97
+  - PromisesObjC (2.3.1)
27 98
 
28 99
 DEPENDENCIES:
29 100
   - "Capacitor (from `../../node_modules/@capacitor/ios`)"
@@ -33,14 +104,30 @@ DEPENDENCIES:
33 104
   - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
34 105
   - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
35 106
   - "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
107
+  - "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)"
36 108
   - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
109
+  - "CodetrixStudioCapacitorGoogleAuth (from `../../node_modules/@codetrix-studio/capacitor-google-auth`)"
110
+  - Firebase/Messaging
37 111
 
38 112
 SPEC REPOS:
39 113
   trunk:
114
+    - AppAuth
40 115
     - FBAEMKit
41 116
     - FBSDKCoreKit
42 117
     - FBSDKCoreKit_Basics
43 118
     - FBSDKLoginKit
119
+    - Firebase
120
+    - FirebaseCore
121
+    - FirebaseCoreInternal
122
+    - FirebaseInstallations
123
+    - FirebaseMessaging
124
+    - GoogleDataTransport
125
+    - GoogleSignIn
126
+    - GoogleUtilities
127
+    - GTMAppAuth
128
+    - GTMSessionFetcher
129
+    - nanopb
130
+    - PromisesObjC
44 131
 
45 132
 EXTERNAL SOURCES:
46 133
   Capacitor:
@@ -57,10 +144,15 @@ EXTERNAL SOURCES:
57 144
     :path: "../../node_modules/@capacitor/keyboard"
58 145
   CapacitorPreferences:
59 146
     :path: "../../node_modules/@capacitor/preferences"
147
+  CapacitorPushNotifications:
148
+    :path: "../../node_modules/@capacitor/push-notifications"
60 149
   CapacitorStatusBar:
61 150
     :path: "../../node_modules/@capacitor/status-bar"
151
+  CodetrixStudioCapacitorGoogleAuth:
152
+    :path: "../../node_modules/@codetrix-studio/capacitor-google-auth"
62 153
 
63 154
 SPEC CHECKSUMS:
155
+  AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
64 156
   Capacitor: 57890b363df14d5d2d5d8461aa23e886cb34da2a
65 157
   CapacitorApp: 024e1b1bea5f883d79f6330d309bc441c88ad04a
66 158
   CapacitorCommunityFacebookLogin: c0e2bb54cb567d90443a80ae20569fdac0df3f89
@@ -68,12 +160,26 @@ SPEC CHECKSUMS:
68 160
   CapacitorHaptics: 1fffc1217c7e64a472d7845be50fb0c2f7d4204c
69 161
   CapacitorKeyboard: b978154b024a5f65e044908e37d15b7de58b9d12
70 162
   CapacitorPreferences: f03954bcb0ff09c792909e46bff88e3183c16b10
163
+  CapacitorPushNotifications: b31e326c6e4eb216a622041d6ca21a973f34943f
71 164
   CapacitorStatusBar: 565c0a1ebd79bb40d797606a8992b4a105885309
165
+  CodetrixStudioCapacitorGoogleAuth: fcce058390347c1ce5d8ac4764bdf1f5c1ee233b
72 166
   FBAEMKit: af2972f39bb0f3f7c45998f435b007833c32ffb2
73 167
   FBSDKCoreKit: 19e2e18b3be578d7a51fed8fdd8c152bef0b9511
74 168
   FBSDKCoreKit_Basics: dd9826ce3c9fd9f8cdf8dbbd0ef0a53e6c0c9e7e
75 169
   FBSDKLoginKit: c395c63a1a6cf4a8a1e6103fd94b8c46329ee81c
170
+  Firebase: f4ac0b02927af9253ae094d23deecf0890da7374
171
+  FirebaseCore: 534544dd98cabcf4bf8598d88ec683b02319a528
172
+  FirebaseCoreInternal: 2cf9202e226e3f78d2bf6d56c472686b935bfb7f
173
+  FirebaseInstallations: 9387bf15abfc69a714f54e54f74a251264fdb79b
174
+  FirebaseMessaging: 1367b28c0c83a63072af4a711328fcc2e6899902
175
+  GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
176
+  GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a
177
+  GoogleUtilities: 202e7a9f5128accd11160fb9c19612de1911aa19
178
+  GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
179
+  GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
180
+  nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
181
+  PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
76 182
 
77
-PODFILE CHECKSUM: c9736b063f76e0be20a97ef4e5e07cd2323fa896
183
+PODFILE CHECKSUM: 13a486d397817692d7e7744cf0c6e77b81469655
78 184
 
79 185
 COCOAPODS: 1.12.1

+ 18 - 0
package-lock.json

@@ -15,7 +15,9 @@
15 15
         "@capacitor/ios": "5.5.0",
16 16
         "@capacitor/keyboard": "5.0.6",
17 17
         "@capacitor/preferences": "^5.0.6",
18
+        "@capacitor/push-notifications": "^5.1.0",
18 19
         "@capacitor/status-bar": "5.0.6",
20
+        "@codetrix-studio/capacitor-google-auth": "^3.3.4",
19 21
         "@ionic/vue": "^7.0.0",
20 22
         "@ionic/vue-router": "^7.0.0",
21 23
         "@vimeo/player": "^2.20.1",
@@ -1908,6 +1910,14 @@
1908 1910
         "@capacitor/core": "^5.0.0"
1909 1911
       }
1910 1912
     },
1913
+    "node_modules/@capacitor/push-notifications": {
1914
+      "version": "5.1.0",
1915
+      "resolved": "https://registry.npmjs.org/@capacitor/push-notifications/-/push-notifications-5.1.0.tgz",
1916
+      "integrity": "sha512-Laxi5TQbwTqQFNJZdyyfJJqb+OVZz+0VRtW4uhM+u5TKWuXCYw/yrctXuIpG+VFUptvtPG7ic7+0WcBs+sQ17Q==",
1917
+      "peerDependencies": {
1918
+        "@capacitor/core": "^5.0.0"
1919
+      }
1920
+    },
1911 1921
     "node_modules/@capacitor/status-bar": {
1912 1922
       "version": "5.0.6",
1913 1923
       "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-5.0.6.tgz",
@@ -1916,6 +1926,14 @@
1916 1926
         "@capacitor/core": "^5.0.0"
1917 1927
       }
1918 1928
     },
1929
+    "node_modules/@codetrix-studio/capacitor-google-auth": {
1930
+      "version": "3.3.4",
1931
+      "resolved": "https://registry.npmjs.org/@codetrix-studio/capacitor-google-auth/-/capacitor-google-auth-3.3.4.tgz",
1932
+      "integrity": "sha512-R9kTWK5x2bT+gXV1ia48Xt/rS1RPXrVVPDCeX4mpGFyIyjdx1FmuAkHeFNsSQ4sGDKkjCWnXf6z+ikcKnusz7g==",
1933
+      "peerDependencies": {
1934
+        "@capacitor/core": "^5.0.0"
1935
+      }
1936
+    },
1919 1937
     "node_modules/@colors/colors": {
1920 1938
       "version": "1.5.0",
1921 1939
       "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",

+ 2 - 0
package.json

@@ -19,7 +19,9 @@
19 19
     "@capacitor/ios": "5.5.0",
20 20
     "@capacitor/keyboard": "5.0.6",
21 21
     "@capacitor/preferences": "^5.0.6",
22
+    "@capacitor/push-notifications": "^5.1.0",
22 23
     "@capacitor/status-bar": "5.0.6",
24
+    "@codetrix-studio/capacitor-google-auth": "^3.3.4",
23 25
     "@ionic/vue": "^7.0.0",
24 26
     "@ionic/vue-router": "^7.0.0",
25 27
     "@vimeo/player": "^2.20.1",

+ 9 - 1
src/App.vue

@@ -5,5 +5,13 @@
5 5
 </template>
6 6
 
7 7
 <script setup lang="ts">
8
-import { IonApp, IonRouterOutlet } from '@ionic/vue';
8
+import { IonApp, IonRouterOutlet, onIonViewWillEnter } from '@ionic/vue';
9
+import { defineComponent, onMounted } from 'vue';
10
+
11
+
12
+
13
+onIonViewWillEnter(() => {
14
+  console.log("Init On Mouting")
15
+});
16
+
9 17
 </script>

+ 14 - 0
src/settings.ts

@@ -63,3 +63,17 @@ export const listMats = async  () => {
63 63
   console.log(data)
64 64
   return data.results
65 65
 }
66
+
67
+export const storeAPNToken = async (device_token) => {
68
+  
69
+  const token = await Preferences.get({ key: 'token' });
70
+  console.log("token = ", token)
71
+  const { data } = await axios.post(BASE_URL + "backend/api/device_tokens/",{token: device_token},
72
+  {
73
+    headers: { 
74
+    'Authorization': `Token ${token.value}`
75
+    }
76
+  })
77
+  console.log(data)
78
+  return data
79
+}

+ 36 - 2
src/views/ProfilePage.vue

@@ -7,8 +7,13 @@
7 7
     </ion-header>
8 8
     <ion-content>
9 9
       <div class="example-content">Listen now content</div>
10
-      <ion-button @click='fbLogout' v-if='isLogin'>Facebook Logout</ion-button>
11
-      <ion-button @click='fbLogin' v-else>Facebook Login</ion-button>
10
+      <template v-if="isLogin">
11
+      <ion-button @click='fbLogout'>Logout</ion-button>
12
+      </template>
13
+      <template v-else>
14
+        <ion-button @click='fbLogin'>Facebook Login</ion-button>
15
+        <ion-button @click='ggLogin'>Google Login</ion-button>
16
+      </template>
12 17
     </ion-content>
13 18
   </ion-page>
14 19
 </template>
@@ -16,6 +21,12 @@
16 21
 <script setup lang="ts">
17 22
 import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonButton, onIonViewWillEnter } from '@ionic/vue';
18 23
 import ExploreContainer from '@/components/ExploreContainer.vue';
24
+import { defineComponent, onMounted } from 'vue';
25
+import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
26
+
27
+onMounted(() => {
28
+  GoogleAuth.initialize();
29
+});
19 30
 
20 31
 import {
21 32
   FacebookLogin,
@@ -33,6 +44,15 @@ const FACEBOOK_PERMISSIONS = [
33 44
 
34 45
 const isLogin = ref(false)
35 46
 
47
+const ggLogin = async () => {
48
+  const response = await GoogleAuth.signIn();
49
+  console.log(response);
50
+  console.log(response.accessToken)
51
+  if( response.authentication.accessToken ) {
52
+    isLogin.value = true
53
+  }
54
+}
55
+
36 56
 const fbLogin = async () => {
37 57
   const result = await (<FacebookLoginResponse>(
38 58
     FacebookLogin.login({ permissions: FACEBOOK_PERMISSIONS })
@@ -60,6 +80,7 @@ onIonViewWillEnter(async () => {
60 80
   }else {
61 81
     isLogin.value = false
62 82
   }
83
+  ggCheckLogin()
63 84
 
64 85
 })
65 86
 const getProfile = async () => {
@@ -69,4 +90,17 @@ const getProfile = async () => {
69 90
 
70 91
   console.log(`Facebook user's email is ${result.email}`);
71 92
 }
93
+const ggCheckLogin = async() => {
94
+    GoogleAuth.refresh()
95
+        .then((data) => {
96
+            if (data.accessToken) {
97
+                isLogin.value = true
98
+            }
99
+        })
100
+        .catch((error) => {
101
+            if (error.type === 'userLoggedOut') {
102
+                //this.signin()
103
+            }
104
+        });
105
+}
72 106
 </script>

+ 44 - 1
src/views/Tab1Page.vue

@@ -79,10 +79,13 @@ import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonIcon, onIonVie
79 79
 import ExploreContainer  from '@/components/ExploreContainer.vue';
80 80
 import { CapacitorHttp } from '@capacitor/core';
81 81
 import { ref } from 'vue';
82
-import { TOKEN, getProducts, setToken, getObject, getToken, getTrainers, listMats } from '@/settings';
82
+import { TOKEN, getProducts, setToken, getObject, getToken, getTrainers, listMats, storeAPNToken } from '@/settings';
83 83
 //import VueCoreVideoPlayer from 'vue-core-video-player'
84 84
 import { vueVimeoPlayer } from 'vue-vimeo-player'
85 85
 
86
+import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
87
+
88
+import { PushNotifications } from '@capacitor/push-notifications';
86 89
 
87 90
 import Player from '@vimeo/player';
88 91
 
@@ -127,6 +130,9 @@ const mats = ref()
127 130
     mats.value = await listMats()
128 131
     console.log(" trainers => ", trainers)
129 132
 
133
+    GoogleAuth.initialize();
134
+    registerNotifications()
135
+    addListeners()
130 136
   })
131 137
 
132 138
   onIonViewWillLeave(() => {
@@ -145,4 +151,41 @@ const mats = ref()
145 151
     const response: HttpResponse = await CapacitorHttp.get(options);
146 152
     console.log(response)
147 153
   }
154
+const addListeners = async () => {
155
+  await PushNotifications.addListener('registration', token => {
156
+    console.info('Registration token: ', token.value);
157
+    storeAPNToken(token.value)
158
+  });
159
+
160
+  await PushNotifications.addListener('registrationError', err => {
161
+    console.error('Registration error: ', err.error);
162
+  });
163
+
164
+  await PushNotifications.addListener('pushNotificationReceived', notification => {
165
+    console.log('Push notification received: ', notification);
166
+  });
167
+
168
+  await PushNotifications.addListener('pushNotificationActionPerformed', notification => {
169
+    console.log('Push notification action performed', notification.actionId, notification.inputValue);
170
+  });
171
+}
172
+
173
+const registerNotifications = async () => {
174
+  let permStatus = await PushNotifications.checkPermissions();
175
+
176
+  if (permStatus.receive === 'prompt') {
177
+    permStatus = await PushNotifications.requestPermissions();
178
+  }
179
+
180
+  if (permStatus.receive !== 'granted') {
181
+    throw new Error('User denied permissions!');
182
+  }
183
+
184
+  await PushNotifications.register();
185
+}
186
+
187
+const getDeliveredNotifications = async () => {
188
+  const notificationList = await PushNotifications.getDeliveredNotifications();
189
+  console.log('delivered notifications', notificationList);
190
+}
148 191
 </script>