Commit 85f80a85 authored by RAUSHAN RAJ's avatar RAUSHAN RAJ

resolved git conflicts

parent b567744b
TalkingReminder @ 167e7542
Subproject commit 167e7542698cedb645460263bd077d9cb54bc539
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.1" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.5.1" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/google-services/debug;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debug/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/google-services/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugAndroidTest/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugUnitTest/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test.ext:junit:1.1.1@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test.espresso:espresso-core:3.2.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test:runner:1.2.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test:core:1.2.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test:monitor:1.2.0@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.test.espresso:espresso-idling-resource:3.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: org.projectlombok:lombok:1.18.10@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout-solver:1.1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.8.6@jar" level="project" />
<orderEntry type="library" name="Gradle: org.jetbrains:annotations-java5:15.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.auto.value:auto-value-annotations:1.6.5@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.material:material:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.bignerdranch.android:recyclerview-multiselect:0.2@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-database:19.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.firebaseui:firebase-ui-auth:6.0.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-auth:19.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-analytics:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement-api:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement-sdk:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-auth-interop:18.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-iid:19.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-common:19.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-auth:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-auth-api-phone:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-auth-base:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-iid-interop:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base:17.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement-impl:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement-sdk-api:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-measurement-base:17.2.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-stats:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-measurement-connector:18.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-ads-identifier:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement:17.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.transition:transition:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.documentfile:documentfile:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.print:print:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout:1.1.3@aar" level="project" />
<orderEntry type="library" name="Gradle: com.amulyakhare:com.amulyakhare.textdrawable:1.0.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.google.firebase:firebase-database-collection:17.0.0@aar" level="project" />
</component>
</module>
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.sudogeeks.talking_reminder"
minSdkVersion 16
targetSdkVersion 29
versionCode 2
versionName "1.0.1"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.bignerdranch.android:recyclerview-multiselect:0.2'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.google.code.gson:gson:2.8.6'
// Lombok Dependencies
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
implementation 'org.jetbrains:annotations-java5:15.0'
// add the Firebase SDK Dependencies
implementation 'com.google.firebase:firebase-analytics:17.2.0'
implementation 'com.google.firebase:firebase-database:19.2.0'
implementation 'com.google.firebase:firebase-auth:19.1.0'
implementation 'com.firebaseui:firebase-ui-auth:6.0.2'
// implementation 'com.google.firebase:firebase-appindexing:19.0.0'
// implementation 'com.google.firebase:firebase-firestore:21.2.0'
// implementation 'com.google.gms:google-services:4.3.2'
// implementation 'com.google.firebase:firebase-storage:19.1.0'
}
apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
{
"project_info": {
"project_number": "101187773727",
"firebase_url": "https://talking-reminder-2.firebaseio.com",
"project_id": "talking-reminder-2",
"storage_bucket": "talking-reminder-2.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:101187773727:android:daff65310a8454ec4cbc2a",
"android_client_info": {
"package_name": "com.sudogeeks.talking_reminder"
}
},
"oauth_client": [
{
"client_id": "101187773727-343eutk6jp3258dj50dvdtl4j2lvs6ol.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyALcQqLVwx7CVr-uuj9p9_nFF3VPpPFWdc"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "101187773727-343eutk6jp3258dj50dvdtl4j2lvs6ol.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Program Files\Android SDK\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.sudogeeks.talking_reminder">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
tools:replace="android:icon,android:theme">
<activity android:name="com.sudogeeks.talking_reminder.ReadReminderTextService"></activity>
<activity android:name="com.sudogeeks.talking_reminder.ReminderReceiveActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/tprd"
android:host="*"
android:pathPattern=".*\\.tprd"
/>
</intent-filter>
</activity>
<activity
android:name="com.sudogeeks.talking_reminder.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.sudogeeks.talking_reminder.ReminderAddActivity"
android:label="@string/activity_add_reminder_label">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<activity
android:name="com.sudogeeks.talking_reminder.ReminderEditActivity"
android:label="@string/activity_edit_reminder_label" />
<receiver android:name="com.sudogeeks.talking_reminder.AlarmReceiver"/>
<receiver android:name="com.sudogeeks.talking_reminder.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.sudogeeks.talking_reminder.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<!-- ressource file to create -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
<service
android:name="com.sudogeeks.talking_reminder.ReadReminderTextService"
android:enabled="true" />
</application>
</manifest>
package com.sudogeeks.talking_reminder;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.SystemClock;
import androidx.core.app.NotificationCompat;
import java.util.Calendar;
/**
* \brief A class implementing basic alarm functions
* This class includes very basic features for an alarm
*/
public class AlarmReceiver extends BroadcastReceiver {
AlarmManager mAlarmManager;
PendingIntent mPendingIntent;
/**
* Notifies user at the time of alarm
*
* @param context:
* @param intent
* @return void
*/
@Override
public void onReceive(Context context, Intent intent) {
int mReceivedID = Integer.parseInt(intent.getStringExtra(ReminderEditActivity.EXTRA_REMINDER_ID));
//Get notification title from ReminderDO Database
ReminderDatabase rb = new ReminderDatabase(context);
ReminderDO reminderDO = rb.getReminder(mReceivedID);
String mTitle = reminderDO.getTitle();
// Create intent to open ReminderEditActivity on notification click
Intent editIntent = new Intent(context, ReminderEditActivity.class);
editIntent.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, Integer.toString(mReceivedID));
PendingIntent mClick = PendingIntent.getActivity(context, mReceivedID, editIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationHelper notificationHelper = new NotificationHelper(context, intent);
NotificationCompat.Builder nb = notificationHelper.getChannelNotification();
notificationHelper.getManager().notify(mReceivedID, nb.build());
// tts
// context.startService(new Intent(context, ReadReminderTextService.class));
Intent i = new Intent(context, ReadReminderTextService.class);
i.putExtra("MyTitle", mTitle);
context.startService(i);
context.startService(i);
context.startService(i);
}
/**
* Method for setting an alarm
*
* @param context
* @param calendar Calendar instance encapsulating date and time of alarm
* @param ID Id of the alarm
* @return void
*/
public void setAlarm(Context context, Calendar calendar, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Put ReminderDO ID in Intent Extra
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, Integer.toString(ID));
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Calculate notification time
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using notification time
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + diffTime,
mPendingIntent);
// Restart alarm if device is rebooted
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
/**
* Method for setting repeating alarm
*
* @param context
* @param calendar Calendar instance encapsulating date and time of alarm
* @param ID Id of the alarm
* @param RepeatTime repeat time of alaram
*/
public void setRepeatAlarm(Context context, Calendar calendar, int ID, long RepeatTime) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Put ReminderDO ID in Intent Extra
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, Integer.toString(ID));
mPendingIntent = PendingIntent.getBroadcast(context, ID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// Calculate notification timein
Calendar c = Calendar.getInstance();
long currentTime = c.getTimeInMillis();
long diffTime = calendar.getTimeInMillis() - currentTime;
// Start alarm using initial notification time and repeat interval time
mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + diffTime,
RepeatTime, mPendingIntent);
// Restart alarm if device is rebooted
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
/**
* Method for cancelling an alarm
*
* @param context
* @param ID Id of the alarm to cancel
*/
public void cancelAlarm(Context context, int ID) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Cancel Alarm using ReminderDO ID
mPendingIntent = PendingIntent.getBroadcast(context, ID, new Intent(context, AlarmReceiver.class), 0);
mAlarmManager.cancel(mPendingIntent);
// Disable alarm
ComponentName receiver = new ComponentName(context, BootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
\ No newline at end of file
package com.sudogeeks.talking_reminder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.Calendar;
import java.util.List;
/**
* \brief A class For handling the reboot scenarios.
* In this case this class reschedules the alarms if the device boots
*
*/
public class BootReceiver extends BroadcastReceiver {
// Constant values in milliseconds
private static final long milMinute = 60000L;
private static final long milHour = 3600000L;
private static final long milDay = 86400000L;
private static final long milWeek = 604800000L;
private static final long milMonth = 2592000000L;
private String mTitle;
private String mTime;
private String mDate;
private String mRepeatNo;
private String mRepeatType;
private String mActive;
private String mRepeat;
private String[] mDateSplit;
private String[] mTimeSplit;
private int mYear, mMonth, mHour, mMinute, mDay, mReceivedID;
private long mRepeatTime;
private Calendar mCalendar;
private AlarmReceiver mAlarmReceiver;
/**
* Overrides onReceive method of BroadcastReceiver class. Once the device boot completes, this method will schedule the alarms again
* @param context
* @param intent
*/
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
ReminderDatabase rb = new ReminderDatabase(context);
mCalendar = Calendar.getInstance();
mAlarmReceiver = new AlarmReceiver();
List<ReminderDO> reminderDOS = rb.getAllReminders();
for (ReminderDO rm : reminderDOS) {
mReceivedID = rm.getID();
mRepeat = rm.getRepeat();
mRepeatNo = rm.getRepeatNo();
mRepeatType = rm.getRepeatType();
mActive = rm.getActive();
mDate = rm.getDate();
mTime = rm.getTime();
mDateSplit = mDate.split("/");
mTimeSplit = mTime.split(":");
mDay = Integer.parseInt(mDateSplit[0]);
mMonth = Integer.parseInt(mDateSplit[1]);
mYear = Integer.parseInt(mDateSplit[2]);
mHour = Integer.parseInt(mTimeSplit[0]);
mMinute = Integer.parseInt(mTimeSplit[1]);
mCalendar.set(Calendar.MONTH, --mMonth);
mCalendar.set(Calendar.YEAR, mYear);
mCalendar.set(Calendar.DAY_OF_MONTH, mDay);
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
mCalendar.set(Calendar.SECOND, 0);
// Cancel existing notification of the reminder by using its ID
// mAlarmReceiver.cancelAlarm(context, mReceivedID);
// Check repeat type
if (mRepeatType.equals("Minute")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMinute;
} else if (mRepeatType.equals("Hour")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milHour;
} else if (mRepeatType.equals("Day")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milDay;
} else if (mRepeatType.equals("Week")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milWeek;
} else if (mRepeatType.equals("Month")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMonth;
}
// Create a new notification
if (mActive.equals("true")) {
if (mRepeat.equals("true")) {
mAlarmReceiver.setRepeatAlarm(context, mCalendar, mReceivedID, mRepeatTime);
} else if (mRepeat.equals("false")) {
mAlarmReceiver.setAlarm(context, mCalendar, mReceivedID);
}
}
}
}
}
}
\ No newline at end of file
package com.sudogeeks.talking_reminder;
/**
* \brief Data Object class for creating DateTime objects to facilitate easy sorting
*
*/
public class DateTimeSorter {
private int mIndex;
private String mDateTime;
public DateTimeSorter(int index, String DateTime) {
mIndex = index;
mDateTime = DateTime;
}
public DateTimeSorter() {
}
public int getIndex() {
return mIndex;
}
public void setIndex(int index) {
mIndex = index;
}
public String getDateTime() {
return mDateTime;
}
public void setDateTime(String dateTime) {
mDateTime = dateTime;
}
}
package com.sudogeeks.talking_reminder;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.bignerdranch.android.multiselector.SwappingHolder;
import com.firebase.ui.auth.AuthUI;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
/**
* \brief Main Activity class
* This activity is the entry point of the app and is responsible for handling User Authentication and Landing page view
*/
public class MainActivity extends AppCompatActivity {
private static final int RC_SIGN_IN = 123; // Choose an arbitrary request code value
private RecyclerView reminderListView;
private SimpleAdapter mAdapter;
private Toolbar mToolbar;
private TextView mNoReminderView;
private FloatingActionButton mAddReminderButton;
private int mTempPost;
private LinkedHashMap<Integer, Integer> IDmap = new LinkedHashMap<>();
private ReminderDatabase rb;
private MultiSelector mMultiSelector = new MultiSelector();
private AlarmReceiver mAlarmReceiver;
private FirebaseDatabase firebaseDatabase; //Entrypoint for our firebase database
private DatabaseReference reminderDatabaseReference; //To references specific part of the database
private ChildEventListener dbChildEventListener; //No notify the app whenever data changes in firebase database
private FirebaseAuth firebaseAuth; //For User authentication
private FirebaseAuth.AuthStateListener authStateListener; //Listener which invokes whenever auth state changes
private ArrayList<ReminderDO> reminderDOArrayList = new ArrayList<>();
// Multi select items in recycler view
private ModalMultiSelectorCallback mDeleteMode = new ModalMultiSelectorCallback(mMultiSelector) {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
getMenuInflater().inflate(R.menu.menu_add_reminder, menu);
return true;
}
/** Defines the behaviour of different menu items
* Overridden Method
* @param actionMode
* @param menuItem
* @return
*/
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
// On clicking discard reminders
case R.id.discard_reminder:
// Close the context menu
actionMode.finish();
// Get the reminder id associated with the recycler view item
for (int i = IDmap.size(); i >= 0; i--) {
if (mMultiSelector.isSelected(i, 0)) {
int id = IDmap.get(i);
// Get reminder from reminder database using id
ReminderDO temp = rb.getReminder(id);
// Delete reminder
rb.deleteReminder(temp);
// Remove reminder from recycler view
mAdapter.removeItemSelected(i);
// Delete reminder alarm
mAlarmReceiver.cancelAlarm(getApplicationContext(), id);
}
}
// Clear selected items in recycler view
mMultiSelector.clearSelections();
// Recreate the recycler items
// This is done to remap the item and reminder ids
mAdapter.onDeleteItem(getDefaultItemCount());
// Display toast to confirm delete
Toast.makeText(getApplicationContext(),
"Deleted",
Toast.LENGTH_SHORT).show();
// To check is there are saved reminders
// If there are no reminders display a message asking the user to create reminders
List<ReminderDO> mTest = rb.getAllReminders();
if (mTest.isEmpty()) {
mNoReminderView.setVisibility(View.VISIBLE);
} else {
mNoReminderView.setVisibility(View.GONE);
}
return true;
// On clicking save reminders
case R.id.save_reminder:
// Close the context menu
actionMode.finish();
// Clear selected items in recycler view
mMultiSelector.clearSelections();
return true;
default:
break;
}
return false;
}
};
/**onCreate() implementation
* Overridden method. In this method initial life cycle of the app is implemented.
* If user is not authenticated then user is sent for login/signup, else database instance and main view is initialized
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Routine : check user Authentication
firebaseDatabase = FirebaseDatabase.getInstance();
firebaseAuth = FirebaseAuth.getInstance();
FirebaseUser user = firebaseAuth.getCurrentUser();
//AuthStateListener: check the user's authentication state. if not signed in the send it for login/signup
authStateListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
//User is signed in
reminderDatabaseReference = firebaseDatabase.getReference().child("reminders").child(user.getUid());
Toast.makeText(MainActivity.this, "You're now signed in.\nWelcome to Talking ReminderDO!", Toast.LENGTH_SHORT).show();
attachDatabaseReadListener();
} else {
//User is signed out
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setIsSmartLockEnabled(false)
.setAvailableProviders(Arrays.asList(
new AuthUI.IdpConfig.GoogleBuilder().build(),
new AuthUI.IdpConfig.EmailBuilder().build()))
.build(),
RC_SIGN_IN);
}
}
};
// Initialize reminder database
rb = new ReminderDatabase(getApplicationContext());
// Initialize views
mToolbar = findViewById(R.id.toolbar);
mAddReminderButton = findViewById(R.id.add_reminder);
reminderListView = findViewById(R.id.reminder_list);
mNoReminderView = findViewById(R.id.no_reminder_text);
// To check is there are saved reminders
// If there are no reminders display a message asking the user to create reminders
List<ReminderDO> mTest = rb.getAllReminders();
if (mTest.isEmpty()) {
mNoReminderView.setVisibility(View.VISIBLE);
}
// Create recycler view
reminderListView.setLayoutManager(getLayoutManager());
registerForContextMenu(reminderListView);
mAdapter = new SimpleAdapter();
mAdapter.setItemCount(getDefaultItemCount());
reminderListView.setAdapter(mAdapter);
// Setup toolbar
setSupportActionBar(mToolbar);
mToolbar.setTitle(R.string.app_name);
// On clicking the floating action button
mAddReminderButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ReminderAddActivity.class);
startActivity(intent);
}
});
// Initialize alarm
mAlarmReceiver = new AlarmReceiver();
}
/* Private Helper method
* This method attaches a listener to the Firebase database reference. The listener listens to any kind of changes in the database.
*
*/
private void attachDatabaseReadListener() {
//TODO Attaching Listener to ChildEventListener
if (dbChildEventListener == null) { // Create new Event Listener only when no listener is attached yet
dbChildEventListener = new ChildEventListener() {
//Specify what to do when a new entry is added in the database. New entry here means "new Reminder object"
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
ReminderDO reminderObject = dataSnapshot.getValue(ReminderDO.class);
reminderDOArrayList.add(reminderObject);
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
}
reminderDatabaseReference.addChildEventListener(dbChildEventListener);
}
/* Private helper method
* this method is called to Detach the database listener in the events of logout or app failure
*/
private void detachDatabaseReadListener() {
if (dbChildEventListener != null) {
reminderDatabaseReference.removeEventListener(dbChildEventListener);
dbChildEventListener = null;
}
}
/**Define what happens when user closes the app
* Overridden method
*/
@Override
protected void onPause() {
super.onPause();
if (authStateListener != null) {
firebaseAuth.removeAuthStateListener(authStateListener);
}
detachDatabaseReadListener();
//reminderAdapter.clear();
}
/** Create context menu for long press actions
*
* @param menu
* @param view
* @param menuInfo
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.menu_add_reminder, menu);
}
/*Private Helper method :
* Implement behaviour : On clicking a reminder item, user shoud be taken to Reminder Edit Activity
*/
private void selectReminder(int mClickID) {
String mStringClickID = Integer.toString(mClickID);
// Create intent to edit the reminder
// Put reminder id as extra
Intent i = new Intent(this, ReminderEditActivity.class);
i.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, mStringClickID);
startActivityForResult(i, 1);
}
/** Standard method for handling the outcome of an activity.
* If user signs in is successful then only take the user to main page. Else force the user to login in first
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mAdapter.setItemCount(getDefaultItemCount());
if (requestCode == RC_SIGN_IN) {
//If user signs in is successful then only take the user to main page. Else force the user to login in first
if (resultCode == RESULT_OK) {
Toast.makeText(this, "Signed in", Toast.LENGTH_SHORT);
startActivity(new Intent(MainActivity.this, ReminderAddActivity.class));
} else if (requestCode == RESULT_CANCELED) {
Toast.makeText(this, "Sign in cancelled", Toast.LENGTH_SHORT);
finish();
}
}
}
/** Define the behaviour of the app in case user comes back after suspending the app.
* -Recreate recycler view : This is done so that newly created reminders are also displayed
*/
@Override
public void onResume() {
super.onResume();
firebaseAuth.addAuthStateListener(authStateListener);
// Get all the reminders : If there are no reminders display a message
List<ReminderDO> mTest = rb.getAllReminders();
if (mTest.isEmpty()) {
mNoReminderView.setVisibility(View.VISIBLE);
} else {
mNoReminderView.setVisibility(View.GONE);
}
mAdapter.setItemCount(getDefaultItemCount());
}
/** Layout manager for recycler view
*
* @return LinearLayoutManager instance
*/
protected RecyclerView.LayoutManager getLayoutManager() {
return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
}
/** Helper method
*
* @return integer 100
*/
protected int getDefaultItemCount() {
return 100;
}
/**
* Creating main menu
*
* @param Menu object
* @return boolean
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
/**Defines behaviours for the menu items.
*
* @param item
* @return Boolean
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.sign_out:
//sign out
AuthUI.getInstance().signOut(this);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**\brief Adapter class (Inner Class) for implementing recycler view
*
* This class will handle how to display the reminder data on the main page.
*/
public class SimpleAdapter extends RecyclerView.Adapter<SimpleAdapter.VerticalItemHolder> {
private ArrayList<ReminderItem> mItems;
public SimpleAdapter() {
mItems = new ArrayList<>();
}
public void onDeleteItem(int count) {
mItems.clear();
mItems.addAll(generateData(count));
}
public void removeItemSelected(int selected) {
if (mItems.isEmpty()) return;
mItems.remove(selected);
notifyItemRemoved(selected);
}
/** View holder for recycler view items
* Overridden method
*
* @param container
* @param viewType
* @return an object of VerticalItemHolder
*/
@Override
public VerticalItemHolder onCreateViewHolder(ViewGroup container, int viewType) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
View root = inflater.inflate(R.layout.recycle_items, container, false);
return new VerticalItemHolder(root, this);
}
/**Bind a reminder item to a position in the main view
* Overridden method
*
* @param itemHolder
* @param position
*/
@Override
public void onBindViewHolder(VerticalItemHolder itemHolder, int position) {
ReminderItem item = mItems.get(position);
itemHolder.setReminderTitle(item.mTitle);
itemHolder.setReminderDateTime(item.mDateTime);
itemHolder.setReminderRepeatInfo(item.mRepeat, item.mRepeatNo, item.mRepeatType);
itemHolder.setActiveImage(item.mActive);
}
/**Retuns the number of reminders in the database
*
* @return
*/
@Override
public int getItemCount() {
return mItems.size();
}
public void setItemCount(int count) {
mItems.clear();
mItems.addAll(generateData(count));
notifyDataSetChanged();
}
/** Prepare data for each reminder item to facilitate proper displaying in the view.
* this Helper method required because all the data in database are not directly representable.
*
* @param count
* @return
*/
public List<ReminderItem> generateData(int count) {
ArrayList<SimpleAdapter.ReminderItem> items = new ArrayList<>();
// Get all reminderDOS from the database
List<ReminderDO> reminderDOS = rb.getAllReminders();
// Initialize lists
List<String> Titles = new ArrayList<>();
List<String> Repeats = new ArrayList<>();
List<String> RepeatNos = new ArrayList<>();
List<String> RepeatTypes = new ArrayList<>();
List<String> Actives = new ArrayList<>();
List<String> DateAndTime = new ArrayList<>();
List<Integer> IDList = new ArrayList<>();
List<DateTimeSorter> DateTimeSortList = new ArrayList<>();
// Add details of all reminderDOS in their respective lists
for (ReminderDO reminderDO : reminderDOS) {
Titles.add(reminderDO.getTitle());
DateAndTime.add(reminderDO.getDate() + " " + reminderDO.getTime());
Repeats.add(reminderDO.getRepeat());
RepeatNos.add(reminderDO.getRepeatNo());
RepeatTypes.add(reminderDO.getRepeatType());
Actives.add(reminderDO.getActive());
IDList.add(reminderDO.getID());
}
int key = 0;
// Add date and time as DateTimeSorter objects
for (int k = 0; k < Titles.size(); k++) {
DateTimeSortList.add(new DateTimeSorter(key, DateAndTime.get(k)));
key++;
}
// Sort items according to date and time in ascending order
Collections.sort(DateTimeSortList, new DateTimeComparator());
int k = 0;
// Plug in the data to each recycler view item
for (DateTimeSorter item : DateTimeSortList) {
int i = item.getIndex();
items.add(new SimpleAdapter.ReminderItem(Titles.get(i), DateAndTime.get(i), Repeats.get(i),
RepeatNos.get(i), RepeatTypes.get(i), Actives.get(i)));
IDmap.put(k, IDList.get(i));
k++;
}
return items;
}
/** Data-Object class for recycler view items
* This class is slightly different form ReminderDO class. Very specific to the requirement of the recyler view
*/
public class ReminderItem {
public String mTitle;
public String mDateTime;
public String mRepeat;
public String mRepeatNo;
public String mRepeatType;
public String mActive;
/**Constructor
*
* @param Title
* @param DateTime
* @param Repeat
* @param RepeatNo number of repeatition
* @param RepeatType
* @param Active
*/
public ReminderItem(String Title, String DateTime, String Repeat, String RepeatNo, String RepeatType, String Active) {
this.mTitle = Title;
this.mDateTime = DateTime;
this.mRepeat = Repeat;
this.mRepeatNo = RepeatNo;
this.mRepeatType = RepeatType;
this.mActive = Active;
}
}
/** Inner class to compare date and time so that items can be sorted in ascending/decending order of date and time
*
*/
public class DateTimeComparator implements Comparator {
DateFormat f = new SimpleDateFormat("dd/mm/yyyy hh:mm");
public int compare(Object a, Object b) {
String o1 = ((DateTimeSorter) a).getDateTime();
String o2 = ((DateTimeSorter) b).getDateTime();
try {
return f.parse(o1).compareTo(f.parse(o2));
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
}
/** UI and data class (Adapter) for recycler view items
*
*/
public class VerticalItemHolder extends SwappingHolder
implements View.OnClickListener, View.OnLongClickListener {
private TextView mTitleText, mDateAndTimeText, mRepeatInfoText;
private ImageView mActiveImage, mThumbnailImage;
private ColorGenerator mColorGenerator = ColorGenerator.DEFAULT;
private TextDrawable mDrawableBuilder;
private SimpleAdapter mAdapter;
/**
* Sets up recycler item selector in the context.
* On long clicks the items should be selected so that user can take actions (like delete) on those items
*
* @param itemView
* @param adapter
*/
public VerticalItemHolder(View itemView, SimpleAdapter adapter) {
super(itemView, mMultiSelector);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this); //Set for long clicks
itemView.setLongClickable(true);
// Initialize adapter for the items
mAdapter = adapter;
// Initialize views
mTitleText = itemView.findViewById(R.id.recycle_title);
mDateAndTimeText = itemView.findViewById(R.id.recycle_date_time);
mRepeatInfoText = itemView.findViewById(R.id.recycle_repeat_info);
mActiveImage = itemView.findViewById(R.id.active_image);
mThumbnailImage = itemView.findViewById(R.id.thumbnail_image);
}
/** On clicking a reminder item
*
* @param view
*/
@Override
public void onClick(View view) {
if (!mMultiSelector.tapSelection(this)) {
mTempPost = reminderListView.getChildAdapterPosition(view);
int mReminderClickID = IDmap.get(mTempPost);
selectReminder(mReminderClickID);
} else if (mMultiSelector.getSelectedPositions().isEmpty()) {
mAdapter.setItemCount(getDefaultItemCount());
}
}
/** On long press enter action mode with context menu
*
* @param view
* @return
*/
@Override
public boolean onLongClick(View view) {
AppCompatActivity activity = MainActivity.this;
activity.startSupportActionMode(mDeleteMode);
mMultiSelector.setSelected(this, true);
return true;
}
/** Set reminder title view
*
* @param reminderTitle
*/
public void setReminderTitle(String reminderTitle) {
mTitleText.setText(reminderTitle);
String letter = "A";
if (reminderTitle != null && !reminderTitle.isEmpty()) {
letter = reminderTitle.substring(0, 1);
}
int color = mColorGenerator.getRandomColor();
// Create a circular icon consisting of a random background colour and first letter of title
mDrawableBuilder = TextDrawable.builder()
.buildRound(letter, color);
mThumbnailImage.setImageDrawable(mDrawableBuilder);
}
/** Set date and time views
*
* @param datetime
*/
public void setReminderDateTime(String datetime) {
mDateAndTimeText.setText(datetime);
}
/** Set repeat views
*
* @param repeat
* @param repeatNo
* @param repeatType
*/
public void setReminderRepeatInfo(String repeat, String repeatNo, String repeatType) {
if (repeat.equals("true")) {
mRepeatInfoText.setText("Every " + repeatNo + " " + repeatType + "(s)");
} else if (repeat.equals("false")) {
mRepeatInfoText.setText("Repeat Off");
}
}
/** Set active image as on or off
* This method is apparently not consistent because on/off behaviour doesn't always work
* @param active
*/
public void setActiveImage(String active) {
if (active.equals("true")) {
mActiveImage.setImageResource(R.drawable.ic_notifications_active);
} else if (active.equals("false")) {
mActiveImage.setImageResource(R.drawable.ic_notifications_off);
}
}
}
}
}
package com.sudogeeks.talking_reminder;
import android.annotation.TargetApi;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.speech.tts.TextToSpeech;
import androidx.core.app.NotificationCompat;
/** \brief Class to implement notification
* This class is for implementing notification popup at alarm time
*/
public class NotificationHelper extends ContextWrapper {
public static final String channelID = "channelID";
public static final String channelName = "Channel Name";
String mTitle;
PendingIntent mClick;
private NotificationManager mManager;
private TextToSpeech t1;
/**
* Constructor for NotificationHelper class
* @param base
* @param intent
*/
public NotificationHelper(Context base, Intent intent) {
super(base);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannel();
}
int mReceivedID = Integer.parseInt(intent.getStringExtra(ReminderEditActivity.EXTRA_REMINDER_ID));
ReminderDatabase rb = new ReminderDatabase(base);
ReminderDO reminderDO = rb.getReminder(mReceivedID);
mTitle = reminderDO.getTitle();
// Create intent to open ReminderEditActivity on notification click
Intent editIntent = new Intent(base, ReminderEditActivity.class);
editIntent.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, Integer.toString(mReceivedID));
mClick = PendingIntent.getActivity(base, mReceivedID, editIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@TargetApi(Build.VERSION_CODES.O)
private void createChannel() {
NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);
getManager().createNotificationChannel(channel);
}
public NotificationManager getManager() {
if (mManager == null) {
mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return mManager;
}
/**
* This method build notificationCompat having various setting of notification likeicon, content,priority,etc..
* @return NotificationCompat.Builder for the notification
*/
public NotificationCompat.Builder getChannelNotification() {
//t1.speak(mTitle, TextToSpeech.QUEUE_FLUSH, null);
// t1.synthesizeToFile(mTitle, null, "/SDCARD/speak1.wav");
//Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/sample");
return new NotificationCompat.Builder(getApplicationContext(), channelID)
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher))
.setSmallIcon(R.drawable.ic_alarm_on_white)
.setContentTitle(getApplicationContext().getResources().getString(R.string.app_name))
.setTicker(mTitle)
.setContentText(mTitle)
//.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
// .setSound(Uri.fromFile(new File("SDCARD/s1.mp3")))
//.setSound(null)
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setContentIntent(mClick)
.setAutoCancel(true)
.setOnlyAlertOnce(true);
}
public TextToSpeech getTextToSpeech() {
return t1;
}
}
//function
\ No newline at end of file
package com.sudogeeks.talking_reminder;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import java.util.Locale;
/**\brief Class for Text to speech service
* This class is extending the tts module service to speak up the reminder text
*/
public class ReadReminderTextService extends Service implements TextToSpeech.OnInitListener, TextToSpeech.OnUtteranceCompletedListener {
private TextToSpeech mTts;
private String spokenText;
/**
* Overrides onCreate , this is the good place to set spokentext.
*/
@Override
public void onCreate() {
mTts = new TextToSpeech(this, this);
// This is a good place to set spokenText
// spokenText="raushan raushan raushan raushan";
}
/**
* Overrides OnStartCommand of service class , this is used to get reminder text which will be spoken.
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
spokenText = intent.getStringExtra("MyTitle");
return START_STICKY;
}
/**
* This method overrides onInit and this is calling TTS object to speak up the spoken text.
* @param status
*/
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = mTts.setLanguage(Locale.US);
if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
mTts.speak(spokenText, TextToSpeech.QUEUE_ADD, null);
}
}
}
@Override
public void onUtteranceCompleted(String uttId) {
stopSelf();
}
@Override
public void onDestroy() {
if (mTts != null) {
mTts.stop();
mTts.shutdown();
}
super.onDestroy();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
\ No newline at end of file
package com.sudogeeks.talking_reminder;
import android.Manifest;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Calendar;
/** \brief Java class for handling UI component of Add reminder layout
*
*/
public class ReminderAddActivity extends AppCompatActivity {
// Values for orientation change
private static final String KEY_TITLE = "title_key";
private static final String KEY_TIME = "time_key";
private static final String KEY_DATE = "date_key";
private static final String KEY_REPEAT = "repeat_key";
private static final String KEY_REPEAT_NO = "repeat_no_key";
private static final String KEY_REPEAT_TYPE = "repeat_type_key";
private static final String KEY_ACTIVE = "active_key";
// Constant values in milliseconds
private static final long milMinute = 60000L;
private static final long milHour = 3600000L;
private static final long milDay = 86400000L;
private static final long milWeek = 604800000L;
private static final long milMonth = 2592000000L;
private static final int MY_PERMISSIONS_REQUEST_WRITE_CONTACTS = 1;
private Toolbar mToolbar;
private EditText mTitleText;
private TextView mDateText, mTimeText, mRepeatText, mRepeatNoText, mRepeatTypeText;
private FloatingActionButton mFAB1;
private FloatingActionButton mFAB2;
private Calendar mCalendar;
private int mYear, mMonth, mHour, mMinute, mDay;
private long mRepeatTime;
private String mTitle;
private String mTime;
private String mDate;
private String mRepeat;
private String mRepeatNo;
private String mRepeatType;
private String mActive;
private FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
private FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
private DatabaseReference dbReference = firebaseDatabase.getReference().child("reminders");
/**
*overrides onCreate method to get all the ui element
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_reminder);
// Initialize Views
mToolbar = findViewById(R.id.toolbar);
mTitleText = findViewById(R.id.reminder_title);
mDateText = findViewById(R.id.set_date);
mTimeText = findViewById(R.id.set_time);
mRepeatText = findViewById(R.id.set_repeat);
mRepeatNoText = findViewById(R.id.set_repeat_no);
mRepeatTypeText = findViewById(R.id.set_repeat_type);
mFAB1 = findViewById(R.id.starred1);
mFAB2 = findViewById(R.id.starred2);
// Setup Toolbar
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle(R.string.activity_add_reminder_label);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// Initialize default values
mActive = "true";
mRepeat = "true";
mRepeatNo = Integer.toString(1);
mRepeatType = "Hour";
mCalendar = Calendar.getInstance();
mHour = mCalendar.get(Calendar.HOUR_OF_DAY);
mMinute = mCalendar.get(Calendar.MINUTE);
mYear = mCalendar.get(Calendar.YEAR);
mMonth = mCalendar.get(Calendar.MONTH) + 1;
mDay = mCalendar.get(Calendar.DATE);
mDate = mDay + "/" + mMonth + "/" + mYear;
mTime = mHour + ":" + mMinute;
// Setup ReminderDO Title EditText
mTitleText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mTitle = s.toString().trim();
mTitleText.setError(null);
}
@Override
public void afterTextChanged(Editable s) {
}
});
// Setup TextViews using reminder values
mDateText.setText(mDate);
mTimeText.setText(mTime);
mRepeatNoText.setText(mRepeatNo);
mRepeatTypeText.setText(mRepeatType);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
// To save state on device rotation
if (savedInstanceState != null) {
String savedTitle = savedInstanceState.getString(KEY_TITLE);
mTitleText.setText(savedTitle);
mTitle = savedTitle;
String savedTime = savedInstanceState.getString(KEY_TIME);
mTimeText.setText(savedTime);
mTime = savedTime;
String savedDate = savedInstanceState.getString(KEY_DATE);
mDateText.setText(savedDate);
mDate = savedDate;
String saveRepeat = savedInstanceState.getString(KEY_REPEAT);
mRepeatText.setText(saveRepeat);
mRepeat = saveRepeat;
String savedRepeatNo = savedInstanceState.getString(KEY_REPEAT_NO);
mRepeatNoText.setText(savedRepeatNo);
mRepeatNo = savedRepeatNo;
String savedRepeatType = savedInstanceState.getString(KEY_REPEAT_TYPE);
mRepeatTypeText.setText(savedRepeatType);
mRepeatType = savedRepeatType;
mActive = savedInstanceState.getString(KEY_ACTIVE);
}
// Setup up active buttons
if (mActive.equals("false")) {
mFAB1.show();
mFAB2.hide();
} else if (mActive.equals("true")) {
mFAB1.hide();
mFAB2.show();
}
}
// To save state on device rotation
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putCharSequence(KEY_TITLE, mTitleText.getText());
outState.putCharSequence(KEY_TIME, mTimeText.getText());
outState.putCharSequence(KEY_DATE, mDateText.getText());
outState.putCharSequence(KEY_REPEAT, mRepeatText.getText());
outState.putCharSequence(KEY_REPEAT_NO, mRepeatNoText.getText());
outState.putCharSequence(KEY_REPEAT_TYPE, mRepeatTypeText.getText());
outState.putCharSequence(KEY_ACTIVE, mActive);
}
/**
* On clicking Time picker , to show time dialog for user to select time
* @param v
*/
public void setTime(View v) {
Calendar now = Calendar.getInstance();
TimePickerDialog timePickerDialog = new TimePickerDialog(this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker timePicker, int hourOfDay,
int minute) {
mHour = hourOfDay;
mMinute = minute;
if (minute < 10) {
mTime = hourOfDay + ":" + "0" + minute;
} else {
mTime = hourOfDay + ":" + minute;
}
mTimeText.setText(mTime);
}
}, mHour, mMinute, false);
timePickerDialog.show();
}
/**
* On clicking Date picker,to show date dialog for user to select date
* @param v
*/
public void setDate(View v) {
Calendar now = Calendar.getInstance();
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int year,
int monthOfYear, int dayOfMonth) {
mDay = dayOfMonth;
mMonth = monthOfYear + 1;
mYear = year;
mDate = mDay + "/" + mMonth + "/" + mYear;
mDateText.setText(mDate);
//mMonth = monthOfYear+1;
}
}, mYear, mMonth, mDay);
datePickerDialog.show();
}
public void selectFab1(View v) {
mFAB1 = findViewById(R.id.starred1);
mFAB1.hide();
mFAB2 = findViewById(R.id.starred2);
mFAB2.show();
mActive = "true";
}
// On clicking the inactive button
public void selectFab2(View v) {
mFAB2 = findViewById(R.id.starred2);
mFAB2.hide();
mFAB1 = findViewById(R.id.starred1);
mFAB1.show();
mActive = "false";
}
/**
* On clicking the repeat switch, to select for repeat alarm
* @param view
*/
public void onSwitchRepeat(View view) {
boolean on = ((Switch) view).isChecked();
if (on) {
mRepeat = "true";
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
} else {
mRepeat = "false";
mRepeatText.setText(R.string.repeat_off);
}
}
/**
* On clicking repeat type button, to select for repeat type like every minute, hour, day,month
* @param v
*/
public void selectRepeatType(View v) {
final String[] items = new String[5];
items[0] = "Minute";
items[1] = "Hour";
items[2] = "Day";
items[3] = "Week";
items[4] = "Month";
// Create List Dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select Type");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
mRepeatType = items[item];
mRepeatTypeText.setText(mRepeatType);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
}
});
AlertDialog alert = builder.create();
alert.show();
}
/**
* On clicking set repeat interval
* @param v
*/
public void setRepeatNo(View v) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Enter Number");
// Create EditText box to input repeat number
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
alert.setView(input);
alert.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
if (input.getText().toString().length() == 0) {
mRepeatNo = Integer.toString(1);
mRepeatNoText.setText(mRepeatNo);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
} else {
mRepeatNo = input.getText().toString().trim();
mRepeatNoText.setText(mRepeatNo);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
}
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// do nothing
}
});
alert.show();
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
/**
* To save reminder data object parsed into json
* @param filename
*/
public void saveReminderToTempStorage(String filename) {
ReminderDO talkingReminderDO = new ReminderDO();
talkingReminderDO.setTitle(mTitle);
talkingReminderDO.setDate(mDate);
talkingReminderDO.setTime(mTime);
talkingReminderDO.setRepeat(mRepeat);
talkingReminderDO.setRepeatNo(mRepeatNo);
talkingReminderDO.setRepeatType(mRepeatType);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
//String fileName=Environment.getExternalStorageDirectory()+"talkingReminderDO.json";
//First write the data to a temporary file
FileOutputStream outputStream;
if (ContextCompat.checkSelfPermission(ReminderAddActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
if (ActivityCompat.shouldShowRequestPermissionRationale(ReminderAddActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(ReminderAddActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_WRITE_CONTACTS);
}
}
try {
String fileContents = gson.toJson(talkingReminderDO);
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(fileContents.getBytes());
outputStream.close();
// FileWriter fw = new FileWriter(filename);
// BufferedWriter bw = new BufferedWriter(fw);
// bw.write(content);
// bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* This method saves the reminder to database and also invokes setAlarm and setRepeatAlarm
*/
public void saveReminder() {
ReminderDatabase rb = new ReminderDatabase(this);
// Creating ReminderDO
int ID = rb.addReminder(new ReminderDO(mTitle, mDate, mTime, mRepeat, mRepeatNo, mRepeatType, mActive));
//Storing Reminders in firebase database
ReminderDO reminderDO = new ReminderDO(mTitle, mDate, mTime, mRepeat, mRepeatNo, mRepeatType, mActive);
FirebaseUser user = firebaseAuth.getCurrentUser();
reminderDO.setOwnerID(user.getEmail());
reminderDO.setReceiverID("null");
dbReference.child(user.getUid()).push().setValue(reminderDO);
// Set up calender for creating the notification
mCalendar.set(Calendar.MONTH, --mMonth);
mCalendar.set(Calendar.YEAR, mYear);
mCalendar.set(Calendar.DAY_OF_MONTH, mDay);
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
mCalendar.set(Calendar.SECOND, 0);
// Check repeat type
if (mRepeatType.equals("Minute")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMinute;
} else if (mRepeatType.equals("Hour")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milHour;
} else if (mRepeatType.equals("Day")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milDay;
} else if (mRepeatType.equals("Week")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milWeek;
} else if (mRepeatType.equals("Month")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMonth;
}
// Create a new notification
if (mActive.equals("true")) {
if (mRepeat.equals("true")) {
new AlarmReceiver().setRepeatAlarm(getApplicationContext(), mCalendar, ID, mRepeatTime);
} else if (mRepeat.equals("false")) {
new AlarmReceiver().setAlarm(getApplicationContext(), mCalendar, ID);
}
}
// Create toast to confirm new reminder
Toast.makeText(getApplicationContext(), "Saved",
Toast.LENGTH_SHORT).show();
onBackPressed();
}
/**
* On pressing the back button
*/
@Override
public void onBackPressed() {
super.onBackPressed();
}
/**
* Creating the menu
* @param menu
* @return true
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_add_reminder, menu);
return true;
}
/**
* On clicking menu buttons :Save reminder (to save reminder), send reminder(to send reminder), discard reminder(to discard reminder)
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// On clicking the back arrow
// Discard any changes
case android.R.id.home:
onBackPressed();
return true;
// On clicking save reminder button
// Update reminder
case R.id.save_reminder:
mTitleText.setText(mTitle);
if (mTitleText.getText().toString().trim().length() == 0)
mTitleText.setError("ReminderDO Title cannot be blank!");
else {
saveReminder();
}
return true;
// On clicking discard reminder button
// Discard any changes
case R.id.discard_reminder:
Toast.makeText(getApplicationContext(), "Discarded",
Toast.LENGTH_SHORT).show();
onBackPressed();
return true;
// On clicking send reminder button
// Initiate sender routine
case R.id.send_reminder:
Context context = this;
String filename = Utility.FILE_NAME_PREFIX + "." + Utility.FILE_EXTENSION; //TODO Consecutive filenames should be unique
saveReminderToTempStorage(filename);
//Check the if the file was written correctly.. Should be printed on console
// FileInputStream fi = null;
// try {
// fi = context.openFileInput(filename);
// int i;
// StringBuilder sb = new StringBuilder();
// while ((i=fi.read()) != -1)
// sb.append((char)i);
// System.out.println("******************************************************************");
// System.out.println(sb.toString());
// System.out.println("******************************************************************");
// } catch (Exception e) {
// e.printStackTrace();
// }
//Pick the written file and send
File filePath = context.getFilesDir();
File fileToSend = new File(filePath, filename);
Uri fileUri = FileProvider.getUriForFile(context,
"com.sudogeeks.talking_reminder.fileprovider", fileToSend); //TODO remove hardcoded dependencies
Intent share = new Intent();
share.setAction(Intent.ACTION_SEND);
share.putExtra(Intent.EXTRA_STREAM, fileUri);
share.setType("text/" + Utility.FILE_EXTENSION);
//share.setDataAndType( fileUri, getContentResolver().getType(fileUri));
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//share.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
//share.putExtra(MediaStore.)
Intent shareIntent = Intent.createChooser(share, null);
startActivity(shareIntent);
//TODO delete the file once job is done
default:
return super.onOptionsItemSelected(item);
}
}
}
\ No newline at end of file
package com.sudogeeks.talking_reminder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
// ReminderDO class
//@Data
@Data
/**\brief Data Object class for Reminder
* This class conatins all the attributes of reminder.
*
*/
public class ReminderDO {
private int mID;
private String mTitle;
private String mDate;
private String mTime;
private String mRepeat;
private String mRepeatNo;
private String mRepeatType;
private String mActive;
private String ownerID = null; //Email Id of the owner/creater of the reminder
private String receiverID = null; //Email Id of the receiver of the reminder;
public ReminderDO(int ID, String Title, String Date, String Time, String Repeat, String RepeatNo, String RepeatType, String Active) {
mID = ID;
mTitle = Title;
mDate = Date;
mTime = Time;
mRepeat = Repeat;
mRepeatNo = RepeatNo;
mRepeatType = RepeatType;
mActive = Active;
}
public ReminderDO(String Title, String Date, String Time, String Repeat, String RepeatNo, String RepeatType, String Active) {
mTitle = Title;
mDate = Date;
mTime = Time;
mRepeat = Repeat;
mRepeatNo = RepeatNo;
mRepeatType = RepeatType;
mActive = Active;
}
ReminderDO() {
}
public String getOwnerID() {
return ownerID;
}
public void setOwnerID(String ownerID) {
this.ownerID = ownerID;
}
public String getReceiverID() {
return receiverID;
}
public void setReceiverID(String receiverID) {
this.receiverID = receiverID;
}
public int getID() {
return mID;
}
public void setID(int ID) {
mID = ID;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public String getDate() {
return mDate;
}
public void setDate(String date) {
mDate = date;
}
public String getTime() {
return mTime;
}
public void setTime(String time) {
mTime = time;
}
public String getRepeatType() {
return mRepeatType;
}
public void setRepeatType(String repeatType) {
mRepeatType = repeatType;
}
public String getRepeatNo() {
return mRepeatNo;
}
public void setRepeatNo(String repeatNo) {
mRepeatNo = repeatNo;
}
public String getRepeat() {
return mRepeat;
}
public void setRepeat(String repeat) {
mRepeat = repeat;
}
public String getActive() {
return mActive;
}
public void setActive(String active) {
mActive = active;
}
}
package com.sudogeeks.talking_reminder;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.List;
/**\brief Class to manage database
* This class is for managing the database
*/
public class ReminderDatabase extends SQLiteOpenHelper {
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "ReminderDatabase";
// Table name
private static final String TABLE_REMINDERS = "ReminderTable";
// Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_TITLE = "title";
private static final String KEY_DATE = "date";
private static final String KEY_TIME = "time";
private static final String KEY_REPEAT = "repeat";
private static final String KEY_REPEAT_NO = "repeat_no";
private static final String KEY_REPEAT_TYPE = "repeat_type";
private static final String KEY_ACTIVE = "active";
public ReminderDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* Creating Tables for reminder
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_REMINDERS_TABLE = "CREATE TABLE " + TABLE_REMINDERS +
"("
+ KEY_ID + " INTEGER PRIMARY KEY,"
+ KEY_TITLE + " TEXT,"
+ KEY_DATE + " TEXT,"
+ KEY_TIME + " INTEGER,"
+ KEY_REPEAT + " BOOLEAN,"
+ KEY_REPEAT_NO + " INTEGER,"
+ KEY_REPEAT_TYPE + " TEXT,"
+ KEY_ACTIVE + " BOOLEAN" + ")";
db.execSQL(CREATE_REMINDERS_TABLE);
}
/**
* Upgrading database
* @param db
* @param oldVersion
* @param newVersion
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
if (oldVersion >= newVersion)
return;
db.execSQL("DROP TABLE IF EXISTS " + TABLE_REMINDERS);
// Create tables again
onCreate(db);
}
/**
* This method is for adding ReminderDO into the reminder table in database
* @param reminderDO
* @return
*/
public int addReminder(ReminderDO reminderDO) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TITLE, reminderDO.getTitle());
values.put(KEY_DATE, reminderDO.getDate());
values.put(KEY_TIME, reminderDO.getTime());
values.put(KEY_REPEAT, reminderDO.getRepeat());
values.put(KEY_REPEAT_NO, reminderDO.getRepeatNo());
values.put(KEY_REPEAT_TYPE, reminderDO.getRepeatType());
values.put(KEY_ACTIVE, reminderDO.getActive());
// Inserting Row
long ID = db.insert(TABLE_REMINDERS, null, values);
db.close();
return (int) ID;
}
/**
* To get single ReminderDO corresponding to the id in parameter
* @param id
* @return reminderDo
*/
public ReminderDO getReminder(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_REMINDERS, new String[]
{
KEY_ID,
KEY_TITLE,
KEY_DATE,
KEY_TIME,
KEY_REPEAT,
KEY_REPEAT_NO,
KEY_REPEAT_TYPE,
KEY_ACTIVE
}, KEY_ID + "=?",
new String[]{String.valueOf(id)}, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
ReminderDO reminderDO = new ReminderDO(Integer.parseInt(cursor.getString(0)), cursor.getString(1),
cursor.getString(2), cursor.getString(3), cursor.getString(4),
cursor.getString(5), cursor.getString(6), cursor.getString(7));
return reminderDO;
}
/**
* This method is for getting all reminders for a particular user
* @return List of <ReminderDo>
*/
// Getting all Reminders
public List<ReminderDO> getAllReminders() {
List<ReminderDO> reminderDOList = new ArrayList<>();
// Select all Query
String selectQuery = "SELECT * FROM " + TABLE_REMINDERS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
ReminderDO reminderDO = new ReminderDO();
reminderDO.setID(Integer.parseInt(cursor.getString(0)));
reminderDO.setTitle(cursor.getString(1));
reminderDO.setDate(cursor.getString(2));
reminderDO.setTime(cursor.getString(3));
reminderDO.setRepeat(cursor.getString(4));
reminderDO.setRepeatNo(cursor.getString(5));
reminderDO.setRepeatType(cursor.getString(6));
reminderDO.setActive(cursor.getString(7));
// Adding Reminders to list
reminderDOList.add(reminderDO);
} while (cursor.moveToNext());
}
return reminderDOList;
}
/**
* This method is for Getting Reminders Count
* @return reminder count
*/
public int getRemindersCount() {
String countQuery = "SELECT * FROM " + TABLE_REMINDERS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
cursor.close();
return cursor.getCount();
}
/**
* This method is for updating single ReminderDO
* @param reminderDO
* @return
*/
public int updateReminder(ReminderDO reminderDO) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TITLE, reminderDO.getTitle());
values.put(KEY_DATE, reminderDO.getDate());
values.put(KEY_TIME, reminderDO.getTime());
values.put(KEY_REPEAT, reminderDO.getRepeat());
values.put(KEY_REPEAT_NO, reminderDO.getRepeatNo());
values.put(KEY_REPEAT_TYPE, reminderDO.getRepeatType());
values.put(KEY_ACTIVE, reminderDO.getActive());
// Updating row
return db.update(TABLE_REMINDERS, values, KEY_ID + "=?",
new String[]{String.valueOf(reminderDO.getID())});
}
/**
* This method is for deleting single ReminderDo
* @param reminderDO
*/
public void deleteReminder(ReminderDO reminderDO) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_REMINDERS, KEY_ID + "=?",
new String[]{String.valueOf(reminderDO.getID())});
db.close();
}
}
package com.sudogeeks.talking_reminder;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.Calendar;
/** \brief Java class for handling UI component of Edit reminder layout
*
*/
public class ReminderEditActivity extends AppCompatActivity {
// Constant Intent String
public static final String EXTRA_REMINDER_ID = "Reminder_ID";
// Values for orientation change
private static final String KEY_TITLE = "title_key";
private static final String KEY_TIME = "time_key";
private static final String KEY_DATE = "date_key";
private static final String KEY_REPEAT = "repeat_key";
private static final String KEY_REPEAT_NO = "repeat_no_key";
private static final String KEY_REPEAT_TYPE = "repeat_type_key";
private static final String KEY_ACTIVE = "active_key";
// Constant values in milliseconds
private static final long milMinute = 60000L;
private static final long milHour = 3600000L;
private static final long milDay = 86400000L;
private static final long milWeek = 604800000L;
private static final long milMonth = 2592000000L;
private Toolbar mToolbar;
private EditText mTitleText;
private TextView mDateText, mTimeText, mRepeatText, mRepeatNoText, mRepeatTypeText;
private FloatingActionButton mFAB1;
private FloatingActionButton mFAB2;
private Switch mRepeatSwitch;
private String mTitle;
private String mTime;
private String mDate;
private String mRepeatNo;
private String mRepeatType;
private String mActive;
private String mRepeat;
private String[] mDateSplit;
private String[] mTimeSplit;
private int mReceivedID;
private int mYear, mMonth, mHour, mMinute, mDay;
private long mRepeatTime;
private Calendar mCalendar;
private ReminderDO mReceivedReminderDO;
private ReminderDatabase rb;
private AlarmReceiver mAlarmReceiver;
/**
*overrides onCreate method to get all the ui element
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_reminder);
// Initialize Views
mToolbar = findViewById(R.id.toolbar);
mTitleText = findViewById(R.id.reminder_title);
mDateText = findViewById(R.id.set_date);
mTimeText = findViewById(R.id.set_time);
mRepeatText = findViewById(R.id.set_repeat);
mRepeatNoText = findViewById(R.id.set_repeat_no);
mRepeatTypeText = findViewById(R.id.set_repeat_type);
mRepeatSwitch = findViewById(R.id.repeat_switch);
// Setup Toolbar
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle(R.string.activity_edit_reminder_label);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// Setup ReminderDO Title EditText
mTitleText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mTitle = s.toString().trim();
mTitleText.setError(null);
}
@Override
public void afterTextChanged(Editable s) {
}
});
// Get reminder id from intent
mReceivedID = Integer.parseInt(getIntent().getStringExtra(EXTRA_REMINDER_ID));
// Get reminder using reminder id
rb = new ReminderDatabase(this);
/*Intent intent = getIntent();
if(intent.getType().equals("text/"+Utility.FILE_EXTENSION)){
mReceivedReminderDO.setTitle(intent.getStringExtra("mTitle"));
System.out.println("**********************************");
System.out.println(mReceivedReminderDO.getTitle());
System.out.println("**********************************");
}
else {*/
// Get reminder id from intent
mReceivedReminderDO = rb.getReminder(mReceivedID);
//}
// Get values from reminder
mTitle = mReceivedReminderDO.getTitle();
mDate = mReceivedReminderDO.getDate();
mTime = mReceivedReminderDO.getTime();
mRepeat = mReceivedReminderDO.getRepeat();
mRepeatNo = mReceivedReminderDO.getRepeatNo();
mRepeatType = mReceivedReminderDO.getRepeatType();
mActive = mReceivedReminderDO.getActive();
// Setup TextViews using reminder values
mTitleText.setText(mTitle);
mDateText.setText(mDate);
mTimeText.setText(mTime);
mRepeatNoText.setText(mRepeatNo);
mRepeatTypeText.setText(mRepeatType);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
// To save state on device rotation
if (savedInstanceState != null) {
String savedTitle = savedInstanceState.getString(KEY_TITLE);
mTitleText.setText(savedTitle);
mTitle = savedTitle;
String savedTime = savedInstanceState.getString(KEY_TIME);
mTimeText.setText(savedTime);
mTime = savedTime;
String savedDate = savedInstanceState.getString(KEY_DATE);
mDateText.setText(savedDate);
mDate = savedDate;
String saveRepeat = savedInstanceState.getString(KEY_REPEAT);
mRepeatText.setText(saveRepeat);
mRepeat = saveRepeat;
String savedRepeatNo = savedInstanceState.getString(KEY_REPEAT_NO);
mRepeatNoText.setText(savedRepeatNo);
mRepeatNo = savedRepeatNo;
String savedRepeatType = savedInstanceState.getString(KEY_REPEAT_TYPE);
mRepeatTypeText.setText(savedRepeatType);
mRepeatType = savedRepeatType;
mActive = savedInstanceState.getString(KEY_ACTIVE);
}
if (mRepeat.equals("false")) {
mRepeatSwitch.setChecked(false);
mRepeatText.setText(R.string.repeat_off);
} else if (mRepeat.equals("true")) {
mRepeatSwitch.setChecked(true);
}
// Obtain Date and Time details
mCalendar = Calendar.getInstance();
mAlarmReceiver = new AlarmReceiver();
mDateSplit = mDate.split("/");
mTimeSplit = mTime.split(":");
mDay = Integer.parseInt(mDateSplit[0]);
mMonth = Integer.parseInt(mDateSplit[1]);
mYear = Integer.parseInt(mDateSplit[2]);
mHour = Integer.parseInt(mTimeSplit[0]);
mMinute = Integer.parseInt(mTimeSplit[1]);
}
// To save state on device rotation
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putCharSequence(KEY_TITLE, mTitleText.getText());
outState.putCharSequence(KEY_TIME, mTimeText.getText());
outState.putCharSequence(KEY_DATE, mDateText.getText());
outState.putCharSequence(KEY_REPEAT, mRepeatText.getText());
outState.putCharSequence(KEY_REPEAT_NO, mRepeatNoText.getText());
outState.putCharSequence(KEY_REPEAT_TYPE, mRepeatTypeText.getText());
outState.putCharSequence(KEY_ACTIVE, mActive);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
/**
* On clicking Time picker , to show time dialog for user to select time
* @param v
*/
public void setTime(View v) {
Calendar now = Calendar.getInstance();
TimePickerDialog timePickerDialog = new TimePickerDialog(this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay,
int minute) {
mHour = hourOfDay;
mMinute = minute;
if (minute < 10) {
mTime = hourOfDay + ":" + "0" + minute;
} else {
mTime = hourOfDay + ":" + minute;
}
mTimeText.setText(mTime);
}
}, mHour, mMinute, false);
timePickerDialog.show();
}
/**
* On clicking Date picker,to show date dialog for user to select date
* @param v
*/
public void setDate(View v) {
Calendar now = Calendar.getInstance();
DatePickerDialog datePickerDialog = new DatePickerDialog(this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
mDay = dayOfMonth;
mMonth = monthOfYear + 1;
mYear = year;
mDate = mDay + "/" + mMonth + "/" + mYear;
mDateText.setText(mDate);
}
}, mYear, mMonth, mDay);
datePickerDialog.show();
}
/**
* On clicking the repeat switch, to select for repeat alarm
* @param view
*/
public void onSwitchRepeat(View view) {
boolean on = ((Switch) view).isChecked();
if (on) {
mRepeat = "true";
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
} else {
mRepeat = "false";
mRepeatText.setText(R.string.repeat_off);
}
}
/**
* On clicking repeat type button, to select for repeat type like every minute, hour, day,month
* @param v
*/
public void selectRepeatType(View v) {
final String[] items = new String[5];
items[0] = "Minute";
items[1] = "Hour";
items[2] = "Day";
items[3] = "Week";
items[4] = "Month";
// Create List Dialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select Type");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
mRepeatType = items[item];
mRepeatTypeText.setText(mRepeatType);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
}
});
AlertDialog alert = builder.create();
alert.show();
}
/**
* On clicking set repeat interval
* @param v
*/
public void setRepeatNo(View v) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Enter Number");
// Create EditText box to input repeat number
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
alert.setView(input);
alert.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
if (input.getText().toString().length() == 0) {
mRepeatNo = Integer.toString(1);
mRepeatNoText.setText(mRepeatNo);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
} else {
mRepeatNo = input.getText().toString().trim();
mRepeatNoText.setText(mRepeatNo);
mRepeatText.setText("Every " + mRepeatNo + " " + mRepeatType + "(s)");
}
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing
}
});
alert.show();
}
/**
* To update reminder upon clicking update button
*/
// On clicking the update button
public void updateReminder() {
// Set new values in the reminder
mReceivedReminderDO.setTitle(mTitle);
mReceivedReminderDO.setDate(mDate);
mReceivedReminderDO.setTime(mTime);
mReceivedReminderDO.setRepeat(mRepeat);
mReceivedReminderDO.setRepeatNo(mRepeatNo);
mReceivedReminderDO.setRepeatType(mRepeatType);
mReceivedReminderDO.setActive(mActive);
// Update reminder
rb.updateReminder(mReceivedReminderDO);
// Set up calender for creating the notification
mCalendar.set(Calendar.MONTH, --mMonth);
mCalendar.set(Calendar.YEAR, mYear);
mCalendar.set(Calendar.DAY_OF_MONTH, mDay);
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
mCalendar.set(Calendar.SECOND, 0);
// Cancel existing notification of the reminder by using its ID
mAlarmReceiver.cancelAlarm(getApplicationContext(), mReceivedID);
// Check repeat type
if (mRepeatType.equals("Minute")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMinute;
} else if (mRepeatType.equals("Hour")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milHour;
} else if (mRepeatType.equals("Day")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milDay;
} else if (mRepeatType.equals("Week")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milWeek;
} else if (mRepeatType.equals("Month")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMonth;
}
// Create a new notification
if (mActive.equals("true")) {
if (mRepeat.equals("true")) {
mAlarmReceiver.setRepeatAlarm(getApplicationContext(), mCalendar, mReceivedID, mRepeatTime);
} else if (mRepeat.equals("false")) {
mAlarmReceiver.setAlarm(getApplicationContext(), mCalendar, mReceivedID);
}
}
// Create toast to confirm update
Toast.makeText(getApplicationContext(), "Edited",
Toast.LENGTH_SHORT).show();
onBackPressed();
}
/**
* On pressing the back button
*/
@Override
public void onBackPressed() {
super.onBackPressed();
}
/**
* Creating the menu
* @param menu
* @return true
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_add_reminder, menu);
return true;
}
/**
* On clicking menu buttons :Save reminder (to save reminder), send reminder(to send reminder), discard reminder(to discard reminder)
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// On clicking the back arrow
// Discard any changes
case android.R.id.home:
onBackPressed();
return true;
// On clicking save reminder button
// Update reminder
case R.id.save_reminder:
mTitleText.setText(mTitle);
if (mTitleText.getText().toString().length() == 0)
mTitleText.setError("ReminderDO Title cannot be blank!");
else {
updateReminder();
}
return true;
// On clicking discard reminder button
// Discard any changes
case R.id.discard_reminder:
Toast.makeText(getApplicationContext(), "Changes Discarded",
Toast.LENGTH_SHORT).show();
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
\ No newline at end of file
package com.sudogeeks.talking_reminder;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import org.json.JSONObject;
import java.io.InputStream;
import java.util.Calendar;
/**\brief Class to read and parse reminder Data after receiving
* This class parse the received reminder object and saves that in database and trigger alarm for that.
*/
public class ReminderReceiveActivity extends AppCompatActivity {
private static final long milMinute = 60000L;
private static final long milHour = 3600000L;
private static final long milDay = 86400000L;
private static final long milWeek = 604800000L;
private static final long milMonth = 2592000000L;
private Toolbar mToolbar;
private EditText mTitleText;
private TextView mDateText, mTimeText, mRepeatText, mRepeatNoText, mRepeatTypeText;
private String mRepeat;
private String mRepeatType;
private String mRepeatNo;
private Calendar mCalendar;
private int mYear, mMonth, mHour, mMinute, mDay;
private long mRepeatTime;
private String mActive;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receive_reminder);
Context context = this;
mCalendar = Calendar.getInstance();
mHour = mCalendar.get(Calendar.HOUR_OF_DAY);
mMinute = mCalendar.get(Calendar.MINUTE);
mYear = mCalendar.get(Calendar.YEAR);
mMonth = mCalendar.get(Calendar.MONTH) + 1;
mDay = mCalendar.get(Calendar.DATE);
//by default
mActive = "true";
// Setup Toolbar
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle(R.string.activity_add_reminder_label);
//Get the file from intent
Intent intent = getIntent();
Uri fileUri = intent.getData();
StringBuilder reminderJson = new StringBuilder();
if (intent.getType().equals("text/" + Utility.FILE_EXTENSION)) {
try {
InputStream in = getContentResolver().openInputStream(fileUri);
int i;
while ((i = in.read()) != -1)
reminderJson.append((char) i);
//System.out.println("******************************************************************");
//System.out.println(sb.toString());
//System.out.println("******************************************************************");
} catch (Exception e) {
e.printStackTrace();
}
try {
JSONObject obj = new JSONObject(reminderJson.toString());
//ReminderDO talkingReminder=new ReminderDO();
mTitleText = findViewById(R.id.reminder_title);
mDateText = findViewById(R.id.set_date);
mTimeText = findViewById(R.id.set_time);
mRepeatText = findViewById(R.id.set_repeat);
mRepeatNoText = findViewById(R.id.set_repeat_no);
mRepeatTypeText = findViewById(R.id.set_repeat_type);
mRepeat = obj.getString("mRepeat");
mRepeatType = obj.getString("mRepeatType");
mRepeatNo = obj.getString("mRepeatNo");
mTitleText.setText(obj.getString("mTitle"));
mDateText.setText(obj.getString("mDate"));
mTimeText.setText(obj.getString("mTime"));
mRepeatText.setText("Every " + obj.getString("mRepeatNo") + " " + obj.getString("mRepeatType") + "(s)");
mRepeatNoText.setText(obj.getString("mRepeatNo"));
mRepeatTypeText.setText(obj.getString("mRepeatType"));
} catch (Throwable t) {
t.printStackTrace();
}
/*Intent senderIntent = new Intent(context, ReminderEditActivity.class);
senderIntent.putExtra("received", true);
senderIntent.putExtra("mTitle", "First Receive ReminderDO test");
startActivity(senderIntent);*/
}
}
/**
* This method populates the ui as received and then saves the reminder to database.
*/
public void saveSendReminder() {
ReminderDatabase rb = new ReminderDatabase(this);
// Creating ReminderDO
int ID = rb.addReminder(new ReminderDO(mTitleText.getText().toString(), mDateText.getText().toString(), mTimeText.getText().toString(), mRepeat, mRepeatNoText.getText().toString(), mRepeatTypeText.getText().toString(), mActive));
// Set up calender for creating the notification
mCalendar.set(Calendar.MONTH, --mMonth);
mCalendar.set(Calendar.YEAR, mYear);
mCalendar.set(Calendar.DAY_OF_MONTH, mDay);
mCalendar.set(Calendar.HOUR_OF_DAY, mHour);
mCalendar.set(Calendar.MINUTE, mMinute);
mCalendar.set(Calendar.SECOND, 0);
// Check repeat type
if (mRepeatType.equals("Minute")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMinute;
} else if (mRepeatType.equals("Hour")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milHour;
} else if (mRepeatType.equals("Day")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milDay;
} else if (mRepeatType.equals("Week")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milWeek;
} else if (mRepeatType.equals("Month")) {
mRepeatTime = Integer.parseInt(mRepeatNo) * milMonth;
}
// Create a new notification
if (mActive.equals("true")) {
if (mRepeat.equals("true")) {
new AlarmReceiver().setRepeatAlarm(getApplicationContext(), mCalendar, ID, mRepeatTime);
} else if (mRepeat.equals("false")) {
new AlarmReceiver().setAlarm(getApplicationContext(), mCalendar, ID);
}
}
// Create toast to confirm new reminder
Toast.makeText(getApplicationContext(), "Saved",
Toast.LENGTH_SHORT).show();
onBackPressed();
}
// Creating the menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_receive_reminder, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// On clicking the back arrow
// Discard any changes
case android.R.id.home:
onBackPressed();
return true;
// On clicking save reminder button
// Update reminder
case R.id.save_reminder:
saveSendReminder();
default:
return super.onOptionsItemSelected(item);
}
}
}
package com.sudogeeks.talking_reminder;
public class Utility {
public static final String FILE_NAME_PREFIX = "Talking_Reminder";
public static final String FILE_EXTENSION = "tprd";
}
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M22,5.72l-4.6,-3.86 -1.29,1.53 4.6,3.86L22,5.72zM7.88,3.39L6.6,1.86 2,5.71l1.29,1.53 4.59,-3.85zM12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7zM10.54,14.53L8.41,12.4l-1.06,1.06 3.18,3.18 6,-6 -1.06,-1.06 -4.93,4.95z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M9,11L7,11v2h2v-2zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM19,4h-1L18,2h-2v2L8,4L8,2L6,2v2L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20L5,9h14v11z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/>
</vector>
<vector android:height="24dp" android:tint="#C8C8C8"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M20,18.69L7.84,6.14 5.27,3.49 4,4.76l2.8,2.8v0.01c-0.52,0.99 -0.8,2.16 -0.8,3.42v5l-2,2v1h13.73l2,2L21,19.72l-1,-1.03zM12,22c1.11,0 2,-0.89 2,-2h-4c0,1.11 0.89,2 2,2zM18,14.68L18,11c0,-3.08 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.15,0.03 -0.29,0.08 -0.42,0.12 -0.1,0.03 -0.2,0.07 -0.3,0.11h-0.01c-0.01,0 -0.01,0 -0.02,0.01 -0.23,0.09 -0.46,0.2 -0.68,0.31 0,0 -0.01,0 -0.01,0.01L18,14.68z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,18.69L7.84,6.14 5.27,3.49 4,4.76l2.8,2.8v0.01c-0.52,0.99 -0.8,2.16 -0.8,3.42v5l-2,2v1h13.73l2,2L21,19.72l-1,-1.03zM12,22c1.11,0 2,-0.89 2,-2h-4c0,1.11 0.89,2 2,2zM18,14.68L18,11c0,-3.08 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.15,0.03 -0.29,0.08 -0.42,0.12 -0.1,0.03 -0.2,0.07 -0.3,0.11h-0.01c-0.01,0 -0.01,0 -0.02,0.01 -0.23,0.09 -0.46,0.2 -0.68,0.31 0,0 -0.01,0 -0.01,0.01L18,14.68z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,15h18v-2L3,13v2zM3,19h18v-2L3,17v2zM3,11h18L21,9L3,9v2zM3,5v2h18L21,5L3,5z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
</vector>
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
</vector>
<vector android:height="24dp" android:tint="#646464"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M15,1L9,1v2h6L15,1zM11,14h2L13,8h-2v6zM19.03,7.39l1.42,-1.42c-0.43,-0.51 -0.9,-0.99 -1.41,-1.41l-1.42,1.42C16.07,4.74 14.12,4 12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9 9,-4.03 9,-9c0,-2.12 -0.74,-4.07 -1.97,-5.61zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
</vector>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@android:color/transparent"
android:endColor="#88333333"
android:angle="90"/>
</shape>
\ No newline at end of file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:contentInsetLeft="0dp"
app:contentInsetStart="16dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<LinearLayout
android:id="@+id/add_reminder_layout_top"
android:layout_width="match_parent"
android:layout_height="148dp"
android:layout_below="@+id/toolbar"
android:background="@color/primary"
android:orientation="vertical"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<EditText
android:id="@+id/reminder_title"
android:layout_width="match_parent"
android:layout_height="140dp"
android:layout_marginLeft="72dp"
android:layout_marginRight="16dp"
android:gravity="top|left"
android:hint="@string/add_reminder"
android:inputType="textCapWords|textMultiLine"
android:lines="4"
android:minLines="4"
android:scrollHorizontally="false"
android:textColor="@android:color/white"
android:textColorHint="@color/primary_text_disabled_material_dark"
android:textSize="25dp" />
</LinearLayout>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/add_reminder_layout_top">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_marginLeft="72dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:text="@string/details"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
<RelativeLayout
android:id="@+id/date"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:onClick="setDate">
<ImageView
android:id="@+id/date_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_date_range" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/date_icon"
android:orientation="vertical">
<TextView
android:id="@+id/date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/date"
android:textColor="@color/abc_primary_text_material_dark"
android:textSize="15dp" />
<TextView
android:id="@+id/set_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/time"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:onClick="setTime">
<ImageView
android:id="@+id/time_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_timer" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/time_icon"
android:orientation="vertical">
<TextView
android:id="@+id/time_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/time"
android:textColor="@color/abc_primary_text_material_dark"
android:textSize="15dp" />
<TextView
android:id="@+id/set_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/repeat"
android:layout_width="match_parent"
android:layout_height="72dp">
<ImageView
android:id="@+id/repeat_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_repeat" />
<LinearLayout
android:id="@+id/repeat_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_icon"
android:orientation="vertical">
<TextView
android:id="@+id/repeat_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/repeat"
android:textColor="@color/abc_primary_text_material_dark"
android:textSize="15dp" />
<TextView
android:id="@+id/set_repeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
</LinearLayout>
<Switch
android:id="@+id/repeat_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:layout_marginRight="16dp"
android:checked="false"
android:onClick="onSwitchRepeat"
android:textOff="Off"
android:textOn="On" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/RepeatNo"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:onClick="setRepeatNo">
<ImageView
android:id="@+id/repeat_no_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_loop" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_no_icon"
android:orientation="vertical">
<TextView
android:id="@+id/repeat_no_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/repeat_no"
android:textColor="@color/abc_primary_text_material_dark"
android:textSize="15dp" />
<TextView
android:id="@+id/set_repeat_no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/RepeatType"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:onClick="selectRepeatType">
<ImageView
android:id="@+id/repeat_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_reorder" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_type_icon"
android:orientation="vertical">
<TextView
android:id="@+id/repeat_type_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/repeat_type"
android:textColor="@color/abc_primary_text_material_dark"
android:textSize="15dp" />
<TextView
android:id="@+id/set_repeat_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/abc_secondary_text_material_dark"
android:textSize="15dp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@+id/add_reminder_layout_top"
android:background="@drawable/toolbar_dropshadow" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/starred1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="8dp"
android:layout_marginTop="168dp"
android:clickable="true"
android:icon="@drawable/ic_notifications_off"
android:onClick="selectFab1" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/starred2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="8dp"
android:layout_marginTop="168dp"
android:clickable="true"
android:icon="@drawable/ic_notifications_active"
android:onClick="selectFab2" />
</RelativeLayout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
app:contentInsetLeft="0dp"
app:contentInsetStart="16dp"
android:theme="@style/AppTheme.NoActionBar"
android:background="?attr/colorPrimary" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/reminder_list"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/no_reminder_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="16dp"
android:gravity="center"
android:visibility="gone"
android:text="@string/no_reminders"/>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@+id/toolbar"
android:background="@drawable/toolbar_dropshadow" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_reminder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:clickable="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_add"/>
</RelativeLayout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:contentInsetLeft="0dp"
app:contentInsetStart="16dp"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:background="?attr/colorPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_below="@+id/toolbar"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:id="@+id/add_reminder_layout_top"
android:background="@color/primary"
android:orientation="vertical"
android:layout_height="148dp">
<EditText
android:layout_width="match_parent"
android:id="@+id/reminder_title"
android:layout_marginLeft="72dp"
android:hint="@string/add_reminder"
android:textSize="25dp"
android:lines="4"
android:minLines="4"
android:gravity="top|left"
android:textColor="@android:color/white"
android:scrollHorizontally="false"
android:textColorHint="@color/primary_text_disabled_material_dark"
android:inputType="textCapWords|textMultiLine"
android:layout_marginRight="16dp"
android:layout_height="140dp"/>
</LinearLayout>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_below="@id/add_reminder_layout_top"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_marginTop="8dp"
android:text="@string/details"
android:id="@+id/details"
android:textSize="15dp"
android:gravity="center_vertical"
android:layout_marginLeft="72dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="72dp"/>
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/date"
android:background="?android:attr/selectableItemBackground"
android:layout_height="72dp">
<ImageView
android:id="@+id/date_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_date_range"
android:layout_centerVertical="true" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/date_icon"
android:layout_height="wrap_content">
<TextView
android:id="@+id/date_text"
android:textColor="@color/abc_primary_text_material_dark"
android:layout_width="wrap_content"
android:textSize="15dp"
android:layout_height="wrap_content"
android:text="@string/date" />
<TextView
android:layout_width="wrap_content"
android:id="@+id/set_date"
android:textSize="15dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/time"
android:background="?android:attr/selectableItemBackground"
android:layout_height="72dp">
<ImageView
android:id="@+id/time_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_timer"
android:layout_centerVertical="true" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/time_icon"
android:layout_height="wrap_content">
<TextView
android:id="@+id/time_text"
android:textColor="@color/abc_primary_text_material_dark"
android:layout_width="wrap_content"
android:textSize="15dp"
android:layout_height="wrap_content"
android:text="@string/time" />
<TextView
android:layout_width="wrap_content"
android:id="@+id/set_time"
android:textSize="15dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/repeat"
android:layout_height="72dp">
<ImageView
android:id="@+id/repeat_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_repeat"
android:layout_centerVertical="true" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:id="@+id/repeat_ll"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_icon"
android:layout_height="wrap_content">
<TextView
android:id="@+id/repeat_text"
android:textColor="@color/abc_primary_text_material_dark"
android:layout_width="wrap_content"
android:textSize="15dp"
android:layout_height="wrap_content"
android:text="@string/repeat" />
<TextView
android:layout_width="wrap_content"
android:id="@+id/set_repeat"
android:textSize="15dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="wrap_content"/>
</LinearLayout>
<Switch
android:id="@+id/repeat_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginLeft="8dp"
android:checked="true"
android:textOn="On"
android:textOff="Off"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/RepeatNo"
android:background="?android:attr/selectableItemBackground"
android:layout_height="72dp">
<ImageView
android:id="@+id/repeat_no_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_loop"
android:layout_centerVertical="true" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_no_icon"
android:layout_height="wrap_content">
<TextView
android:id="@+id/repeat_no_text"
android:textColor="@color/abc_primary_text_material_dark"
android:layout_width="wrap_content"
android:textSize="15dp"
android:layout_height="wrap_content"
android:text="@string/repeat_no" />
<TextView
android:layout_width="wrap_content"
android:id="@+id/set_repeat_no"
android:textSize="15dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:id="@+id/RepeatType"
android:background="?android:attr/selectableItemBackground"
android:layout_height="72dp">
<ImageView
android:id="@+id/repeat_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="32dp"
android:src="@drawable/ic_reorder"
android:layout_centerVertical="true" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/repeat_type_icon"
android:layout_height="wrap_content">
<TextView
android:id="@+id/repeat_type_text"
android:textColor="@color/abc_primary_text_material_dark"
android:layout_width="wrap_content"
android:textSize="15dp"
android:layout_height="wrap_content"
android:text="@string/repeat_type" />
<TextView
android:layout_width="wrap_content"
android:id="@+id/set_repeat_type"
android:textSize="15dp"
android:textColor="@color/abc_secondary_text_material_dark"
android:layout_height="wrap_content"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@+id/add_reminder_layout_top"
android:background="@drawable/toolbar_dropshadow" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/starred1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="selectFab1"
android:icon="@drawable/ic_notifications_off"
android:layout_alignParentLeft="true"
android:layout_marginTop="168dp"
android:layout_centerHorizontal="true"
android:layout_marginLeft="8dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/starred2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="selectFab2"
android:icon="@drawable/ic_notifications_active"
android:layout_alignParentLeft="true"
android:layout_marginTop="168dp"
android:layout_centerHorizontal="true"
android:layout_marginLeft="8dp"/>
</RelativeLayout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="?android:attr/selectableItemBackground"
android:layout_height="86dp">
<ImageView android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_centerVertical="true"
android:id="@+id/thumbnail_image"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_toRightOf="@id/thumbnail_image"
android:layout_toLeftOf="@+id/active_image"
android:orientation="vertical">
<TextView
android:id="@+id/recycle_title"
android:layout_width="match_parent"
android:ellipsize="end"
android:maxLines="2"
android:layout_height="wrap_content"
android:textColor="@color/abc_primary_text_material_dark"
tools:text="Title"
android:textSize="16dp"/>
<TextView
android:id="@+id/recycle_date_time"
android:layout_width="match_parent"
android:ellipsize="marquee"
android:singleLine="true"
android:layout_height="wrap_content"
android:textSize="13dp"
android:textColor="@color/abc_secondary_text_material_dark"
tools:text="Date and Time"/>
<TextView
android:id="@+id/recycle_repeat_info"
android:layout_width="match_parent"
android:ellipsize="marquee"
android:singleLine="true"
android:layout_height="wrap_content"
android:textSize="13dp"
android:textColor="@color/abc_secondary_text_material_dark"
tools:text="Repeat No and Type"/>
</LinearLayout>
<ImageView android:layout_width="wrap_content"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_notifications_off"
android:layout_centerVertical="true"
android:id="@+id/active_image"/>
</RelativeLayout>
\ No newline at end of file
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.sudogeeks.talking_reminder.MainActivity">
<item
android:id="@+id/sign_out"
android:orderInCategory="100"
android:title="@string/sign_out"
app:showAsAction="never" />
</menu>
\ No newline at end of file
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/discard_reminder"
android:icon="@drawable/ic_delete_white"
android:title="@string/action_discard_reminder"
app:showAsAction="ifRoom" />
<item android:id="@+id/send_reminder"
android:icon="@drawable/ic_send"
android:title="@string/action_discard_reminder"
app:showAsAction="ifRoom" />
<item android:id="@+id/save_reminder"
android:icon="@drawable/ic_save_white"
android:title="@string/action_save_reminder"
app:showAsAction="ifRoom" />
</menu>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/save_reminder"
android:icon="@drawable/ic_save_white"
android:title="@string/action_save_reminder"
app:showAsAction="ifRoom" />
</menu>
\ No newline at end of file
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<item name="windowActionModeOverlay">true</item>
<item name="android:actionModeBackground">@color/primary</item>
</style>
</resources>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/primary_dark</item>
<item name="android:actionBarPopupTheme">@style/ThemeOverlay.AppCompat</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:actionModeBackground">@color/primary</item>
</style>
</resources>
<resources>
<color name="primary">#008577</color>
<color name="primary_dark">#00574B</color>
<color name="accent">#D81B60</color>
<color name="textheader">#ffffff</color>
<color name="textbody">#000000</color>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">Talking Reminder</string>
<string name="activity_add_reminder_label">Add Reminder</string>
<string name="activity_edit_reminder_label">Edit Reminder</string>
<string name="add_reminder">Reminder</string>
<string name="details">Details</string>
<string name="date">Date</string>
<string name="time">Time</string>
<string name="repeat">Repeat</string>
<string name="repeat_off">Off</string>
<string name="repeat_no">Repetition Interval </string>
<string name="repeat_type">Type of Repetitions</string>
<string name="action_discard_reminder">Discard Reminder</string>
<string name="action_save_reminder">Save Reminder</string>
<string name="no_reminders">Click on the plus button below to begin creating your reminderDOS!</string>
<string name="sign_out">sign_out</string>
</resources>
<resources>
<!-- Base application theme. -->
<!-- <style name="AppTheme" parent="AppTheme.Base"/>-->
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.Base" parent="Theme.AppCompat.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primary_dark</item>
<item name="colorAccent">@color/accent</item>
<item name="actionModeBackground">@color/primary</item>
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionModeOverlay">true</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<root-path
name="root"
path="." />
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
\ No newline at end of file
## Compiled JavaScript files
**/*.js
**/*.js.map
# Typescript v1 declaration files
typings/
node_modules/
\ No newline at end of file
{
"name": "functions",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@babel/code-frame": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
"integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
"dev": true,
"requires": {
"@babel/highlight": "^7.0.0"
}
},
"@babel/highlight": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
"integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@firebase/app-types": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.4.8.tgz",
"integrity": "sha512-VTjWRooelMExK/rKArp6WqnWJJfi8Vs6VuDYDSeMcQ3NpSux2bW1dfJFuzYmiK1+37hEJP1F43DyUDv2lCJquw=="
},
"@firebase/database": {
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.13.tgz",
"integrity": "sha512-B1+6Ns3jbpryDUi6ZohByXk8EPcuD5rUla1UchzdCjsU1waq06QyUrakow5Hr5RugqmziMAOfzpXid+wV4+bvw==",
"requires": {
"@firebase/database-types": "0.4.8",
"@firebase/logger": "0.1.31",
"@firebase/util": "0.2.34",
"faye-websocket": "0.11.3",
"tslib": "1.10.0"
}
},
"@firebase/database-types": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.4.8.tgz",
"integrity": "sha512-bYGzvcwjGOSWuL43nldY3kD3ldPDLTiiOF0TItsJx2JdL58PzGiGaR71dvPJhueNBn+bwJ5KPJxpqTSVqM/j8w==",
"requires": {
"@firebase/app-types": "0.4.8"
}
},
"@firebase/logger": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.31.tgz",
"integrity": "sha512-1OEJaCMMaaT0VleNwer3bocbd25beR6KZUaHBweLNHEFxaNvniSv+lm83g08dWLBml3ZVOb945hp6m8REFx6/Q=="
},
"@firebase/util": {
"version": "0.2.34",
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.34.tgz",
"integrity": "sha512-k8pNIzNLncvxDrqYVZN6/lnqZWy0OCJuZmK5urodARwdLy3sVLw5p9PWce0v9qzMO8tLdrBbCpnm1KJ8jg/kBQ==",
"requires": {
"tslib": "1.10.0"
}
},
"@google-cloud/common": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.2.3.tgz",
"integrity": "sha512-lvw54mGKn8VqVIy2NzAk0l5fntBFX4UwQhHk6HaqkyCQ7WBl5oz4XhzKMtMilozF/3ObPcDogqwuyEWyZ6rnQQ==",
"optional": true,
"requires": {
"@google-cloud/projectify": "^1.0.0",
"@google-cloud/promisify": "^1.0.0",
"arrify": "^2.0.0",
"duplexify": "^3.6.0",
"ent": "^2.2.0",
"extend": "^3.0.2",
"google-auth-library": "^5.5.0",
"retry-request": "^4.0.0",
"teeny-request": "^5.2.1"
}
},
"@google-cloud/firestore": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-2.6.0.tgz",
"integrity": "sha512-5bpC7KZA+dCc+4Byp9yA7uvmM1kmVaXm6QiSQbf2Zz/rWftTr0N23f+5BKe9OXyY/nT44l2ygZjmP4Aw3ngLFg==",
"optional": true,
"requires": {
"bun": "^0.0.12",
"deep-equal": "^1.0.1",
"functional-red-black-tree": "^1.0.1",
"google-gax": "^1.7.5",
"through2": "^3.0.0"
}
},
"@google-cloud/paginator": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-2.0.2.tgz",
"integrity": "sha512-PCddVtZWvw0iZ3BLIsCXMBQvxUcS9O5CgfHBu8Zd8T3DCiML+oQED1odsbl3CQ9d3RrvBaj+eIh7Dv12D15PbA==",
"optional": true,
"requires": {
"arrify": "^2.0.0",
"extend": "^3.0.2"
}
},
"@google-cloud/projectify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-1.0.2.tgz",
"integrity": "sha512-WnkGxvk4U1kAJpoS/Ehk+3MZXVW+XHHhwc/QyD6G8Za4xml3Fv+NRn/bYffl1TxSg+gE0N0mj9Shgc7e8+fl8A==",
"optional": true
},
"@google-cloud/promisify": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.3.tgz",
"integrity": "sha512-Rufgfl3TnkIil3CjsH33Q6093zeoVqyqCdvtvgHuCqRJxCZYfaVPIyr8JViMeLTD4Ja630pRKKZVSjKggoVbNg==",
"optional": true
},
"@google-cloud/storage": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-4.1.3.tgz",
"integrity": "sha512-79Ag+4eQq+KFJcKB85AimepoqTJOGuDLAmJd7JkLc8NM12a87JTCoGi65oi1eZ4H77AV0uUQxSS2Fo/hZL3+kQ==",
"optional": true,
"requires": {
"@google-cloud/common": "^2.1.1",
"@google-cloud/paginator": "^2.0.0",
"@google-cloud/promisify": "^1.0.0",
"arrify": "^2.0.0",
"compressible": "^2.0.12",
"concat-stream": "^2.0.0",
"date-and-time": "^0.11.0",
"duplexify": "^3.5.0",
"extend": "^3.0.2",
"gaxios": "^2.0.1",
"gcs-resumable-upload": "^2.2.4",
"hash-stream-validation": "^0.2.2",
"mime": "^2.2.0",
"mime-types": "^2.0.8",
"onetime": "^5.1.0",
"p-limit": "^2.2.0",
"pumpify": "^2.0.0",
"readable-stream": "^3.4.0",
"snakeize": "^0.1.0",
"stream-events": "^1.0.1",
"through2": "^3.0.0",
"xdg-basedir": "^4.0.0"
},
"dependencies": {
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"optional": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"requires": {
"safe-buffer": "~5.2.0"
}
}
}
},
"@grpc/grpc-js": {
"version": "0.6.9",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.6.9.tgz",
"integrity": "sha512-r1nDOEEiYmAsVYBaS4DPPqdwPOXPw7YhVOnnpPdWhlNtKbYzPash6DqWTTza9gBiYMA5d2Wiq6HzrPqsRaP4yA==",
"optional": true,
"requires": {
"semver": "^6.2.0"
}
},
"@grpc/proto-loader": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.3.tgz",
"integrity": "sha512-8qvUtGg77G2ZT2HqdqYoM/OY97gQd/0crSG34xNmZ4ZOsv3aQT/FQV9QfZPazTGna6MIoyUd+u6AxsoZjJ/VMQ==",
"optional": true,
"requires": {
"lodash.camelcase": "^4.3.0",
"protobufjs": "^6.8.6"
}
},
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=",
"optional": true
},
"@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
"optional": true
},
"@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
"optional": true
},
"@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=",
"optional": true
},
"@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
"optional": true,
"requires": {
"@protobufjs/aspromise": "^1.1.1",
"@protobufjs/inquire": "^1.1.0"
}
},
"@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=",
"optional": true
},
"@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=",
"optional": true
},
"@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=",
"optional": true
},
"@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=",
"optional": true
},
"@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
"optional": true
},
"@types/body-parser": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz",
"integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==",
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/connect": {
"version": "3.4.32",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
"integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==",
"requires": {
"@types/node": "*"
}
},
"@types/express": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
"integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==",
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "*",
"@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.0.tgz",
"integrity": "sha512-Xnub7w57uvcBqFdIGoRg1KhNOeEj0vB6ykUM7uFWyxvbdE89GFyqgmUcanAriMr4YOxNFZBAWkfcWIb4WBPt3g==",
"requires": {
"@types/node": "*",
"@types/range-parser": "*"
}
},
"@types/lodash": {
"version": "4.14.149",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
"integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==",
"dev": true
},
"@types/long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz",
"integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==",
"optional": true
},
"@types/mime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
"integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw=="
},
"@types/node": {
"version": "8.10.59",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
"integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ=="
},
"@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
},
"@types/serve-static": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
"integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
"requires": {
"@types/express-serve-static-core": "*",
"@types/mime": "*"
}
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"optional": true,
"requires": {
"event-target-shim": "^5.0.0"
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"optional": true,
"requires": {
"es6-promisify": "^5.0.0"
}
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
"optional": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
"optional": true
},
"bignumber.js": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz",
"integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==",
"optional": true
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"optional": true
},
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
"bun": {
"version": "0.0.12",
"resolved": "https://registry.npmjs.org/bun/-/bun-0.0.12.tgz",
"integrity": "sha512-Toms18J9DqnT+IfWkwxVTB2EaBprHvjlMWrTIsfX4xbu3ZBqVBwrERU0em1IgtRe04wT+wJxMlKHZok24hrcSQ==",
"optional": true,
"requires": {
"readable-stream": "~1.0.32"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"compressible": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
"integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
"optional": true,
"requires": {
"mime-db": ">= 1.40.0 < 2"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"optional": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
},
"dependencies": {
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"optional": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"requires": {
"safe-buffer": "~5.2.0"
}
}
}
},
"configstore": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.0.tgz",
"integrity": "sha512-eE/hvMs7qw7DlcB5JPRnthmrITuHMmACUJAp89v6PT6iOqzoLS7HRWhBtuHMlhNHo2AhUSA/3Dh1bKNJHcublQ==",
"optional": true,
"requires": {
"dot-prop": "^5.1.0",
"graceful-fs": "^4.1.2",
"make-dir": "^3.0.0",
"unique-string": "^2.0.0",
"write-file-atomic": "^3.0.0",
"xdg-basedir": "^4.0.0"
}
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"requires": {
"safe-buffer": "5.1.2"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
},
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
"optional": true
},
"date-and-time": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.11.0.tgz",
"integrity": "sha512-VyzhHurex4wlg9oMszn7O+kxHchphWjzDn7Mv0WfkFKI6hSNOQePpTBFGsnRakvLNzQKXqPBAVV8DOxUGtUxqA==",
"optional": true
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"optional": true,
"requires": {
"ms": "^2.1.1"
}
},
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"optional": true,
"requires": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
}
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"optional": true,
"requires": {
"object-keys": "^1.0.12"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dicer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz",
"integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==",
"requires": {
"streamsearch": "0.1.2"
}
},
"diff": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
"dev": true
},
"dot-prop": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
"integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
"optional": true,
"requires": {
"is-obj": "^2.0.0"
}
},
"duplexify": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
"integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
"optional": true,
"requires": {
"end-of-stream": "^1.0.0",
"inherits": "^2.0.1",
"readable-stream": "^2.0.0",
"stream-shift": "^1.0.0"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"optional": true
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"optional": true,
"requires": {
"once": "^1.4.0"
}
},
"ent": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
"integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
"optional": true
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
"optional": true
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"optional": true,
"requires": {
"es6-promise": "^4.0.3"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"optional": true
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"optional": true
},
"fast-text-encoding": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz",
"integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==",
"optional": true
},
"faye-websocket": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
"integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
"requires": {
"websocket-driver": ">=0.5.1"
}
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"firebase-admin": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-8.8.0.tgz",
"integrity": "sha512-IKtyL7doZu3Sh3pCz+O7vFWc/UwxEfXe263X/bPbucu/qEsM+5UdljIklnInSMunO+A1BUXKtsKkQf91iZQ2Ew==",
"requires": {
"@firebase/database": "^0.5.11",
"@google-cloud/firestore": "^2.6.0",
"@google-cloud/storage": "^4.1.2",
"@types/node": "^8.0.53",
"dicer": "^0.3.0",
"jsonwebtoken": "8.1.0",
"node-forge": "0.7.4"
}
},
"firebase-functions": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.3.0.tgz",
"integrity": "sha512-dP6PCG+OwR6RtFpOqwPsLnfiCr3CwXAm/SVGMbO53vDAk0nhUQ1WGAyHDYmIyMAkaLJkIKGwDnX7XmZ5+yAg7g==",
"requires": {
"@types/express": "^4.17.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.14"
},
"dependencies": {
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
}
},
"firebase-functions-test": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/firebase-functions-test/-/firebase-functions-test-0.1.7.tgz",
"integrity": "sha512-/zVQhaUZ+M7z25aUaZSIah0MIDZIfnRfQxtHYTE8hgUgODmKdaMX20vh5Gv23hnCPauIHuYb7XFTUOZiWU1udA==",
"dev": true,
"requires": {
"@types/lodash": "^4.14.104",
"lodash": "^4.17.5"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"optional": true
},
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"optional": true
},
"gaxios": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.1.0.tgz",
"integrity": "sha512-Gtpb5sdQmb82sgVkT2GnS2n+Kx4dlFwbeMYcDlD395aEvsLCSQXJJcHt7oJ2LrGxDEAeiOkK79Zv2A8Pzt6CFg==",
"optional": true,
"requires": {
"abort-controller": "^3.0.0",
"extend": "^3.0.2",
"https-proxy-agent": "^3.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.3.0"
}
},
"gcp-metadata": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.2.2.tgz",
"integrity": "sha512-vR7kcJMCYJG/mYWp/a1OszdOqnLB/XW1GorWW1hc1lWVNL26L497zypWb9cG0CYDQ4Bl1Wk0+fSZFFjwJlTQgQ==",
"optional": true,
"requires": {
"gaxios": "^2.1.0",
"json-bigint": "^0.3.0"
}
},
"gcs-resumable-upload": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-2.3.1.tgz",
"integrity": "sha512-zEO7L+jz99VznQsbsF7vFTnIFbSu+CjdJqt5htnjIrfsp5j+QCVBvbbKdqpaTfCPzpUPYj1Q9O9DhIh/8newfA==",
"optional": true,
"requires": {
"abort-controller": "^3.0.0",
"configstore": "^5.0.0",
"gaxios": "^2.0.0",
"google-auth-library": "^5.0.0",
"pumpify": "^2.0.0",
"stream-events": "^1.0.4"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"google-auth-library": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.5.1.tgz",
"integrity": "sha512-zCtjQccWS/EHYyFdXRbfeSGM/gW+d7uMAcVnvXRnjBXON5ijo6s0nsObP0ifqileIDSbZjTlLtgo+UoN8IFJcg==",
"optional": true,
"requires": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
"fast-text-encoding": "^1.0.0",
"gaxios": "^2.1.0",
"gcp-metadata": "^3.2.0",
"gtoken": "^4.1.0",
"jws": "^3.1.5",
"lru-cache": "^5.0.0"
}
},
"google-gax": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.11.1.tgz",
"integrity": "sha512-v/APF2G5h2nS5R/1DW2vsgloaMu2/B3xjHdAptR1yUwZpEd9rxPTlhqosrjl/VRu+gWGr9JZN19ZgJTXQ/Db6Q==",
"optional": true,
"requires": {
"@grpc/grpc-js": "0.6.9",
"@grpc/proto-loader": "^0.5.1",
"@types/long": "^4.0.0",
"abort-controller": "^3.0.0",
"duplexify": "^3.6.0",
"google-auth-library": "^5.0.0",
"is-stream-ended": "^0.1.4",
"lodash.at": "^4.6.0",
"lodash.has": "^4.5.2",
"node-fetch": "^2.6.0",
"protobufjs": "^6.8.8",
"retry-request": "^4.0.0",
"semver": "^6.0.0",
"walkdir": "^0.4.0"
}
},
"google-p12-pem": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.3.tgz",
"integrity": "sha512-Tq2kBCANxYYPxaBpTgCpRfdoPs9+/lNzc/Iaee4kuMVW5ascD+HwhpBsTLwH85C9Ev4qfB8KKHmpPQYyD2vg2w==",
"optional": true,
"requires": {
"node-forge": "^0.9.0"
},
"dependencies": {
"node-forge": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz",
"integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==",
"optional": true
}
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"optional": true
},
"gtoken": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.3.tgz",
"integrity": "sha512-ofW+FiXjswyKdkjMcDbe6E4K7cDDdE82dGDhZIc++kUECqaE7MSErf6arJPAjcnYn1qxE1/Ti06qQuqgVusovQ==",
"optional": true,
"requires": {
"gaxios": "^2.1.0",
"google-p12-pem": "^2.0.0",
"jws": "^3.1.5",
"mime": "^2.2.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"optional": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"hash-stream-validation": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.2.tgz",
"integrity": "sha512-cMlva5CxWZOrlS/cY0C+9qAzesn5srhFA8IT1VPiHc9bWWBLkJfEUIZr7MWoi89oOOGmpg8ymchaOjiArsGu5A==",
"optional": true,
"requires": {
"through2": "^2.0.0"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"optional": true
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"optional": true,
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
}
}
}
},
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
},
"dependencies": {
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
}
}
},
"http-parser-js": {
"version": "0.4.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q="
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"optional": true,
"requires": {
"agent-base": "4",
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"optional": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"optional": true
}
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
"optional": true,
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"optional": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ipaddr.js": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
"is-arguments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
"optional": true
},
"is-date-object": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"optional": true
},
"is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"optional": true
},
"is-regex": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
"optional": true,
"requires": {
"has": "^1.0.1"
}
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"optional": true
},
"is-stream-ended": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz",
"integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==",
"optional": true
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"optional": true
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"optional": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"js-yaml": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"json-bigint": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz",
"integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=",
"optional": true,
"requires": {
"bignumber.js": "^7.0.0"
}
},
"jsonwebtoken": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz",
"integrity": "sha1-xjl80uX9WD1lwAeoPce7eOaYK4M=",
"requires": {
"jws": "^3.1.4",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.0.0",
"xtend": "^4.0.1"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.at": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz",
"integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=",
"optional": true
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
"optional": true
},
"lodash.has": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
"integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=",
"optional": true
},
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
},
"lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
},
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
},
"lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
"optional": true
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"optional": true,
"requires": {
"yallist": "^3.0.2"
}
},
"make-dir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
"integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
"optional": true,
"requires": {
"semver": "^6.0.0"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
"optional": true
},
"mime-db": {
"version": "1.42.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
"integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ=="
},
"mime-types": {
"version": "2.1.25",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
"integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
"requires": {
"mime-db": "1.42.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"optional": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
"optional": true
},
"node-forge": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.4.tgz",
"integrity": "sha512-8Df0906+tq/omxuCZD6PqhPaQDYuyJ1d+VITgxoIA8zvQd1ru+nMJcDChHH324MWitIgbVkAkQoGEEVJNpn/PA=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-is": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz",
"integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=",
"optional": true
},
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"optional": true
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
"optional": true,
"requires": {
"mimic-fn": "^2.1.0"
}
},
"p-limit": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
"integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
"optional": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"optional": true
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"optional": true
},
"protobufjs": {
"version": "6.8.8",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz",
"integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==",
"optional": true,
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.0",
"@types/node": "^10.1.0",
"long": "^4.0.0"
},
"dependencies": {
"@types/node": {
"version": "10.17.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.5.tgz",
"integrity": "sha512-RElZIr/7JreF1eY6oD5RF3kpmdcreuQPjg5ri4oQ5g9sq7YWU8HkfB3eH8GwAwxf5OaCh0VPi7r4N/yoTGelrA==",
"optional": true
}
}
},
"proxy-addr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
"integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.0"
}
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"optional": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"pumpify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz",
"integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==",
"optional": true,
"requires": {
"duplexify": "^4.1.1",
"inherits": "^2.0.3",
"pump": "^3.0.0"
},
"dependencies": {
"duplexify": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz",
"integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==",
"optional": true,
"requires": {
"end-of-stream": "^1.4.1",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1",
"stream-shift": "^1.0.0"
}
},
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"optional": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"requires": {
"safe-buffer": "~5.2.0"
}
}
}
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"regexp.prototype.flags": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz",
"integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==",
"optional": true,
"requires": {
"define-properties": "^1.1.2"
}
},
"resolve": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.2.tgz",
"integrity": "sha512-cAVTI2VLHWYsGOirfeYVVQ7ZDejtQ9fp4YhYckWDEkFfqbVjaT11iM8k6xSAfGFMM+gDpZjMnFssPu8we+mqFw==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"retry-request": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz",
"integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==",
"optional": true,
"requires": {
"debug": "^4.1.1",
"through2": "^3.0.1"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"optional": true,
"requires": {
"ms": "^2.1.1"
}
}
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"optional": true
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"optional": true
},
"snakeize": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz",
"integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=",
"optional": true
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"stream-events": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
"integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==",
"optional": true,
"requires": {
"stubs": "^3.0.0"
}
},
"stream-shift": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
"optional": true
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"optional": true
},
"stubs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz",
"integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=",
"optional": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"teeny-request": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-5.3.1.tgz",
"integrity": "sha512-hnUeun3xryzv92FbrnprltcdeDfSVaGFBlFPRvKJ2fO/ioQx9N0aSUbbXSfTO+ArRXine1gSWdWFWcgfrggWXw==",
"optional": true,
"requires": {
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^3.0.0",
"node-fetch": "^2.2.0",
"stream-events": "^1.0.5",
"uuid": "^3.3.2"
}
},
"through2": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
"integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
"optional": true,
"requires": {
"readable-stream": "2 || 3"
},
"dependencies": {
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"optional": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"optional": true,
"requires": {
"safe-buffer": "~5.2.0"
}
}
}
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
},
"tslint": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
"integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"builtin-modules": "^1.1.1",
"chalk": "^2.3.0",
"commander": "^2.12.1",
"diff": "^4.0.1",
"glob": "^7.1.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"resolve": "^1.3.2",
"semver": "^5.3.0",
"tslib": "^1.8.0",
"tsutils": "^2.29.0"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}
}
},
"tsutils": {
"version": "2.29.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
}
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"optional": true
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"optional": true,
"requires": {
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
"integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==",
"dev": true
},
"unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
"integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
"optional": true,
"requires": {
"crypto-random-string": "^2.0.0"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"optional": true
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"walkdir": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz",
"integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==",
"optional": true
},
"websocket-driver": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
"integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
"requires": {
"http-parser-js": ">=0.4.0 <0.4.11",
"safe-buffer": ">=5.1.0",
"websocket-extensions": ">=0.1.1"
}
},
"websocket-extensions": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"write-file-atomic": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz",
"integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==",
"optional": true,
"requires": {
"imurmurhash": "^0.1.4",
"is-typedarray": "^1.0.0",
"signal-exit": "^3.0.2",
"typedarray-to-buffer": "^3.1.5"
}
},
"xdg-basedir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"optional": true
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"optional": true
}
}
}
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "8"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^8.6.0",
"firebase-functions": "^3.3.0"
},
"devDependencies": {
"tslint": "^5.12.0",
"typescript": "^3.2.2",
"firebase-functions-test": "^0.1.6"
},
"private": true
}
import * as functions from 'firebase-functions';
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
// export const helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
export const onMessageCreate = function.database
.ref('/rooms/{roomid}/message/{messageid}')
.onCreate((snapshot,context)=>{
const roomId=context.params.roomId
const messageId=context.params.messageId
const messageData=snapshot.val()
const text=addpizzazz(messageData.text)
return snapshot.ref.update({text: text})
})
function addpizzazz(text : string): string{
return text.replace()
}
export const onMessageUpdate = function.database
.ref('/rooms/{roomid}/message/{messageid}')
.onUpdate((change,context)=>{
const before=change.before.val()
const after=change.after.val()
if (before.text===after.text){
return null
}
const text=addpizzazz(after.text)
const timeedited=Date.now()
return chnage.after.ref.update({text: text})
})
function addpizzazz(text : string): string{
return text.replace()
}
/////////////////////////////////////////////////////////////////////
export const onMessageCreate = function.database
.ref('/rooms/{roomid}/message/{messageid}')
.onCreate(async (snapshot,context)=>{
const roomId=context.params.roomId
const messageId=context.params.messageId
const messageData=snapshot.val()
const text=addpizzazz(messageData.text)
await snapshot.ref.update({text: text})
const countRef=snapshot.ref.parent.parent.child('messageCount')
return countRef.transaction(count=>{
return count+1
})
})
export const onMessageDelete = function.database
.ref('/rooms/{roomid}/message/{messageid}')
.onDelete(async (snapshot,context)=>{
const countRef=snapshot.ref.parent.parent.child('messageCount')
return countRef.transaction(count=>{
return count-1
})
})
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017"
},
"compileOnSave": true,
"include": [
"src"
]
}
{
"rules": {
// -- Strict errors --
// These lint rules are likely always a good idea.
// Force function overloads to be declared together. This ensures readers understand APIs.
"adjacent-overload-signatures": true,
// Do not allow the subtle/obscure comma operator.
"ban-comma-operator": true,
// Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.
"no-namespace": true,
// Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.
"no-parameter-reassignment": true,
// Force the use of ES6-style imports instead of /// <reference path=> imports.
"no-reference": true,
// Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the
// code currently being edited (they may be incorrectly handling a different type case that does not exist).
"no-unnecessary-type-assertion": true,
// Disallow nonsensical label usage.
"label-position": true,
// Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.
"no-conditional-assignment": true,
// Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).
"no-construct": true,
// Do not allow super() to be called twice in a constructor.
"no-duplicate-super": true,
// Do not allow the same case to appear more than once in a switch block.
"no-duplicate-switch-case": true,
// Do not allow a variable to be declared more than once in the same block. Consider function parameters in this
// rule.
"no-duplicate-variable": [true, "check-parameters"],
// Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should
// instead use a separate variable name.
"no-shadowed-variable": true,
// Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.
"no-empty": [true, "allow-empty-catch"],
// Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.
// This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.
"no-floating-promises": true,
// Do not allow any imports for modules that are not in package.json. These will almost certainly fail when
// deployed.
"no-implicit-dependencies": true,
// The 'this' keyword can only be used inside of classes.
"no-invalid-this": true,
// Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.
"no-string-throw": true,
// Disallow control flow statements, such as return, continue, break, and throw in finally blocks.
"no-unsafe-finally": true,
// Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
// Disallow duplicate imports in the same file.
"no-duplicate-imports": true,
// -- Strong Warnings --
// These rules should almost never be needed, but may be included due to legacy code.
// They are left as a warning to avoid frustration with blocked deploys when the developer
// understand the warning and wants to deploy anyway.
// Warn when an empty interface is defined. These are generally not useful.
"no-empty-interface": {"severity": "warning"},
// Warn when an import will have side effects.
"no-import-side-effect": {"severity": "warning"},
// Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for
// most values and let for values that will change.
"no-var-keyword": {"severity": "warning"},
// Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.
"triple-equals": {"severity": "warning"},
// Warn when using deprecated APIs.
"deprecation": {"severity": "warning"},
// -- Light Warnings --
// These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info"
// if TSLint supported such a level.
// prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.
// (Even better: check out utils like .map if transforming an array!)
"prefer-for-of": {"severity": "warning"},
// Warns if function overloads could be unified into a single function with optional or rest parameters.
"unified-signatures": {"severity": "warning"},
// Prefer const for values that will not change. This better documents code.
"prefer-const": {"severity": "warning"},
// Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts.
"trailing-comma": {"severity": "warning"}
},
"defaultSeverity": "error"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment