├── .editorconfig ├── .eslintrc.json ├── .firebaserc ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ionic-issue-bot.yml └── workflows │ └── CI.yml ├── .gitignore ├── .stylelintrc.yml ├── LICENSE ├── README.md ├── android ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── capacitor.build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── getcapacitor │ │ │ └── myapp │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── AndroidManifest.xml.orig │ │ ├── assets │ │ │ ├── capacitor.config.json │ │ │ └── capacitor.plugins.json │ │ ├── java │ │ │ └── com │ │ │ │ └── ionicframework │ │ │ │ └── conferenceapp │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable-land-hdpi │ │ │ └── splash.png │ │ │ ├── drawable-land-mdpi │ │ │ └── splash.png │ │ │ ├── drawable-land-xhdpi │ │ │ └── splash.png │ │ │ ├── drawable-land-xxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-land-xxxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-port-hdpi │ │ │ └── splash.png │ │ │ ├── drawable-port-mdpi │ │ │ └── splash.png │ │ │ ├── drawable-port-xhdpi │ │ │ └── splash.png │ │ │ ├── drawable-port-xxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-port-xxxhdpi │ │ │ └── splash.png │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ ├── ic_launcher_background.xml │ │ │ └── splash.png │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ ├── ic_launcher_background.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ ├── config.xml │ │ │ └── file_paths.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── getcapacitor │ │ └── myapp │ │ └── ExampleUnitTest.java ├── build.gradle ├── capacitor.settings.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── variables.gradle ├── angular.json ├── capacitor.config.ts ├── cypress.config.ts ├── cypress ├── downloads │ └── downloads.html ├── support │ ├── commands.ts │ ├── component-index.html │ ├── component.ts │ └── e2e.ts └── tsconfig.json ├── e2e ├── fixtures │ └── login.json └── specs │ ├── about.cy.ts │ ├── map.cy.ts │ ├── schedule.cy.ts │ ├── speakers.cy.ts │ └── tutorial.cy.ts ├── firebase.json ├── generate-h2-push.js ├── ionic.config.json ├── ios ├── .gitignore └── App │ ├── App.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── App.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ ├── App │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon-512@2x.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── Splash.imageset │ │ │ ├── Contents.json │ │ │ ├── splash-2732x2732-1.png │ │ │ ├── splash-2732x2732-2.png │ │ │ └── splash-2732x2732.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── capacitor.config.json │ └── config.xml │ ├── Podfile │ └── Podfile.lock ├── ngsw-config.json ├── package-lock.json ├── package.json ├── resources ├── android │ ├── icon │ │ ├── drawable-hdpi-icon.png │ │ ├── drawable-ldpi-icon.png │ │ ├── drawable-mdpi-icon.png │ │ ├── drawable-xhdpi-icon.png │ │ ├── drawable-xxhdpi-icon.png │ │ └── drawable-xxxhdpi-icon.png │ └── splash │ │ ├── drawable-land-hdpi-screen.png │ │ ├── drawable-land-ldpi-screen.png │ │ ├── drawable-land-mdpi-screen.png │ │ ├── drawable-land-xhdpi-screen.png │ │ ├── drawable-land-xxhdpi-screen.png │ │ ├── drawable-land-xxxhdpi-screen.png │ │ ├── drawable-port-hdpi-screen.png │ │ ├── drawable-port-ldpi-screen.png │ │ ├── drawable-port-mdpi-screen.png │ │ ├── drawable-port-xhdpi-screen.png │ │ ├── drawable-port-xxhdpi-screen.png │ │ └── drawable-port-xxxhdpi-screen.png ├── icon.png ├── icon.psd ├── icon.psd.md5 ├── ios │ ├── icon │ │ ├── icon-1024.png │ │ ├── icon-108@2x.png │ │ ├── icon-20.png │ │ ├── icon-20@2x.png │ │ ├── icon-20@3x.png │ │ ├── icon-24@2x.png │ │ ├── icon-27.5@2x.png │ │ ├── icon-29.png │ │ ├── icon-29@2x.png │ │ ├── icon-29@3x.png │ │ ├── icon-40.png │ │ ├── icon-40@2x.png │ │ ├── icon-40@3x.png │ │ ├── icon-44@2x.png │ │ ├── icon-50.png │ │ ├── icon-50@2x.png │ │ ├── icon-60.png │ │ ├── icon-60@2x.png │ │ ├── icon-60@3x.png │ │ ├── icon-72.png │ │ ├── icon-72@2x.png │ │ ├── icon-76.png │ │ ├── icon-76@2x.png │ │ ├── icon-83.5@2x.png │ │ ├── icon-86@2x.png │ │ ├── icon-98@2x.png │ │ ├── icon-small.png │ │ ├── icon-small@2x.png │ │ ├── icon-small@3x.png │ │ ├── icon.png │ │ └── icon@2x.png │ └── splash │ │ ├── Default-1792h~iphone.png │ │ ├── Default-2436h.png │ │ ├── Default-2688h~iphone.png │ │ ├── Default-568h@2x~iphone.png │ │ ├── Default-667h.png │ │ ├── Default-736h.png │ │ ├── Default-Landscape-1792h~iphone.png │ │ ├── Default-Landscape-2436h.png │ │ ├── Default-Landscape-2688h~iphone.png │ │ ├── Default-Landscape-736h.png │ │ ├── Default-Landscape@2x~ipad.png │ │ ├── Default-Landscape@~ipadpro.png │ │ ├── Default-Landscape~ipad.png │ │ ├── Default-Portrait@2x~ipad.png │ │ ├── Default-Portrait@~ipadpro.png │ │ ├── Default-Portrait~ipad.png │ │ ├── Default@2x~iphone.png │ │ ├── Default@2x~universal~anyany.png │ │ └── Default~iphone.png ├── splash.png └── splash.png.md5 ├── src ├── app │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.routes.ts │ ├── app.scss │ ├── interfaces │ │ ├── conference.interfaces.ts │ │ └── user-options.ts │ ├── pages │ │ ├── about-popover │ │ │ └── about-popover.ts │ │ ├── about │ │ │ ├── about.html │ │ │ ├── about.scss │ │ │ └── about.ts │ │ ├── account │ │ │ ├── account.html │ │ │ ├── account.scss │ │ │ └── account.ts │ │ ├── login │ │ │ ├── login.html │ │ │ ├── login.scss │ │ │ └── login.ts │ │ ├── map │ │ │ ├── map-dark-style.js │ │ │ ├── map.html │ │ │ ├── map.scss │ │ │ └── map.ts │ │ ├── schedule-filter │ │ │ ├── schedule-filter.html │ │ │ ├── schedule-filter.scss │ │ │ └── schedule-filter.ts │ │ ├── schedule │ │ │ ├── schedule.html │ │ │ ├── schedule.scss │ │ │ └── schedule.ts │ │ ├── session-detail │ │ │ ├── session-detail.html │ │ │ ├── session-detail.scss │ │ │ └── session-detail.ts │ │ ├── signup │ │ │ ├── signup.html │ │ │ ├── signup.scss │ │ │ └── signup.ts │ │ ├── speaker-detail │ │ │ ├── speaker-detail.html │ │ │ ├── speaker-detail.scss │ │ │ └── speaker-detail.ts │ │ ├── speaker-list │ │ │ ├── speaker-list.html │ │ │ ├── speaker-list.scss │ │ │ ├── speaker-list.spec.ts │ │ │ └── speaker-list.ts │ │ ├── support │ │ │ ├── support.html │ │ │ ├── support.scss │ │ │ └── support.ts │ │ ├── tabs-page │ │ │ ├── routes.ts │ │ │ ├── tabs-page.html │ │ │ ├── tabs-page.scss │ │ │ ├── tabs-page.spec.ts │ │ │ └── tabs-page.ts │ │ └── tutorial │ │ │ ├── tutorial.html │ │ │ ├── tutorial.scss │ │ │ ├── tutorial.spec.ts │ │ │ └── tutorial.ts │ └── providers │ │ ├── can-deactivate-support.guard.ts │ │ ├── check-tutorial.guard.ts │ │ ├── conference.service.ts │ │ ├── location.service.ts │ │ └── user.service.ts ├── assets │ ├── data │ │ └── data.json │ ├── icon │ │ └── favicon.png │ ├── icons │ │ ├── 128.png │ │ ├── 144.png │ │ ├── 152.png │ │ ├── 180.png │ │ ├── 192.png │ │ ├── 384.png │ │ ├── 512.png │ │ ├── 72.png │ │ └── 96.png │ ├── img │ │ ├── about │ │ │ ├── Archive.zip │ │ │ ├── austin.jpg │ │ │ ├── chicago.jpg │ │ │ ├── madison.jpg │ │ │ └── seattle.jpg │ │ ├── appicon.png │ │ ├── appicon.svg │ │ ├── ica-slidebox-img-1.png │ │ ├── ica-slidebox-img-2.png │ │ ├── ica-slidebox-img-3.png │ │ ├── ica-slidebox-img-4.png │ │ ├── ionic-logo-white.svg │ │ ├── speaker-background.png │ │ └── speakers │ │ │ ├── bear.jpg │ │ │ ├── cheetah.jpg │ │ │ ├── duck.jpg │ │ │ ├── eagle.jpg │ │ │ ├── elephant.jpg │ │ │ ├── giraffe.jpg │ │ │ ├── iguana.jpg │ │ │ ├── kitten.jpg │ │ │ ├── lion.jpg │ │ │ ├── mouse.jpg │ │ │ ├── puppy.jpg │ │ │ ├── rabbit.jpg │ │ │ └── turtle.jpg │ └── manifest.webmanifest ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── global.scss ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── test.ts ├── theme │ └── variables.scss └── zone-flags.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "overrides": [ 4 | { 5 | "files": ["*.ts"], 6 | "parserOptions": { 7 | "project": ["tsconfig.json"], 8 | "createDefaultProgram": true 9 | }, 10 | "extends": [ 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:@angular-eslint/recommended", 13 | "plugin:@angular-eslint/template/process-inline-templates" 14 | ], 15 | "rules": { 16 | "@typescript-eslint/explicit-member-accessibility": "off", 17 | "@typescript-eslint/explicit-function-return-type": "off", 18 | "@typescript-eslint/no-inferrable-types": [ 19 | "error", 20 | { 21 | "ignoreParameters": true 22 | } 23 | ], 24 | "@typescript-eslint/no-non-null-assertion": "error", 25 | "@typescript-eslint/no-explicit-any": "off", 26 | "@typescript-eslint/member-ordering": [ 27 | "error", 28 | { 29 | "default": [ 30 | "static-field", 31 | "instance-field", 32 | "static-method", 33 | "instance-method" 34 | ] 35 | } 36 | ], 37 | "@typescript-eslint/naming-convention": [ 38 | "error", 39 | { 40 | "selector": "variable", 41 | "format": ["camelCase", "UPPER_CASE", "PascalCase"] 42 | } 43 | ], 44 | "@angular-eslint/component-class-suffix": "off", 45 | "@angular-eslint/no-host-metadata-property": "error", 46 | "@angular-eslint/no-inputs-metadata-property": "error", 47 | "@angular-eslint/no-output-rename": "error", 48 | "@angular-eslint/use-lifecycle-interface": "error", 49 | "@angular-eslint/use-pipe-transform-interface": "error", 50 | "quotes": ["error", "single"], 51 | "semi": ["error", "always"], 52 | "max-len": ["error", { "code": 140 }], 53 | "no-console": "off", 54 | "curly": "error", 55 | "eqeqeq": "error", 56 | "no-empty": "off", 57 | "arrow-parens": ["error", "as-needed"], 58 | "object-shorthand": "error", 59 | "eol-last": "error", 60 | "import/order": "off", 61 | "no-multiple-empty-lines": ["error", { "max": 1 }], 62 | "no-trailing-spaces": "error" 63 | } 64 | }, 65 | { 66 | "files": ["*.html"], 67 | "extends": [ 68 | "plugin:@angular-eslint/template/recommended" 69 | ], 70 | "rules": {} 71 | } 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "ionic-ng-conf-app" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Ionic Angular Conference Application 2 | 3 | Thank you for taking the time to contribute! :tada::+1: 4 | 5 | The following is a set of guidelines for contributing to the conference app. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. 6 | 7 | ## Table of Contents 8 | - [Reporting Issues](#reporting-issues) 9 | - [Before Submitting an Issue](#before-submitting-an-issue) 10 | - [Determining the Repository](#determining-the-repository) 11 | - [Submitting the Issue](#submitting-the-issue) 12 | - [Submitting a Pull Request](#submitting-a-pull-request) 13 | - [Guidelines for Submitting](#guidelines-for-submitting) 14 | - [Code Style](#code-style) 15 | 16 | ## Reporting Issues 17 | 18 | Before submitting an issue, please go through [the list below](#before-submitting-an-issue) as you might find a solution to your issue. 19 | 20 | ### Before Submitting an Issue 21 | 22 | * Make sure you get the latest version of the code and run through the [Getting Started](https://github.com/ionic-team/ionic-conference-app#getting-started) steps to see if this resolves your issue. 23 | * Check the [forum](https://forum.ionicframework.com) for similar questions and answers. 24 | * Go through [all issues](https://github.com/ionic-team/ionic-conference-app/issues?utf8=%E2%9C%93&q=is%3Aissue) on this repository to see if the issue has already been created. It could have been closed with a resolution, so check closed issues, too. 25 | * Chat with us on [Discord](https://ionic.link/discord) to see if we can find a solution to the problem! 26 | * [Determine which repository](#determining-the-repository) the problem should be reported in. 27 | 28 | ### Determining the Repository 29 | 30 | There are several repositories being used for Ionic, which makes it difficult to determine which one to report an issue to. Don't worry if you aren't sure, we can always move it! 31 | 32 | * The [Ionic Framework repository](https://github.com/ionic-team/ionic-framework) is a repository for all things related to the Ionic Framework. If you are able to reproduce the issue in any of the Ionic starters (or an existing project), you'll want to submit the issue [here](https://github.com/ionic-team/ionic-framework/issues). 33 | * The [Ionic CLI repository](https://github.com/ionic-team/ionic-cli) contains all of the code that allows you to run `ionic` commands from a terminal window. It is safe to put any issues [here](https://github.com/ionic-team/ionic-cli/issues) that relate to running an `ionic` command. 34 | * **This repository** is a demo of the Ionic Framework. If you find an issue with this app that does not occur on [a new app](https://ionicframework.com/docs/intro/cli#start-an-app), please submit the issue [here](https://github.com/ionic-team/ionic-conference-app/issues). 35 | 36 | ### Submitting the Issue 37 | 38 | * **Use a clear and descriptive title** for the issue to identify the problem. This makes it easier for others to find. 39 | * **Describe the exact steps to reproduce the problem** with as many details as needed. 40 | * **Provide your configuration** by running `ionic info` in a terminal from *within* the project folder and pasting this information in the issue. 41 | 42 | ## Submitting a Pull Request 43 | 44 | ### Guidelines for Submitting 45 | 46 | When in doubt, keep your pull requests small. To give a PR the best chance of getting accepted, do not bundle more than one "feature" or bug fix per PR. Doing so makes it very hard to accept it if one of the fixes has issues. 47 | 48 | It's always best to create two smaller PRs than one big one. 49 | 50 | Talk to us before creating a PR that refactors the code or directory structure of the project. This project is constantly changing to reflect the latest version of Ionic Framework so sometimes it will be in the process of getting fixed. 51 | 52 | ### Code Style 53 | 54 | Make sure to follow the existing code style as much as possible. 55 | 56 | * No underscores prefixing JS functions. 57 | * Use flat Sass: 58 | * **Don't** use [BEM conventions](https://css-tricks.com/bem-101/) 59 | * Avoid nesting selectors. This is done to make it easier for users without Sass experience to understand and read. 60 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | **I'm submitting a ...** (check one with "x") 8 | [ ] bug report 9 | [ ] feature request 10 | [ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://ionic.link/discord 11 | 12 | **Current behavior:** 13 | 14 | 15 | **Expected behavior:** 16 | 17 | 18 | **Steps to reproduce:** 19 | 23 | 24 | **Related code:** 25 | 26 | ``` 27 | insert any relevant code here 28 | ``` 29 | 30 | **Other information:** 31 | 32 | 33 | **Ionic info:** (run `ionic info` from a terminal/cmd prompt and paste output below): 34 | 35 | ``` 36 | insert the output from ionic info here 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions docs 2 | # https://help.github.com/en/articles/about-github-actions 3 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 4 | 5 | name: Install Dependencies, Lint, Build and Test 6 | 7 | on: [pull_request] 8 | 9 | jobs: 10 | test: 11 | name: Test on node ${{ matrix.node_version }} and ${{ matrix.os }} 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | # When node version is updated, update the version in the GitHub repository settings (admin access required): 16 | # Branches -> Edit `main` -> Protect matching branches -> 17 | # Require status checks to pass before merging -> 18 | # Search for the new version -> Add them to the list -> 19 | # Remove the old version from the list -> Save changes 20 | node_version: [18] 21 | os: [windows-latest, macOS-latest] 22 | 23 | steps: 24 | - uses: actions/checkout@v1 25 | - name: Use Node.js ${{ matrix.node_version }} 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node_version }} 29 | - name: Install Dependencies 30 | run: npm ci 31 | - name: Lint 32 | run: npm run lint 33 | - name: Build 34 | run: npm run build -- --configuration=production 35 | - name: Test 36 | run: npm test -- --configuration=ci 37 | - name: E2E 38 | run: npm run e2e -- --configuration=ci 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.angular/cache 2 | # Specifies intentionally untracked files to ignore when using Git 3 | # http://git-scm.com/docs/gitignore 4 | www/ 5 | 6 | *~ 7 | *.sw[mnpcod] 8 | *.log 9 | *.tmp 10 | *.tmp.* 11 | log.txt 12 | *.sublime-project 13 | *.sublime-workspace 14 | .vscode/ 15 | npm-debug.log* 16 | .firebase/ 17 | .idea/ 18 | .sourcemaps/ 19 | .sass-cache/ 20 | .tmp/ 21 | .versions/ 22 | coverage/ 23 | dist/ 24 | node_modules/ 25 | tmp/ 26 | temp/ 27 | hooks/ 28 | platforms/ 29 | plugins/ 30 | plugins/android.json 31 | plugins/ios.json 32 | $RECYCLE.BIN/ 33 | 34 | .DS_Store 35 | Thumbs.db 36 | UserInterfaceState.xcuserstate 37 | 38 | cypress/videos 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015-present Drifty Co. 2 | http://drifty.com/ 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ionic Angular Conference App 2 | 3 | [![Built with Ionic](https://img.shields.io/badge/-Built%20with%20Ionic-3880FF?style=flat&logo=ionic&logoColor=white)](https://ionicframework.com) 4 | [![Angular](https://img.shields.io/badge/-Angular-DD0031?style=flat&logo=angular&logoColor=white)](https://angular.io) 5 | [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) 6 | 7 | This is a **kitchen-sink demo application** built with **Ionic Framework** and **Angular**. It showcases a wide range of Ionic components and features in the context of a fictional tech conference app. 8 | 9 | **Note**: There is no actual Ionic Conference. This project is purely for demonstration purposes. 10 | 11 | 👉 [Try the Live Demo](https://ionic-conference-app-git-main-ionic1.vercel.app/app/tabs/schedule) 12 | 13 | ## 🧱 Framework Variants 14 | 15 | This app is also available in other frameworks: 16 | 17 | - 🔗 [Ionic React Conference App](https://github.com/ionic-team/ionic-react-conference-app) 18 | - 🔗 [Ionic Vue Conference App](https://github.com/ionic-team/ionic-vue-conference-app) 19 | - ✅ **You're viewing the Angular version** 20 | 21 | ## ✨ Features 22 | 23 | - Browse conference schedule with filtering 24 | - View speaker bios and session details 25 | - User authentication and profile management 26 | - Interactive maps for venue navigation 27 | - Push notifications support 28 | - Dark/Light mode toggling 29 | - Cross-platform support: iOS, Android, and Web 30 | 31 | ## ⚙️ Getting Started 32 | 33 | ### Prerequisites 34 | 35 | - Node.js (LTS version recommended) → [Download](https://nodejs.org/) 36 | - npm (included with Node.js) 37 | - Ionic CLI → Install globally: 38 | ```bash 39 | npm install -g @ionic/cli 40 | ``` 41 | - Angular CLI → Install globally: 42 | ```bash 43 | npm install -g @angular/cli 44 | ``` 45 | 46 | ### Installation 47 | 1. Clone the repository: 48 | ```bash 49 | git clone https://github.com/ionic-team/ionic-conference-app.git 50 | ``` 51 | 2. Navigate into the project: 52 | ```bash 53 | cd ionic-conference-app 54 | ``` 55 | 3. Install dependencies: 56 | ```bash 57 | npm install 58 | ``` 59 | 4. Start the dev server: 60 | ```bash 61 | ionic serve 62 | ``` 63 | 5. Open your browser to: 64 | ``` 65 | http://localhost:8100 66 | ``` 67 | 68 | ## 🤝 Contributing 69 | 70 | We welcome contributions! Please see our [Contributing Guide](.github/CONTRIBUTING.md) for details on how to submit pull requests, report issues, and contribute to the project. 71 | 72 | ## 📄 License 73 | 74 | This project is licensed under the MIT [License](./LICENSE). 75 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | # Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore 2 | 3 | # Built application files 4 | *.apk 5 | *.aar 6 | *.ap_ 7 | *.aab 8 | 9 | # Files for the ART/Dalvik VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | out/ 19 | # Uncomment the following line in case you need and you don't have the release build type files in your app 20 | # release/ 21 | 22 | # Gradle files 23 | .gradle/ 24 | build/ 25 | 26 | # Local configuration file (sdk path, etc) 27 | local.properties 28 | 29 | # Proguard folder generated by Eclipse 30 | proguard/ 31 | 32 | # Log Files 33 | *.log 34 | 35 | # Android Studio Navigation editor temp files 36 | .navigation/ 37 | 38 | # Android Studio captures folder 39 | captures/ 40 | 41 | # IntelliJ 42 | *.iml 43 | .idea/workspace.xml 44 | .idea/tasks.xml 45 | .idea/gradle.xml 46 | .idea/assetWizardSettings.xml 47 | .idea/dictionaries 48 | .idea/libraries 49 | # Android Studio 3 in .gitignore file. 50 | .idea/caches 51 | .idea/modules.xml 52 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 53 | .idea/navEditor.xml 54 | 55 | # Keystore files 56 | # Uncomment the following lines if you do not want to check your keystore files in. 57 | #*.jks 58 | #*.keystore 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | .cxx/ 63 | 64 | # Google Services (e.g. APIs or Firebase) 65 | # google-services.json 66 | 67 | # Freeline 68 | freeline.py 69 | freeline/ 70 | freeline_project_description.json 71 | 72 | # fastlane 73 | fastlane/report.xml 74 | fastlane/Preview.html 75 | fastlane/screenshots 76 | fastlane/test_output 77 | fastlane/readme.md 78 | 79 | # Version control 80 | vcs.xml 81 | 82 | # lint 83 | lint/intermediates/ 84 | lint/generated/ 85 | lint/outputs/ 86 | lint/tmp/ 87 | # lint/reports/ 88 | 89 | # Android Profiling 90 | *.hprof 91 | 92 | # Cordova plugins for Capacitor 93 | capacitor-cordova-android-plugins 94 | 95 | # Copied web assets 96 | app/src/main/assets/public 97 | # Generated Config files 98 | app/src/main/assets/capacitor.config.json 99 | app/src/main/assets/capacitor.plugins.json 100 | app/src/main/res/xml/config.xml 101 | -------------------------------------------------------------------------------- /android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | !/build/.npmkeep 3 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | namespace "com.ionicframework.conferenceapp" 5 | compileSdk rootProject.ext.compileSdkVersion 6 | defaultConfig { 7 | applicationId "com.ionicframework.conferenceapp" 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | versionCode 2 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | aaptOptions { 14 | // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. 15 | // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 16 | ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | } 26 | 27 | repositories { 28 | flatDir{ 29 | dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" 35 | implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" 36 | implementation fileTree(include: ['*.jar'], dir: 'libs') 37 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 38 | implementation project(':capacitor-android') 39 | testImplementation "junit:junit:$junitVersion" 40 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 41 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 42 | implementation project(':capacitor-cordova-android-plugins') 43 | } 44 | 45 | apply from: 'capacitor.build.gradle' 46 | 47 | try { 48 | def servicesJSON = file('google-services.json') 49 | if (servicesJSON.text) { 50 | apply plugin: 'com.google.gms.google-services' 51 | } 52 | } catch(Exception e) { 53 | logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") 54 | } 55 | -------------------------------------------------------------------------------- /android/app/capacitor.build.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | 3 | android { 4 | compileOptions { 5 | sourceCompatibility JavaVersion.VERSION_17 6 | targetCompatibility JavaVersion.VERSION_17 7 | } 8 | } 9 | 10 | apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" 11 | dependencies { 12 | implementation project(':capacitor-app') 13 | implementation project(':capacitor-device') 14 | implementation project(':capacitor-haptics') 15 | implementation project(':capacitor-keyboard') 16 | implementation project(':capacitor-splash-screen') 17 | implementation project(':capacitor-status-bar') 18 | 19 | } 20 | 21 | 22 | if (hasProperty('postBuildExtras')) { 23 | postBuildExtras() 24 | } 25 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import android.content.Context; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * @see Testing documentation 15 | */ 16 | @RunWith(AndroidJUnit4.class) 17 | public class ExampleInstrumentedTest { 18 | 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | 24 | assertEquals("com.getcapacitor.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml.orig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/app/src/main/assets/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "ionic.conference.app", 3 | "appName": "ionic-conference-app", 4 | "webDir": "www", 5 | "plugins": { 6 | "SplashScreen": { 7 | "launchShowDuration": 3000, 8 | "launchAutoHide": true, 9 | "backgroundColor": "#ffffffff", 10 | "androidSplashResourceName": "splash", 11 | "androidScaleType": "CENTER_CROP", 12 | "showSpinner": true, 13 | "androidSpinnerStyle": "large", 14 | "iosSpinnerStyle": "small", 15 | "spinnerColor": "#999999", 16 | "splashFullScreen": true, 17 | "splashImmersive": true 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/app/src/main/assets/capacitor.plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pkg": "@capacitor/app", 4 | "classpath": "com.capacitorjs.plugins.app.AppPlugin" 5 | }, 6 | { 7 | "pkg": "@capacitor/device", 8 | "classpath": "com.capacitorjs.plugins.device.DevicePlugin" 9 | }, 10 | { 11 | "pkg": "@capacitor/haptics", 12 | "classpath": "com.capacitorjs.plugins.haptics.HapticsPlugin" 13 | }, 14 | { 15 | "pkg": "@capacitor/keyboard", 16 | "classpath": "com.capacitorjs.plugins.keyboard.KeyboardPlugin" 17 | }, 18 | { 19 | "pkg": "@capacitor/splash-screen", 20 | "classpath": "com.capacitorjs.plugins.splashscreen.SplashScreenPlugin" 21 | }, 22 | { 23 | "pkg": "@capacitor/status-bar", 24 | "classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/ionicframework/conferenceapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ionicframework.conferenceapp; 2 | 3 | import com.getcapacitor.BridgeActivity; 4 | 5 | public class MainActivity extends BridgeActivity {} 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-land-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-land-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-land-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-land-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-land-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-land-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-land-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-land-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-land-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-land-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-port-hdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-port-hdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-port-mdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-port-mdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-port-xhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-port-xhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-port-xxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-port-xxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-port-xxxhdpi/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable-port-xxxhdpi/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ionic-conference-app 4 | ionic-conference-app 5 | ionic.conference.app 6 | ionic.conference.app 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 17 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.myapp; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:8.6.0' 11 | classpath 'com.google.gms:google-services:4.4.0' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | apply from: "variables.gradle" 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | mavenCentral() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | 31 | -------------------------------------------------------------------------------- /android/capacitor.settings.gradle: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN 2 | include ':capacitor-android' 3 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') 4 | 5 | include ':capacitor-app' 6 | project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') 7 | 8 | include ':capacitor-device' 9 | project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android') 10 | 11 | include ':capacitor-haptics' 12 | project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android') 13 | 14 | include ':capacitor-keyboard' 15 | project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android') 16 | 17 | include ':capacitor-splash-screen' 18 | project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android') 19 | 20 | include ':capacitor-status-bar' 21 | project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') 22 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # AndroidX package structure to make it clearer which packages are bundled with the 20 | # Android operating system, and which are packaged with your app's APK 21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 22 | android.useAndroidX=true 23 | 24 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':capacitor-cordova-android-plugins' 3 | project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') 4 | 5 | apply from: 'capacitor.settings.gradle' -------------------------------------------------------------------------------- /android/variables.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | minSdkVersion = 22 3 | compileSdkVersion = 34 4 | targetSdkVersion = 34 5 | androidxActivityVersion = '1.8.0' 6 | androidxAppCompatVersion = '1.6.1' 7 | androidxCoordinatorLayoutVersion = '1.2.0' 8 | androidxCoreVersion = '1.12.0' 9 | androidxFragmentVersion = '1.6.2' 10 | junitVersion = '4.13.2' 11 | androidxJunitVersion = '1.1.5' 12 | androidxEspressoCoreVersion = '3.5.1' 13 | cordovaAndroidVersion = '10.1.1' 14 | coreSplashScreenVersion='1.0.0' 15 | coreSplashScreenVersion = '1.0.1' 16 | androidxWebkitVersion = '1.9.0' 17 | } -------------------------------------------------------------------------------- /capacitor.config.ts: -------------------------------------------------------------------------------- 1 | import { CapacitorConfig } from '@capacitor/cli'; 2 | 3 | const config: CapacitorConfig = { 4 | appId: 'ionic.conference.app', 5 | appName: 'ionic-conference-app', 6 | webDir: 'www', 7 | plugins: { 8 | SplashScreen: { 9 | launchShowDuration: 3000, 10 | launchAutoHide: true, 11 | backgroundColor: '#ffffffff', 12 | androidSplashResourceName: 'splash', 13 | androidScaleType: 'CENTER_CROP', 14 | showSpinner: true, 15 | androidSpinnerStyle: 'large', 16 | iosSpinnerStyle: 'small', 17 | spinnerColor: '#999999', 18 | splashFullScreen: true, 19 | splashImmersive: true, 20 | }, 21 | }, 22 | }; 23 | 24 | export default config; 25 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | video: false, 5 | screenshotOnRunFailure: false, 6 | defaultCommandTimeout: 10000, 7 | fixturesFolder: "e2e/fixtures", 8 | screenshotsFolder: "e2e/screenshots", 9 | e2e: { 10 | baseUrl: "http://localhost:8100", 11 | specPattern: ["e2e/specs/**/*.cy.{js,jsx,ts,tsx}"], 12 | }, 13 | component: { 14 | devServer: { 15 | framework: "angular", 16 | bundler: "webpack", 17 | }, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /cypress/downloads/downloads.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/cypress/downloads/downloads.html -------------------------------------------------------------------------------- /cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example namespace declaration will help 3 | // with Intellisense and code completion in your 4 | // IDE or Text Editor. 5 | // *********************************************** 6 | // declare namespace Cypress { 7 | // interface Chainable { 8 | // customCommand(param: any): typeof customCommand; 9 | // } 10 | // } 11 | // 12 | // function customCommand(param: any): void { 13 | // console.warn(param); 14 | // } 15 | // 16 | // NOTE: You can use it like so: 17 | // Cypress.Commands.add('customCommand', customCommand); 18 | // 19 | // *********************************************** 20 | // This example commands.js shows you how to 21 | // create various custom commands and overwrite 22 | // existing commands. 23 | // 24 | // For more comprehensive examples of custom 25 | // commands please read more here: 26 | // https://on.cypress.io/custom-commands 27 | // *********************************************** 28 | // 29 | // 30 | // -- This is a parent command -- 31 | // Cypress.Commands.add("login", (email, password) => { ... }) 32 | // 33 | // 34 | // -- This is a child command -- 35 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 36 | // 37 | // 38 | // -- This is a dual command -- 39 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 40 | // 41 | // 42 | // -- This will overwrite an existing command -- 43 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 44 | 45 | import { Storage } from '@ionic/storage'; 46 | const storage = new Storage(); 47 | storage.create(); 48 | 49 | Cypress.Commands.add('bypassTutorial', () => { 50 | cy.log('bypass tutorial'); 51 | storage.set('ion_did_tutorial', true); 52 | }); 53 | 54 | Cypress.Commands.add('enableTutorial', () => { 55 | cy.log('enable tutorial'); 56 | cy.visit('/', { 57 | onBeforeLoad() { 58 | storage.set('ion_did_tutorial', false); 59 | }, 60 | }); 61 | }); 62 | 63 | declare global { 64 | namespace Cypress { 65 | interface Chainable { 66 | /** 67 | * Custom command to bypass the tutorial screens in the app 68 | */ 69 | bypassTutorial(): Chainable>; 70 | /** 71 | * Custom command to avoid bypassing the tutorial screens in the app 72 | */ 73 | enableTutorial(): Chainable>; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /cypress/support/component.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | 22 | import { mount } from 'cypress/angular'; 23 | 24 | // Augment the Cypress namespace to include type definitions for 25 | // your custom command. 26 | // Alternatively, can be defined in cypress/support/component.d.ts 27 | // with a at the top of your spec. 28 | declare global { 29 | namespace Cypress { 30 | interface Chainable { 31 | mount: typeof mount; 32 | } 33 | } 34 | } 35 | 36 | Cypress.Commands.add('mount', mount); 37 | 38 | // Example use: 39 | // cy.mount(MyComponent) 40 | -------------------------------------------------------------------------------- /cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // When a command from ./commands is ready to use, import with `import './commands'` syntax 17 | import './commands'; 18 | 19 | beforeEach(() => { 20 | // bypass the app tutorial screens before each test 21 | cy.bypassTutorial(); 22 | }); 23 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "sourceMap": false, 6 | "types": ["cypress"], 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /e2e/fixtures/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": "ionicrocks", 3 | "password": "plainpassword" 4 | } 5 | -------------------------------------------------------------------------------- /e2e/specs/about.cy.ts: -------------------------------------------------------------------------------- 1 | describe('About Page', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('navigates to the about tab', () => { 7 | cy.get('ion-tab-button').contains('About').click(); 8 | cy.contains('About'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /e2e/specs/map.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Map Page', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('navigates to the map tab', () => { 7 | cy.get('ion-tab-button').contains('Map').click(); 8 | cy.contains('Map'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /e2e/specs/schedule.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Schedule Page', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('navigates to the schedule', () => { 7 | cy.contains('Schedule'); 8 | }); 9 | 10 | it('has a menu', () => { 11 | cy.get('ion-menu'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /e2e/specs/speakers.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Speakers Page', () => { 2 | beforeEach(() => { 3 | cy.visit('/'); 4 | }); 5 | 6 | it('navigates to the speakers tab', () => { 7 | cy.get('ion-tab-button').contains('Speakers').click(); 8 | cy.contains('Speakers'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /e2e/specs/tutorial.cy.ts: -------------------------------------------------------------------------------- 1 | // TODO(ROU-10791): enable tutorial tests after fixing the flakiness 2 | describe.skip('Tutorial Page', () => { 3 | beforeEach(() => { 4 | cy.enableTutorial(); 5 | }); 6 | 7 | it('visits the tutorial page', () => { 8 | cy.contains('Welcome to ICA'); 9 | }); 10 | 11 | it('navigates to the schedule via the skip button', () => { 12 | cy.get('ion-button').contains('Skip').click(); 13 | cy.contains('Schedule'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "www", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ], 15 | 16 | "headers": [ 17 | { 18 | "source": "ngsw-worker.js", 19 | "headers": [ 20 | { 21 | "key": "Cache-Control", 22 | "value": "no-cache" 23 | } 24 | ] 25 | }, 26 | { 27 | "source": "/", 28 | "headers": [ 29 | { 30 | "key": "Link", 31 | "value": 32 | ";rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=style,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script,;rel=preload;as=script," 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /generate-h2-push.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const puppeteer = require('puppeteer'); 3 | const fs = require('fs'); 4 | const args = process.argv.slice(2); 5 | const host = args[0] || 'http://127.0.0.1:8080'; 6 | const indexMatches = [ 7 | '.gz', 8 | '.map', 9 | '3rdpartylicenses.txt', 10 | 'ngsw-manifest.json', 11 | 'ngsw.json', 12 | 'worker-basic.min.js', 13 | 'ngsw-worker.js', 14 | 'favicon', 15 | 'index.html', 16 | 'manifest.webmanifest', 17 | '.svg' 18 | ]; 19 | let results = ''; 20 | async function main() { 21 | const browser = await puppeteer.launch(); 22 | const page = await browser.newPage(); 23 | await page._client.send('ServiceWorker.disable') 24 | 25 | page.on('console', msg => console.log(msg.text())); 26 | 27 | console.log('Page: loaded'); 28 | await page.goto(host); 29 | 30 | const allRequests = new Map(); 31 | page.on('request', req => { 32 | allRequests.set(req.url(), req); 33 | }); 34 | 35 | await page.reload({ waitUntil: 'networkidle2' }); 36 | 37 | Array.from(allRequests.values()).forEach(req => { 38 | const url = req.url(); 39 | 40 | // filter out urls that match these extensions 41 | for (const exlude of indexMatches) { 42 | if (url.indexOf(exlude) != -1) return false; 43 | } 44 | 45 | // if external, dont worry about it for now 46 | // 47 | const origin = new URL(host); 48 | 49 | if (url.indexOf(origin.origin) === -1) return false; 50 | 51 | // Format the url to remove the host 52 | const formatted = url.replace(`${origin.origin}/`, ''); 53 | 54 | if (origin.pathname.includes(formatted)) return false; 55 | 56 | // if it's an empty string, just ignore it 57 | if (!formatted) return false; 58 | 59 | let type = url.substr(-3) == 'css' ? 'style' : 'script'; 60 | results += `;rel=preload;as=${type},`; 61 | 62 | }); 63 | await browser.close(); 64 | updateWith(results); 65 | } 66 | function updateWith(result) { 67 | fs.readFile('firebase.json', 'utf8', function(err, data) { 68 | if (err) { 69 | return console.log(err); 70 | } 71 | let re = /("headers":\s*\[\s*{\s*"key":\s*"Link",\s*"value":\s*")(.*)("\s*}\s*\])/gm; 72 | if (re.exec(data)) { 73 | let newConfig = data.replace(re, `$1${result}$3`); 74 | fs.writeFile('firebase.json', newConfig, 'utf8', function(err) { 75 | if (err) return console.log(err); 76 | console.log('firebase.json updated successfully.'); 77 | }); 78 | } else { 79 | console.log("Couldn't find a valid firebase config to update."); 80 | return; 81 | } 82 | }); 83 | } 84 | 85 | main(); 86 | -------------------------------------------------------------------------------- /ionic.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-conference-app", 3 | "type": "angular", 4 | "integrations": { 5 | "capacitor": {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | App/build 2 | App/Pods 3 | App/App/public 4 | App/output 5 | DerivedData 6 | xcuserdata 7 | 8 | # Cordova plugins for Capacitor 9 | capacitor-cordova-ios-plugins 10 | # Generated Config files 11 | App/App/capacitor.config.json 12 | App/App/config.xml 13 | 14 | -------------------------------------------------------------------------------- /ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/App/App.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/App/App/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Capacitor 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | 9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 10 | // Override point for customization after application launch. 11 | return true 12 | } 13 | 14 | func applicationWillResignActive(_ application: UIApplication) { 15 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 16 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 17 | } 18 | 19 | func applicationDidEnterBackground(_ application: UIApplication) { 20 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 22 | } 23 | 24 | func applicationWillEnterForeground(_ application: UIApplication) { 25 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 26 | } 27 | 28 | func applicationDidBecomeActive(_ application: UIApplication) { 29 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 30 | } 31 | 32 | func applicationWillTerminate(_ application: UIApplication) { 33 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 34 | } 35 | 36 | func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { 37 | // Called when the app was launched with a url. Feel free to add additional processing here, 38 | // but if you want the App API to support tracking app url opens, make sure to keep this call 39 | return ApplicationDelegateProxy.shared.application(app, open: url, options: options) 40 | } 41 | 42 | func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { 43 | // Called when the app was launched with an activity, including Universal Links. 44 | // Feel free to add additional processing here, but if you want the App API to support 45 | // tracking app url opens, make sure to keep this call 46 | return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler) 47 | } 48 | 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppIcon-512@2x.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/Splash.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "splash-2732x2732-2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "splash-2732x2732-1.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "splash-2732x2732.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png -------------------------------------------------------------------------------- /ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png -------------------------------------------------------------------------------- /ios/App/App/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/App/App/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ios/App/App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ionic-conference-app 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | 54 | -------------------------------------------------------------------------------- /ios/App/App/capacitor.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId": "ionic.conference.app", 3 | "appName": "ionic-conference-app", 4 | "webDir": "www", 5 | "plugins": { 6 | "SplashScreen": { 7 | "launchShowDuration": 3000, 8 | "launchAutoHide": true, 9 | "backgroundColor": "#ffffffff", 10 | "androidSplashResourceName": "splash", 11 | "androidScaleType": "CENTER_CROP", 12 | "showSpinner": true, 13 | "androidSpinnerStyle": "large", 14 | "iosSpinnerStyle": "small", 15 | "spinnerColor": "#999999", 16 | "splashFullScreen": true, 17 | "splashImmersive": true 18 | } 19 | }, 20 | "packageClassList": [ 21 | "AppPlugin", 22 | "DevicePlugin", 23 | "HapticsPlugin", 24 | "KeyboardPlugin", 25 | "SplashScreenPlugin", 26 | "StatusBarPlugin", 27 | "CDVPlugin" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /ios/App/App/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/App/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers' 2 | 3 | platform :ios, '14.0' 4 | use_frameworks! 5 | 6 | # workaround to avoid Xcode caching of Pods that requires 7 | # Product -> Clean Build Folder after new Cordova plugins installed 8 | # Requires CocoaPods 1.6 or newer 9 | install! 'cocoapods', :disable_input_output_paths => true 10 | 11 | def capacitor_pods 12 | pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' 13 | pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' 14 | pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' 15 | pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device' 16 | pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' 17 | pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard' 18 | pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen' 19 | pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' 20 | pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins' 21 | end 22 | 23 | target 'App' do 24 | capacitor_pods 25 | # Add your Pods here 26 | end 27 | 28 | 29 | post_install do |installer| 30 | assertDeploymentTarget(installer) 31 | end 32 | -------------------------------------------------------------------------------- /ios/App/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Capacitor (6.2.0): 3 | - CapacitorCordova 4 | - CapacitorApp (6.0.2): 5 | - Capacitor 6 | - CapacitorCordova (6.2.0) 7 | - CapacitorDevice (6.0.2): 8 | - Capacitor 9 | - CapacitorHaptics (6.0.2): 10 | - Capacitor 11 | - CapacitorKeyboard (6.0.3): 12 | - Capacitor 13 | - CapacitorSplashScreen (6.0.3): 14 | - Capacitor 15 | - CapacitorStatusBar (6.0.2): 16 | - Capacitor 17 | - CordovaPlugins (6.2.0): 18 | - CapacitorCordova 19 | 20 | DEPENDENCIES: 21 | - "Capacitor (from `../../node_modules/@capacitor/ios`)" 22 | - "CapacitorApp (from `../../node_modules/@capacitor/app`)" 23 | - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" 24 | - "CapacitorDevice (from `../../node_modules/@capacitor/device`)" 25 | - "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)" 26 | - "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)" 27 | - "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)" 28 | - "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)" 29 | - CordovaPlugins (from `../capacitor-cordova-ios-plugins`) 30 | 31 | EXTERNAL SOURCES: 32 | Capacitor: 33 | :path: "../../node_modules/@capacitor/ios" 34 | CapacitorApp: 35 | :path: "../../node_modules/@capacitor/app" 36 | CapacitorCordova: 37 | :path: "../../node_modules/@capacitor/ios" 38 | CapacitorDevice: 39 | :path: "../../node_modules/@capacitor/device" 40 | CapacitorHaptics: 41 | :path: "../../node_modules/@capacitor/haptics" 42 | CapacitorKeyboard: 43 | :path: "../../node_modules/@capacitor/keyboard" 44 | CapacitorSplashScreen: 45 | :path: "../../node_modules/@capacitor/splash-screen" 46 | CapacitorStatusBar: 47 | :path: "../../node_modules/@capacitor/status-bar" 48 | CordovaPlugins: 49 | :path: "../capacitor-cordova-ios-plugins" 50 | 51 | SPEC CHECKSUMS: 52 | Capacitor: 1f3c7b9802d958cd8c4eb63895fff85dff2e1eea 53 | CapacitorApp: 2a8c3a0b0814322e5e6e15fe595f02c3808f0f8b 54 | CapacitorCordova: b33e7f4aa4ed105dd43283acdd940964374a87d9 55 | CapacitorDevice: 1a215717f0b5061503b21a03508b0ec458a57d78 56 | CapacitorHaptics: b53409aaca1203f79c6d0eb3ed5de40556339518 57 | CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0 58 | CapacitorSplashScreen: 68893659d77b5f82d753b3a70475082845e3039c 59 | CapacitorStatusBar: 3b9ac7d0684770522c532d1158a1434512ab1477 60 | CordovaPlugins: c80279d2aa351c75c1bea88c018029ad156a6891 61 | 62 | PODFILE CHECKSUM: 0307b9f7c64148b6aece5e77c1cb493e1a834776 63 | 64 | COCOAPODS: 1.15.2 65 | -------------------------------------------------------------------------------- /ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/service-worker/config/schema.json", 3 | "index": "/index.html", 4 | "assetGroups": [ 5 | { 6 | "name": "app", 7 | "installMode": "prefetch", 8 | "resources": { 9 | "files": [ 10 | "/index.csr.html", 11 | "/index.html", 12 | "/assets/manifest.webmanifest", 13 | "/*.css", 14 | "/*.js" 15 | ] 16 | } 17 | }, 18 | { 19 | "name": "assets", 20 | "installMode": "lazy", 21 | "updateMode": "prefetch", 22 | "resources": { 23 | "files": [ 24 | "/**/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)" 25 | ] 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-conference-app", 3 | "version": "0.0.0", 4 | "description": "Ionic Conference App", 5 | "author": "Ionic Team ", 6 | "license": "MIT", 7 | "scripts": { 8 | "ng": "ng", 9 | "start": "ng serve", 10 | "build": "ng build", 11 | "test": "ng test", 12 | "lint": "ng lint && npm run lint:sass", 13 | "lint:sass": "stylelint \"src/**/*.scss\"", 14 | "e2e": "ng e2e", 15 | "cypress:open": "cypress open", 16 | "cypress:run": "cypress run" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/ionic-team/ionic-conference-app.git" 21 | }, 22 | "private": true, 23 | "dependencies": { 24 | "@angular/common": "^19.1.6", 25 | "@angular/core": "^19.1.6", 26 | "@angular/forms": "^19.1.6", 27 | "@angular/platform-browser": "^19.1.6", 28 | "@angular/platform-browser-dynamic": "^19.1.6", 29 | "@angular/pwa": "^19.1.7", 30 | "@angular/router": "^19.1.6", 31 | "@angular/service-worker": "^19.1.6", 32 | "@awesome-cordova-plugins/core": "6.3.0", 33 | "@awesome-cordova-plugins/in-app-browser": "6.3.0", 34 | "@capacitor/android": "^6.0.0", 35 | "@capacitor/app": "^6.0.0", 36 | "@capacitor/core": "^6.0.0", 37 | "@capacitor/device": "^6.0.0", 38 | "@capacitor/haptics": "^6.0.0", 39 | "@capacitor/ios": "^6.0.0", 40 | "@capacitor/keyboard": "^6.0.0", 41 | "@capacitor/splash-screen": "^6.0.0", 42 | "@capacitor/status-bar": "^6.0.0", 43 | "@ionic/angular": "^8.0.0", 44 | "@ionic/storage-angular": "^4.0.0", 45 | "cordova-plugin-inappbrowser": "5.0.0", 46 | "core-js": "^3.6.4", 47 | "leaflet": "^1.9.4", 48 | "rxjs": "^7.8.0", 49 | "sw-toolbox": "3.6.0", 50 | "tslib": "^2.0.0", 51 | "wait-on": "^7.0.1", 52 | "webdriver-manager": "12.1.9", 53 | "zone.js": "~0.15.0" 54 | }, 55 | "devDependencies": { 56 | "@angular-devkit/architect": "^0.1901.7", 57 | "@angular-devkit/build-angular": "^19.1.7", 58 | "@angular-devkit/core": "^19.1.7", 59 | "@angular-devkit/schematics": "^19.1.0", 60 | "@angular-eslint/builder": "^18.0.0", 61 | "@angular-eslint/eslint-plugin": "^18.0.0", 62 | "@angular-eslint/eslint-plugin-template": "^18.0.0", 63 | "@angular-eslint/schematics": "^19.1.0", 64 | "@angular-eslint/template-parser": "^18.0.0", 65 | "@angular/cli": "^19.1.7", 66 | "@angular/compiler": "^19.1.6", 67 | "@angular/compiler-cli": "^19.1.6", 68 | "@angular/language-service": "^19.1.6", 69 | "@capacitor/cli": "^6.0.0", 70 | "@cypress/schematic": "^2.5.0", 71 | "@ionic/angular-toolkit": "12.1.1", 72 | "@ionic/cli": "7.2.0", 73 | "@ionic/storage": "^3.0.6", 74 | "@types/jasmine": "~3.6.0", 75 | "@types/leaflet": "^1.9.17", 76 | "@types/node": "^12.11.1", 77 | "@typescript-eslint/eslint-plugin": "^8.24.1", 78 | "@typescript-eslint/parser": "^8.24.1", 79 | "cordova-res": "0.15.4", 80 | "cypress": "latest", 81 | "eslint": "^9.20.0", 82 | "jasmine-core": "~3.8.0", 83 | "jasmine-spec-reporter": "~5.0.0", 84 | "karma": "~6.3.7", 85 | "karma-chrome-launcher": "~3.1.0", 86 | "karma-coverage-istanbul-reporter": "~3.0.2", 87 | "karma-jasmine": "~4.0.0", 88 | "karma-jasmine-html-reporter": "^1.5.0", 89 | "puppeteer": "^11.0.0", 90 | "stylelint": "15.3.0", 91 | "stylelint-config-standard-scss": "7.0.1", 92 | "stylelint-order": "6.0.3", 93 | "ts-node": "8.5.0", 94 | "typescript": "~5.7.3" 95 | }, 96 | "browserslist": [ 97 | "Chrome >=79", 98 | "ChromeAndroid >=79", 99 | "Firefox >=70", 100 | "Edge >=79", 101 | "Safari >=14", 102 | "iOS >=14" 103 | ] 104 | } 105 | -------------------------------------------------------------------------------- /resources/android/icon/drawable-hdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-hdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-ldpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-ldpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-mdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-mdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-xhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-xxhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/icon/drawable-xxxhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-land-xxxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/android/splash/drawable-port-xxxhdpi-screen.png -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/icon.png -------------------------------------------------------------------------------- /resources/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/icon.psd -------------------------------------------------------------------------------- /resources/icon.psd.md5: -------------------------------------------------------------------------------- 1 | c1760af57a8089fda7537fc043804bc8 -------------------------------------------------------------------------------- /resources/ios/icon/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-1024.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-108@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-108@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-20.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-20@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-20@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-24@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-27.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-27.5@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-29.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-29@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-29@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-40.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-40@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-40@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-44@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-44@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-50.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-50@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-60.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-60@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-60@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-72.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-72@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-76.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-76@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-83.5@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-86@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-86@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-98@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-98@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-small.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-small@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon-small@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon.png -------------------------------------------------------------------------------- /resources/ios/icon/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/icon/icon@2x.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-1792h~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-1792h~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-2436h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-2436h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-2688h~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-2688h~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-667h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-1792h~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape-1792h~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-2436h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape-2436h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-2688h~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape-2688h~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape@~ipadpro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape@~ipadpro.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait@~ipadpro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Portrait@~ipadpro.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default@2x~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default@2x~universal~anyany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default@2x~universal~anyany.png -------------------------------------------------------------------------------- /resources/ios/splash/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/ios/splash/Default~iphone.png -------------------------------------------------------------------------------- /resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/resources/splash.png -------------------------------------------------------------------------------- /resources/splash.png.md5: -------------------------------------------------------------------------------- 1 | 0dcf1df8c92c1ece4382d3357d9f8562 -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | ion-menu ion-content { 2 | --padding-top: 20px; 3 | --padding-bottom: 20px; 4 | --background: var(--ion-item-background, var(--ion-background-color, #ffffff)); 5 | } 6 | 7 | /* Remove background transitions for switching themes */ 8 | ion-menu ion-item { 9 | --transition: none; 10 | } 11 | 12 | ion-item.selected { 13 | --color: var(--ion-color-primary); 14 | } 15 | 16 | /* 17 | * Material Design Menu 18 | */ 19 | ion-menu.md ion-list { 20 | padding: 20px 0; 21 | } 22 | 23 | ion-menu.md ion-list-header { 24 | padding-right: 18px; 25 | padding-left: 18px; 26 | 27 | font-size: min(0.875rem, 32px); 28 | 29 | font-weight: 450; 30 | 31 | letter-spacing: 0.1em; 32 | 33 | text-transform: uppercase; 34 | } 35 | 36 | ion-menu.md ion-item { 37 | --padding-start: 18px; 38 | 39 | margin-right: 10px; 40 | 41 | border-radius: 0 50px 50px 0; 42 | 43 | font-weight: 500; 44 | } 45 | 46 | ion-menu.md ion-item.selected { 47 | /* stylelint-disable-next-line color-function-notation */ 48 | --background: rgba(var(--ion-color-primary-rgb), 0.14); 49 | } 50 | 51 | ion-menu.md ion-item.selected ion-icon { 52 | color: var(--ion-color-primary); 53 | } 54 | 55 | ion-menu.md ion-list-header, 56 | ion-menu.md ion-item ion-icon { 57 | color: var(--ion-color-step-650, #5f6368); 58 | } 59 | 60 | ion-menu.md ion-list:not(:last-of-type) { 61 | border-bottom: 1px solid var(--ion-color-step-150, #d7d8da); 62 | } 63 | 64 | /* 65 | * iOS Menu 66 | */ 67 | ion-menu.ios ion-list-header { 68 | margin-bottom: 8px; 69 | 70 | padding-right: 16px; 71 | padding-left: 16px; 72 | 73 | font-size: clamp(22px, 1.375rem, 40px); 74 | } 75 | 76 | ion-menu.ios ion-list { 77 | padding: 20px 0 0; 78 | } 79 | 80 | ion-menu.ios ion-item { 81 | --padding-start: 16px; 82 | --min-height: 50px; 83 | } 84 | 85 | ion-menu.ios ion-item ion-icon { 86 | color: #73849a; 87 | 88 | font-size: 24px; 89 | } 90 | 91 | ion-menu.ios ion-item.selected ion-icon { 92 | color: var(--ion-color-primary); 93 | } 94 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { provideHttpClientTesting } from '@angular/common/http/testing'; 2 | import { CUSTOM_ELEMENTS_SCHEMA, importProvidersFrom } from '@angular/core'; 3 | import { TestBed } from '@angular/core/testing'; 4 | import { provideRouter } from '@angular/router'; 5 | import { SwUpdate } from '@angular/service-worker'; 6 | import { MenuController, provideIonicAngular } from '@ionic/angular/standalone'; 7 | import { IonicStorageModule } from '@ionic/storage-angular'; 8 | import { AppComponent } from './app.component'; 9 | import { routes } from './app.routes'; 10 | import { UserService } from './providers/user.service'; 11 | 12 | describe('AppComponent', () => { 13 | let menuSpy, userDataSpy, swUpdateSpy, app, fixture; 14 | 15 | beforeEach(async () => { 16 | menuSpy = jasmine.createSpyObj('MenuController', ['toggle', 'enable']); 17 | userDataSpy = jasmine.createSpyObj('UserData', ['isLoggedIn', 'logout']); 18 | swUpdateSpy = jasmine.createSpyObj('SwUpdate', [ 19 | 'available', 20 | 'activateUpdate', 21 | ]); 22 | 23 | await TestBed.configureTestingModule({ 24 | imports: [AppComponent], 25 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 26 | providers: [ 27 | provideIonicAngular(), 28 | provideRouter(routes), 29 | provideHttpClientTesting(), 30 | importProvidersFrom(IonicStorageModule.forRoot()), 31 | { provide: MenuController, useValue: menuSpy }, 32 | { provide: UserService, useValue: userDataSpy }, 33 | { provide: SwUpdate, useValue: swUpdateSpy }, 34 | ], 35 | }).compileComponents(); 36 | }); 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(AppComponent); 39 | app = fixture.debugElement.componentInstance; 40 | app.storage.create(); 41 | fixture.detectChanges(); 42 | }); 43 | 44 | it('should create the app', () => { 45 | expect(app).toBeTruthy(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { canDeactivateSupportPage } from './providers/can-deactivate-support.guard'; 3 | import { checkTutorialGuard } from './providers/check-tutorial.guard'; 4 | 5 | export const routes: Routes = [ 6 | { 7 | path: '', 8 | redirectTo: '/tutorial', 9 | pathMatch: 'full', 10 | }, 11 | { 12 | path: 'account', 13 | loadComponent: () => 14 | import('./pages/account/account').then(m => m.AccountPage), 15 | }, 16 | { 17 | path: 'support', 18 | loadComponent: () => 19 | import('./pages/support/support').then(m => m.SupportPage), 20 | canDeactivate: [canDeactivateSupportPage], 21 | }, 22 | { 23 | path: 'login', 24 | loadComponent: () => import('./pages/login/login').then(m => m.LoginPage), 25 | }, 26 | { 27 | path: 'signup', 28 | loadComponent: () => 29 | import('./pages/signup/signup').then(m => m.SignupPage), 30 | }, 31 | { 32 | path: 'app', 33 | loadChildren: () => 34 | import('./pages/tabs-page/routes').then(m => m.TABS_ROUTES), 35 | }, 36 | { 37 | path: 'tutorial', 38 | loadComponent: () => 39 | import('./pages/tutorial/tutorial').then(m => m.TutorialPage), 40 | canMatch: [checkTutorialGuard], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /src/app/app.scss: -------------------------------------------------------------------------------- 1 | [hidden] { 2 | /* stylelint-disable-next-line declaration-no-important */ 3 | display: none !important; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/interfaces/conference.interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface Speaker { 2 | name: string; 3 | profilePic: string; 4 | instagram: string; 5 | twitter: string; 6 | about: string; 7 | title: string; 8 | location: string; 9 | email: string; 10 | phone: string; 11 | id: string; 12 | sessions?: Session[]; 13 | } 14 | 15 | export interface Session { 16 | hide?: boolean; 17 | name: string; 18 | location: string; 19 | description?: string; 20 | speakerNames: string[]; 21 | timeStart: string; 22 | timeEnd: string; 23 | tracks: string[]; 24 | id: string; 25 | speakers?: Speaker[]; 26 | } 27 | 28 | export interface Group { 29 | time: string; 30 | sessions: Session[]; 31 | hide?: boolean; 32 | } 33 | 34 | export interface ScheduleDay { 35 | date: string; 36 | groups: Group[]; 37 | shownSessions?: number; 38 | } 39 | 40 | export interface Track { 41 | name: string; 42 | icon: string; 43 | } 44 | 45 | export interface MapLocation { 46 | name: string; 47 | lat: number; 48 | lng: number; 49 | center?: boolean; 50 | } 51 | 52 | export interface ConferenceData { 53 | schedule: ScheduleDay[]; 54 | speakers: Speaker[]; 55 | tracks: Track[]; 56 | map: MapLocation[]; 57 | } 58 | 59 | export interface Location { 60 | id: number; 61 | name: string; 62 | lat: number; 63 | lng: number; 64 | center?: boolean; 65 | } 66 | -------------------------------------------------------------------------------- /src/app/interfaces/user-options.ts: -------------------------------------------------------------------------------- 1 | export interface UserOptions { 2 | username: string; 3 | password: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/pages/about-popover/about-popover.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { 4 | IonItem, 5 | IonLabel, 6 | IonList, 7 | PopoverController, 8 | } from '@ionic/angular/standalone'; 9 | 10 | @Component({ 11 | template: ` 12 | 13 | 17 | Learn Ionic 18 | 19 | 20 | Documentation 21 | 22 | 23 | Showcase 24 | 25 | 26 | GitHub Repo 27 | 28 | 29 | Support 30 | 31 | 32 | `, 33 | imports: [IonList, IonItem, IonLabel], 34 | providers: [PopoverController] 35 | }) 36 | export class PopoverPage { 37 | private router = inject(Router); 38 | private popoverCtrl = inject(PopoverController); 39 | 40 | support() { 41 | this.router.navigate(['/support']); 42 | this.popoverCtrl.dismiss(); 43 | } 44 | 45 | close(url: string) { 46 | window.open(url, '_blank'); 47 | this.popoverCtrl.dismiss(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/pages/about/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
25 |
29 |
33 |
37 |
38 | 39 |
40 |

