Merge branch 'db-24-fix-menu' into 'main'

Db 24 fix menu

See merge request walljm/dynamicbible!19
This commit is contained in:
Jason Wall 2024-02-28 00:53:24 +00:00
commit d714d4ceee
68 changed files with 41824 additions and 12932 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ DynamicBibleUtility/packages/Shaman.ValueString.1.0.2.19/.signature.p7s
DynamicBibleUtility/packages/
DynamicBibleUtility/.vs/
utils/DynamicBibleUtility/packages/
src/.angular/cache/

View File

@ -6,7 +6,7 @@ stages:
build-site:
stage: build
image: node:14.5.0
image: node:18.14.1
variables:
NODE_OPTIONS: "--max_old_space_size=2048"
script:
@ -18,10 +18,8 @@ build-site:
build-android:
stage: build
image: gradle:6.7.1-jdk8
image: walljm/gradle_android_node:7.5.0-jdk11-28-18
before_script:
- curl -sL https://deb.nodesource.com/setup_14.x | bash -
- apt-get install -y nodejs
- cd ./src/android
- bash ./install-sdk.sh
- cd ..
@ -40,7 +38,7 @@ build-android:
test:
stage: test
image: walljm/node-chrome-headless:14.8.0
image: walljm/node-chrome-headless:18.14.1
variables:
NODE_OPTIONS: "--max_old_space_size=2048"
script:
@ -74,10 +72,8 @@ deploy-prod-site:
deploy-android:
stage: prod
image: gradle:6.7.1-jdk8
image: walljm/gradle_android_node:7.5.0-jdk11-28-18
before_script:
- curl -sL https://deb.nodesource.com/setup_14.x | bash -
- apt-get install -y nodejs
- cd ./src/android
- bash ./install-sdk.sh
- cd ..

View File

@ -1,4 +1,4 @@
FROM node:14.8.0-buster-slim
FROM node:18.14.1-buster-slim
RUN apt-get update -qqy \
&& apt-get -qqy install \

View File

@ -0,0 +1,2 @@
docker build -t walljm/node-chrome-headless:18.14.1 .
docker push walljm/node-chrome-headless:18.14.1

View File

@ -0,0 +1,43 @@
FROM gradle:7.5.0-jdk11
# install node 18
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
RUN apt-get install -y nodejs
# Install Git and dependencies
RUN apt-get update \
&& apt-get install -y file git curl zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists /var/cache/apt
# Set up environment variables
ENV ANDROID_SDK_ROOT="/home/user/android-sdk-linux" \
SDK_URL="https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip" \
GRADLE_URL="https://services.gradle.org/distributions/gradle-7.5.1-bin.zip" \
ANDROID_VERSION=28 \
ANDROID_BUILD_TOOLS_VERSION=33.0.1
# Create a non-root user
RUN useradd -m user
USER user
WORKDIR /home/user
# Download Android SDK
RUN mkdir "$ANDROID_SDK_ROOT" .android \
&& cd "$ANDROID_SDK_ROOT" \
&& mkdir cmdline-tools \
&& cd cmdline-tools \
&& curl -o sdk.zip $SDK_URL \
&& unzip sdk.zip \
&& rm sdk.zip \
&& mv cmdline-tools latest \
&& cd .. \
&& yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses
# Install Android Build Tool and Libraries
RUN $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --update
RUN $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools"

View File

@ -0,0 +1,2 @@
docker build -t walljm/gradle_android_node:7.5.0-jdk11-28-18 .
docker push walljm/gradle_android_node:7.5.0-jdk11-28-18

52
src/.eslintrc.json Normal file
View File

@ -0,0 +1,52 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {
}
}
]
}

View File

@ -10,7 +10,7 @@ build-site:
npm run-script build
build-android:
npm run-script copy
npm run-script sync
cd android/
./gradlew assembleRelease
./gradlew bundleRelease

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
<bytecodeTargetLevel target="11" />
</component>
</project>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK" />
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK" />
</project>

View File

@ -8,7 +8,9 @@ def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion rootProject.ext.compileSdkVersion
namespace 'walljm.dynamicbible'
compileSdkVersion rootProject.ext.compileSdkVersion
def versionPropsFile = rootProject.file('version.properties')
@ -59,6 +61,8 @@ repositories {
}
dependencies {
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation project(':capacitor-android')
@ -74,7 +78,7 @@ dependencies {
implementation 'com.google.firebase:firebase-auth'
// Also declare the dependency for the Google Play services library and specify its version
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'com.google.android.gms:play-services-auth:20.4.1'
}
apply from: 'capacitor.build.gradle'

View File

@ -2,8 +2,8 @@
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="walljm.dynamicbible">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
@ -11,6 +10,7 @@
android:theme="@style/AppTheme">
<activity
android:exported="true"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name="walljm.dynamicbible.MainActivity"
android:label="@string/title_activity_main"

View File

@ -1,18 +1,21 @@
{
"appId": "walljm.dynamicbible",
"appName": "dynamicbible",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "dist/dynamicbible",
"plugins": {
"SplashScreen": {
"launchShowDuration": 0
},
"GoogleAuth": {
"scopes": ["profile", "email"],
"serverClientId": "200739882604-i4mk6rp4mcb8n590j5kc8i6bncpm5bo1.apps.googleusercontent.com",
"forceCodeForRefreshToken" : true
}
},
"cordova": {}
"appId": "walljm.dynamicbible",
"appName": "dynamicbible",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "dist/dynamicbible",
"plugins": {
"SplashScreen": {
"launchShowDuration": 0
},
"GoogleAuth": {
"scopes": [
"profile",
"email"
],
"serverClientId": "200739882604-i4mk6rp4mcb8n590j5kc8i6bncpm5bo1.apps.googleusercontent.com",
"forceCodeForRefreshToken": true
}
},
"cordova": {}
}

View File

@ -0,0 +1,6 @@
[
{
"pkg": "@codetrix-studio/capacitor-google-auth",
"classpath": "com.codetrixstudio.capacitor.GoogleAuth.GoogleAuth"
}
]

View File

@ -9,15 +9,4 @@ import java.util.ArrayList;
import com.codetrixstudio.capacitor.GoogleAuth.GoogleAuth;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
add(GoogleAuth.class);
}});
}
}

View File

@ -9,14 +9,14 @@
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:background">@null</item>
</style>
<style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
<item name="android:background">@drawable/splash</item>
</style>
</resources>

View File

@ -4,15 +4,15 @@ buildscript {
repositories {
google()
jcenter()
maven {
url "https://plugins.gradle.org/m2/"
mavenCentral()
}
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.google.gms:google-services:4.3.3'
classpath "com.github.triplet.gradle:play-publisher:3.1.0"
classpath 'com.android.tools.build:gradle:7.4.1'
classpath 'com.google.gms:google-services:4.3.15'
classpath "com.github.triplet.gradle:play-publisher:3.8.1"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@ -24,10 +24,11 @@ apply from: "variables.gradle"
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -1,24 +1,25 @@
ext {
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '7.0.0'
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.1'
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '10.1.1'
}
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.android.tools.build:gradle:7.2.1'
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29
compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32
defaultConfig {
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21
targetSdkVersion targetSdkVersion = project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32
versionCode 1
versionName "1.0"
}
@ -26,14 +27,13 @@ android {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
repositories {
google()
jcenter()
mavenCentral()
flatDir{
dirs 'src/main/libs', 'libs'
@ -42,6 +42,7 @@ repositories {
dependencies {
implementation fileTree(dir: 'src/main/libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
// SUB-PROJECT DEPENDENCIES START

View File

@ -1,6 +1,7 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
ext {
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21
cdvMinSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
// Plugin gradle extensions can append to this to have code run at the end.
cdvPluginPostBuildExtras = []
cordovaConfig = [:]
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,39 +1,14 @@
#!/usr/bin/env bash
SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip"
ANDROID_HOME="$(pwd)/android-sdk"
ANDROID_VERSION=28
ANDROID_BUILD_TOOLS_VERSION=27.0.3
# Download Android SDK
mkdir "$ANDROID_HOME" .android \
&& cd "$ANDROID_HOME" \
&& curl -o sdk.zip $SDK_URL \
&& unzip sdk.zip \
&& rm sdk.zip \
&& mkdir "$ANDROID_HOME/licenses" || true \
&& echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" > "$ANDROID_HOME/licenses/android-sdk-license" \
&& yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses
# Install Android Build Tool and Libraries
$ANDROID_HOME/tools/bin/sdkmanager --update
$ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
"platforms;android-${ANDROID_VERSION}" \
"platform-tools"
# to prevent annoying warnings...
touch /root/.android/repositories.cfg
# Install Build Essentials
echo sdk.dir=$ANDROID_HOME > ../local.properties
# Insall the signing keys
cd ..
# Install the signing keys
echo "Creating store key file and signing properties"
base64 -d $play_store_key > ./walljm-play-store-key.jks
cp $play_store_signing_properties ./signing.properties
cp $play_store_credential ./play-store.json
# Install Build Essentials
echo sdk.dir="/home/user/android-sdk-linux" > ./local.properties
# diagnostics, show me what you've got and where you're at
ls -laF
pwd

View File

@ -1,17 +1,22 @@
ext {
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
androidxAppCompatVersion = '1.1.0'
androidxCoreVersion = '1.2.0'
androidxMaterialVersion = '1.1.0-rc02'
androidxBrowserVersion = '1.2.0'
androidxLocalbroadcastmanagerVersion = '1.0.0'
androidxExifInterfaceVersion = '1.2.0'
firebaseMessagingVersion = '20.1.2'
playServicesLocationVersion = '17.0.0'
junitVersion = '4.12'
androidxJunitVersion = '1.1.1'
androidxEspressoCoreVersion = '3.2.0'
cordovaAndroidVersion = '7.0.0'
minSdkVersion = 22
compileSdkVersion = 32
targetSdkVersion = 32
androidxAppCompatVersion = '1.4.2'
androidxCoreVersion = '1.8.0'
androidxMaterialVersion = '1.6.1'
androidxBrowserVersion = '1.4.0'
androidxLocalbroadcastmanagerVersion = '1.0.0'
androidxExifInterfaceVersion = '1.3.3'
firebaseMessagingVersion = '23.0.5'
playServicesLocationVersion = '20.0.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.3'
androidxEspressoCoreVersion = '3.4.0'
cordovaAndroidVersion = '10.1.1'
androidxActivityVersion = '1.4.0'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxFragmentVersion = '1.4.1'
coreSplashScreenVersion = '1.0.0-rc01'
androidxWebkitVersion = '1.4.0'
}

View File

@ -22,10 +22,16 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [
"node_modules/marked/marked.min.js"
],
"allowedCommonJsDependencies": [
"firebase",
"@firebase/app",
@ -33,7 +39,13 @@
"@firebase/database",
"@firebase/util",
"@firebase/component"
]
],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
@ -46,7 +58,6 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
@ -64,7 +75,8 @@
}
]
}
}
},
"defaultConfiguration": ""
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
@ -90,20 +102,14 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
"assets": [
"src/favicon.ico",
"src/assets"
],
"exclude": ["**/node_modules/**"]
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"e2e": {
@ -121,9 +127,24 @@
"deploy": {
"builder": "@angular/fire:deploy",
"options": {}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"defaultProject": "dynamicbible"
"cli": {
"analytics": false,
"schematicCollections": [
"@angular-eslint/schematics",
"@angular-eslint/schematics"
]
}
}

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../tsconfig.base.json",
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",

53515
src/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,69 +4,76 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"build": "ng build --configuration production",
"test": "ng test",
"test-headless-watch": "ng test --watch=true --browsers=ChromeHeadlessNoSandbox ",
"test-headless": "ng test --watch=false --browsers=ChromeHeadlessNoSandbox ",
"lint": "ng lint",
"e2e": "ng e2e",
"copy": "npx cap sync",
"all": "ng lint & ng test --watch=false --browsers=ChromeHeadlessNoSandbox & ng build --prod & npx cap sync"
"all": "ng lint & ng test --watch=false --browsers=ChromeHeadlessNoSandbox & ng build --configuration production & npx cap sync"
},
"private": true,
"dependencies": {
"@angular/animations": "~10.0.4",
"@angular/cdk": "^10.0.2",
"@angular/common": "~10.0.4",
"@angular/compiler": "~10.0.4",
"@angular/core": "~10.0.4",
"@angular/fire": "^6.0.2",
"@angular/forms": "~10.0.4",
"@angular/material": "^10.0.2",
"@angular/platform-browser": "~10.0.4",
"@angular/platform-browser-dynamic": "~10.0.4",
"@angular/router": "~10.0.4",
"@capacitor/android": "^2.4.0",
"@capacitor/cli": "^2.4.0",
"@capacitor/core": "^2.4.0",
"@capacitor/ios": "^2.4.0",
"@codetrix-studio/capacitor-google-auth": "^2.1.3",
"@ngx-pwa/local-storage": "^10.0.1",
"@types/mathjs": "^6.0.5",
"@angular/animations": "^14.2.12",
"@angular/cdk": "^14.2.7",
"@angular/common": "^14.2.12",
"@angular/compiler": "^14.2.12",
"@angular/core": "^14.2.12",
"@angular/fire": "^7.4.1",
"@angular/forms": "^14.2.12",
"@angular/material": "^14.2.7",
"@angular/platform-browser": "^14.2.12",
"@angular/platform-browser-dynamic": "^14.2.12",
"@angular/router": "^14.2.12",
"@capacitor/android": "^4.6.3",
"@capacitor/core": "^4.6.3",
"@capacitor/ios": "^4.6.3",
"@codetrix-studio/capacitor-google-auth": "^3.2.2",
"@ngx-pwa/local-storage": "^13.0.6",
"angular2-uuid": "^1.1.1",
"component": "^1.1.0",
"firebase": "^7.13.1",
"ngx-md": "^8.1.6",
"redux": "^4.0.5",
"reselect": "^4.0.0",
"rxjs": "~6.5.5",
"tslib": "^2.0.0",
"zone.js": "~0.10.3"
"firebase": "^9.17.1",
"marked": "^4.2.12",
"ngx-markdown": "^14.0.1",
"redux": "^4.2.1",
"reselect": "^4.1.7",
"rxjs": "^6.6.0",
"tslib": "^2.5.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1000.3",
"@angular/cli": "~10.0.3",
"@angular/compiler-cli": "~10.0.4",
"@angular-devkit/architect": "0.1402.10",
"@angular-devkit/build-angular": "^14.2.10",
"@angular-eslint/builder": "14.4.0",
"@angular-eslint/eslint-plugin": "14.4.0",
"@angular-eslint/eslint-plugin-template": "14.4.0",
"@angular-eslint/schematics": "14.4.0",
"@angular-eslint/template-parser": "14.4.0",
"@angular/cli": "^14.2.10",
"@angular/compiler-cli": "^14.2.12",
"@capacitor/cli": "^4.6.3",
"@types/jasmine": "~4.3.1",
"@types/jasminewd2": "~2.0.10",
"@types/marked": "^4.0.8",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~3.3.0",
"karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~3.9.5",
"@angular-devkit/architect": ">= 0.900 < 0.1100",
"firebase-tools": "^8.0.0",
"@typescript-eslint/eslint-plugin": "5.43.0",
"@typescript-eslint/parser": "5.43.0",
"eslint": "^8.28.0",
"firebase-tools": "^11.23.1",
"fuzzy": "^0.1.3",
"inquirer": "^6.2.2",
"inquirer-autocomplete-prompt": "^1.0.1",
"open": "^7.0.3"
"jasmine-core": "~4.5.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.1",
"karma-chrome-launcher": "~3.1.1",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"open": "^8.4.2",
"protractor": "~7.0.0",
"ts-node": "~10.9.1",
"typescript": "~4.6.4"
}
}
}

View File

@ -1,8 +1,8 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SearchPage } from './pages/search/search.page';
import { SavedPagesAdminPage } from './pages/saved-pages-admin/saved-pages-admin.page';
import { NotesAdminPage } from './pages/notes-admin/notes-admin.page';
import { SearchPageComponent } from './pages/search/search.page';
import { SavedPagesAdminPageComponent } from './pages/saved-pages-admin/saved-pages-admin.page';
import { NotesAdminPageComponent } from './pages/notes-admin/notes-admin.page';
const routes: Routes = [
{
@ -13,32 +13,32 @@ const routes: Routes = [
{
path: 'search',
pathMatch: 'prefix',
component: SearchPage,
component: SearchPageComponent,
},
{
path: 'search/:term',
pathMatch: 'prefix',
component: SearchPage,
component: SearchPageComponent,
},
{
path: 'page/:id',
pathMatch: 'prefix',
component: SearchPage,
component: SearchPageComponent,
},
{
path: 'saved/admin',
pathMatch: 'prefix',
component: SavedPagesAdminPage,
component: SavedPagesAdminPageComponent,
},
{
path: 'notes/admin',
pathMatch: 'prefix',
component: NotesAdminPage,
component: NotesAdminPageComponent,
},
];
@NgModule({
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload', relativeLinkResolution: 'legacy' })],
exports: [RouterModule],
})
export class AppRoutingModule {}

View File

@ -16,7 +16,7 @@ import { MatDialog } from '@angular/material/dialog';
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent extends SubscriberBase implements AfterViewInit, OnDestroy {
export class AppComponent extends SubscriberBase implements AfterViewInit {
savedPages$ = this.appService.select((state) => (state.savedPages === null ? null : state.savedPages.value));
fontSize$ = this.appService.select((state) => state.settings.value.displaySettings.cardFontSize + 'pt');
cardFont$ = this.appService.select((state) => state.settings.value.displaySettings.cardFontFamily);
@ -95,16 +95,6 @@ export class AppComponent extends SubscriberBase implements AfterViewInit, OnDes
}
ngAfterViewInit(): void {
this.navService.afterViewInit(this.sidenav, this.settings, this.cd);
this.addSubscription(
this.navService.swipe.disableAnimation$.subscribe((v) => {
this.disableAnimation = v;
})
);
}
ngOnDestroy() {
this.navService.onDestroy();
this.navService.afterViewInit(this.sidenav, this.settings);
}
}

View File

@ -4,14 +4,13 @@ import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgxMdModule } from 'ngx-md';
import { MarkdownModule } from 'ngx-markdown';
import { AngularFireModule } from '@angular/fire';
import { AngularFireModule } from '@angular/fire/compat';
import { FirebaseConfig } from './constants';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireDatabaseModule } from '@angular/fire/database';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatButtonModule } from '@angular/material/button';
@ -37,21 +36,21 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatBadgeModule } from '@angular/material/badge';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatDividerModule } from '@angular/material/divider';
import {MatChipsModule} from '@angular/material/chips';
import { MatChipsModule } from '@angular/material/chips';
import { MatNativeDateModule, MatRippleModule } from '@angular/material/core';
import { ClipboardModule } from '@angular/cdk/clipboard';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NotesAdminPage } from './pages/notes-admin/notes-admin.page';
import { NotesAdminPageComponent } from './pages/notes-admin/notes-admin.page';
import { SavedPagesAdminPage } from './pages/saved-pages-admin/saved-pages-admin.page';
import { SavedPagesAdminPageComponent } from './pages/saved-pages-admin/saved-pages-admin.page';
import { SavedPageCardComponent } from './components/saved-page-card/saved-page-card.component';
import { HelpModalComponent } from './components/help-modal/help-modal.component';
import { SearchPage } from './pages/search/search.page';
import { SearchPageComponent } from './pages/search/search.page';
import { OkCancelModalComponent } from './components/ok-cancel-modal/ok-cancel-modal.component';
import { SettingsComponent } from './components/settings/settings.component';
@ -67,14 +66,35 @@ import { NoteEditModalComponent } from './components/note/edit-modal/note-edit-m
import { VersePickerModalComponent } from './components/verse-picker-modal/verse-picker-modal.component';
import { AddToPageModalComponent } from './components/add-to-page-modal/add-to-page-modal.component';
import { MarkedOptions, MarkedRenderer } from 'ngx-markdown';
// function that returns `MarkedOptions` with renderer override
export function markedOptionsFactory(): MarkedOptions {
const renderer = new MarkedRenderer();
renderer.heading = (text: string, level: number) => {
return `<h${level + 1}>${text}</h${level + 1}>\n`;
};
return {
renderer: renderer,
gfm: true,
breaks: false,
pedantic: false,
smartLists: true,
smartypants: false,
};
}
@NgModule({
declarations: [
AppComponent,
NotesAdminPage,
SavedPagesAdminPage,
NotesAdminPageComponent,
SavedPagesAdminPageComponent,
SavedPageCardComponent,
HelpModalComponent,
SearchPage,
SearchPageComponent,
PassageCardComponent,
StrongsComponent,
StrongsCardComponent,
@ -97,7 +117,12 @@ import { AddToPageModalComponent } from './components/add-to-page-modal/add-to-p
AppRoutingModule,
BrowserAnimationsModule,
NgxMdModule.forRoot(),
MarkdownModule.forRoot({
markedOptions: {
provide: MarkedOptions,
useFactory: markedOptionsFactory,
},
}),
AngularFireModule.initializeApp(FirebaseConfig),
AngularFireAuthModule,

View File

@ -95,7 +95,7 @@ type IfImmutable<TState extends {}, TImmutable = TState, TMutable = never> = IfE
TMutable
>;
// tslint:disable-next-line
// eslint-disable-next-line
type YourStateTypeNeedsToBeImmutable<TState> = {};
/**

View File

@ -1,7 +1,8 @@
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}

View File

@ -1,7 +1,7 @@
import { Component, Inject, ViewChild } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSelectionList } from '@angular/material/list';
import { FormBuilder, FormGroup } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { AppService } from '../../services/app.service';
import { CardItem } from '../../models/card-state';
@ -11,7 +11,7 @@ import { CardItem } from '../../models/card-state';
styleUrls: ['./add-to-page-modal.component.scss'],
})
export class AddToPageModalComponent {
form: FormGroup;
form: UntypedFormGroup;
title: string;
pages$ = this.appService.select((state) => (state.savedPages === null ? null : state.savedPages.value));
@ -22,7 +22,7 @@ export class AddToPageModalComponent {
@Inject(MAT_DIALOG_DATA) public card: CardItem,
public dialogRef: MatDialogRef<AddToPageModalComponent>,
private appService: AppService,
private fb: FormBuilder
private fb: UntypedFormBuilder
) {
this.form = this.fb.group({
title: this.title,

View File

@ -12,7 +12,7 @@ import { CardItem } from '../models/card-state';
})
export class CardComponent extends SubscriberBase {
@Output()
onClose = new EventEmitter<CardItem>();
closeCard = new EventEmitter<CardItem>();
@Input()
cardItem: CardItem;
@ -53,7 +53,7 @@ export class CardComponent extends SubscriberBase {
);
setTimeout(() => {
this.onClose.emit(this.cardItem);
this.closeCard.emit(this.cardItem);
}, d);
}

View File

@ -1,7 +1,8 @@
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}

View File

@ -1,5 +1,5 @@
import { Component, Inject } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { UntypedFormGroup, UntypedFormBuilder } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
@ -17,7 +17,7 @@ import { CardItem } from 'src/app/models/card-state';
styleUrls: ['./note-edit-modal.component.scss'],
})
export class NoteEditModalComponent {
noteForm: FormGroup;
noteForm: UntypedFormGroup;
data: NoteItem;
isNew = false;
@ -34,7 +34,7 @@ export class NoteEditModalComponent {
@Inject(MAT_DIALOG_DATA) public cardItem: CardItem,
public dialogRef: MatDialogRef<NoteEditModalComponent>,
private appService: AppService,
private fb: FormBuilder
private fb: UntypedFormBuilder
) {
if (cardItem) {
this.data = cardItem.data as NoteItem;

View File

@ -16,7 +16,7 @@
>
</div>
<div class="card-content" *ngIf="cardItem" #note>
<ngx-md class="markdown" *ngIf="this.data">{{ this.data.content }}</ngx-md>
<markdown class="markdown" *ngIf="this.data">{{ this.data.content }}</markdown>
<p class="center grey" *ngIf="cardItem && this.data.xref !== ''">&#10018;</p>
<mat-expansion-panel *ngIf="cardItem && this.data.xref !== ''">
<mat-expansion-panel-header>

View File

@ -1,6 +1,5 @@
import { Component, ViewChild, ElementRef, Input, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { NgxMdService } from 'ngx-md';
import { NoteEditModalComponent } from './edit-modal/note-edit-modal.component';
import { CardComponent } from '../../components/card.component';
import { AppService } from '../../services/app.service';
@ -13,7 +12,7 @@ import { OkCancelModalComponent, OkCancelResult } from '../ok-cancel-modal/ok-ca
templateUrl: './note-card.component.html',
styleUrls: ['./note-card.component.scss'],
})
export class NoteCardComponent extends CardComponent implements OnInit {
export class NoteCardComponent extends CardComponent {
@ViewChild('note') noteElement: ElementRef;
@Input()
@ -26,20 +25,13 @@ export class NoteCardComponent extends CardComponent implements OnInit {
constructor(
protected elementRef: ElementRef,
protected appService: AppService,
public dialog: MatDialog,
private markdown: NgxMdService
public dialog: MatDialog
) {
super(elementRef, dialog, appService);
this.icon$ = appService.select((state) => state.settings.value.cardIcons.note);
}
ngOnInit(): void {
this.markdown.renderer.heading = (text: string, level: number) => {
return `<h${level + 1}>${text}</h${level + 1}>\n`;
};
}
copy() {
const html = this.noteElement.nativeElement.innerHTML;
const text = this.noteElement.nativeElement.innerText;

View File

@ -1,7 +1,8 @@
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}

View File

@ -1,7 +1,8 @@
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}

View File

@ -1,5 +1,5 @@
import { Component, Inject } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { UntypedFormGroup, UntypedFormBuilder } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { AppService } from '../../services/app.service';
import { SavedPage } from 'src/app/models/page-state';
@ -10,14 +10,14 @@ import { SavedPage } from 'src/app/models/page-state';
styleUrls: ['./page-edit-modal.component.scss'],
})
export class PageEditModalComponent {
form: FormGroup;
form: UntypedFormGroup;
dialogTitle = 'Save Page using Current Cards';
constructor(
@Inject(MAT_DIALOG_DATA) public title: PageEditModalData,
public dialogRef: MatDialogRef<PageEditModalComponent>,
private appService: AppService,
private fb: FormBuilder
private fb: UntypedFormBuilder
) {
if (title) {
this.dialogTitle = 'Edit Page Name';

View File

@ -40,10 +40,10 @@
<ng-container *ngFor="let w of vs.w">
<a
[title]="getDict(this.cardItem) + w.s"
*ngIf="w.s != null"
*ngIf="w.s !== null"
(click)="openStrongs(w.s, display.showStrongsAsModal)"
>{{ w.t }}</a
><ng-container *ngIf="w.s == null">{{
><ng-container *ngIf="w.s === null">{{
w.t
}}</ng-container> </ng-container
><br *ngIf="display.showVersesOnNewLine" />

View File

@ -19,7 +19,7 @@ import { NoteItem } from 'src/app/models/note-state';
styleUrls: ['./saved-page-card.component.scss'],
preserveWhitespaces: true,
})
export class SavedPageCardComponent extends SubscriberBase implements OnInit {
export class SavedPageCardComponent extends SubscriberBase {
icon$: Observable<string>;
cache: HashTable<CardItem>;
cardIcons: CardIcons;
@ -137,8 +137,4 @@ export class SavedPageCardComponent extends SubscriberBase implements OnInit {
moveSavedPageCard(event: CdkDragDrop<string[]>) {
this.appService.moveSavedPageCard(this.savedPage, event.previousIndex, event.currentIndex);
}
ngOnInit(): void {
// console.log(this.savedPage);
}
}

View File

@ -5,10 +5,10 @@ import { MatSliderChange } from '@angular/material/slider';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatDialog } from '@angular/material/dialog';
import { AngularFireAuth } from '@angular/fire/auth';
import { auth } from 'firebase/app';
import { Capacitor, Plugins } from '@capacitor/core';
import '@codetrix-studio/capacitor-google-auth';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import firebase from '@firebase/app-compat';
import { Capacitor } from '@capacitor/core';
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth'
import { SubscriberBase } from '../../common/subscriber-base';
import { DisplaySettings } from 'src/app/models/app-state';
@ -48,7 +48,7 @@ export class SettingsComponent extends SubscriberBase {
) {
super();
this.fonts = CardFonts;
// tslint:disable-next-line: forin
// eslint-disable-next-line guard-for-in
for (const enumIdx in Overlap) {
this.cardMergeStrategies.push(Overlap[enumIdx]);
}
@ -76,20 +76,22 @@ export class SettingsComponent extends SubscriberBase {
}
async login() {
if (Capacitor.isNative) {
const googleUser = await Plugins.GoogleAuth.signIn();
const credential = auth.GoogleAuthProvider.credential(googleUser.authentication.idToken);
this.authService.signInAndRetrieveDataWithCredential(credential);
if (Capacitor.isNativePlatform()) {
GoogleAuth.initialize();
const googleUser = await GoogleAuth.signIn();
const credential = firebase.auth.GoogleAuthProvider.credential(googleUser.authentication.idToken);
(await this.authService.app).auth().signInWithCredential(credential);
} else {
this.authService.signInWithPopup(new auth.GoogleAuthProvider()).then((cred) => {
this.authService.signInWithPopup(new firebase.auth.GoogleAuthProvider()).then((cred) => {
console.log('Authenticated.');
});
}
}
async logout() {
if (Capacitor.isNative) {
await Plugins.GoogleAuth.signOut();
if (Capacitor.isNativePlatform()) {
await GoogleAuth.signOut();
}
await this.authService.signOut();
this.appService.setUser(null); // clear the user.

View File

@ -16,8 +16,8 @@
<app-strongs
[data]="cardItem.data"
[isCard]="true"
(onOpenPassage)="openPassage($event)"
(onOpenStrongs)="openStrongs($event)"
(openPassage)="triggerOpenPassage($event)"
(openStrongs)="triggerOpenStrongs($event)"
></app-strongs>
</div>
<div class="card-actions">

View File

@ -12,7 +12,7 @@ import { BibleReference } from 'src/app/common/bible-reference';
preserveWhitespaces: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StrongsCardComponent extends CardComponent implements OnInit {
export class StrongsCardComponent extends CardComponent {
asModal = false;
@ViewChild('strongs') strongsElement: ElementRef;
@ -25,9 +25,6 @@ export class StrongsCardComponent extends CardComponent implements OnInit {
})
);
}
ngOnInit(): void {
// console.log(this.cardItem);
}
copy() {
const html = this.strongsElement.nativeElement.innerHTML;

View File

@ -19,6 +19,6 @@
<br />
<app-strongs
[data]="cardItem.data"
(onOpenPassage)="openPassage($event)"
(openPassage)="openPassage($event)"
></app-strongs>
</mat-dialog-content>

View File

@ -1,7 +1,8 @@
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}
@ -22,4 +23,3 @@ mat-toolbar {
padding: 0px 16px 0px 16px;
width: auto;
}

View File

@ -16,19 +16,19 @@ export class StrongsComponent {
isCard = false;
@Output()
onOpenPassage = new EventEmitter<string>();
openPassage = new EventEmitter<string>();
@Output()
onOpenStrongs = new EventEmitter<string>();
openStrongs = new EventEmitter<string>();
constructor() {}
openPassage(p: string) {
this.onOpenPassage.emit(p);
triggerOpenPassage(p: string) {
this.openPassage.emit(p);
}
openStrongs(q: string) {
this.onOpenStrongs.emit(q);
triggerOpenStrongs(q: string) {
this.openStrongs.emit(q);
}
makePassage(p: string) {

View File

@ -55,8 +55,9 @@ h2 {
.close-button {
float: right;
mat-icon {
font-size: 2rem;
transform: scale(1.5);
}
}

View File

@ -11,7 +11,7 @@ import { MatDialog } from '@angular/material/dialog';
templateUrl: './notes-admin.page.html',
styleUrls: ['./notes-admin.page.scss'],
})
export class NotesAdminPage extends SubscriberBase implements OnInit {
export class NotesAdminPageComponent extends SubscriberBase implements OnInit {
notes$ = this.appService.select((state) =>
state.notes === null
? null

View File

@ -8,7 +8,7 @@ import { SubscriberBase } from '../../common/subscriber-base';
templateUrl: './saved-pages-admin.page.html',
styleUrls: ['./saved-pages-admin.page.scss'],
})
export class SavedPagesAdminPage extends SubscriberBase implements OnInit {
export class SavedPagesAdminPageComponent extends SubscriberBase implements OnInit {
savedPages$ = this.appService.select((state) => (state.savedPages === null ? null : state.savedPages.value));
constructor(public navService: NavService, private appService: AppService) {

View File

@ -8,7 +8,7 @@ mat-card {
width: 100%;
position: relative;
margin-left: 6px;
margin-right: 6px;
margin-right: 60px;
}
.search-bar-input {

View File

@ -1,6 +1,6 @@
import { Component, OnInit, ViewChild, ChangeDetectionStrategy } from '@angular/core';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { FormControl } from '@angular/forms';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
import { AppService } from '../../services/app.service';
@ -16,14 +16,14 @@ import { getFromCardCache } from 'src/app/common/card-cache-operations';
styleUrls: ['./search.page.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SearchPage extends SubscriberBase implements OnInit {
export class SearchPageComponent extends SubscriberBase implements OnInit {
cards$ = this.appService.select((state) => state.currentCards.value.map((o) => getFromCardCache(o, state.cardCache)));
suggestions$ = this.appService.select((state) => state.autocomplete);
savedPagedLoaded = false;
clearSearchAfterQuery = true;
searchControl = new FormControl();
searchControl = new UntypedFormControl();
@ViewChild(MatAutocomplete)
autoComplete: MatAutocomplete;

View File

@ -4,7 +4,7 @@ import { User, Settings, DisplaySettings, PageSettings } from '../models/app-sta
import { Section, BibleReference, Overlap } from '../common/bible-reference';
import { createStateService } from '../common/state-service';
import { StorageMap } from '@ngx-pwa/local-storage';
import { AngularFireDatabase } from '@angular/fire/database';
import { AngularFireDatabase } from '@angular/fire/compat/database';
import { IStorable, Storable } from '../common/storable';
import { NoteItem } from '../models/note-state';
import {
@ -999,7 +999,7 @@ export class AppService extends createStateService(reducer, initialState) {
// FindSharedSet takes an array of reference arrays, and figures out
// which references are shared by all arrays/sets, then returns a single
// array of references.
// tslint:disable-next-line: prefer-for-of
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let j = 0; j < referenceSet.length; j++) {
const refs = referenceSet[j];
results[j] = []; // initialize inner array

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireObject } from '@angular/fire/database';
import { DataSnapshot } from '@angular/fire/database/interfaces';
import { AngularFireDatabase, AngularFireObject } from '@angular/fire/compat/database';
import { DataSnapshot } from '@angular/fire/compat/database/interfaces';
import { UUID } from 'angular2-uuid';
import { AppService } from './app.service';
import { Overlap } from '../common/bible-reference';
@ -9,7 +9,6 @@ import { SavedPage } from '../models/page-state';
import { CardType, DataReference } from '../models/card-state';
import { StorageService } from './storage.service';
import { Storable, StorableType } from '../common/storable';
import { NoteItem } from '../models/note-state';
@Injectable({
providedIn: 'root',

View File

@ -1,351 +1,16 @@
import { ChangeDetectorRef, Injectable } from '@angular/core';
import {Injectable } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { BehaviorSubject } from 'rxjs';
export class Swipe {
public disableAnimation$ = new BehaviorSubject<boolean>(false);
private backdropEl: HTMLElement;
private leftDrawerEl: HTMLElement;
private rightDrawerEl: HTMLElement;
private touchStartHandler = this.bodyTouchStart.bind(this);
private touchMoveHandler = this.bodyTouchMove.bind(this);
private touchEndHandler = this.bodyTouchEnd.bind(this);
private transitionEndHandler = this.resetDrawer.bind(this);
private isIosDevice =
typeof window !== 'undefined' &&
window.navigator &&
window.navigator.platform &&
(/iP(ad|hone|od)/.test(window.navigator.platform) ||
(window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1));
private readonly swipeInfo: SwipeInfo = {
x1: 0,
y1: 0,
x2: 0,
y2: 0,
scrolling: null,
manual: false,
side: null,
};
constructor(private leftDrawer: MatSidenav, private rightDrawer: MatSidenav, private cd: ChangeDetectorRef) {}
afterViewInit(leftDrawerId: string, rightDrawerId: string) {
this.backdropEl = document.querySelector('.mat-drawer-backdrop');
this.leftDrawerEl = document.getElementById(leftDrawerId);
this.rightDrawerEl = document.getElementById(rightDrawerId);
window.document.body.addEventListener('touchstart', this.touchStartHandler);
window.document.body.addEventListener('touchmove', this.touchMoveHandler, { passive: !this.isIosDevice });
window.document.body.addEventListener('touchend', this.touchEndHandler);
}
onDestroy() {
window.document.body.removeEventListener('touchstart', this.touchStartHandler);
window.document.body.removeEventListener('touchmove', this.touchMoveHandler);
window.document.body.removeEventListener('touchend', this.touchEndHandler);
this.leftDrawerEl.removeEventListener('transitionend', this.transitionEndHandler);
this.rightDrawerEl.removeEventListener('transitionend', this.transitionEndHandler);
}
private bodyTouchStart(event: TouchEvent) {
const t = event.touches[0];
console.log(this.swipeInfo);
this.swipeInfo.x1 = t.pageX;
this.swipeInfo.y1 = t.pageY;
this.swipeInfo.x2 = 0;
this.swipeInfo.y2 = 0;
this.swipeInfo.scrolling = null;
this.swipeInfo.manual = false;
this.swipeInfo.side = null;
}
/**
* Handles touch move events to detect if the user is attempting to scroll or swipe.
* If the user moves the touch more than 5 px vertically then we assume the user is scrolling.
* If the user moves the touch more than 10 px horizontally then we assume the user is swiping and disable scrolling.
* Touch end cleans up the scroll disabling.
*/
private bodyTouchMove(event: TouchEvent) {
if (this.isScrolling(event)) {
// if we're scrolling then ignore these events
return;
}
let offset = this.swipeInfo.x2 - this.swipeInfo.x1;
const side = this.determineSide(offset);
// if the user swipes one direction then the other without removing the touch,
// we should ignore it... i think...
if (
this.swipeInfo.side !== null &&
this.swipeInfo.side.direction !== null &&
this.swipeInfo.side.direction !== side.direction
) {
return;
}
this.swipeInfo.side = side;
// the user is swiping
// ignore swiping if the menu is not over
if (side.drawer.mode !== 'over') {
return;
}
// swipe left is -px, right is +px
let translate = 0;
if (side.drawer.opened) {
// if nav is open then offset should be negative
if (this.isOpening(offset)) {
return;
}
translate = offset;
} else {
// if nav is closed then offset should be positive
if (!this.isOpening(offset)) {
return;
}
// make sure the offset is not greater than sidenav width
// to prevent the sidenav from floating off the left side
if (side.direction === 'left') {
offset = offset > side.drawer._width ? side.drawer._width : offset;
translate = -side.drawer._width + offset;
} else {
offset = Math.abs(offset) > side.drawer._width ? -side.drawer._width : offset;
translate = side.drawer._width - Math.abs(offset);
}
side.el.style.boxShadow = null;
}
side.el.style.visibility = 'visible';
// update translate3d of sidenav by offset so the drawer moves
side.el.style.transform = `translate3d(${translate}px, 0, 0)`;
// update the opacity of the background so it fades in/out while the drawer moves
this.backdropEl.style.visibility = 'visible';
this.backdropEl.style.backgroundColor = `rgba(0,0,0,${
(0.6 * Math.abs((side.direction === 'left' ? offset : -offset) + (side.drawer.opened ? side.drawer._width : 0))) /
side.drawer._width
})`;
// disable backdrop transition while we're dragging to prevent lag
this.backdropEl.style.transitionDuration = '0ms';
}
private bodyTouchEnd(event: TouchEvent) {
const t = event.changedTouches[0];
this.swipeInfo.x2 = t.pageX;
this.swipeInfo.y2 = t.pageY;
const offset = this.swipeInfo.x2 - this.swipeInfo.x1;
// decide if we need to hide or show the sidenav
if (this.swipeInfo.scrolling === false) {
// enable scrolling again
window.document.body.classList.remove('lock-scroll');
// restore backdrop transition
this.backdropEl.style.transitionDuration = null;
// if the menu is not over then ignore
if (this.swipeInfo.side.drawer.mode !== 'over') {
return;
}
// if you're swiping open and the drawer is already open.
if (this.isOpening(offset) && this.swipeInfo.side.drawer.opened) {
console.log('ignoring end event (already open)');
return;
}
// if you're swiping closed and the drawer is not open
if (!this.isOpening(offset) && !this.swipeInfo.side.drawer.opened) {
console.log('resetting to closed (already closed)');
this.swipeInfo.side.el.style.transform = null;
this.swipeInfo.side.el.style.boxShadow = 'none';
this.backdropEl.style.visibility = null;
this.backdropEl.style.backgroundColor = null;
return;
}
// if the change is less than the min, just ignore it.
// this block puts everything back the way it was.
console.log(`Offset: ${Math.abs(offset)}, Tolerance: ${this.swipeInfo.side.drawer._width * 0.08}`);
if (Math.abs(offset) < this.swipeInfo.side.drawer._width * 0.08) {
this.backdropEl.style.visibility = null;
if (this.swipeInfo.side.drawer.opened) {
// reset to open position
console.log('resetting to open (no tolerance)');
this.swipeInfo.side.el.style.transform = 'none';
this.backdropEl.style.backgroundColor = 'rgba(0,0,0,0.6)';
} else {
// reset to closed position
console.log('resetting to closed (no tolerance)');
this.swipeInfo.side.el.style.transform = null;
this.swipeInfo.side.el.style.boxShadow = 'none';
this.backdropEl.style.backgroundColor = null;
}
return;
}
// manually close/open the drawer using css and then update the state of the sidenav
// if we close/open the sidenav directly it restarts the animation at fully opened/closed causing jank
// so we have to fake the animation and then update the sidenav so the state matches
this.swipeInfo.manual = true;
this.disableAnimation$.next(true);
this.cd.markForCheck();
// wait for the end of the transition so we can reset anything we hacked to make this work
this.swipeInfo.side.el.addEventListener('transitionend', this.transitionEndHandler);
// wait one frame for the handler to be established before setting the transition
requestAnimationFrame(() => {
this.swipeInfo.side.el.style.transition = '400ms cubic-bezier(0.25, 0.8, 0.25, 1)';
this.cd.markForCheck();
if (this.swipeInfo.side.drawer.opened) {
console.log('manually transitioning (closed)');
// update translate3d of sidenav so that it animates closed
if (this.swipeInfo.side.direction === 'left') {
this.swipeInfo.side.el.style.transform = 'translate3d(-100%, 0, 0)';
} else {
this.swipeInfo.side.el.style.transform = 'translate3d(100%, 0, 0)';
}
} else {
console.log('manually transitioning (open)');
// update the transform on the sidenav so that it animates open
this.swipeInfo.side.el.style.transform = 'none';
// reset background opacity
this.backdropEl.style.backgroundColor = 'rgba(0,0,0,0.6)';
}
});
}
}
private resetDrawer() {
this.swipeInfo.side.el.removeEventListener('transitionend', this.transitionEndHandler);
this.swipeInfo.side.el.style.transition = null;
this.backdropEl.style.visibility = null;
this.backdropEl.style.backgroundColor = null;
if (this.swipeInfo.side.drawer.opened) {
console.log('manually transitioning (final closed)');
// make the backdrop hide as if the sidenav is closed
this.backdropEl.classList.remove('mat-drawer-shown');
this.swipeInfo.side.el.style.transform = 'none';
this.swipeInfo.side.drawer.toggle(false);
} else {
console.log('manually transitioning (final open)');
// make the backdrop show as if the sidenav is open
this.backdropEl.classList.add('mat-drawer-shown');
this.swipeInfo.side.drawer.toggle(true);
}
this.cd.markForCheck();
requestAnimationFrame(() => {
this.swipeInfo.manual = false;
this.disableAnimation$.next(false);
this.cd.markForCheck();
});
}
private isOpening(offset: number) {
if (this.swipeInfo.side.direction === 'right') {
return offset < 0; // its on the right not the left, so its inverted.
} else {
return offset > 0;
}
}
private isScrolling(event: TouchEvent) {
if (this.swipeInfo.scrolling) {
// if we're scrolling then ignore these events
return true;
}
const t = event.touches[0];
this.swipeInfo.x2 = t.pageX;
this.swipeInfo.y2 = t.pageY;
// check if we have decided if the user is scrolling or not
if (this.swipeInfo.scrolling === null) {
if (Math.abs(this.swipeInfo.y2 - this.swipeInfo.y1) > 5) {
// if the user has moved more than 5 pixels y then they're scrolling
this.swipeInfo.scrolling = true;
return true;
}
// if the user has moved more than 5 pixels x then they're swiping
this.swipeInfo.scrolling = false;
// disable scrolling
window.document.body.classList.add('lock-scroll');
if (this.isIosDevice) {
// css overflow:hidden doesn't work on the body for iOS so we have to use a
// non-passive listener and preventdefault to prevent scrolling
event.preventDefault();
}
}
return false;
}
private determineSide(offset: number): Side {
if (this.leftDrawer.opened) {
return { drawer: this.leftDrawer, el: this.leftDrawerEl, direction: 'left' };
}
if (this.rightDrawer.opened) {
return { drawer: this.rightDrawer, el: this.rightDrawerEl, direction: 'right' };
}
// both are closed, so you must be opening.
// return the one from the side you start swiping on.
if (offset < 0) {
// negative indicates swiping left
return { drawer: this.rightDrawer, el: this.rightDrawerEl, direction: 'right' }; // swiping left means starting right, so return the right drawer.
}
return { drawer: this.leftDrawer, el: this.leftDrawerEl, direction: 'left' };
}
}
interface Side {
drawer: MatSidenav;
el: HTMLElement;
direction: 'left' | 'right' | null;
}
export interface SwipeInfo {
x1: number;
y1: number;
x2: number;
y2: number;
scrolling: boolean | null;
manual: boolean;
side: Side;
}
@Injectable({
providedIn: 'root',
})
export class NavService {
public swipe: Swipe;
private sidenav: MatSidenav;
private settings: MatSidenav;
public afterViewInit(sidenav: MatSidenav, settings: MatSidenav, cd: ChangeDetectorRef) {
public afterViewInit(sidenav: MatSidenav, settings: MatSidenav) {
this.sidenav = sidenav;
this.settings = settings;
this.swipe = new Swipe(sidenav, settings, cd);
this.swipe.afterViewInit('drawer', 'settings');
}
public onDestroy() {
this.swipe.onDestroy();
}
public openNav() {

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { StorageMap } from '@ngx-pwa/local-storage';
import { AngularFireDatabase, AngularFireObject } from '@angular/fire/database';
import { DataSnapshot } from '@angular/fire/database/interfaces';
import { AngularFireDatabase, AngularFireObject } from '@angular/fire/compat/database';
import { DataSnapshot } from '@angular/fire/compat/database/interfaces';
import { SubscriberBase } from '../common/subscriber-base';
import { IStorable, StorableType, UserVersion } from '../common/storable';
@ -11,7 +11,6 @@ import { MigrationVersion0to1 } from './migration0to1.service';
import { User, Settings, AppState } from '../models/app-state';
import { NoteItem } from '../models/note-state';
import { SavedPage } from '../models/page-state';
import { Observable } from 'rxjs';
import { isNullOrUndefined } from '../common/helpers';
import { DataReference } from '../models/card-state';
import { createSelector } from 'reselect';
@ -209,7 +208,7 @@ export class StorageService extends SubscriberBase {
},
// error
() => {
// tslint:disable-next-line: quotemark
// eslint-disable-next-line @typescript-eslint/quotes
this.appService.dispatchError(`Something went wrong and the Settings weren't saved. :(`);
}
);
@ -236,7 +235,7 @@ export class StorageService extends SubscriberBase {
},
// error
() => {
// tslint:disable-next-line: quotemark
// eslint-disable-next-line @typescript-eslint/quotes
this.appService.dispatchError(`Something went wrong and the Page wasn't saved. :(`);
}
);
@ -263,7 +262,7 @@ export class StorageService extends SubscriberBase {
},
// error
() => {
// tslint:disable-next-line: quotemark
// eslint-disable-next-line @typescript-eslint/quotes
this.appService.dispatchError(`Something went wrong and the Note wasn't saved. :(`);
}
);
@ -295,7 +294,7 @@ export class StorageService extends SubscriberBase {
},
// error
() => {
// tslint:disable-next-line: quotemark
// eslint-disable-next-line @typescript-eslint/quotes
this.appService.dispatchError(`Something went wrong and the current cards weren't saved. :(`);
}
);

View File

@ -13,4 +13,4 @@ export const environment = {
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.

View File

@ -18,16 +18,6 @@
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
@ -55,7 +45,7 @@
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************

View File

@ -1,6 +1,7 @@
// Custom Theming for Angular Material
@use '@angular/material' as mat;
// For more information: https://material.angular.io/guide/theming
@import "~@angular/material/theming";
@import "@angular/material/theming";
// Plus imports for other components in your app.
@import "./styles/app.scss";
@ -9,20 +10,20 @@
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();
@include mat.core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$db-primary: mat-palette($mat-indigo);
$db-accent: mat-palette($mat-pink, A200, A100, A400);
$db-primary: mat.define-palette(mat.$indigo-palette);
$db-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
// The warn palette is optional (defaults to red).
$db-warn: mat-palette($mat-red);
$db-warn: mat.define-palette(mat.$red-palette);
// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$db-theme: mat-light-theme(
$db-theme: mat.define-light-theme(
(
color: (
primary: $db-primary,
@ -35,6 +36,6 @@ $db-theme: mat-light-theme(
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($db-theme);
@include mat.all-component-themes($db-theme);
/* You can add global styles to this file, and also import other style files */

View File

@ -50,8 +50,8 @@ body {
border-top-right-radius: var(--card-border-radius);
padding-right: 3.2rem;
> mat-icon {
font-size: 1.8rem;
mat-icon {
transform: scale(1.5);
}
span {
@ -73,24 +73,22 @@ body {
position: absolute !important;
right: 1.5rem;
top: 0.5rem;
mat-icon {
font-size: 2.3rem;
line-height: 2rem !important;
}
}
.card-actions {
clear: both;
width: 100%;
height: 3.5rem;
height: 3rem;
color: var(--card-color);
background-color: var(--card-actions-background-color);
border-bottom-left-radius: var(--card-border-radius);
border-bottom-right-radius: var(--card-border-radius);
padding-top: 10px;
mat-icon {
font-size: 1.7rem;
line-height: 2.4rem !important;
}
transform: scale(1.2);
}
}
.card-actions-right {

View File

@ -1,6 +1,6 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.base.json",
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []

View File

@ -1,18 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "ESNext",
"lib": ["es2018", "dom"]
}
}

View File

@ -1,17 +1,18 @@
/*
This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScripts language server to improve development experience.
It is not intended to be used to perform a compilation.
To learn more about this file see: https://angular.io/config/solution-tsconfig.
*/
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2020",
"module": "ESNext",
"lib": ["es2018", "dom"]
}
}

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.base.json",
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [

View File

@ -1,103 +0,0 @@
{
"extends": "tslint:recommended",
"rules": {
"align": {
"options": ["parameters", "statements"]
},
"array-type": false,
"arrow-return-shorthand": true,
"curly": true,
"deprecation": {
"severity": "warning"
},
"component-class-suffix": [true, "Page", "Component"],
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "kebab-case"],
"eofline": true,
"import-blacklist": [true, "rxjs/Rx"],
"import-spacing": true,
"indent": {
"options": ["spaces"]
},
"max-classes-per-file": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
"no-empty": false,
"no-inferrable-types": [true, "ignore-params"],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"quotemark": [true, "single"],
"semicolon": {
"options": ["always"]
},
"space-before-function-paren": {
"options": {
"anonymous": "never",
"asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
},
"typedef-whitespace": {
"options": [
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
},
"variable-name": {
"options": ["ban-keywords", "check-format", "allow-pascal-case"]
},
"whitespace": {
"options": [
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
},
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": false,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"object-literal-sort-keys": false
},
"rulesDirectory": ["codelyzer"]
}