About

41 | 42 |

43 | The Ionic Conference is a one-day event happening on {{ conferenceDate | date: 44 | 'mediumDate' }}, featuring talks from the Ionic team. The conference focuses on 45 | building applications with Ionic Framework, including topics such as app migration 46 | to the latest version, Angular best practices, Webpack, Sass, and other technologies 47 | commonly used in the Ionic ecosystem. Tickets are completely sold out, and we're expecting 48 | over 1,000 developers — making this the largest Ionic conference to date! 49 |

50 | 51 |

Details

52 | 53 | 54 | 55 | 60 | Madison, WI 61 | Austin, TX 62 | Chicago, IL 63 | Seattle, WA 64 | 65 | 66 | 67 | Date 68 | {{ conferenceDate | date: 'mediumDate' }} 71 | 78 | 79 | 84 | 85 | 86 | 87 | 88 | 89 |

Internet

90 | 91 | 92 | 93 | Wifi network 94 | 95 | ica{{conferenceDate | date: 'y'}} 96 | 97 | 98 | 99 | Password 100 | makegoodthings 101 | 102 | 103 |
104 |
105 | -------------------------------------------------------------------------------- /src/app/pages/about/about.scss: -------------------------------------------------------------------------------- 1 | ion-toolbar { 2 | --background: transparent; 3 | --color: white; 4 | position: absolute; 5 | 6 | top: 0; 7 | right: 0; 8 | left: 0; 9 | } 10 | 11 | ion-toolbar ion-button, 12 | ion-toolbar ion-back-button, 13 | ion-toolbar ion-menu-button { 14 | --color: white; 15 | } 16 | 17 | .about-header { 18 | position: relative; 19 | 20 | width: 100%; 21 | height: 30%; 22 | } 23 | 24 | .about-header .about-image { 25 | position: absolute; 26 | 27 | inset: 0; 28 | 29 | transition: opacity 500ms ease-in-out; 30 | 31 | background-repeat: no-repeat; 32 | 33 | background-position: center; 34 | background-size: cover; 35 | 36 | opacity: 0; 37 | } 38 | 39 | .about-header .madison { 40 | background-image: url('/assets/img/about/madison.jpg'); 41 | } 42 | 43 | .about-header .austin { 44 | background-image: url('/assets/img/about/austin.jpg'); 45 | } 46 | 47 | .about-header .chicago { 48 | background-image: url('/assets/img/about/chicago.jpg'); 49 | } 50 | 51 | .about-header .seattle { 52 | background-image: url('/assets/img/about/seattle.jpg'); 53 | } 54 | 55 | .about-info { 56 | position: relative; 57 | 58 | margin-top: -10px; 59 | 60 | border-radius: 10px; 61 | 62 | background: var(--ion-background-color, #ffffff); 63 | 64 | z-index: 2; // display rounded border above header image 65 | } 66 | 67 | .about-info h3 { 68 | margin-top: 0; 69 | } 70 | 71 | .about-info ion-list { 72 | padding-top: 0; 73 | } 74 | 75 | .about-info p { 76 | color: var(--ion-color-dark); 77 | 78 | line-height: 130%; 79 | } 80 | 81 | .about-info ion-icon { 82 | margin-inline-end: 32px; 83 | } 84 | 85 | #date-input-popover { 86 | --offset-y: -var(--ion-safe-area-bottom); 87 | --max-width: 90%; 88 | --width: 336px; 89 | } 90 | 91 | /* 92 | * iOS Only 93 | */ 94 | 95 | .ios .about-info { 96 | --ion-padding: 19px; 97 | } 98 | 99 | .ios .about-info h3 { 100 | font-weight: 700; 101 | } 102 | -------------------------------------------------------------------------------- /src/app/pages/about/about.ts: -------------------------------------------------------------------------------- 1 | import { DatePipe, NgStyle } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { 5 | IonButton, 6 | IonButtons, 7 | IonContent, 8 | IonDatetime, 9 | IonHeader, 10 | IonIcon, 11 | IonItem, 12 | IonLabel, 13 | IonList, 14 | IonMenuButton, 15 | IonPopover, 16 | IonSelect, 17 | IonSelectOption, 18 | IonText, 19 | IonToolbar, 20 | PopoverController, 21 | } from '@ionic/angular/standalone'; 22 | import { addIcons } from 'ionicons'; 23 | import { ellipsisHorizontal, ellipsisVertical } from 'ionicons/icons'; 24 | import { PopoverPage } from '../about-popover/about-popover'; 25 | 26 | @Component({ 27 | selector: 'page-about', 28 | templateUrl: 'about.html', 29 | styleUrls: ['./about.scss'], 30 | imports: [ 31 | NgStyle, 32 | FormsModule, 33 | DatePipe, 34 | IonContent, 35 | IonHeader, 36 | IonToolbar, 37 | IonButtons, 38 | IonMenuButton, 39 | IonButton, 40 | IonIcon, 41 | IonList, 42 | IonItem, 43 | IonLabel, 44 | IonSelect, 45 | IonSelectOption, 46 | IonPopover, 47 | IonDatetime, 48 | IonText, 49 | ], 50 | providers: [PopoverController] 51 | }) 52 | export class AboutPage { 53 | location = 'madison'; 54 | conferenceDate = '2047-05-17'; 55 | 56 | selectOptions = { 57 | header: 'Select a Location', 58 | }; 59 | 60 | private popoverCtrl = inject(PopoverController); 61 | 62 | constructor() { 63 | addIcons({ ellipsisHorizontal, ellipsisVertical }); 64 | } 65 | 66 | async presentPopover(event: Event) { 67 | const popover = await this.popoverCtrl.create({ 68 | component: PopoverPage, 69 | event, 70 | }); 71 | await popover.present(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/app/pages/account/account.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Account 7 | 8 | 9 | 10 | 11 | @if(username) { 12 |
13 | User avatar 21 |

{{username}}

22 | 23 | 24 | Update Picture 25 | Change Username 26 | Change Password 27 | Support 28 | Logout 29 | 30 |
31 | } 32 |
33 | -------------------------------------------------------------------------------- /src/app/pages/account/account.scss: -------------------------------------------------------------------------------- 1 | img { 2 | max-width: 140px; 3 | 4 | border-radius: 50%; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/pages/account/account.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, inject } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { NgOptimizedImage } from '@angular/common'; 5 | import { 6 | AlertController, 7 | IonButtons, 8 | IonContent, 9 | IonHeader, 10 | IonItem, 11 | IonList, 12 | IonMenuButton, 13 | IonTitle, 14 | IonToolbar, 15 | } from '@ionic/angular/standalone'; 16 | import { UserService } from '../../providers/user.service'; 17 | 18 | @Component({ 19 | selector: 'page-account', 20 | templateUrl: 'account.html', 21 | styleUrls: ['./account.scss'], 22 | imports: [ 23 | IonHeader, 24 | IonToolbar, 25 | IonButtons, 26 | IonMenuButton, 27 | IonTitle, 28 | IonContent, 29 | IonItem, 30 | IonList, 31 | NgOptimizedImage, 32 | ], 33 | providers: [AlertController] 34 | }) 35 | export class AccountPage implements AfterViewInit { 36 | private alertCtrl = inject(AlertController); 37 | private router = inject(Router); 38 | private user = inject(UserService); 39 | 40 | username: string; 41 | 42 | ngAfterViewInit() { 43 | this.getUsername(); 44 | } 45 | 46 | updatePicture() { 47 | console.log('Clicked to update picture'); 48 | } 49 | 50 | // Present an alert with the current username populated 51 | // clicking OK will update the username and display it 52 | // clicking Cancel will close the alert and do nothing 53 | async changeUsername() { 54 | const alert = await this.alertCtrl.create({ 55 | header: 'Change Username', 56 | buttons: [ 57 | 'Cancel', 58 | { 59 | text: 'Ok', 60 | handler: (data: { username: string }) => { 61 | this.user.setUsername(data.username); 62 | this.getUsername(); 63 | }, 64 | }, 65 | ], 66 | inputs: [ 67 | { 68 | type: 'text', 69 | name: 'username', 70 | value: this.username, 71 | placeholder: 'username', 72 | }, 73 | ], 74 | }); 75 | await alert.present(); 76 | } 77 | 78 | getUsername() { 79 | this.user.getUsername().then(username => { 80 | this.username = username; 81 | }); 82 | } 83 | 84 | changePassword() { 85 | console.log('Clicked to change password'); 86 | } 87 | 88 | logout() { 89 | this.user.logout(); 90 | this.router.navigateByUrl('/login'); 91 | } 92 | 93 | support() { 94 | this.router.navigateByUrl('/support'); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/app/pages/login/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Login 8 | 9 | 10 | 11 | 12 | 15 | 16 | 60 | 61 | -------------------------------------------------------------------------------- /src/app/pages/login/login.scss: -------------------------------------------------------------------------------- 1 | .login-logo { 2 | min-height: 200px; 3 | 4 | padding: 20px 0; 5 | 6 | text-align: center; 7 | } 8 | 9 | .login-logo img { 10 | max-width: 150px; 11 | } 12 | 13 | .login-form { 14 | padding: 16px; 15 | } 16 | 17 | ion-input { 18 | margin-bottom: 10px; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/login/login.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FormsModule, NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { 5 | IonButton, 6 | IonButtons, 7 | IonCol, 8 | IonContent, 9 | IonHeader, 10 | IonInput, 11 | IonMenuButton, 12 | IonRow, 13 | IonTitle, 14 | IonToolbar, 15 | } from '@ionic/angular/standalone'; 16 | 17 | import { UserOptions } from '../../interfaces/user-options'; 18 | import { UserService } from '../../providers/user.service'; 19 | 20 | @Component({ 21 | selector: 'page-login', 22 | templateUrl: 'login.html', 23 | styleUrls: ['./login.scss'], 24 | imports: [ 25 | FormsModule, 26 | IonButton, 27 | IonButtons, 28 | IonCol, 29 | IonContent, 30 | IonHeader, 31 | IonInput, 32 | IonMenuButton, 33 | IonRow, 34 | IonTitle, 35 | IonToolbar, 36 | ], 37 | }) 38 | export class LoginPage { 39 | private router = inject(Router); 40 | private user = inject(UserService); 41 | 42 | login: UserOptions = { username: '', password: '' }; 43 | submitted = false; 44 | 45 | onLogin(form: NgForm) { 46 | this.submitted = true; 47 | 48 | if (form.valid) { 49 | this.user.login(this.login.username); 50 | this.router.navigateByUrl('/app/tabs/schedule'); 51 | } 52 | } 53 | 54 | onSignup() { 55 | this.router.navigateByUrl('/signup'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/pages/map/map-dark-style.js: -------------------------------------------------------------------------------- 1 | export const darkStyle = [ 2 | { 3 | elementType: 'geometry', 4 | stylers: [ 5 | { 6 | color: '#242f3e', 7 | }, 8 | ], 9 | }, 10 | { 11 | elementType: 'labels.text.fill', 12 | stylers: [ 13 | { 14 | color: '#746855', 15 | }, 16 | ], 17 | }, 18 | { 19 | elementType: 'labels.text.stroke', 20 | stylers: [ 21 | { 22 | color: '#242f3e', 23 | }, 24 | ], 25 | }, 26 | { 27 | featureType: 'administrative.locality', 28 | elementType: 'labels.text.fill', 29 | stylers: [ 30 | { 31 | color: '#d59563', 32 | }, 33 | ], 34 | }, 35 | { 36 | featureType: 'poi', 37 | elementType: 'labels.text.fill', 38 | stylers: [ 39 | { 40 | color: '#d59563', 41 | }, 42 | ], 43 | }, 44 | { 45 | featureType: 'poi.park', 46 | elementType: 'geometry', 47 | stylers: [ 48 | { 49 | color: '#263c3f', 50 | }, 51 | ], 52 | }, 53 | { 54 | featureType: 'poi.park', 55 | elementType: 'labels.text.fill', 56 | stylers: [ 57 | { 58 | color: '#6b9a76', 59 | }, 60 | ], 61 | }, 62 | { 63 | featureType: 'road', 64 | elementType: 'geometry', 65 | stylers: [ 66 | { 67 | color: '#38414e', 68 | }, 69 | ], 70 | }, 71 | { 72 | featureType: 'road', 73 | elementType: 'geometry.stroke', 74 | stylers: [ 75 | { 76 | color: '#212a37', 77 | }, 78 | ], 79 | }, 80 | { 81 | featureType: 'road', 82 | elementType: 'labels.text.fill', 83 | stylers: [ 84 | { 85 | color: '#9ca5b3', 86 | }, 87 | ], 88 | }, 89 | { 90 | featureType: 'road.highway', 91 | elementType: 'geometry', 92 | stylers: [ 93 | { 94 | color: '#746855', 95 | }, 96 | ], 97 | }, 98 | { 99 | featureType: 'road.highway', 100 | elementType: 'geometry.stroke', 101 | stylers: [ 102 | { 103 | color: '#1f2835', 104 | }, 105 | ], 106 | }, 107 | { 108 | featureType: 'road.highway', 109 | elementType: 'labels.text.fill', 110 | stylers: [ 111 | { 112 | color: '#f3d19c', 113 | }, 114 | ], 115 | }, 116 | { 117 | featureType: 'transit', 118 | elementType: 'geometry', 119 | stylers: [ 120 | { 121 | color: '#2f3948', 122 | }, 123 | ], 124 | }, 125 | { 126 | featureType: 'transit.station', 127 | elementType: 'labels.text.fill', 128 | stylers: [ 129 | { 130 | color: '#d59563', 131 | }, 132 | ], 133 | }, 134 | { 135 | featureType: 'water', 136 | elementType: 'geometry', 137 | stylers: [ 138 | { 139 | color: '#17263c', 140 | }, 141 | ], 142 | }, 143 | { 144 | featureType: 'water', 145 | elementType: 'labels.text.fill', 146 | stylers: [ 147 | { 148 | color: '#515c6d', 149 | }, 150 | ], 151 | }, 152 | { 153 | featureType: 'water', 154 | elementType: 'labels.text.stroke', 155 | stylers: [ 156 | { 157 | color: '#17263c', 158 | }, 159 | ], 160 | }, 161 | ]; 162 | -------------------------------------------------------------------------------- /src/app/pages/map/map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Map 7 | 8 | 9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/app/pages/map/map.scss: -------------------------------------------------------------------------------- 1 | .map-canvas { 2 | position: absolute; 3 | 4 | width: 100%; 5 | 6 | height: 100%; 7 | 8 | transition: opacity 150ms ease-in; 9 | 10 | background-color: transparent; 11 | 12 | opacity: 0; 13 | } 14 | 15 | .show-map { 16 | opacity: 1; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/map/map.ts: -------------------------------------------------------------------------------- 1 | import { DOCUMENT } from '@angular/common'; 2 | import { 3 | AfterViewInit, 4 | Component, 5 | ElementRef, 6 | OnDestroy, 7 | ViewChild, 8 | inject, 9 | } from '@angular/core'; 10 | import { 11 | IonButtons, 12 | IonContent, 13 | IonHeader, 14 | IonMenuButton, 15 | IonTitle, 16 | IonToolbar, 17 | } from '@ionic/angular/standalone'; 18 | import { LocationService } from '../../providers/location.service'; 19 | import { Location } from '../../interfaces/conference.interfaces'; 20 | import * as L from 'leaflet'; 21 | import { Subscription, firstValueFrom } from 'rxjs'; 22 | 23 | @Component({ 24 | selector: 'page-map', 25 | template: ` 26 | 27 | 28 | 29 | 30 | 31 | Map 32 | 33 | 34 | 35 | 36 |
37 |
38 | `, 39 | styleUrls: ['./map.scss'], 40 | imports: [ 41 | IonHeader, 42 | IonToolbar, 43 | IonButtons, 44 | IonMenuButton, 45 | IonTitle, 46 | IonContent, 47 | ], 48 | standalone: true, 49 | }) 50 | export class MapPage implements AfterViewInit, OnDestroy { 51 | private doc = inject(DOCUMENT); 52 | private locationService = inject(LocationService); 53 | private map: L.Map | null = null; 54 | private markers: L.Marker[] = []; 55 | private subscription: Subscription; 56 | 57 | @ViewChild('mapCanvas', { static: true }) mapElement!: ElementRef; 58 | 59 | ngAfterViewInit() { 60 | this.locationService.loadLocations().subscribe(() => { 61 | this.initializeMap(); 62 | }); 63 | 64 | // Subscribe to location changes 65 | this.subscription = this.locationService.getLocations().subscribe(() => { 66 | if (this.map) { 67 | this.initializeMap(); 68 | } 69 | }); 70 | } 71 | 72 | ngOnDestroy() { 73 | if (this.subscription) { 74 | this.subscription.unsubscribe(); 75 | } 76 | if (this.map) { 77 | this.map.remove(); 78 | } 79 | } 80 | 81 | private async initializeMap() { 82 | const mapEle = this.mapElement.nativeElement; 83 | 84 | // Remove existing map if it exists 85 | if (this.map) { 86 | this.map.remove(); 87 | this.markers.forEach(marker => marker.remove()); 88 | this.markers = []; 89 | } 90 | 91 | try { 92 | // Get center location 93 | const centerLocation = await firstValueFrom(this.locationService.getCenterLocation()); 94 | if (!centerLocation) { 95 | return; 96 | } 97 | 98 | // Initialize map 99 | this.map = L.map(mapEle, { 100 | center: [centerLocation.lat, centerLocation.lng], 101 | zoom: 16, 102 | preferCanvas: true 103 | }); 104 | 105 | // Configure default marker icon with shadow 106 | L.Marker.prototype.options.icon = L.icon({ 107 | iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png', 108 | iconSize: [25, 41], 109 | iconAnchor: [12, 41], 110 | popupAnchor: [1, -34], 111 | shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png', 112 | shadowSize: [41, 41], 113 | shadowAnchor: [12, 41] 114 | }); 115 | 116 | // Add tile layer 117 | L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 118 | attribution: '© OpenStreetMap contributors' 119 | }).addTo(this.map); 120 | 121 | // Add markers for all locations 122 | const locations = await firstValueFrom(this.locationService.getLocations()); 123 | if (this.map && locations) { 124 | locations.forEach((location: Location) => { 125 | const marker = L.marker([location.lat, location.lng]) 126 | .addTo(this.map as L.Map) 127 | .bindPopup(`${location.name}`, { 128 | className: 'location-popup' 129 | }); 130 | this.markers.push(marker); 131 | }); 132 | } 133 | 134 | mapEle.classList.add('show-map'); 135 | 136 | // Force a resize after a short delay to ensure proper rendering 137 | setTimeout(() => { 138 | this.map?.invalidateSize(); 139 | }, 100); 140 | } catch (error) { 141 | console.error('Error initializing map:', error); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/app/pages/schedule-filter/schedule-filter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @if (ios) { 5 | Cancel 6 | } @else { 7 | Reset 8 | } 9 | 10 | 11 | Filter Sessions 12 | 13 | 14 | Done 15 | 16 | 17 | 18 | 19 | 20 | 21 | Tracks 22 | 23 | @for(track of tracks; track track.name){ 24 | 25 | @if(ios) { 26 | 27 | } 28 | 29 | 32 | {{track.name}} 33 | 34 | 35 | } 36 | 37 | 38 | 39 | 40 | 41 | 42 | Deselect All 43 | 44 | 45 | Select All 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/app/pages/schedule-filter/schedule-filter.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Material Design 3 | */ 4 | 5 | .md ion-toolbar ion-button { 6 | letter-spacing: 0; 7 | 8 | text-transform: capitalize; 9 | } 10 | 11 | .md ion-checkbox { 12 | --checkbox-background-checked: transparent; 13 | --border-color: transparent; 14 | --border-color-checked: transparent; 15 | --checkmark-color: var(--ion-color-primary); 16 | } 17 | 18 | .md ion-list { 19 | background: inherit; 20 | } 21 | 22 | /* 23 | * iOS 24 | */ 25 | 26 | .ios ion-list-header { 27 | margin-top: 10px; 28 | } 29 | 30 | .ios ion-checkbox { 31 | color: var(--ion-color-primary); 32 | } 33 | -------------------------------------------------------------------------------- /src/app/pages/schedule-filter/schedule-filter.ts: -------------------------------------------------------------------------------- 1 | import { LowerCasePipe } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { 5 | Config, 6 | IonButton, 7 | IonButtons, 8 | IonCheckbox, 9 | IonContent, 10 | IonFooter, 11 | IonHeader, 12 | IonIcon, 13 | IonItem, 14 | IonList, 15 | IonListHeader, 16 | IonTitle, 17 | IonToolbar, 18 | ModalController, 19 | NavParams, 20 | } from '@ionic/angular/standalone'; 21 | import { addIcons } from 'ionicons'; 22 | import { 23 | call, 24 | cog, 25 | colorPalette, 26 | compass, 27 | construct, 28 | document, 29 | hammer, 30 | logoAngular, 31 | logoIonic, 32 | restaurant, 33 | } from 'ionicons/icons'; 34 | import { ConferenceService } from '../../providers/conference.service'; 35 | 36 | @Component({ 37 | selector: 'page-schedule-filter', 38 | templateUrl: 'schedule-filter.html', 39 | styleUrls: ['./schedule-filter.scss'], 40 | imports: [ 41 | IonHeader, 42 | IonToolbar, 43 | IonButtons, 44 | IonButton, 45 | IonTitle, 46 | IonContent, 47 | IonList, 48 | IonListHeader, 49 | IonCheckbox, 50 | IonFooter, 51 | IonItem, 52 | FormsModule, 53 | LowerCasePipe, 54 | IonIcon, 55 | ], 56 | providers: [ModalController] 57 | }) 58 | export class ScheduleFilterPage { 59 | private config = inject(Config); 60 | private modalCtrl = inject(ModalController); 61 | private navParams = inject(NavParams); 62 | private confService = inject(ConferenceService); 63 | 64 | ios: boolean; 65 | 66 | tracks: { name: string; icon: string; isChecked: boolean }[] = []; 67 | 68 | constructor() { 69 | addIcons({ 70 | logoAngular, 71 | document, 72 | restaurant, 73 | logoIonic, 74 | hammer, 75 | colorPalette, 76 | cog, 77 | construct, 78 | call, 79 | compass, 80 | }); 81 | } 82 | 83 | ionViewWillEnter() { 84 | this.ios = this.config.get('mode') === 'ios'; 85 | 86 | // passed in array of track names that should be excluded (unchecked) 87 | const excludedTrackNames = this.navParams.get('excludedTracks'); 88 | 89 | this.confService.getTracks().subscribe(tracks => { 90 | tracks.forEach(track => { 91 | this.tracks.push({ 92 | name: track.name, 93 | icon: track.icon, 94 | isChecked: excludedTrackNames.indexOf(track.name) === -1, 95 | }); 96 | }); 97 | // Sort tracks alphabetically by name 98 | this.tracks.sort((a, b) => a.name.localeCompare(b.name)); 99 | }); 100 | } 101 | 102 | selectAll(check: boolean) { 103 | // set all to checked or unchecked 104 | this.tracks.forEach(track => { 105 | track.isChecked = check; 106 | }); 107 | } 108 | 109 | applyFilters() { 110 | // Pass back a new array of track names to exclude 111 | const excludedTrackNames = this.tracks 112 | .filter(c => !c.isChecked) 113 | .map(c => c.name); 114 | this.dismiss(excludedTrackNames); 115 | } 116 | 117 | dismiss(data?: string[]) { 118 | // using the injected ModalController this page 119 | // can "dismiss" itself and pass back data 120 | this.modalCtrl.dismiss(data); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/app/pages/schedule/schedule.scss: -------------------------------------------------------------------------------- 1 | @use "sass:map"; 2 | @import '../../../theme/variables'; 3 | 4 | ion-fab-button { 5 | --background: var(--ion-color-step-150, #ffffff); 6 | --background-hover: var(--ion-color-step-200, #f2f2f2); 7 | --background-focused: var(--ion-color-step-250, #d9d9d9); 8 | --color: var(--ion-color-primary, #3880ff); 9 | } 10 | 11 | /* 12 | * Material Design uses the ripple for activated 13 | * so only style the iOS activated background 14 | */ 15 | .ios ion-fab-button { 16 | --background-activated: var(--ion-color-step-250, #d9d9d9); 17 | } 18 | 19 | @each $track in $tracks { 20 | ion-item-sliding[track='#{$track}'] ion-label { 21 | padding-left: 10px; 22 | 23 | border-left: 2px solid var(--ion-color-#{$track}); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/pages/session-detail/session-detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @if (!isFavorite) { 9 | 10 | } @if (isFavorite) { 11 | 12 | } 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | @if (session) { 23 |
24 |

{{session.name}}

25 | @for (track of session?.tracks; track $index) { 26 | {{track}} 27 | } 28 |

{{session.description}}

29 | 30 | {{session.timeStart}} – {{session.timeEnd}} 31 |
32 | {{session.location}} 33 |
34 |
35 | } 36 | 37 | 38 | 39 | Watch 40 | 41 | 42 | Add to Calendar 43 | 44 | 45 | Mark as Unwatched 46 | 47 | 48 | Download Video 49 | 55 | 56 | 57 | Leave Feedback 58 | 59 | 60 |
61 | -------------------------------------------------------------------------------- /src/app/pages/session-detail/session-detail.scss: -------------------------------------------------------------------------------- 1 | @import '../../../theme/variables'; 2 | 3 | @each $track in $tracks { 4 | .session-track-#{$track} { 5 | color: var(--ion-color-#{$track}); 6 | } 7 | } 8 | 9 | /* Favorite Icon 10 | * -------------------------------------------------------- 11 | */ 12 | 13 | .show-favorite { 14 | position: relative; 15 | } 16 | 17 | .icon-heart-empty, 18 | .icon-heart { 19 | --border-radius: 50%; 20 | --padding-start: 0; 21 | --padding-end: 0; 22 | 23 | position: absolute; 24 | 25 | top: 5px; 26 | right: 5px; 27 | 28 | width: 48px; 29 | height: 48px; 30 | 31 | transition: transform 300ms ease; 32 | 33 | font-size: 16px; 34 | } 35 | 36 | .icon-heart-empty { 37 | transform: scale(1); 38 | } 39 | 40 | .icon-heart { 41 | transform: scale(0); 42 | } 43 | 44 | .show-favorite .icon-heart { 45 | transform: scale(1); 46 | } 47 | 48 | .show-favorite .icon-heart-empty { 49 | transform: scale(0); 50 | } 51 | 52 | h1 { 53 | margin: 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/app/pages/session-detail/session-detail.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { 4 | IonBackButton, 5 | IonButton, 6 | IonButtons, 7 | IonContent, 8 | IonHeader, 9 | IonIcon, 10 | IonItem, 11 | IonLabel, 12 | IonList, 13 | IonText, 14 | IonToolbar, 15 | } from '@ionic/angular/standalone'; 16 | import { addIcons } from 'ionicons'; 17 | import { 18 | cloudDownload, 19 | share, 20 | shareOutline, 21 | star, 22 | starOutline, 23 | } from 'ionicons/icons'; 24 | 25 | import { Session } from '../../interfaces/conference.interfaces'; 26 | import { ConferenceService } from '../../providers/conference.service'; 27 | import { UserService } from '../../providers/user.service'; 28 | 29 | @Component({ 30 | selector: 'page-session-detail', 31 | styleUrls: ['./session-detail.scss'], 32 | templateUrl: 'session-detail.html', 33 | imports: [ 34 | IonHeader, 35 | IonToolbar, 36 | IonButtons, 37 | IonBackButton, 38 | IonContent, 39 | IonButton, 40 | IonIcon, 41 | IonList, 42 | IonItem, 43 | IonLabel, 44 | IonText, 45 | ] 46 | }) 47 | export class SessionDetailPage { 48 | private confService = inject(ConferenceService); 49 | private userService = inject(UserService); 50 | private route = inject(ActivatedRoute); 51 | 52 | session: Session; 53 | isFavorite = false; 54 | defaultHref = ''; 55 | 56 | constructor() { 57 | addIcons({ shareOutline, starOutline, star, cloudDownload, share }); 58 | } 59 | 60 | ionViewWillEnter() { 61 | this.confService.load().subscribe(data => { 62 | if ( 63 | data && 64 | data.schedule && 65 | data.schedule[0] && 66 | data.schedule[0].groups 67 | ) { 68 | const sessionId = this.route.snapshot.paramMap.get('sessionId'); 69 | for (const group of data.schedule[0].groups) { 70 | if (group && group.sessions) { 71 | for (const session of group.sessions) { 72 | if (session && session.id === sessionId) { 73 | this.session = session; 74 | 75 | this.isFavorite = this.userService.hasFavorite( 76 | this.session.name 77 | ); 78 | 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | } 85 | }); 86 | } 87 | 88 | ionViewDidEnter() { 89 | this.defaultHref = '/app/tabs/schedule'; 90 | } 91 | 92 | sessionClick(item: string) { 93 | console.log('Clicked', item); 94 | } 95 | 96 | toggleFavorite() { 97 | const sessionName = this.session.name; 98 | if (this.userService.hasFavorite(sessionName)) { 99 | this.userService.removeFavorite(sessionName); 100 | this.isFavorite = false; 101 | } else { 102 | this.userService.addFavorite(this.session.name); 103 | this.isFavorite = true; 104 | } 105 | } 106 | 107 | shareSession() { 108 | console.log('Clicked share session'); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/app/pages/signup/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Signup 7 | 8 | 9 | 10 | 11 | 14 | 15 | 52 | 53 | -------------------------------------------------------------------------------- /src/app/pages/signup/signup.scss: -------------------------------------------------------------------------------- 1 | .signup-logo { 2 | min-height: 200px; 3 | 4 | padding: 20px 0; 5 | 6 | text-align: center; 7 | } 8 | 9 | .signup-logo img { 10 | max-width: 150px; 11 | } 12 | 13 | .signup-form { 14 | padding: 16px; 15 | } 16 | 17 | ion-input { 18 | margin-bottom: 10px; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/signup/signup.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormsModule, NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { 5 | IonButton, 6 | IonButtons, 7 | IonContent, 8 | IonHeader, 9 | IonInput, 10 | IonMenuButton, 11 | IonTitle, 12 | IonToolbar, 13 | IonCol, 14 | IonRow 15 | } from '@ionic/angular/standalone'; 16 | 17 | import { UserService } from '../../providers/user.service'; 18 | 19 | import { UserOptions } from '../../interfaces/user-options'; 20 | 21 | @Component({ 22 | selector: 'page-signup', 23 | templateUrl: 'signup.html', 24 | styleUrls: ['./signup.scss'], 25 | imports: [ 26 | IonRow, 27 | IonCol, 28 | FormsModule, 29 | IonHeader, 30 | IonToolbar, 31 | IonButtons, 32 | IonMenuButton, 33 | IonTitle, 34 | IonContent, 35 | IonInput, 36 | IonButton, 37 | ] 38 | }) 39 | export class SignupPage { 40 | signup: UserOptions = { username: '', password: '' }; 41 | submitted = false; 42 | 43 | constructor(public router: Router, public userService: UserService) {} 44 | 45 | onSignup(form: NgForm) { 46 | this.submitted = true; 47 | 48 | if (form.valid) { 49 | this.userService.signup(this.signup.username); 50 | this.router.navigateByUrl('/app/tabs/schedule'); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/app/pages/speaker-detail/speaker-detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @if (speaker) { 9 | 10 | 11 | 16 | 17 | 18 | 23 | 24 | 25 | } 26 | 27 | 28 | 29 |
30 | 37 |

{{speaker?.name ?? 'Loading...'}}

38 |
39 | 40 |
41 |

42 | {{speaker?.about ?? 'Loading biography...'}} Say hello on social media! 43 |

44 | 45 |
46 | 47 | @if (speaker) { 48 | 79 | } 80 |
81 |
82 | -------------------------------------------------------------------------------- /src/app/pages/speaker-detail/speaker-detail.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Speaker Background 3 | */ 4 | 5 | ion-toolbar { 6 | --background: transparent; 7 | --color: white; 8 | 9 | position: absolute; 10 | 11 | top: 0; 12 | right: 0; 13 | left: 0; 14 | } 15 | 16 | ion-toolbar ion-button, 17 | ion-toolbar ion-back-button, 18 | ion-toolbar ion-menu-button { 19 | --color: white; 20 | } 21 | 22 | .speaker-background { 23 | display: flex; 24 | position: relative; 25 | 26 | flex-direction: column; 27 | 28 | align-items: center; 29 | justify-content: center; 30 | 31 | height: calc(250px + var(--ion-safe-area-top)); 32 | 33 | padding-top: var(--ion-safe-area-top); 34 | 35 | background: center / cover url('/assets/img/speaker-background.png') no-repeat; 36 | } 37 | 38 | .speaker-background img { 39 | width: 70px; 40 | height: auto; 41 | 42 | margin-top: calc(-1 * var(--ion-safe-area-top)); 43 | 44 | border-radius: 50%; 45 | } 46 | 47 | .speaker-background h2 { 48 | position: absolute; 49 | 50 | bottom: 10px; 51 | 52 | color: white; 53 | } 54 | 55 | .md .speaker-background { 56 | box-shadow: rgb(0 0 0 / 20%) 0 3px 1px -2px, rgb(0 0 0 / 14%) 0 2px 2px 0, 57 | rgb(0 0 0 / 12%) 0 1px 5px 0; 58 | } 59 | 60 | .ios .speaker-background { 61 | box-shadow: rgb(0 0 0 / 12%) 0 4px 16px; 62 | } 63 | 64 | /* 65 | * Speaker Details 66 | */ 67 | 68 | .speaker-detail p { 69 | margin-right: 6px; 70 | margin-left: 6px; 71 | } 72 | 73 | .speaker-detail hr { 74 | margin-top: 20px; 75 | margin-bottom: 20px; 76 | 77 | background: var(--ion-color-step-150, #d7d8da); 78 | } 79 | -------------------------------------------------------------------------------- /src/app/pages/speaker-detail/speaker-detail.ts: -------------------------------------------------------------------------------- 1 | import { NgOptimizedImage } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { InAppBrowser } from '@awesome-cordova-plugins/in-app-browser/ngx'; 5 | import { 6 | ActionSheetController, 7 | IonBackButton, 8 | IonButton, 9 | IonButtons, 10 | IonChip, 11 | IonContent, 12 | IonHeader, 13 | IonIcon, 14 | IonLabel, 15 | IonToolbar, 16 | } from '@ionic/angular/standalone'; 17 | import { addIcons } from 'ionicons'; 18 | import { 19 | callOutline, 20 | callSharp, 21 | logoGithub, 22 | logoInstagram, 23 | logoTwitter, 24 | shareOutline, 25 | shareSharp, 26 | } from 'ionicons/icons'; 27 | import { Speaker } from '../../interfaces/conference.interfaces'; 28 | import { ConferenceService } from '../../providers/conference.service'; 29 | 30 | @Component({ 31 | selector: 'page-speaker-detail', 32 | templateUrl: 'speaker-detail.html', 33 | styleUrls: ['./speaker-detail.scss'], 34 | imports: [ 35 | IonContent, 36 | IonHeader, 37 | IonToolbar, 38 | IonButtons, 39 | IonBackButton, 40 | IonButton, 41 | IonIcon, 42 | IonChip, 43 | IonLabel, 44 | NgOptimizedImage, 45 | ], 46 | providers: [InAppBrowser, ActionSheetController] 47 | }) 48 | export class SpeakerDetailPage { 49 | speaker: Speaker; 50 | 51 | private confService = inject(ConferenceService); 52 | private route = inject(ActivatedRoute); 53 | private actionSheetCtrl = inject(ActionSheetController); 54 | private inAppBrowser = inject(InAppBrowser); 55 | 56 | constructor() { 57 | addIcons({ 58 | callOutline, 59 | callSharp, 60 | shareOutline, 61 | shareSharp, 62 | logoTwitter, 63 | logoGithub, 64 | logoInstagram, 65 | }); 66 | } 67 | 68 | ionViewWillEnter() { 69 | this.confService.load().subscribe(data => { 70 | const speakerId = this.route.snapshot.paramMap.get('speakerId'); 71 | if (data && data.speakers) { 72 | for (const speaker of data.speakers) { 73 | if (speaker && speaker.id === speakerId) { 74 | this.speaker = speaker; 75 | break; 76 | } 77 | } 78 | } 79 | }); 80 | } 81 | 82 | openExternalUrl(url: string) { 83 | this.inAppBrowser.create(url, '_blank'); 84 | } 85 | 86 | async openSpeakerShare(speaker: any) { 87 | const actionSheet = await this.actionSheetCtrl.create({ 88 | header: 'Share ' + speaker.name, 89 | buttons: [ 90 | { 91 | text: 'Copy Link', 92 | handler: () => { 93 | console.log( 94 | 'Copy link clicked on https://twitter.com/' + speaker.twitter 95 | ); 96 | if ( 97 | (window as any).cordova && 98 | (window as any).cordova.plugins.clipboard 99 | ) { 100 | (window as any).cordova.plugins.clipboard.copy( 101 | 'https://twitter.com/' + speaker.twitter 102 | ); 103 | } 104 | }, 105 | }, 106 | { 107 | text: 'Share via ...', 108 | }, 109 | { 110 | text: 'Cancel', 111 | role: 'cancel', 112 | }, 113 | ], 114 | }); 115 | 116 | await actionSheet.present(); 117 | } 118 | 119 | async openContact(speaker: Speaker) { 120 | const mode = 'ios'; // this.config.get('mode'); 121 | 122 | const actionSheet = await this.actionSheetCtrl.create({ 123 | header: 'Contact ' + speaker.name, 124 | buttons: [ 125 | { 126 | text: `Email ( ${speaker.email} )`, 127 | icon: mode !== 'ios' ? 'mail' : null, 128 | handler: () => { 129 | window.open('mailto:' + speaker.email); 130 | }, 131 | }, 132 | { 133 | text: `Call ( ${speaker.phone} )`, 134 | icon: mode !== 'ios' ? 'call' : null, 135 | handler: () => { 136 | window.open('tel:' + speaker.phone); 137 | }, 138 | }, 139 | { 140 | text: 'Cancel', 141 | role: 'cancel', 142 | }, 143 | ], 144 | }); 145 | 146 | await actionSheet.present(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/app/pages/speaker-list/speaker-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Speakers 7 | 8 | 9 | 10 | 11 | 12 | 13 | Speakers 14 | 15 | 16 | 17 | 18 | 19 | @for (speaker of speakers; track speaker.id) { 20 | 21 | 22 | 23 | 29 | 30 | 34 | 35 | 36 |

{{speaker.name}}

37 |

{{speaker.title}}

38 |
39 |
40 |
41 | 42 | 43 | 44 | @for (session of speaker.sessions; track session.id) { 45 | 49 | 50 |

{{session.name}}

51 |
52 |
53 | } 54 | 55 | 59 | 60 |

About {{speaker.name}}

61 |
62 |
63 |
64 |
65 |
66 |
67 | } 68 |
69 |
70 |
71 | -------------------------------------------------------------------------------- /src/app/pages/speaker-list/speaker-list.scss: -------------------------------------------------------------------------------- 1 | .speaker-card { 2 | display: flex; 3 | 4 | flex-direction: column; 5 | } 6 | 7 | /* Due to the fact the cards are inside of columns the margins don't overlap 8 | * properly so we want to remove the extra margin between cards 9 | */ 10 | ion-col:not(:last-of-type) .speaker-card { 11 | margin-bottom: 0; 12 | } 13 | 14 | .speaker-card .speaker-item { 15 | --min-height: 85px; 16 | } 17 | 18 | .speaker-card .speaker-item h2 { 19 | font-size: 18px; 20 | font-weight: 500; 21 | 22 | letter-spacing: 0.02em; 23 | } 24 | 25 | .speaker-card .speaker-item p { 26 | font-size: 13px; 27 | 28 | letter-spacing: 0.02em; 29 | } 30 | 31 | .speaker-card ion-card-header { 32 | padding: 0; 33 | } 34 | 35 | .speaker-card ion-card-content { 36 | flex: 1 1 auto; 37 | 38 | padding: 0; 39 | } 40 | 41 | .ios ion-list { 42 | margin-bottom: 10px; 43 | } 44 | 45 | .md ion-list { 46 | padding: 0; 47 | 48 | border-top: 1px solid var(--ion-color-step-150, #d7d8da); 49 | } 50 | -------------------------------------------------------------------------------- /src/app/pages/speaker-list/speaker-list.spec.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { RouteReuseStrategy, Router } from '@angular/router'; 4 | import { ActionSheetController, IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone'; 5 | 6 | import { InAppBrowser } from '@awesome-cordova-plugins/in-app-browser/ngx'; 7 | import { ConferenceService } from '../../providers/conference.service'; 8 | import { SpeakerListPage } from './speaker-list'; 9 | 10 | const confDataSub = {}; 11 | 12 | describe('SpeakerListPage', () => { 13 | let fixture, app; 14 | beforeEach(async () => { 15 | const actionSheetSpy = jasmine.createSpyObj('ActionSheetController', [ 16 | 'create', 17 | ]); 18 | const routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']); 19 | const iabSpy = jasmine.createSpyObj('InAppBrowser', ['create']); 20 | 21 | await TestBed.configureTestingModule({ 22 | declarations: [], 23 | imports: [SpeakerListPage], 24 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 25 | providers: [ 26 | provideIonicAngular(), 27 | { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, 28 | { provide: ActionSheetController, useValue: actionSheetSpy }, 29 | { provide: InAppBrowser, useValue: iabSpy }, 30 | { provide: Router, useValue: routerSpy }, 31 | { provide: ConferenceService, useValue: confDataSub }, 32 | ], 33 | }).compileComponents(); 34 | 35 | fixture = TestBed.createComponent(SpeakerListPage); 36 | app = fixture.debugElement.componentInstance; 37 | fixture.detectChanges(); 38 | }); 39 | 40 | it('should create the speaker list page', () => { 41 | expect(app).toBeTruthy(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/app/pages/speaker-list/speaker-list.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { RouterLink } from '@angular/router'; 3 | import { 4 | IonAvatar, 5 | IonButtons, 6 | IonCard, 7 | IonCardContent, 8 | IonCardHeader, 9 | IonCol, 10 | IonContent, 11 | IonGrid, 12 | IonHeader, 13 | IonItem, 14 | IonLabel, 15 | IonList, 16 | IonMenuButton, 17 | IonRow, 18 | IonTitle, 19 | IonToolbar, 20 | } from '@ionic/angular/standalone'; 21 | import { Speaker } from '../../interfaces/conference.interfaces'; 22 | import { ConferenceService } from '../../providers/conference.service'; 23 | 24 | @Component({ 25 | selector: 'page-speaker-list', 26 | templateUrl: 'speaker-list.html', 27 | styleUrls: ['./speaker-list.scss'], 28 | imports: [ 29 | IonHeader, 30 | IonToolbar, 31 | IonButtons, 32 | IonMenuButton, 33 | IonTitle, 34 | IonContent, 35 | IonGrid, 36 | IonRow, 37 | IonCol, 38 | IonCard, 39 | IonCardHeader, 40 | IonItem, 41 | IonAvatar, 42 | IonLabel, 43 | IonCardContent, 44 | IonList, 45 | RouterLink, 46 | ] 47 | }) 48 | export class SpeakerListPage { 49 | private confData = inject(ConferenceService); 50 | 51 | speakers: Speaker[] = []; 52 | 53 | ionViewDidEnter() { 54 | this.confData.getSpeakers().subscribe(speakers => { 55 | this.speakers = speakers; 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/app/pages/support/support.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Support 7 | 8 | 9 | 10 | 11 | 20 | 21 |
22 |
23 | 34 | 35 | 36 | 37 | 38 | Submit 39 | 40 | 41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /src/app/pages/support/support.scss: -------------------------------------------------------------------------------- 1 | .support-logo { 2 | min-height: 200px; 3 | 4 | text-align: center; 5 | } 6 | 7 | .support-logo img { 8 | max-width: 150px; 9 | } 10 | 11 | .list { 12 | margin-bottom: 0; 13 | } 14 | 15 | .support-form { 16 | padding: 16px; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/support/support.ts: -------------------------------------------------------------------------------- 1 | import { NgOptimizedImage } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FormsModule, NgForm } from '@angular/forms'; 4 | import { 5 | AlertController, 6 | IonButton, 7 | IonButtons, 8 | IonContent, 9 | IonCol, 10 | IonHeader, 11 | IonMenuButton, 12 | IonRow, 13 | IonTextarea, 14 | IonTitle, 15 | IonToolbar, 16 | ToastController, 17 | } from '@ionic/angular/standalone'; 18 | 19 | @Component({ 20 | selector: 'page-support', 21 | templateUrl: 'support.html', 22 | styleUrls: ['./support.scss'], 23 | imports: [ 24 | FormsModule, 25 | IonHeader, 26 | IonButton, 27 | IonButtons, 28 | IonContent, 29 | IonCol, 30 | IonHeader, 31 | IonMenuButton, 32 | IonRow, 33 | IonTextarea, 34 | IonTitle, 35 | IonToolbar, 36 | NgOptimizedImage, 37 | ], 38 | providers: [AlertController, ToastController] 39 | }) 40 | export class SupportPage { 41 | private toastCtrl = inject(ToastController); 42 | 43 | submitted = false; 44 | supportMessage: string; 45 | 46 | async ionViewDidEnter() { 47 | const toast = await this.toastCtrl.create({ 48 | message: 'This does not actually send a support request.', 49 | duration: 3000, 50 | }); 51 | await toast.present(); 52 | } 53 | 54 | async submit(form: NgForm) { 55 | this.submitted = true; 56 | 57 | if (form.valid) { 58 | this.supportMessage = ''; 59 | this.submitted = false; 60 | 61 | const toast = await this.toastCtrl.create({ 62 | message: 'Your support request has been sent.', 63 | duration: 3000, 64 | }); 65 | await toast.present(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/app/pages/tabs-page/routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { TabsPage } from './tabs-page'; 3 | 4 | export const TABS_ROUTES: Routes = [ 5 | { 6 | path: 'tabs', 7 | component: TabsPage, 8 | children: [ 9 | { 10 | path: 'schedule', 11 | children: [ 12 | { 13 | path: '', 14 | loadComponent: () => 15 | import('../schedule/schedule').then(m => m.SchedulePage), 16 | }, 17 | { 18 | path: 'session/:sessionId', 19 | loadComponent: () => 20 | import('../session-detail/session-detail').then( 21 | m => m.SessionDetailPage 22 | ), 23 | }, 24 | ], 25 | }, 26 | { 27 | path: 'speakers', 28 | children: [ 29 | { 30 | path: '', 31 | loadComponent: () => 32 | import('../speaker-list/speaker-list').then( 33 | m => m.SpeakerListPage 34 | ), 35 | }, 36 | { 37 | path: 'session/:sessionId', 38 | loadComponent: () => 39 | import('../session-detail/session-detail').then( 40 | m => m.SessionDetailPage 41 | ), 42 | }, 43 | { 44 | path: 'speaker-details/:speakerId', 45 | loadComponent: () => 46 | import('../speaker-detail/speaker-detail').then( 47 | m => m.SpeakerDetailPage 48 | ), 49 | }, 50 | ], 51 | }, 52 | { 53 | path: 'map', 54 | loadComponent: () => import('../map/map').then(m => m.MapPage), 55 | }, 56 | { 57 | path: 'about', 58 | children: [ 59 | { 60 | path: '', 61 | loadComponent: () => 62 | import('../about/about').then(m => m.AboutPage), 63 | }, 64 | ], 65 | }, 66 | { 67 | path: '', 68 | redirectTo: '/app/tabs/schedule', 69 | pathMatch: 'full', 70 | }, 71 | ], 72 | }, 73 | ]; 74 | -------------------------------------------------------------------------------- /src/app/pages/tabs-page/tabs-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Schedule 6 | 7 | 8 | 9 | 10 | Speakers 11 | 12 | 13 | 14 | 15 | Map 16 | 17 | 18 | 19 | 20 | About 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/app/pages/tabs-page/tabs-page.scss: -------------------------------------------------------------------------------- 1 | .tabbar { 2 | justify-content: center; 3 | } 4 | 5 | .tab-button { 6 | max-width: 200px; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/pages/tabs-page/tabs-page.spec.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | 4 | import { provideRouter } from '@angular/router'; 5 | import { routes } from '../../app.routes'; 6 | import { TabsPage } from './tabs-page'; 7 | 8 | describe('TabsPage', () => { 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [], 12 | imports: [TabsPage], 13 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 14 | providers: [provideRouter(routes)], 15 | }).compileComponents(); 16 | }); 17 | 18 | it('should create the tabs page', () => { 19 | const fixture = TestBed.createComponent(TabsPage); 20 | const app = fixture.debugElement.componentInstance; 21 | expect(app).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/tabs-page/tabs-page.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | import { 4 | IonIcon, 5 | IonLabel, 6 | IonTabBar, 7 | IonTabButton, 8 | IonTabs, 9 | } from '@ionic/angular/standalone'; 10 | import { addIcons } from 'ionicons'; 11 | import { calendar, informationCircle, location, people } from 'ionicons/icons'; 12 | 13 | @Component({ 14 | templateUrl: 'tabs-page.html', 15 | imports: [ 16 | IonTabs, 17 | IonTabBar, 18 | IonTabButton, 19 | IonIcon, 20 | IonLabel, 21 | RouterModule, 22 | ] 23 | }) 24 | export class TabsPage { 25 | constructor() { 26 | addIcons({ calendar, people, location, informationCircle }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/pages/tutorial/tutorial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Skip 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |

16 | Welcome to 17 | ICA 18 |

19 |

20 | The ionic conference app is a practical preview of the ionic 21 | framework in action, and a demonstration of proper code use. 22 |

23 |
24 | 25 |
26 | 27 |

What is Ionic?

28 |

29 | Ionic Framework is an open source SDK that enables developers to 30 | build high quality mobile apps with web technologies like HTML, CSS, and 31 | JavaScript. 32 |

33 |
34 | 35 |
36 | 37 |

What is Ionic Appflow?

38 |

39 | Ionic Appflow is a powerful set of services and features built on 40 | top of Ionic Framework that brings a totally new level of app 41 | development agility to mobile dev teams. 42 |

43 |
44 | 45 |
46 | 47 |

Ready to Play?

48 | 49 | Continue 50 | 51 | 52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /src/app/pages/tutorial/tutorial.scss: -------------------------------------------------------------------------------- 1 | ion-toolbar { 2 | --background: transparent; 3 | } 4 | 5 | ion-content { 6 | --overflow: hidden; 7 | } 8 | 9 | .slide-container { 10 | display: grid; 11 | grid-template-columns: repeat(4, 100%); 12 | grid-template-rows: 1fr; 13 | 14 | height: 100%; 15 | 16 | overflow: scroll; 17 | scroll-snap-type: x mandatory; 18 | } 19 | 20 | .slide { 21 | display: flex; 22 | 23 | flex-direction: column; 24 | align-items: center; 25 | justify-content: center; 26 | 27 | width: 100%; 28 | 29 | text-align: center; 30 | 31 | scroll-snap-align: center; 32 | scroll-snap-stop: always; 33 | } 34 | 35 | .slide-title { 36 | margin-top: 2.8rem; 37 | } 38 | 39 | .slide-image { 40 | max-width: 80%; 41 | max-height: 50%; 42 | 43 | margin: -5vh 0 0; 44 | pointer-events: none; 45 | } 46 | 47 | b { 48 | font-weight: 500; 49 | } 50 | 51 | p { 52 | padding: 0 40px; 53 | 54 | color: var(--ion-color-step-600, #60646b); 55 | 56 | font-size: 14px; 57 | 58 | line-height: 1.5; 59 | 60 | b { 61 | color: var(--ion-text-color, #000000); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/app/pages/tutorial/tutorial.spec.ts: -------------------------------------------------------------------------------- 1 | import { CUSTOM_ELEMENTS_SCHEMA, importProvidersFrom } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { Router, provideRouter } from '@angular/router'; 4 | import { MenuController, provideIonicAngular } from '@ionic/angular/standalone'; 5 | import { IonicStorageModule } from '@ionic/storage-angular'; 6 | import { routes } from '../../app.routes'; 7 | import { TutorialPage } from './tutorial'; 8 | 9 | describe('TutorialPage', () => { 10 | let fixture, app; 11 | beforeEach(async () => { 12 | const menuSpy = jasmine.createSpyObj('MenuController', [ 13 | 'toggle', 14 | 'enable', 15 | ]); 16 | const routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']); 17 | 18 | await TestBed.configureTestingModule({ 19 | declarations: [], 20 | imports: [TutorialPage], 21 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 22 | providers: [ 23 | provideIonicAngular(), 24 | provideRouter(routes), 25 | importProvidersFrom(IonicStorageModule.forRoot()), 26 | { provide: MenuController, useValue: menuSpy }, 27 | { provide: Router, useValue: routerSpy }, 28 | ], 29 | }).compileComponents(); 30 | }); 31 | 32 | beforeEach(() => { 33 | fixture = TestBed.createComponent(TutorialPage); 34 | app = fixture.debugElement.componentInstance; 35 | app.storage.create(); 36 | }); 37 | it('should create the tutorial page', () => { 38 | expect(app).toBeTruthy(); 39 | }); 40 | 41 | it('should check the tutorial status', async () => { 42 | const didTuts = await app.storage.get('ion_did_tutorial'); 43 | expect(didTuts).toBeFalsy(); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/app/pages/tutorial/tutorial.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | import { 5 | IonButton, 6 | IonButtons, 7 | IonContent, 8 | IonHeader, 9 | IonIcon, 10 | IonToolbar, 11 | MenuController, 12 | } from '@ionic/angular/standalone'; 13 | import { Storage } from '@ionic/storage-angular'; 14 | import { addIcons } from 'ionicons'; 15 | import { arrowForward, close } from 'ionicons/icons'; 16 | 17 | @Component({ 18 | selector: 'page-tutorial', 19 | templateUrl: 'tutorial.html', 20 | styleUrls: ['./tutorial.scss'], 21 | imports: [IonHeader, IonToolbar, IonButtons, IonButton, IonContent, IonIcon] 22 | }) 23 | export class TutorialPage { 24 | showSkip = true; 25 | 26 | constructor( 27 | public menu: MenuController, 28 | public router: Router, 29 | public storage: Storage 30 | ) { 31 | addIcons({ 32 | arrowForward, 33 | close, 34 | }); 35 | } 36 | 37 | startApp() { 38 | this.router 39 | .navigateByUrl('/app/tabs/schedule', { replaceUrl: true }) 40 | .then(() => this.storage.set('ion_did_tutorial', true)); 41 | } 42 | 43 | ionViewWillEnter() { 44 | this.storage.get('ion_did_tutorial').then(res => { 45 | if (res === true) { 46 | this.router.navigateByUrl('/app/tabs/schedule', { replaceUrl: true }); 47 | } 48 | }); 49 | 50 | this.menu.enable(false); 51 | } 52 | 53 | ionViewWillLeave() { 54 | // enable the root left menu when leaving the tutorial page 55 | this.menu.enable(true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/providers/can-deactivate-support.guard.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { CanDeactivateFn } from '@angular/router'; 3 | import { AlertController } from '@ionic/angular/standalone'; 4 | import { SupportPage } from '../pages/support/support'; 5 | 6 | export const canDeactivateSupportPage: CanDeactivateFn = async ( 7 | component: SupportPage 8 | ) => { 9 | // If the support message is empty we should just navigate 10 | if ( 11 | !component.supportMessage || 12 | component.supportMessage.trim().length === 0 13 | ) { 14 | return true; 15 | } 16 | 17 | const alertCtrl = inject(AlertController); 18 | const alert = await alertCtrl.create({ 19 | header: 'Leave this page?', 20 | message: 21 | 'Are you sure you want to leave this page? Your support message will not be submitted.', 22 | buttons: [ 23 | { 24 | text: 'Stay', 25 | role: 'cancel', 26 | handler: () => false, 27 | }, 28 | { 29 | text: 'Leave', 30 | handler: () => true, 31 | }, 32 | ], 33 | }); 34 | 35 | await alert.present(); 36 | const { role } = await alert.onDidDismiss(); 37 | return role !== 'cancel'; 38 | }; 39 | -------------------------------------------------------------------------------- /src/app/providers/check-tutorial.guard.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { Storage } from '@ionic/storage-angular'; 4 | import { from, map, tap } from 'rxjs'; 5 | 6 | export const checkTutorialGuard = () => { 7 | const storage = inject(Storage); 8 | const router = inject(Router); 9 | 10 | return from(storage.get('ion_did_tutorial')).pipe( 11 | tap(didTutorial => { 12 | if (didTutorial === true) { 13 | router.navigate(['/app', 'tabs', 'schedule']); 14 | } 15 | }), 16 | map(didTutorial => !didTutorial) 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /src/app/providers/location.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { BehaviorSubject, Observable, catchError, map, of } from 'rxjs'; 4 | import { Location } from '../interfaces/conference.interfaces'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class LocationService { 10 | private locationsSubject = new BehaviorSubject([]); 11 | public readonly locations$ = this.locationsSubject.asObservable(); 12 | 13 | constructor(private http: HttpClient) {} 14 | 15 | loadLocations(): Observable { 16 | return this.http.get('assets/data/data.json').pipe( 17 | map(data => { 18 | if (data.map && Array.isArray(data.map)) { 19 | // Add IDs to locations 20 | const locations = data.map.map((location: any, index: number) => ({ 21 | ...location, 22 | id: index + 1 23 | })); 24 | this.locationsSubject.next(locations); 25 | return locations; 26 | } else { 27 | throw new Error('Invalid data format: map array not found'); 28 | } 29 | }), 30 | catchError(error => { 31 | console.error('Error loading locations:', error); 32 | // Set default locations if data cannot be loaded 33 | const defaultLocations = [{ 34 | id: 1, 35 | name: 'Monona Terrace Convention Center', 36 | lat: 43.071584, 37 | lng: -89.38012, 38 | center: true 39 | }]; 40 | this.locationsSubject.next(defaultLocations); 41 | return of(defaultLocations); 42 | }) 43 | ); 44 | } 45 | 46 | getLocations(): Observable { 47 | return this.locations$; 48 | } 49 | 50 | getCenterLocation(): Observable { 51 | return this.locations$.pipe( 52 | map(locations => locations.find(location => location.center)) 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/providers/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Storage } from '@ionic/storage-angular'; 3 | 4 | @Injectable({ 5 | providedIn: 'root', 6 | }) 7 | export class UserService { 8 | favorites: string[] = []; 9 | HAS_LOGGED_IN = 'hasLoggedIn'; 10 | HAS_SEEN_TUTORIAL = 'hasSeenTutorial'; 11 | 12 | constructor(public storage: Storage) {} 13 | 14 | hasFavorite(sessionName: string): boolean { 15 | return this.favorites.indexOf(sessionName) > -1; 16 | } 17 | 18 | addFavorite(sessionName: string): void { 19 | this.favorites.push(sessionName); 20 | } 21 | 22 | removeFavorite(sessionName: string): void { 23 | const index = this.favorites.indexOf(sessionName); 24 | if (index > -1) { 25 | this.favorites.splice(index, 1); 26 | } 27 | } 28 | 29 | login(username: string): Promise { 30 | return this.storage.set(this.HAS_LOGGED_IN, true).then(() => { 31 | this.setUsername(username); 32 | return window.dispatchEvent(new CustomEvent('user:login')); 33 | }); 34 | } 35 | 36 | signup(username: string): Promise { 37 | return this.storage.set(this.HAS_LOGGED_IN, true).then(() => { 38 | this.setUsername(username); 39 | return window.dispatchEvent(new CustomEvent('user:signup')); 40 | }); 41 | } 42 | 43 | logout(): Promise { 44 | return this.storage 45 | .remove(this.HAS_LOGGED_IN) 46 | .then(() => { 47 | return this.storage.remove('username'); 48 | }) 49 | .then(() => { 50 | window.dispatchEvent(new CustomEvent('user:logout')); 51 | }); 52 | } 53 | 54 | setUsername(username: string): Promise { 55 | return this.storage.set('username', username); 56 | } 57 | 58 | getUsername(): Promise { 59 | return this.storage.get('username').then(value => { 60 | return value; 61 | }); 62 | } 63 | 64 | isLoggedIn(): Promise { 65 | return this.storage.get(this.HAS_LOGGED_IN).then(value => { 66 | return value === true; 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/assets/icon/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icon/favicon.png -------------------------------------------------------------------------------- /src/assets/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/128.png -------------------------------------------------------------------------------- /src/assets/icons/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/144.png -------------------------------------------------------------------------------- /src/assets/icons/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/152.png -------------------------------------------------------------------------------- /src/assets/icons/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/180.png -------------------------------------------------------------------------------- /src/assets/icons/192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/192.png -------------------------------------------------------------------------------- /src/assets/icons/384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/384.png -------------------------------------------------------------------------------- /src/assets/icons/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/512.png -------------------------------------------------------------------------------- /src/assets/icons/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/72.png -------------------------------------------------------------------------------- /src/assets/icons/96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/icons/96.png -------------------------------------------------------------------------------- /src/assets/img/about/Archive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/about/Archive.zip -------------------------------------------------------------------------------- /src/assets/img/about/austin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/about/austin.jpg -------------------------------------------------------------------------------- /src/assets/img/about/chicago.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/about/chicago.jpg -------------------------------------------------------------------------------- /src/assets/img/about/madison.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/about/madison.jpg -------------------------------------------------------------------------------- /src/assets/img/about/seattle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/about/seattle.jpg -------------------------------------------------------------------------------- /src/assets/img/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/appicon.png -------------------------------------------------------------------------------- /src/assets/img/appicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/img/ica-slidebox-img-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/ica-slidebox-img-1.png -------------------------------------------------------------------------------- /src/assets/img/ica-slidebox-img-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/ica-slidebox-img-2.png -------------------------------------------------------------------------------- /src/assets/img/ica-slidebox-img-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/ica-slidebox-img-3.png -------------------------------------------------------------------------------- /src/assets/img/ica-slidebox-img-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/ica-slidebox-img-4.png -------------------------------------------------------------------------------- /src/assets/img/ionic-logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/img/speaker-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speaker-background.png -------------------------------------------------------------------------------- /src/assets/img/speakers/bear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/bear.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/cheetah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/cheetah.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/duck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/duck.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/eagle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/eagle.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/elephant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/elephant.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/giraffe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/giraffe.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/iguana.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/iguana.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/kitten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/kitten.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/lion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/lion.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/mouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/mouse.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/puppy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/puppy.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/rabbit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/rabbit.jpg -------------------------------------------------------------------------------- /src/assets/img/speakers/turtle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-conference-app/1da3d218aad35fff7cbf482e89bef6829e4ace24/src/assets/img/speakers/turtle.jpg -------------------------------------------------------------------------------- /src/assets/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "short_name": "app", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "./", 8 | "start_url": "./", 9 | "icons": [ 10 | { 11 | "src": "icons/72.png", 12 | "sizes": "72x72", 13 | "type": "image/png", 14 | "purpose": "maskable any" 15 | }, 16 | { 17 | "src": "icons/96.png", 18 | "sizes": "96x96", 19 | "type": "image/png", 20 | "purpose": "maskable any" 21 | }, 22 | { 23 | "src": "icons/128.png", 24 | "sizes": "128x128", 25 | "type": "image/png", 26 | "purpose": "maskable any" 27 | }, 28 | { 29 | "src": "icons/144.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "purpose": "maskable any" 33 | }, 34 | { 35 | "src": "icons/152.png", 36 | "sizes": "152x152", 37 | "type": "image/png", 38 | "purpose": "maskable any" 39 | }, 40 | { 41 | "src": "icons/180.png", 42 | "sizes": "180x180", 43 | "type": "image/png", 44 | "purpose": "maskable any" 45 | }, 46 | { 47 | "src": "icons/192.png", 48 | "sizes": "192x192", 49 | "type": "image/png", 50 | "purpose": "maskable any" 51 | }, 52 | { 53 | "src": "icons/384.png", 54 | "sizes": "384x384", 55 | "type": "image/png", 56 | "purpose": "maskable any" 57 | }, 58 | { 59 | "src": "icons/512.png", 60 | "sizes": "512x512", 61 | "type": "image/png", 62 | "purpose": "maskable any" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * In development mode, to ignore zone related error stack frames such as 11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can 12 | * import the following file, but please comment it out in production mode 13 | * because it will have performance impact when throw error 14 | */ 15 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 16 | -------------------------------------------------------------------------------- /src/global.scss: -------------------------------------------------------------------------------- 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 | @use '@ionic/angular/css/core.css'; 14 | 15 | /* Basic CSS for apps built with Ionic */ 16 | @use '@ionic/angular/css/normalize.css'; 17 | @use '@ionic/angular/css/structure.css'; 18 | @use '@ionic/angular/css/typography.css'; 19 | 20 | /* Optional CSS utils that can be commented out */ 21 | @use '@ionic/angular/css/padding.css'; 22 | @use '@ionic/angular/css/float-elements.css'; 23 | @use '@ionic/angular/css/text-alignment.css'; 24 | @use '@ionic/angular/css/text-transformation.css'; 25 | @use '@ionic/angular/css/flex-utils.css'; 26 | 27 | /* 28 | * App CSS 29 | * ---------------------------------------------------------------------------- 30 | * Imports a file that can contain Sass/CSS that should be used throughout 31 | * the entire app. 32 | */ 33 | 34 | @use './app/app.scss'; 35 | 36 | /** 37 | * Ionic Dark Mode 38 | * ----------------------------------------------------- 39 | * For more info, please see: 40 | * https://ionicframework.com/docs/theming/dark-mode 41 | */ 42 | 43 | // @use "@ionic/angular/css/palettes/dark.always.css"; 44 | // @use "@ionic/angular/css/palettes/dark.system.css"; 45 | @use '@ionic/angular/css/palettes/dark.class.css'; 46 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ionic Conference App 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 5 | 6 | module.exports = function (config) { 7 | config.set({ 8 | basePath: '', 9 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 10 | plugins: [ 11 | require('karma-jasmine'), 12 | require('karma-chrome-launcher'), 13 | require('karma-jasmine-html-reporter'), 14 | require('karma-coverage-istanbul-reporter'), 15 | require('@angular-devkit/build-angular/plugins/karma'), 16 | ], 17 | client: { 18 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 19 | }, 20 | coverageIstanbulReporter: { 21 | dir: require('path').join(__dirname, 'coverage'), 22 | reports: ['html', 'lcovonly'], 23 | fixWebpackSourcePaths: true, 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome', 'ChromeHeadless'], 31 | customLaunchers: { 32 | ChromeHeadlessCI: { 33 | base: 'ChromeHeadless', 34 | flags: ['--no-sandbox', '--disable-gpu'], 35 | }, 36 | }, 37 | singleRun: false, 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import '@angular/compiler'; 2 | 3 | import { enableProdMode, importProvidersFrom, isDevMode } from '@angular/core'; 4 | import { 5 | IonicRouteStrategy, 6 | provideIonicAngular, 7 | } from '@ionic/angular/standalone'; 8 | 9 | import { provideHttpClient } from '@angular/common/http'; 10 | import { bootstrapApplication } from '@angular/platform-browser'; 11 | import { 12 | PreloadAllModules, 13 | provideRouter, 14 | RouteReuseStrategy, 15 | withComponentInputBinding, 16 | withPreloading, 17 | } from '@angular/router'; 18 | import { 19 | provideServiceWorker, 20 | ServiceWorkerModule, 21 | } from '@angular/service-worker'; 22 | import { IonicStorageModule } from '@ionic/storage-angular'; 23 | import { AppComponent } from './app/app.component'; 24 | import { routes } from './app/app.routes'; 25 | import { environment } from './environments/environment'; 26 | 27 | if (environment.production) { 28 | enableProdMode(); 29 | } 30 | 31 | bootstrapApplication(AppComponent, { 32 | providers: [ 33 | { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, 34 | provideIonicAngular(), 35 | provideRouter( 36 | routes, 37 | withPreloading(PreloadAllModules), 38 | withComponentInputBinding() 39 | ), 40 | provideHttpClient(), 41 | importProvidersFrom( 42 | IonicStorageModule.forRoot(), 43 | ServiceWorkerModule.register('ngsw-worker.js', { 44 | enabled: environment.production, 45 | }) 46 | ), 47 | provideServiceWorker('ngsw-worker.js', { 48 | enabled: !isDevMode(), 49 | registrationStrategy: 'registerWhenStable:30000', 50 | }), 51 | ], 52 | }).catch(err => console.error(err)); 53 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 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 | // BROWSER POLYFILLS 18 | // --------------------------------------------------------------------------------- 19 | 20 | // IE9, IE10 and IE11 requires all of the following polyfills. 21 | // import 'core-js/es6/symbol'; 22 | // import 'core-js/es6/object'; 23 | // import 'core-js/es6/function'; 24 | // import 'core-js/es6/parse-int'; 25 | // import 'core-js/es6/parse-float'; 26 | // import 'core-js/es6/number'; 27 | // import 'core-js/es6/math'; 28 | // import 'core-js/es6/string'; 29 | // import 'core-js/es6/date'; 30 | // import 'core-js/es6/array'; 31 | // import 'core-js/es6/regexp'; 32 | // import 'core-js/es6/map'; 33 | // import 'core-js/es6/weak-map'; 34 | // import 'core-js/es6/set'; 35 | 36 | /** IE10 and IE11 requires the following for the Reflect API. */ 37 | // import 'core-js/es6/reflect'; 38 | 39 | // Evergreen browsers require these. 40 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 41 | 42 | // Required to support Web Animations `@angular/platform-browser/animations`. 43 | 44 | // Zone JS is required by Angular itself. 45 | import 'zone.js'; // Included with Angular CLI. 46 | 47 | // APPLICATION IMPORTS 48 | // ------------------------------------------------------------------------ 49 | 50 | /** 51 | * Date, currency, decimal and percent pipes. 52 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 53 | */ 54 | // import 'intl'; // Run `npm install --save intl`. 55 | /** 56 | * Need to import at least one locale-data with intl. 57 | */ 58 | // import 'intl/locale-data/jsonp/en'; 59 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import { getTestBed } from '@angular/core/testing'; 4 | import { 5 | BrowserDynamicTestingModule, 6 | platformBrowserDynamicTesting, 7 | } from '@angular/platform-browser-dynamic/testing'; 8 | import 'zone.js/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting(), 14 | { 15 | teardown: { destroyAfterEach: false }, 16 | } 17 | ); 18 | -------------------------------------------------------------------------------- /src/zone-flags.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Prevents Angular change detection from 3 | * running with certain Web Component callbacks 4 | */ 5 | (window as any).__Zone_disable_customElements = true; 6 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "importHelpers": true, 4 | "module": "es2020", 5 | "esModuleInterop": true, 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": false, 8 | "declaration": false, 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "ES2022", 13 | "skipLibCheck": true, 14 | "lib": ["es2017", "dom"], 15 | "useDefineForClassFields": false 16 | }, 17 | "angularCompilerOptions": { 18 | "enableI18nLegacyMessageIdFormat": false, 19 | "strictInjectionParameters": true, 20 | "strictInputAccessModifiers": true, 21 | "strictTemplates": true 22 | }, 23 | "include": ["src", "node_modules/cypress"], 24 | "exclude": ["node_modules/cypress"] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": ["jasmine", "cypress"] 6 | }, 7 | "files": ["src/test.ts", "src/zone-flags.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"], 9 | "exclude": ["**/node_modules"] 10 | } 11 | --------------------------------------------------------------------------------