├── .github └── ISSUE_TEMPLATE │ └── config.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── android ├── FirebaseContinue │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── library │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── firebasecontinue │ │ │ │ └── FirebaseContinue.java │ │ │ └── res │ │ │ └── values │ │ │ └── public.xml │ └── settings.gradle └── README.md ├── chrome-extensions ├── README.md └── firebase-continue.js ├── ios ├── .gitignore ├── FirebaseContinue │ ├── Example │ │ ├── FirebaseContinue.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── FirebaseContinue-Example.xcscheme │ │ ├── FirebaseContinue │ │ │ ├── Base.lproj │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── FCNAppDelegate.h │ │ │ ├── FCNAppDelegate.m │ │ │ ├── FCNViewController.h │ │ │ ├── FCNViewController.m │ │ │ ├── FirebaseContinue-Info.plist │ │ │ ├── FirebaseContinue-Prefix.pch │ │ │ ├── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ ├── en.lproj │ │ │ │ └── InfoPlist.strings │ │ │ └── main.m │ │ ├── Podfile │ │ └── Tests │ │ │ ├── Tests-Info.plist │ │ │ ├── Tests-Prefix.pch │ │ │ ├── Tests.m │ │ │ └── en.lproj │ │ │ └── InfoPlist.strings │ ├── FirebaseContinue.podspec │ ├── FirebaseContinue │ │ ├── Assets │ │ │ └── .gitkeep │ │ └── Classes │ │ │ ├── FCNContinue.h │ │ │ └── FCNContinue.m │ └── _Pods.xcodeproj └── README.md ├── sample-firebase-continue-database.rules.json └── samples ├── README.md ├── android ├── Continote │ ├── app │ │ ├── build.gradle │ │ ├── libs │ │ │ └── .gitkeep │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── firebasecontinue │ │ │ │ └── sample │ │ │ │ └── continote │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── EditNoteActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MyNotesActivity.java │ │ │ │ ├── Note.java │ │ │ │ └── NoteListItemViewHolder.java │ │ │ └── res │ │ │ ├── layout │ │ │ ├── activity_edit_note.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_my_notes.xml │ │ │ └── note_list_item.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-ldpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── setup-file-templates │ │ └── sample-strings.xml └── README.md ├── chrome-extension ├── Continote │ ├── background.html │ ├── images │ │ └── icons │ │ │ ├── icon-128.png │ │ │ ├── icon-16.png │ │ │ ├── icon-24.png │ │ │ ├── icon-32.png │ │ │ └── icon-48.png │ ├── main-popup.html │ ├── manifest.json │ ├── scripts │ │ ├── auth-helper.js │ │ ├── background.js │ │ ├── constants.js │ │ ├── main-popup.js │ │ ├── sample-config.js │ │ ├── signin-popup.js │ │ └── utils.js │ ├── signin-popup.html │ └── styles │ │ └── all-popups.css └── README.md ├── ios ├── Continote │ ├── Continote.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── sample-project.pbxproj │ ├── Continote.xcworkspace │ │ └── contents.xcworkspacedata │ ├── Continote │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-60@2x.png │ │ │ │ ├── Icon-60@3x.png │ │ │ │ ├── Icon-76@1x.png │ │ │ │ ├── Icon-76@2x.png │ │ │ │ └── Icon-83.5@2x.png │ │ │ └── LaunchImage.launchimage │ │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── BaseViewController.swift │ │ ├── Continote-Bridging-Header.h │ │ ├── EditNoteViewController.swift │ │ ├── MainViewController.swift │ │ ├── MyNotesTableViewCell.swift │ │ ├── MyNotesTableViewDataSource.swift │ │ ├── MyNotesViewController.swift │ │ ├── Note.swift │ │ ├── Sample-Constants.swift │ │ ├── Utils.swift │ │ └── sample-Info.plist │ ├── Podfile │ └── Podfile.lock └── README.md └── web ├── Continote ├── firebase.json ├── public │ ├── 404.html │ ├── edit-note.html │ ├── images │ │ └── favicon.ico │ ├── index.html │ ├── my-notes.html │ ├── scripts │ │ ├── auth-helper.js │ │ ├── edit-note.js │ │ ├── index.js │ │ ├── my-notes.js │ │ ├── sample-config.js │ │ └── utils.js │ └── styles │ │ └── all-pages.css └── sample-database.rules.json └── README.md /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 🛑 Library Archived 4 | url: https://firebaseopensource.com/ 5 | about: This repository is archived. Visit our open source site to browse other Firebase libraries. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the 10 | # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # 14 | 15 | # Intellij 16 | *.iml 17 | .idea 18 | 19 | # Android Studio 20 | captures/ 21 | .externalNativeBuild 22 | 23 | # Gradle files 24 | .gradle/ 25 | build/ 26 | 27 | # Built Android application files 28 | *.apk 29 | 30 | # Local configuration file (ex. SDK path) 31 | local.properties 32 | 33 | # Google Services (ex. APIs and Firebase) 34 | google-services.json 35 | GoogleService-Info.plist 36 | 37 | # Firebase Hosting 38 | .firebaserc 39 | firebase-debug.log 40 | 41 | # Build generated 42 | build/ 43 | DerivedData/ 44 | 45 | # Various Xcode settings 46 | *.pbxuser 47 | !default.pbxuser 48 | *.mode1v3 49 | !default.mode1v3 50 | *.mode2v3 51 | !default.mode2v3 52 | *.perspectivev3 53 | !default.perspectivev3 54 | xcuserdata/ 55 | 56 | # Other Xcode files 57 | *.moved-aside 58 | *.xccheckout 59 | *.xcscmblueprint 60 | 61 | # Obj-C/Swift specific 62 | *.hmap 63 | *.ipa 64 | *.dSYM.zip 65 | *.dSYM 66 | 67 | # CocoaPods 68 | Pods/ 69 | 70 | # Chrome Extension related 71 | *.pem 72 | *.crx 73 | 74 | # Local config/setup 75 | database.rules.json 76 | samples/android/Continote/app/src/main/res/values/strings.xml 77 | samples/chrome-extension/Continote/scripts/config.js 78 | samples/ios/Continote/Continote/Constants.swift 79 | samples/ios/Continote/Continote/Info.plist 80 | samples/ios/Continote/Continote.xcodeproj/project.pbxproj 81 | samples/web/Continote/database.rules.json 82 | samples/web/Continote/public/scripts/config.js 83 | 84 | # Libraries for samples 85 | samples/android/Continote/app/libs/*.aar 86 | samples/chrome-extension/Continote/scripts/firebase-continue.js 87 | samples/ios/Continote/Continote/FCNContinue.h 88 | samples/ios/Continote/Continote/FCNContinue.m 89 | 90 | # Misc. 91 | .DS_Store 92 | *.swp 93 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contibuting to Firebase Continue 2 | 3 | Want to contribute? Great! 4 | 5 | First, please read this page (including the [the small print at the end](#the-small-print)). 6 | 7 | ## Table of Contents 8 | 9 | 1. [Before You Contribute](#before-you-contribute) 10 | 2. [Adding New Features](#adding-new-features) 11 | 3. [Code Reviews](#code-reviews) 12 | 4. [The Small Print](#the-small-print) 13 | 14 | ## Before You Contribute 15 | 16 | Before we can use your code, you must sign the [Google Individual Contributor 17 | License Agreement](https://cla.developers.google.com/about/google-individual) 18 | (CLA), which you can do online. The CLA is necessary mainly because you own the 19 | copyright to your changes, even after your contribution becomes part of our 20 | codebase, so we need your permission to use and distribute your code. We also 21 | need to be sure of various other things — for instance that you'll tell us if you 22 | know that your code infringes on other people's patents. You don't have to sign 23 | the CLA until after you've submitted your code for review and a member has 24 | approved it, but you must do it before we can put your code into our codebase. 25 | 26 | ## Adding New Features 27 | 28 | Before you start working on a larger contribution, you should get in touch with 29 | us first through the issue tracker with your idea so that we can help out and 30 | possibly guide you. Coordinating up front makes it much easier to avoid 31 | frustration later on. 32 | 33 | If this has been discussed in an issue, make sure to mention the issue number. 34 | If not, go file an issue about this to make sure this is a desirable change. 35 | 36 | ## Code Reviews 37 | 38 | All submissions, including submissions by project members, require review. We 39 | use GitHub pull requests for this purpose. 40 | 41 | ## The Small Print 42 | 43 | Contributions made by corporations are covered by a different agreement than the 44 | one above, the [Software Grant and Corporate Contributor License 45 | Agreement](https://cla.developers.google.com/about/google-corporate). 46 | -------------------------------------------------------------------------------- /android/FirebaseContinue/build.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | buildscript { 16 | repositories { 17 | jcenter() 18 | } 19 | 20 | dependencies { 21 | classpath 'com.android.tools.build:gradle:2.3.3' 22 | } 23 | } 24 | 25 | allprojects { 26 | repositories { 27 | jcenter() 28 | } 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /android/FirebaseContinue/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the 10 | # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # 14 | 15 | # Project-wide Gradle settings. 16 | 17 | # IDE (e.g. Android Studio) users: 18 | # Gradle settings configured through the IDE *will override* 19 | # any settings specified in this file. 20 | 21 | # For more details on how to configure your build environment visit 22 | # http://www.gradle.org/docs/current/userguide/build_environment.html 23 | 24 | # Specifies the JVM arguments used for the daemon process. 25 | # The setting is particularly useful for tweaking memory settings. 26 | org.gradle.jvmargs=-Xmx1536m 27 | 28 | # When configured, Gradle will run in incubating parallel mode. 29 | # This option should only be used with decoupled projects. More details, visit 30 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 31 | # org.gradle.parallel=true 32 | -------------------------------------------------------------------------------- /android/FirebaseContinue/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/android/FirebaseContinue/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/FirebaseContinue/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the 10 | # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # 14 | 15 | #Mon Jul 31 16:51:28 EDT 2017 16 | distributionBase=GRADLE_USER_HOME 17 | distributionPath=wrapper/dists 18 | zipStoreBase=GRADLE_USER_HOME 19 | zipStorePath=wrapper/dists 20 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 21 | -------------------------------------------------------------------------------- /android/FirebaseContinue/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Copyright (c) 2017 Google Inc. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | # in compliance with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software distributed under the 12 | # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | # express or implied. See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | ############################################################################## 18 | ## 19 | ## Gradle start up script for UN*X 20 | ## 21 | ############################################################################## 22 | 23 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 24 | DEFAULT_JVM_OPTS="" 25 | 26 | APP_NAME="Gradle" 27 | APP_BASE_NAME=`basename "$0"` 28 | 29 | # Use the maximum available, or set MAX_FD != -1 to use that value. 30 | MAX_FD="maximum" 31 | 32 | warn ( ) { 33 | echo "$*" 34 | } 35 | 36 | die ( ) { 37 | echo 38 | echo "$*" 39 | echo 40 | exit 1 41 | } 42 | 43 | # OS specific support (must be 'true' or 'false'). 44 | cygwin=false 45 | msys=false 46 | darwin=false 47 | case "`uname`" in 48 | CYGWIN* ) 49 | cygwin=true 50 | ;; 51 | Darwin* ) 52 | darwin=true 53 | ;; 54 | MINGW* ) 55 | msys=true 56 | ;; 57 | esac 58 | 59 | # Attempt to set APP_HOME 60 | # Resolve links: $0 may be a link 61 | PRG="$0" 62 | # Need this for relative symlinks. 63 | while [ -h "$PRG" ] ; do 64 | ls=`ls -ld "$PRG"` 65 | link=`expr "$ls" : '.*-> \(.*\)$'` 66 | if expr "$link" : '/.*' > /dev/null; then 67 | PRG="$link" 68 | else 69 | PRG=`dirname "$PRG"`"/$link" 70 | fi 71 | done 72 | SAVED="`pwd`" 73 | cd "`dirname \"$PRG\"`/" >/dev/null 74 | APP_HOME="`pwd -P`" 75 | cd "$SAVED" >/dev/null 76 | 77 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 78 | 79 | # Determine the Java command to use to start the JVM. 80 | if [ -n "$JAVA_HOME" ] ; then 81 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 82 | # IBM's JDK on AIX uses strange locations for the executables 83 | JAVACMD="$JAVA_HOME/jre/sh/java" 84 | else 85 | JAVACMD="$JAVA_HOME/bin/java" 86 | fi 87 | if [ ! -x "$JAVACMD" ] ; then 88 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 89 | 90 | Please set the JAVA_HOME variable in your environment to match the 91 | location of your Java installation." 92 | fi 93 | else 94 | JAVACMD="java" 95 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | 101 | # Increase the maximum file descriptors if we can. 102 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 103 | MAX_FD_LIMIT=`ulimit -H -n` 104 | if [ $? -eq 0 ] ; then 105 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 106 | MAX_FD="$MAX_FD_LIMIT" 107 | fi 108 | ulimit -n $MAX_FD 109 | if [ $? -ne 0 ] ; then 110 | warn "Could not set maximum file descriptor limit: $MAX_FD" 111 | fi 112 | else 113 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 114 | fi 115 | fi 116 | 117 | # For Darwin, add options to specify how the application appears in the dock 118 | if $darwin; then 119 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 120 | fi 121 | 122 | # For Cygwin, switch paths to Windows format before running java 123 | if $cygwin ; then 124 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 125 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 126 | JAVACMD=`cygpath --unix "$JAVACMD"` 127 | 128 | # We build the pattern for arguments to be converted via cygpath 129 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 130 | SEP="" 131 | for dir in $ROOTDIRSRAW ; do 132 | ROOTDIRS="$ROOTDIRS$SEP$dir" 133 | SEP="|" 134 | done 135 | OURCYGPATTERN="(^($ROOTDIRS))" 136 | # Add a user-defined pattern to the cygpath arguments 137 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 138 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 139 | fi 140 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 141 | i=0 142 | for arg in "$@" ; do 143 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 144 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 145 | 146 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 147 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 148 | else 149 | eval `echo args$i`="\"$arg\"" 150 | fi 151 | i=$((i+1)) 152 | done 153 | case $i in 154 | (0) set -- ;; 155 | (1) set -- "$args0" ;; 156 | (2) set -- "$args0" "$args1" ;; 157 | (3) set -- "$args0" "$args1" "$args2" ;; 158 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 159 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 160 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 161 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 162 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 163 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 164 | esac 165 | fi 166 | 167 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 168 | function splitJvmOpts() { 169 | JVM_OPTS=("$@") 170 | } 171 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 172 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 173 | 174 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 175 | -------------------------------------------------------------------------------- /android/FirebaseContinue/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | 3 | @rem # 4 | @rem # Copyright (c) 2017 Google Inc. All Rights Reserved. 5 | @rem # 6 | @rem # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 7 | @rem # except in compliance with the License. You may obtain a copy of the License at 8 | @rem # 9 | @rem # http://www.apache.org/licenses/LICENSE-2.0 10 | @rem # 11 | @rem # Unless required by applicable law or agreed to in writing, software distributed under the 12 | @rem # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | @rem # either express or implied. See the License for the specific language governing permissions 14 | @rem # and limitations under the License. 15 | @rem # 16 | 17 | @rem ########################################################################## 18 | @rem 19 | @rem Gradle startup script for Windows 20 | @rem 21 | @rem ########################################################################## 22 | 23 | @rem Set local scope for the variables with windows NT shell 24 | if "%OS%"=="Windows_NT" setlocal 25 | 26 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 27 | set DEFAULT_JVM_OPTS= 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%" == "" set DIRNAME=. 31 | set APP_BASE_NAME=%~n0 32 | set APP_HOME=%DIRNAME% 33 | 34 | @rem Find java.exe 35 | if defined JAVA_HOME goto findJavaFromJavaHome 36 | 37 | set JAVA_EXE=java.exe 38 | %JAVA_EXE% -version >NUL 2>&1 39 | if "%ERRORLEVEL%" == "0" goto init 40 | 41 | echo. 42 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 43 | echo. 44 | echo Please set the JAVA_HOME variable in your environment to match the 45 | echo location of your Java installation. 46 | 47 | goto fail 48 | 49 | :findJavaFromJavaHome 50 | set JAVA_HOME=%JAVA_HOME:"=% 51 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 52 | 53 | if exist "%JAVA_EXE%" goto init 54 | 55 | echo. 56 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 57 | echo. 58 | echo Please set the JAVA_HOME variable in your environment to match the 59 | echo location of your Java installation. 60 | 61 | goto fail 62 | 63 | :init 64 | @rem Get command-line arguments, handling Windowz variants 65 | 66 | if not "%OS%" == "Windows_NT" goto win9xME_args 67 | if "%@eval[2+2]" == "4" goto 4NT_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | goto execute 79 | 80 | :4NT_args 81 | @rem Get arguments from the 4NT Shell from JP Software 82 | set CMD_LINE_ARGS=%$ 83 | 84 | :execute 85 | @rem Setup the command line 86 | 87 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 88 | 89 | @rem Execute Gradle 90 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 91 | 92 | :end 93 | @rem End local scope for the variables with windows NT shell 94 | if "%ERRORLEVEL%"=="0" goto mainEnd 95 | 96 | :fail 97 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 98 | rem the _cmd.exe /c_ return code! 99 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 100 | exit /b 1 101 | 102 | :mainEnd 103 | if "%OS%"=="Windows_NT" endlocal 104 | 105 | :omega 106 | -------------------------------------------------------------------------------- /android/FirebaseContinue/library/build.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | // TODO: Look into a more robust build process, possibly including minification for release builds 16 | // (look to FirebaseUI-Android for an example). 17 | 18 | apply plugin: 'com.android.library' 19 | 20 | android { 21 | compileSdkVersion 25 22 | buildToolsVersion '25.0.0' 23 | 24 | defaultConfig { 25 | minSdkVersion 14 26 | targetSdkVersion 25 27 | 28 | versionCode 1 29 | versionName '0.1.0' 30 | } 31 | 32 | buildTypes.all { 33 | minifyEnabled false 34 | 35 | // Rename the output file. 36 | libraryVariants.all { variant -> 37 | variant.outputs.each { output -> 38 | output.outputFile = new File(output.outputFile.parent, 39 | "FirebaseContinue-${defaultConfig.versionName}.aar") 40 | } 41 | } 42 | } 43 | } 44 | 45 | dependencies { 46 | // Firebase 47 | compile 'com.google.firebase:firebase-auth:11.0.0' 48 | compile 'com.google.firebase:firebase-database:11.0.0' 49 | } 50 | -------------------------------------------------------------------------------- /android/FirebaseContinue/library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /android/FirebaseContinue/library/src/main/res/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /android/FirebaseContinue/settings.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | include ':library' 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | # For libraries, this should not be checked in 2 | Podfile.lock 3 | 4 | # The workspace is generated 5 | *.xcworkspace 6 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue.xcodeproj/xcshareddata/xcschemes/FirebaseContinue-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FCNAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | @import UIKit; 18 | 19 | /** 20 | * Important Note: This is not a working example of using Firebase Continue. 21 | * 22 | * The Firebase Continue for iOS library is planned to eventually be available via Cocoapods 23 | * (rather than being required to manually copy-paste its source into your project), so this 24 | * Cocoapods-provided development environment lays the groundwork for that. 25 | * 26 | * For an actual, working sample of Firebase Continue, see the samples/ios subdirectory 27 | * from the root of the repository at: 28 | * https://github.com/firebase/firebase-continue/tree/master/samples/ios 29 | */ 30 | @interface FCNAppDelegate : UIResponder 31 | 32 | @property(strong, nonatomic) UIWindow *window; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FCNAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import "FCNAppDelegate.h" 18 | 19 | /** 20 | * Important Note: This is not a working example of using Firebase Continue. 21 | * 22 | * The Firebase Continue for iOS library is planned to eventually be available via Cocoapods 23 | * (rather than being required to manually copy-paste its source into your project), so this 24 | * Cocoapods-provided development environment lays the groundwork for that. 25 | * 26 | * For an actual, working sample of Firebase Continue, see the samples/ios subdirectory 27 | * from the root of the repository at: 28 | * https://github.com/firebase/firebase-continue/tree/master/samples/ios 29 | */ 30 | @implementation FCNAppDelegate 31 | 32 | - (BOOL)application:(UIApplication *)application 33 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FCNViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | @import UIKit; 18 | 19 | /** 20 | * Important Note: This is not a working example of using Firebase Continue. 21 | * 22 | * The Firebase Continue for iOS library is planned to eventually be available via Cocoapods 23 | * (rather than being required to manually copy-paste its source into your project), so this 24 | * Cocoapods-provided development environment lays the groundwork for that. 25 | * 26 | * For an actual, working sample of Firebase Continue, see the samples/ios subdirectory 27 | * from the root of the repository at: 28 | * https://github.com/firebase/firebase-continue/tree/master/samples/ios 29 | */ 30 | @interface FCNViewController : UIViewController 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FCNViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import "FCNViewController.h" 18 | 19 | @import FirebaseContinue; 20 | 21 | /** 22 | * Important Note: This is not a working example of using Firebase Continue. 23 | * 24 | * The Firebase Continue for iOS library is planned to eventually be available via Cocoapods 25 | * (rather than being required to manually copy-paste its source into your project), so this 26 | * Cocoapods-provided development environment lays the groundwork for that. 27 | * 28 | * For an actual, working sample of Firebase Continue, see the samples/ios subdirectory 29 | * from the root of the repository at: 30 | * https://github.com/firebase/firebase-continue/tree/master/samples/ios 31 | */ 32 | @implementation FCNViewController 33 | 34 | - (void)viewDidAppear:(BOOL)animated { 35 | [super viewDidAppear:animated]; 36 | 37 | // Attempt to use Firebase Continue here. This should fail for any number of reasons, 38 | // including that Firebase has not been set up for this app. 39 | [FCNContinue broadcastToContinueActivityWithUrl:[TODO:YOUR-URL-TO-ALLOW-THE-USER-TO- 40 | CONTINUE-THEIR-ACTIVITY-HERE] 41 | withinApplicationWithName:[TODO:YOUR-APPLICATION-NAME-HERE] 42 | withCompletionBlock:^(NSError *_Nullable firebaseContinueError) { 43 | if (firebaseContinueError) { 44 | // The activity failed to broadcast. 45 | } else { 46 | // The activity was successfully broadcast. 47 | 48 | // An example use of this could be to inform the user to open 49 | // Chrome (with your Chrome extension installed which uses the 50 | // Firebase Continue for Chrome Extensions library), or their 51 | // macOS computer with Apple Handoff, if they wish continue their 52 | // activity there. 53 | } 54 | }]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FirebaseContinue-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/FirebaseContinue-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import 18 | 19 | #ifndef __IPHONE_5_0 20 | #warning "This project uses features only available in iOS SDK 5.0 and later." 21 | #endif 22 | 23 | #ifdef __OBJC__ 24 | @import UIKit; 25 | @import Foundation; 26 | #endif 27 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/FirebaseContinue/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | @import UIKit; 18 | 19 | #import "FCNAppDelegate.h" 20 | 21 | /** 22 | * Important Note: This is not a working example of using Firebase Continue. 23 | * 24 | * The Firebase Continue for iOS library is planned to eventually be available via Cocoapods 25 | * (rather than being required to manually copy-paste its source into your project), so this 26 | * Cocoapods-provided development environment lays the groundwork for that. 27 | * 28 | * For an actual, working sample of Firebase Continue, see the samples/ios subdirectory 29 | * from the root of the repository at: 30 | * https://github.com/firebase/firebase-continue/tree/master/samples/ios 31 | */ 32 | int main(int argc, char *argv[]) { 33 | @autoreleasepool { 34 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([FCNAppDelegate class])); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'FirebaseContinue_Example' do 4 | pod 'FirebaseContinue', :path => '../' 5 | 6 | target 'FirebaseContinue_Tests' do 7 | inherit! :search_paths 8 | 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #ifdef __OBJC__ 18 | 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | @import XCTest; 18 | 19 | @interface Tests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation Tests 24 | 25 | - (void)setUp 26 | { 27 | [super setUp]; 28 | // Put setup code here. This method is called before the invocation of each test method in the class. 29 | } 30 | 31 | - (void)tearDown 32 | { 33 | // Put teardown code here. This method is called after the invocation of each test method in the class. 34 | [super tearDown]; 35 | } 36 | 37 | - (void)testExample 38 | { 39 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 40 | } 41 | 42 | @end 43 | 44 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/FirebaseContinue.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'FirebaseContinue' 3 | s.version = '0.1.0' 4 | s.summary = 'Firebase Continue enables mobile developers to integrate activity transitioning from their mobile apps to the web.' 5 | 6 | s.description = <<-DESC 7 | Firebase Continue for iOS enables iOS developers to easily integrate activity transitioning 8 | from their apps to the web by way of Chrome extensions (or Apple Handoff for users with both an 9 | iOS device and macOS computer that are Apple Handoff enabled). 10 | DESC 11 | 12 | s.homepage = 'https://github.com/firebase/firebase-continue' 13 | s.license = { :type => 'Apache 2.0', :file => '../../LICENSE' } 14 | s.authors = 'Google, Inc' 15 | s.source = { :git => 'https://github.com/firebase/firebase-continue.git', :tag => s.version.to_s } 16 | 17 | s.ios.deployment_target = '8.0' 18 | 19 | s.source_files = 'FirebaseContinue/Classes/**/*' 20 | 21 | s.public_header_files = 'FirebaseContinue/Classes/**/*.h' 22 | end 23 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/FirebaseContinue/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/ios/FirebaseContinue/FirebaseContinue/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/FirebaseContinue/FirebaseContinue/Classes/FCNContinue.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | @import Foundation; 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /** 22 | * A block which is invoked on the main thread when something the Firebase Continue library 23 | * attempted to do asynchronously completed. The error provided to the block will be non-nil if 24 | * the it was unsuccessful. See the library method documentation below for more details. 25 | */ 26 | typedef void (^FCNContinueCompletionBlock)(NSError *_Nullable firebaseContinueError); 27 | 28 | /** 29 | * @class FCNContinue 30 | * @brief The Firebase Continue for iOS library. 31 | * 32 | * Firebase Continue enables developers to easily integrate activity transitioning from their 33 | * iOS apps to the web, by way of Firebase and Chrome extensions (or Apple Handoff for users with 34 | * both an iOS device and macOS computer that are Apple Handoff enabled). 35 | * For more details, see: https://github.com/firebase/firebase-continue 36 | * 37 | * Please see the usage instructions in the relevant README file(s). 38 | * There is also more specific documentation within the library itself below. 39 | * 40 | * TODO: Add unit tests, including tests while the app/Firebase is offline. 41 | */ 42 | @interface FCNContinue : NSObject 43 | 44 | /** 45 | * Attempts to asynchronously broadcast an Activity (codified as a URL) within an application 46 | * that the currently signed in user may wish to continue elsewhere (in the immediate future) 47 | * to all potential clients (ex. Chrome extension(s) and/or Apple Handoff enabled macOS computers) 48 | * which could allow the user to do so by opening said URL. 49 | * 50 | * Note that, by design, only the most recently successfully broadcast Activity (for a given 51 | * application) could possibly be relevant to the user. The Firebase Continue database rules 52 | * and libraries enforce this. For more details, please see the relevant README file(s). 53 | * 54 | * @param activityUrl The URL which, if the current user were to navigate to, would allow the user 55 | * to continue their Activity. 56 | * @param applicationName The name of the application, as defined in the Firebase Realtime 57 | * Database rules for Firebase Continue, that the user's Activity is within. 58 | * @param completionBlock An optional completion block which is invoked on the main thread when the 59 | * broadcast attempt is complete. The error provided to the block will be non-nil if the broadcast 60 | * was unsuccessful. 61 | */ 62 | + (void)broadcastToContinueActivityWithUrl:(NSString *)activityUrl 63 | withinApplicationWithName:(NSString *)applicationName 64 | withCompletionBlock:(nullable FCNContinueCompletionBlock)completionBlock 65 | NS_SWIFT_NAME(broadcastToContinueActivity(withUrl:withinApplication:onComplete:)); 66 | 67 | /** 68 | * TODO: Possibly add a "dismissActivityToContinue" method akin to dismissing within the Chrome 69 | * extensions library. This could be used by mobile apps when an Activity that was broadcast would 70 | * certainly no longer be relevant to the user (rather than letting the Chrome extension library 71 | * itself (or the user within a Chrome extension) decide that). 72 | */ 73 | 74 | - (id)init __attribute__((unavailable("FCNContinue cannot be instantiated"))); 75 | 76 | @end 77 | 78 | NS_ASSUME_NONNULL_END 79 | -------------------------------------------------------------------------------- /ios/FirebaseContinue/_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /sample-firebase-continue-database.rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | 4 | // Disallow all data reading and writing by default. 5 | // This will be overridden in specific cases. 6 | ".read": false, 7 | ".write": false, 8 | 9 | [TODO: YOUR-APPLICATION'S-OTHER-FIREBASE-REALTIME-DATABASE-RULES-HERE] 10 | 11 | // This node holds all Firebase Continue specific data. 12 | "firebaseContinue": { 13 | 14 | // Firebase Continue has support for multiple applications using the same 15 | // Firebase project, so we need to separate each application (in this 16 | // sample's case, only "[TODO: YOUR-APPLICATION-NAME-HERE]") into its own 17 | // child node directly under firebaseContinue here. 18 | "$application": { 19 | 20 | // Firebase Continue data is user specific. Furthermore, we only need 21 | // to store at most one data point per user (per application): the data 22 | // for the activity the user most recently may wish to continue elsewhere. 23 | // Finally, a data point is essentially immutable: it can either be 24 | // added or deleted, but the library never has a need to update it. 25 | "$uid": { 26 | 27 | // The ".read" and ".write" security rules first ensure that Firebase Continue 28 | // data is user specific. Then, they ensure the data is for an application which you, 29 | // the developer, have specifically listed here. 30 | // 31 | // Important Reminder: Remember to use the exact same application name when required 32 | // while using the various Firebase Continue libraries. 33 | // 34 | // To support multiple applications within one Firebase project, simply modify the 35 | // ".read" and ".write" rules below like so: 36 | // ".read": "$uid === auth.uid && ($application === 'someappname' || $application === 'otherappname')", 37 | // ".write": "$uid === auth.uid && ($application === 'someappname' || $application === 'otherappname')", 38 | ".read": "$uid === auth.uid && $application === '[TODO: YOUR-APPLICATION-NAME-HERE]'", 39 | ".write": "$uid === auth.uid && $application === '[TODO: YOUR-APPLICATION-NAME-HERE]'", 40 | 41 | ".validate": "!data.exists() && newData.hasChildren(['metadata', 'url'])", 42 | 43 | // This is the metadata for this Firebase Continue data point. 44 | // It allows the library to determine relevancy. 45 | // Note: the metadata should never need to be updated - data points 46 | // are either added or removed altogether. 47 | "metadata": { 48 | ".validate": "newData.hasChildren(['addedAt'])", 49 | 50 | // This is a timestamp denoting when the data point was added to 51 | // Firebase. We ensure that this value is between now and 5 minutes 52 | // in the past, since that is the window of time that 53 | // Firebase Continue data is considered relevant. 54 | "addedAt": { 55 | ".validate": "newData.isNumber() && newData.val() >= (now - 300000) && newData.val() <= now" 56 | }, 57 | 58 | // Prevent extraneous data from being added to the metadata. 59 | "$other": { 60 | ".validate": false 61 | } 62 | }, 63 | 64 | // This is the URL which, if navigated to by the user, would allow 65 | // them to continue their activity elsewhere. 66 | // The URL validation is from: 67 | // https://firebase.google.com/docs/reference/security/database/regex#usage 68 | // Note: the URL should never need to be updated - data points are 69 | // either added or removed altogether. 70 | "url": { 71 | ".validate": "newData.isString() && newData.val().matches(/^(ht|f)tp(s?):\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*((0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\'\\/\\\\+&=%\\$#_]*)?$/)" 72 | }, 73 | 74 | // Prevent extraneous data from being added to this data point. 75 | "$other": { 76 | ".validate": false 77 | } 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | # Firebase Continue Samples - "Continote" Application 2 | 3 | This directory contains a set of Firebase Continue samples, collectively titled 4 | "Continote". 5 | 6 | "Continote" allows users to begin writing plaintext notes in either the 7 | [Android sample app](android) or the [iOS sample app](ios), and then continue 8 | writing in Chrome from exactly where they are thanks to the 9 | [sample Chrome extension](chrome-extension) 10 | (or [Apple Handoff](https://developer.apple.com/handoff/), 11 | for users with both an iOS device running "Continote" and 12 | macOS computer) opening a link to the correct location in the [sample web app](web). 13 | 14 | All of the samples provided here are designed to be used with the same 15 | Firebase project. 16 | 17 | It is strongly recommended that you create a new Firebase project specifically 18 | for the "Continote" samples. 19 | See the [Initial Setup guide](#initial-setup) below for more details. 20 | 21 | ## Table of Contents 22 | 23 | 1. [Initial Setup](#initial-setup) 24 | 2. [Usage](#usage) 25 | 3. [Compatibility](#compatibility) 26 | 4. [Dependencies](#dependencies) 27 | 28 | ## Initial Setup 29 | 30 | After completing the following steps, you will have properly set up a Firebase 31 | project to be able to try the Firebase Continue samples, collectively titled 32 | "Continote": 33 | 34 | 1. First, if you have not already done so, either download a copy of this 35 | repository from the Releases page to get a stable version of 36 | Firebase Continue (including its samples), 37 | or clone the repository locally for an unstable, development version. 38 | 39 | 2. [Create a Firebase project](https://firebase.google.com/) 40 | to use for the Continote samples. 41 | 42 | Note that [Firebase offers a free plan](https://firebase.google.com/pricing/) 43 | which you may be able to take advantage of. 44 | 45 | **Reminder**: Firebase Continue, and thus these samples, requires use of 46 | [Firebase Authentication](https://firebase.google.com/products/auth/) 47 | and the 48 | [Firebase Realtime Database](https://firebase.google.com/products/database/) 49 | for your project. Furthermore, the Firebase Realtime Database rules for Continote 50 | will be applied to your project, and the 51 | [sample web app](web) will be deployed to 52 | [Firebase Hosting](https://firebase.google.com/products/hosting/), 53 | using the 54 | [Firebase CLI](https://firebase.google.com/docs/cli/). 55 | 56 | 3. Enable signing in with Google for your Firebase project: 57 | 58 | 1. In the [Firebase console](https://console.firebase.google.com/) 59 | for your project, open the Authentication section. 60 | 61 | 2. On the Sign in method tab, enable the Google sign-in method, and click 62 | **Save**. 63 | 64 | 4. Enable signing in with Facebook for your Firebase project: 65 | 66 | 1. On the [Facebook for Developers website](https://developers.facebook.com/), 67 | create an app for use with the Continote samples. 68 | 69 | 2. Make note of the **name** you gave your new Facebook app, as well as its 70 | **App ID** and **App Secret** as you will need those values for this and 71 | other Continote samples. 72 | 73 | 3. In the [Firebase console](https://console.firebase.google.com/) 74 | for your project, open the Authentication section. 75 | 76 | 4. On the SIGN-IN METHOD tab, enable the Facebook sign-in method and 77 | specify the App ID and App Secret from above, and click **Save**. 78 | 79 | 5. Within that same Facebook sign-in method dialog, copy your OAuth redirect URI 80 | (ex. `my-app-12345.firebaseapp.com/__/auth/handler`) 81 | and add it to your "Valid OAuth redirect URIs" in your Facebook app's settings 82 | on the [Facebook for Developers website](https://developers.facebook.com/) 83 | in the Product Settings > Facebook Login configuration page. 84 | 85 | 5. [Follow the setup guide for the Continote sample web app](web#setup), 86 | since doing so will also apply the necessary Firebase Realtime Database rules 87 | for both Firebase Continue and Continote itself to your Firebase project. 88 | 89 | 6. Done! 90 | 91 | You can now follow the other setup guides for each Continote 92 | sample you plan on trying (for example, the 93 | [sample Chrome extension](chrome-extension#setup) and the 94 | [sample iOS app](ios#setup)). 95 | 96 | ## Usage 97 | 98 | Please see each sample subdirectory for relevant usage guides. 99 | 100 | ## Compatibility 101 | 102 | Please see each sample subdirectory for relevant compatibility information. 103 | 104 | ## Dependencies 105 | 106 | Please see each sample subdirectory for relevant dependency information. 107 | -------------------------------------------------------------------------------- /samples/android/Continote/app/build.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | apply plugin: 'com.android.application' 16 | 17 | android { 18 | compileSdkVersion 25 19 | buildToolsVersion '25.0.0' 20 | 21 | defaultConfig { 22 | applicationId 'com.firebasecontinue.sample.continote' 23 | minSdkVersion 16 24 | targetSdkVersion 25 25 | versionCode 1 26 | versionName '0.1.0' 27 | } 28 | 29 | buildTypes.all { 30 | minifyEnabled false 31 | 32 | // Rename the output file. 33 | applicationVariants.all { variant -> 34 | variant.outputs.each { output -> 35 | output.outputFile = new File(output.outputFile.parent, 36 | "Continote-${defaultConfig.versionName}.apk") 37 | } 38 | } 39 | } 40 | } 41 | 42 | dependencies { 43 | // Android support libraries 44 | compile 'com.android.support:appcompat-v7:25.0.0' 45 | compile 'com.android.support:design:25.0.0' 46 | compile 'com.android.support:support-annotations:25.0.0' 47 | compile 'com.android.support.constraint:constraint-layout:1.0.0' 48 | 49 | // Firebase 50 | compile 'com.google.firebase:firebase-auth:11.0.0' 51 | compile 'com.google.firebase:firebase-database:11.0.0' 52 | 53 | // Firebase Continue 54 | // TODO: Include non-local version of Firebase Continue and remove local libs folder when 55 | // the Firebase Continue for Android library v0.1.0 is released. 56 | compile(name: 'FirebaseContinue-0.1.0', ext: 'aar') 57 | 58 | // FirebaseUI 59 | compile 'com.firebaseui:firebase-ui-auth:2.0.0' 60 | compile 'com.firebaseui:firebase-ui-database:2.0.0' 61 | 62 | // Required by FirebaseUI for signing in via Facebook. 63 | compile 'com.facebook.android:facebook-android-sdk:4.22.0' 64 | } 65 | 66 | apply plugin: 'com.google.gms.google-services' 67 | -------------------------------------------------------------------------------- /samples/android/Continote/app/libs/.gitkeep: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | # in compliance with the License. You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software distributed under the 10 | # License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | # express or implied. See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # 14 | -------------------------------------------------------------------------------- /samples/android/Continote/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /samples/android/Continote/app/src/main/java/com/firebasecontinue/sample/continote/BaseActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.firebasecontinue.sample.continote; 16 | 17 | import android.support.annotation.StringRes; 18 | import android.support.design.widget.Snackbar; 19 | import android.support.v7.app.AppCompatActivity; 20 | import android.view.View; 21 | 22 | import com.google.firebase.auth.FirebaseAuth; 23 | import com.google.firebase.auth.FirebaseUser; 24 | 25 | /** 26 | * The abstract Activity which all other Activities in this app must subclass. 27 | * 28 | * It provides functionality needed by all Activities, such as setting up Firebase Auth to listen 29 | * for authentication state changes. 30 | */ 31 | public abstract class BaseActivity extends AppCompatActivity { 32 | 33 | // Firebase-related 34 | private final FirebaseAuth.AuthStateListener mHandleAuthStateChanged = 35 | new FirebaseAuth.AuthStateListener() { 36 | @Override 37 | public void onAuthStateChanged(FirebaseAuth firebaseAuth) { 38 | FirebaseUser user = firebaseAuth.getCurrentUser(); 39 | if (user != null) { 40 | // Since the user object is non-null, the current user is now signed in. 41 | BaseActivity.this.handleUserSignedIn(user); 42 | } else { 43 | // Since the user object is null, the current user is now signed out. 44 | BaseActivity.this.handleUserSignedOut(); 45 | } 46 | } 47 | }; 48 | 49 | @Override 50 | protected void onStart() { 51 | super.onStart(); 52 | 53 | // Start listening for Firebase Auth state changes. 54 | FirebaseAuth.getInstance().addAuthStateListener(mHandleAuthStateChanged); 55 | } 56 | 57 | @Override 58 | protected void onStop() { 59 | super.onStop(); 60 | 61 | // Stop listening for Firebase Auth state changes. 62 | FirebaseAuth.getInstance().removeAuthStateListener(mHandleAuthStateChanged); 63 | } 64 | 65 | /** 66 | * Displays the provided message in a snackbar. 67 | * 68 | * See: https://developer.android.com/reference/android/support/design/widget/Snackbar.html 69 | */ 70 | protected void showSnackbar(@StringRes final int messageRes) { 71 | runOnUiThread(new Runnable() { 72 | public void run() { 73 | View rootView = findViewById(android.R.id.content); 74 | if (rootView != null) { 75 | Snackbar.make(rootView, messageRes, Snackbar.LENGTH_LONG).show(); 76 | } 77 | } 78 | }); 79 | } 80 | 81 | /** 82 | * Determines and then returns whether or not the current user is signed in. 83 | * 84 | * @return true iff the current user is signed into this app, false otherwise. 85 | */ 86 | protected boolean currentUserIsSignedIn() { 87 | return FirebaseAuth.getInstance().getCurrentUser() != null; 88 | } 89 | 90 | /** 91 | * Handles when the user signs in. 92 | * 93 | * Override in subclasses to respond to this authentication state change. 94 | * 95 | * @param user The user who is now signed in. 96 | */ 97 | protected void handleUserSignedIn(FirebaseUser user) {} 98 | 99 | /** 100 | * Handles when the user signs out. 101 | * 102 | * Override in subclasses to respond to this authentication state change. 103 | */ 104 | protected void handleUserSignedOut() {} 105 | } 106 | -------------------------------------------------------------------------------- /samples/android/Continote/app/src/main/java/com/firebasecontinue/sample/continote/Note.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.firebasecontinue.sample.continote; 16 | 17 | import android.support.annotation.Nullable; 18 | 19 | /** 20 | * A Note for the user within Continote. 21 | * The schema of each Note is outlined in sample-database.rules.json within the web sample. 22 | */ 23 | public class Note { 24 | 25 | // The title of this Note. 26 | @Nullable 27 | private String mTitle = null; 28 | 29 | // The main content of this Note. 30 | @Nullable 31 | private String mContent = null; 32 | 33 | /** 34 | * Constructs a default Note without any values. 35 | * 36 | * This is necessary for Firebase to be able to create a new instance of this class. 37 | */ 38 | public Note() {} 39 | 40 | /** 41 | * Constructs a new Note instance with the provided values. 42 | * 43 | * Important reminder: 44 | * Changes to Notes (such as creating a new Note) on the client-side do not automatically 45 | * propagate to the Firebase Realtime Database. 46 | * 47 | * @param title The title of the Note. 48 | * @param content The main content of the Note. 49 | */ 50 | public Note(@Nullable String title, @Nullable String content) { 51 | mTitle = title; 52 | mContent = content; 53 | } 54 | 55 | /** 56 | * Gets and returns the title of this Note. 57 | * 58 | * @return The title of this Note. 59 | */ 60 | @Nullable 61 | public String getTitle() { 62 | return mTitle; 63 | } 64 | 65 | /** 66 | * Gets and returns the main content of this Note. 67 | * 68 | * @return The main content of this Note. 69 | */ 70 | @Nullable 71 | public String getContent() { 72 | return mContent; 73 | } 74 | 75 | /** 76 | * Sets the title of this Note on the client-side. 77 | * 78 | * This is necessary for Firebase to create and update Note instances. 79 | * 80 | * @param title The new title of this Note. 81 | */ 82 | public void setTitle(@Nullable String title) { 83 | mTitle = title; 84 | } 85 | 86 | /** 87 | * Sets the main content of this Note on the client-side. 88 | * 89 | * This is necessary for Firebase to create and update Note instances. 90 | * 91 | * @param content The new main content of this Note. 92 | */ 93 | public void setContent(@Nullable String content) { 94 | mContent = content; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /samples/android/Continote/app/src/main/java/com/firebasecontinue/sample/continote/NoteListItemViewHolder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.firebasecontinue.sample.continote; 16 | 17 | import android.graphics.Typeface; 18 | import android.support.annotation.Nullable; 19 | import android.text.TextUtils; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * The ListView within MyNotesActivity is filled with items managed by these ViewHolders 25 | * (one per Note). 26 | * 27 | * For more details about the ViewHolder design pattern, see: 28 | * https://developer.android.com/training/improving-layouts/smooth-scrolling.html 29 | */ 30 | public class NoteListItemViewHolder { 31 | 32 | // The key from the Firebase Realtime Database for the Note this ViewHolder represents. 33 | // This is passed to the EditNoteActivity. 34 | @Nullable 35 | private String mNoteDatabaseKey = null; 36 | 37 | /** 38 | * Constructs a new NoteListItemViewHolder instance for the provided View and Note combination. 39 | * 40 | * @param itemView The View managed by this ViewHolder. 41 | * @param note The Note this ViewHolder is for. 42 | * @param databaseKey The database key of the Note this ViewHolder is for. 43 | */ 44 | public NoteListItemViewHolder(View itemView, Note note, String databaseKey) { 45 | if (itemView == null || note == null || TextUtils.isEmpty(databaseKey)) { 46 | // This should not happen, but just in case. 47 | throw new AssertionError("itemView, note, and database key must be non-null/non-empty"); 48 | } 49 | 50 | update(itemView, note, databaseKey); 51 | } 52 | 53 | /** 54 | * Updates this ViewHolder and the UI of the View managed by it based on the provided Note and 55 | * database key. 56 | * 57 | * @param itemView The View managed by this ViewHolder which may need its UI updated. 58 | * @param note The Note this ViewHolder is for (to update the UI based on). 59 | * @param databaseKey The database key of the Note this ViewHolder is for. 60 | */ 61 | public void update(View itemView, Note note, String databaseKey) { 62 | if (itemView == null || note == null || TextUtils.isEmpty(databaseKey)) { 63 | // This should not happen, but just in case. 64 | throw new AssertionError("itemView, note, and database key must be non-null/non-empty"); 65 | } 66 | 67 | mNoteDatabaseKey = databaseKey; 68 | 69 | TextView titleTextView = (TextView) itemView.findViewById(R.id.noteItemTitleTextView); 70 | setTextWithPlaceholder(titleTextView, note.getTitle(), "No Title"); 71 | TextView contentTextView = (TextView) itemView.findViewById(R.id.noteItemContentTextView); 72 | setTextWithPlaceholder(contentTextView, note.getContent(), "No Content"); 73 | } 74 | 75 | /** 76 | * Gets and returns Note database key. 77 | * 78 | * @return The Firebase Realtime Database key for the Note this ViewHolder is for. 79 | */ 80 | @Nullable 81 | public String getNoteDatabaseKey() { 82 | return mNoteDatabaseKey; 83 | } 84 | 85 | /** 86 | * Sets the text of the provided textView to the provided value, or the placeholder if the 87 | * value is null or empty. Also italicizes the textView if the placeholder is used. 88 | * 89 | * This could go into a "Utils" class, but this is the only place it is used, so this 90 | * is sufficient for this sample app. 91 | * 92 | * @param textView The TextView to set the text for. 93 | * @param value The value to set the text to. 94 | * @param placeholder The placeholder text to use if the value above is null or empty. 95 | */ 96 | private static void setTextWithPlaceholder(TextView textView, 97 | @Nullable String value, 98 | @Nullable String placeholder) { 99 | if (!TextUtils.isEmpty(value)) { 100 | // The provided value is nonempty, so use it. 101 | textView.setText(value); 102 | textView.setTypeface(textView.getTypeface(), Typeface.NORMAL); 103 | } else { 104 | // The provided value is empty, so use the placeholder. 105 | textView.setText(placeholder); 106 | textView.setTypeface(textView.getTypeface(), Typeface.ITALIC); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /samples/android/Continote/app/src/main/res/layout/activity_edit_note.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 29 | 30 | 43 | 44 | 55 | 56 | 57 | 66 | 67 | 81 | 82 | 99 | 100 | 117 | 118 | 119 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /samples/chrome-extension/Continote/styles/all-popups.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * These styles apply to all popup pages. 17 | * They are based on the Material Design Lite samples provided here: 18 | * https://getmdl.io/templates/index.html 19 | */ 20 | 21 | html, 22 | body { 23 | margin: 0; 24 | padding: 0; 25 | width: 500px; 26 | min-height: 300px; 27 | font-family: 'Roboto', 'Helvetica', sans-serif; 28 | } 29 | 30 | .mdl-layout__header-row { 31 | padding-left: 16px; 32 | } 33 | 34 | .app-title { 35 | font-weight: bold; 36 | } 37 | 38 | .mdl-layout__content { 39 | padding: 20px; 40 | } 41 | 42 | section:not(:last-child) { 43 | margin-bottom: 20px !important; 44 | } 45 | 46 | .mdl-card { 47 | height: auto; 48 | min-height: 0; 49 | display: -webkit-flex; 50 | display: -ms-flexbox; 51 | display: flex; 52 | -webkit-flex-direction: column; 53 | -ms-flex-direction: column; 54 | flex-direction: column; 55 | } 56 | 57 | .mdl-card > * { 58 | height: auto; 59 | } 60 | 61 | .mdl-card .mdl-card__title { 62 | padding: 10px 10px 0; 63 | } 64 | 65 | .mdl-card .mdl-card__supporting-text { 66 | margin: 10px; 67 | padding: 0; 68 | -webkit-flex-grow: 1; 69 | flex-grow: 1; 70 | } 71 | 72 | .mdl-card__actions { 73 | margin: 0; 74 | padding: 10px; 75 | } 76 | 77 | .hidden { 78 | display: none; 79 | } 80 | -------------------------------------------------------------------------------- /samples/chrome-extension/README.md: -------------------------------------------------------------------------------- 1 | # Firebase Continue Samples - "Continote" Chrome Extension 2 | 3 | This directory contains a sample Chrome extension titled "Continote" which uses 4 | the Firebase Continue for Chrome Extensions library. 5 | 6 | In both the [Android sample app](../android) and the [iOS sample app](../ios), 7 | after a user taps to continue writing their note in Chrome, this extension 8 | allows them to complete that process by opening a link to the 9 | ["Continote" sample web app](../web) to exactly where they left off. 10 | 11 | ## Table of Contents 12 | 13 | 1. [Prerequisites](#prerequisites) 14 | 2. [Setup](#setup) 15 | 3. [Usage](#usage) 16 | 4. [Compatibility](#compatibility) 17 | 5. [Dependencies](#dependencies) 18 | 6. [Disclaimer](#disclaimer) 19 | 20 | ## Prerequisites 21 | 22 | Before proceeding to the [Setup section](#setup) below, you 23 | must first follow the [main `samples` README](../) so that you have a properly 24 | configured Firebase project for this and any other "Continote" samples 25 | you run. 26 | 27 | ## Setup 28 | 29 | After completing the following steps, you will have a properly configured instance of 30 | this sample packaged and installed to try out: 31 | 32 | 1. First, make sure you followed the [Prerequisites section](#prerequisites) above. 33 | 34 | 2. Copy the `firebase-continue.js` Chrome extensions library file 35 | from the Chrome extensions library directory at 36 | [`../../chrome-extensions/`](../../chrome-extensions) 37 | and paste a copy of it in the 38 | [`Continote/scripts/`](Continote/scripts/) directory. 39 | 40 | 3. Copy the `sample-config.js` file from the 41 | [`Continote/scripts/`](Continote/scripts) 42 | directory and paste a copy of it also in 43 | [`Continote/scripts/`](Continote/scripts). 44 | 45 | 4. Rename the `sample-config.js` copy to `config.js`. 46 | 47 | 5. Open `config.js` and fill out the clearly marked *[TODO: YOUR-VALUE-HERE]* details 48 | with the values for your Firebase project which should be listed in the 49 | [initialization code snippet](https://firebase.google.com/docs/web/setup#add_firebase_to_your_app) 50 | for it. 51 | 52 | For example: 53 | 54 | ```javascript 55 | var config_ = { 56 | apiKey: "abcdef123456", 57 | authDomain: "SomeFirebaseProjectName.firebaseapp.com", 58 | databaseURL: "https://SomeFirebaseProjectName.firebaseio.com", 59 | projectId: "SomeFirebaseProjectName" 60 | }; 61 | ``` 62 | 63 | 6. Package and install the extension to Chrome: 64 | 65 | 1. Open Google Chrome if you are not already using it. 66 | 67 | 2. Go to [chrome://extensions](chrome://extensions) to view and modify the 68 | extensions currently installed to your browser. 69 | 70 | 3. If it is not already checked, enable "Developer mode" by clicking the 71 | "Developer mode" checkbox at the top of your 72 | [chrome://extensions](chrome://extensions) page. 73 | 74 | 4. Click the "Pack extension..." button at the top of the page. 75 | 76 | 5. In the "Pack Extension" dialog that appears: 77 | 78 | 1. For the "Extension root directory", choose [`Continote/`](Continote). 79 | 80 | 2. For the "Private key file", choose nothing since this initial packaging 81 | and installing will generate a private key file for you to use in 82 | the future. 83 | 84 | 6. Click the "Pack Extension" to package the extension (i.e. generate 85 | installation and private key files). 86 | 87 | 7. Make note of where your extenion's `Continote.crx` and `Continote.pem` files 88 | were generated (most likely, they could be generated in this directory). 89 | 90 | **Keep your `Continote.pem` key file in a safe place. 91 | You will need it to package and install new versions of your extension.** 92 | 93 | 8. Navigate to where your `Continote.crx` file is, and drag it onto the 94 | [chrome://extensions](chrome://extensions) page in Chrome to install 95 | your extension. 96 | 97 | 9. Make note of your extension's **ID** on that page. You will need it later. 98 | 99 | 7. [Whitelist your Chrome extension ID in Firebase](https://firebase.google.com/docs/auth/web/google-signin#authenticate_with_firebase_in_a_chrome_extension) 100 | to allow Firebase Authentication within the extension. 101 | 102 | 8. Done! 103 | 104 | **Important Reminder**: 105 | If you make any changes to the code of your Chrome extension, remember 106 | to repeat the "package and install" step of this setup guide with one difference: 107 | provide the "Pack Extension" dialog with your private key file that was generated 108 | the first time you packaged and installed the extension. This is so that 109 | the packaging updates your existing Chrome extension, instead of creating 110 | a new Chrome extension with a new ID. 111 | 112 | ## Usage 113 | 114 | After this sample is properly set up and installed to your Chrome browser, 115 | open it by clicking its 116 | [browser action icon button](https://developer.chrome.com/extensions/browserAction). 117 | 118 | From there, you will be asked to sign in to be able to receive notifications to 119 | continue writing notes. 120 | 121 | ## Compatibility 122 | 123 | This sample Chrome extension is compatible with the 124 | [same versions of Chrome as the Firebase Continue library itself](../../chrome-extensions/#compatibility). 125 | 126 | Please ensure popups are not blocked, and JavaScript is enabled. 127 | 128 | ## Dependencies 129 | 130 | This sample is dependent on the following libraries/SDKs: 131 | 132 | ### Firebase 133 | - [firebase-app.js v4.0.0+](https://firebase.google.com/docs/web/setup#add_firebase_to_your_app) 134 | - [firebase-auth.js v4.0.0+](https://firebase.google.com/docs/web/setup#add_firebase_to_your_app) 135 | - [firebase-database.js v4.0.0+](https://firebase.google.com/docs/web/setup#add_firebase_to_your_app) 136 | 137 | ### Firebase Continue 138 | - [Firebase Continue for Chrome Extensions v0.1.0+](../../chrome-extensions) 139 | 140 | ### Material Design Lite 141 | - [Material Design Lite v1.3.0+](https://getmdl.io/) 142 | 143 | ## Disclaimer 144 | 145 | The focus of this sample is to demonstrate Firebase Continue usage in a 146 | somewhat realistic scenario. This sample can also act as a simple model of how 147 | to use Firebase in a Chrome extension. 148 | 149 | The focus is *not*, however, to have a perfect user interface or user 150 | experience. Please keep that in mind when trying out this sample. 151 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | import Firebase 19 | import FirebaseAuth 20 | import FirebaseAuthUI 21 | 22 | @UIApplicationMain 23 | class AppDelegate: UIResponder, UIApplicationDelegate { 24 | 25 | var window: UIWindow? 26 | 27 | func application(_ application: UIApplication, 28 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 29 | 30 | // Set up Firebase 31 | FirebaseApp.configure() 32 | 33 | return true 34 | } 35 | 36 | @available(iOS 9.0, *) 37 | func application(_ app: UIApplication, open url: URL, 38 | options: [UIApplicationOpenURLOptionsKey: Any]) -> Bool { 39 | let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String? 40 | return handleOpenUrl(url, sourceApplication: sourceApplication) 41 | } 42 | 43 | @available(iOS 8.0, *) 44 | func application(_ application: UIApplication, open url: URL, 45 | sourceApplication: String?, annotation: Any) -> Bool { 46 | return handleOpenUrl(url, sourceApplication: sourceApplication) 47 | } 48 | 49 | /** 50 | Handles opening a URL to complete the sign in process. 51 | 52 | - Parameter url: This is passed to FirebaseUI to complete the sign in process. 53 | - Parameter sourceApplication: This is passed to FirebaseUI to complete the sign in process. 54 | - Returns: true iff FirebaseAuthUI handled the url, false otherwise. 55 | */ 56 | func handleOpenUrl(_ url: URL, sourceApplication: String?) -> Bool { 57 | // This is needed to complete the sign in process. 58 | if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false { 59 | return true 60 | } 61 | 62 | return false 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "filename" : "Icon-60@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "idiom" : "iphone", 41 | "size" : "60x60", 42 | "filename" : "Icon-60@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ipad", 47 | "size" : "20x20", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "idiom" : "ipad", 52 | "size" : "20x20", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "idiom" : "ipad", 57 | "size" : "29x29", 58 | "scale" : "1x" 59 | }, 60 | { 61 | "idiom" : "ipad", 62 | "size" : "29x29", 63 | "scale" : "2x" 64 | }, 65 | { 66 | "idiom" : "ipad", 67 | "size" : "40x40", 68 | "scale" : "1x" 69 | }, 70 | { 71 | "idiom" : "ipad", 72 | "size" : "40x40", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "idiom" : "ipad", 77 | "size" : "76x76", 78 | "filename" : "Icon-76@1x.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "idiom" : "ipad", 83 | "size" : "76x76", 84 | "filename" : "Icon-76@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "idiom" : "ipad", 89 | "size" : "83.5x83.5", 90 | "filename" : "Icon-83.5@2x.png", 91 | "scale" : "2x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-76@1x.png -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/ios/Continote/Continote/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "ipad", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "1x" 9 | }, 10 | { 11 | "orientation" : "landscape", 12 | "idiom" : "ipad", 13 | "extent" : "full-screen", 14 | "minimum-system-version" : "7.0", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "orientation" : "portrait", 19 | "idiom" : "ipad", 20 | "extent" : "full-screen", 21 | "minimum-system-version" : "7.0", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "orientation" : "landscape", 26 | "idiom" : "ipad", 27 | "extent" : "full-screen", 28 | "minimum-system-version" : "7.0", 29 | "scale" : "2x" 30 | } 31 | ], 32 | "info" : { 33 | "version" : 1, 34 | "author" : "xcode" 35 | } 36 | } -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | import Firebase 19 | import MaterialComponents.MaterialAppBar 20 | 21 | /** 22 | The abstract UIViewController which all other ViewControllers in this app must subclass. 23 | 24 | It sets up various common UI elements (such as the top AppBar for navigation and title purposes), 25 | and listens for authentication state changes to pass along to subclasses. 26 | */ 27 | class BaseViewController: UIViewController { 28 | 29 | // Firebase related 30 | private lazy var auth: Auth = { Auth.auth() }() 31 | private var authStateDidChangeListenerHandle: AuthStateDidChangeListenerHandle? 32 | 33 | // AppBar for navigation and title purposes. This replaces the standard UINavigationController's 34 | // navigation bar. 35 | private let appBar = MDCAppBar() 36 | 37 | override func viewDidLoad() { 38 | super.viewDidLoad() 39 | 40 | // Set up this screen's AppBar. 41 | addChildViewController(appBar.headerViewController) 42 | appBar.addSubviewsToParent() 43 | appBar.applyAppTheme() 44 | } 45 | 46 | override func viewWillAppear(_ animated: Bool) { 47 | super.viewWillAppear(animated) 48 | 49 | // Hide the UINavigationController's NavigationBar since we are using a Material Components 50 | // AppBar. 51 | // See: https://material.io/components/ios/catalog/flexible-headers/#interacting-with-uinavigationcontroller 52 | navigationController?.setNavigationBarHidden(true, animated: animated) 53 | 54 | // Add the authentication state handler to get current state as well as any future changes. 55 | authStateDidChangeListenerHandle = 56 | auth.addStateDidChangeListener(handleAuthStateDidChange(auth:user:)) 57 | } 58 | 59 | override func viewWillDisappear(_ animated: Bool) { 60 | super.viewWillDisappear(animated) 61 | 62 | // Remove the authentication state handler. 63 | if let handle = authStateDidChangeListenerHandle { 64 | auth.removeStateDidChangeListener(handle) 65 | authStateDidChangeListenerHandle = nil 66 | } 67 | } 68 | 69 | override func viewWillLayoutSubviews() { 70 | super.viewDidLayoutSubviews() 71 | 72 | // Ensure the main screen UI falls below the top AppBar. 73 | // See: https://material.io/components/ios/catalog/flexible-headers/ 74 | appBar.headerViewController.updateTopLayoutGuide() 75 | } 76 | 77 | /** 78 | Handles when the user signs in. 79 | 80 | Override in a subclass to react to this event. 81 | 82 | - Parameter user: The user who is now signed in. 83 | */ 84 | func handleUserSignedIn(_ user: User) {} 85 | 86 | /** 87 | Handles when the user signs out. 88 | 89 | Override in a subclass to react to this event. 90 | */ 91 | func handleUserSignedOut() {} 92 | 93 | /** 94 | Determines if the user is currently signed in. 95 | 96 | - Returns: true iff the current user is signed into this app, false otherwise. 97 | */ 98 | func currentUserIsSignedIn() -> Bool { 99 | return auth.currentUser != nil 100 | } 101 | 102 | /** 103 | Handles when the user's Auth state changes. 104 | 105 | Firebase is provided this method as a callback for when the user signs in or out. 106 | 107 | It is also invoked right away by Firebase with the initial Auth state when the handler is 108 | registered with Firebase. 109 | 110 | See: https://firebase.google.com/docs/reference/ios/firebaseauth/api/reference/Classes/FIRAuth#-addauthstatedidchangelistener 111 | 112 | - Parameter auth: The Auth instance which called this listener. 113 | - Parameter user: The user who is now signed in, or nil if no user is signed in. 114 | */ 115 | func handleAuthStateDidChange(auth: Auth, user: User?) { 116 | if let user = user { 117 | // The user IS signed in. 118 | handleUserSignedIn(user) 119 | } else { 120 | // The user is NOT signed in. 121 | handleUserSignedOut() 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Continote-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import "FCNContinue.h" 18 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | import FirebaseAuthUI 19 | import FirebaseFacebookAuthUI 20 | import FirebaseGoogleAuthUI 21 | import MaterialComponents.MaterialButtons 22 | import MaterialComponents.MaterialSnackbar 23 | 24 | /** 25 | The ViewController that is initially pushed onto this app's UINavigationController. 26 | 27 | It presents the user with an initial screen to either sign in and then navigate to other screens, 28 | or sign out. 29 | */ 30 | class MainViewController: BaseViewController { 31 | 32 | // FirebaseUI related 33 | private lazy var authUI: FUIAuth = { 34 | // Set up FirebaseUI authentication. 35 | let customizedAuthUI: FUIAuth = FUIAuth.defaultAuthUI()! 36 | customizedAuthUI.providers = Constants.Auth.providers 37 | customizedAuthUI.isSignInWithEmailHidden = true 38 | return customizedAuthUI 39 | }() 40 | 41 | // UI outlets 42 | @IBOutlet var authLabel: UILabel! 43 | @IBOutlet var authButton: MDCRaisedButton! 44 | @IBOutlet var myNotesButton: MDCRaisedButton! 45 | 46 | override func viewDidLoad() { 47 | super.viewDidLoad() 48 | 49 | // Set up this screen's AppBar title. 50 | title = Constants.appName 51 | 52 | // Style all labels. 53 | authLabel.applyAppTheme(for: .normalText) 54 | 55 | // Style all buttons. 56 | authButton.applyAppTheme() 57 | myNotesButton.applyAppTheme() 58 | } 59 | 60 | override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { 61 | guard let destination = Constants.Segue(rawValue: identifier) else { return false } 62 | 63 | if destination == .myNotes { 64 | // The user should only be able to go to the notes screen if they are signed in. 65 | return currentUserIsSignedIn() 66 | } 67 | 68 | return false 69 | } 70 | 71 | override func handleUserSignedIn(_ user: User) { 72 | super.handleUserSignedIn(user) 73 | 74 | // Update the UI to reflect the user now being signed in. 75 | let name:String = user.displayName! 76 | let email:String = user.email! 77 | authLabel.text = String(format: Constants.Text.welcomeMessage, name, email) 78 | authButton.setTitle(Constants.Text.signOutButtonTitle, for: .normal) 79 | myNotesButton.isHidden = false 80 | } 81 | 82 | override func handleUserSignedOut() { 83 | super.handleUserSignedOut() 84 | 85 | // Update the UI to reflect the user now being signed out. 86 | authLabel.text = Constants.Text.signInMessage 87 | authButton.setTitle(Constants.Text.signInButtonTitle, for: .normal) 88 | myNotesButton.isHidden = true 89 | } 90 | 91 | /** 92 | Presents the sign in screen to the user, if they are currently signed out. 93 | */ 94 | func presentSignInScreen() { 95 | guard !currentUserIsSignedIn() else { return } 96 | 97 | // Present the sign in screen. 98 | present(authUI.authViewController(), animated: true) 99 | } 100 | 101 | /** 102 | Signs the user out, if they are currently signed in. 103 | */ 104 | func signUserOut() { 105 | guard currentUserIsSignedIn() else { return } 106 | 107 | do { 108 | // Try to sign the user out. 109 | try authUI.signOut() 110 | } catch { 111 | MDCSnackbarManager.show(Constants.Text.ErrorMessage.couldNotSignOut) 112 | } 113 | } 114 | 115 | /** 116 | Handles when the user taps the auth (i.e. "Sign In"/"Sign Out") button. 117 | 118 | - Parameter sender: The object that called this action. This should only be the authButton. 119 | */ 120 | @IBAction func authButtonAction(_ sender: Any) { 121 | if !currentUserIsSignedIn() { 122 | // The user is NOT signed in, so they want to sign in. 123 | presentSignInScreen() 124 | } else { 125 | // The user IS signed in, so they want to sign out. 126 | signUserOut() 127 | } 128 | } 129 | } 130 | 131 | /** 132 | These local constants are organized as a private extension to the global Constants struct 133 | for clarity and a cleaner namespace. 134 | */ 135 | private extension Constants { 136 | struct Auth { 137 | // These are the authentication methods this app allows. 138 | static let providers: [FUIAuthProvider] = [FUIGoogleAuth(), FUIFacebookAuth()] 139 | } 140 | 141 | struct Text { 142 | static let signInMessage: String = "Please sign in below to use \(appName)." 143 | static let welcomeMessage: String = "Hello %@!\nYou are currently signed in as %@" 144 | 145 | static let signInButtonTitle: String = "Sign In" 146 | static let signOutButtonTitle: String = "Sign Out" 147 | 148 | struct ErrorMessage { 149 | static let couldNotSignOut: String = "Could not sign out. Please try again." 150 | } 151 | } 152 | 153 | // These segue identifiers must match the identifiers defined in the Main storyboard. 154 | enum Segue: String { 155 | case myNotes = "myNotes" 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/MyNotesTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | 19 | /** 20 | The TableView within MyNotesViewController is filled with these cells (one per Note). 21 | */ 22 | class MyNotesTableViewCell: UITableViewCell { 23 | 24 | // The key from the Firebase Realtime Database for the Note this cell represents. 25 | // This is passed to the EditNoteViewController. 26 | var noteKey: String? 27 | 28 | // The Note this cell represents. 29 | var note: Note? { 30 | didSet { 31 | // Populate this cell with the values from the Note. 32 | titleLabel.setText(to: note?.title, 33 | withPlaceholder: "No Title", 34 | using: Constants.Theme.LabelKind.titleText.getFont()) 35 | contentLabel.setText(to: note?.content, 36 | withPlaceholder: "No Content", 37 | using: Constants.Theme.LabelKind.normalText.getFont()) 38 | } 39 | } 40 | 41 | // UI outlets 42 | @IBOutlet var titleLabel: UILabel! 43 | @IBOutlet var contentLabel: UILabel! 44 | 45 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 46 | super.init(style: style, reuseIdentifier: reuseIdentifier) 47 | 48 | // Style all labels. 49 | titleLabel.applyAppTheme(for: .titleText) 50 | contentLabel.applyAppTheme(for: .normalText) 51 | } 52 | 53 | required init?(coder aDecoder: NSCoder) { 54 | super.init(coder: aDecoder) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/MyNotesTableViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | import FirebaseDatabase 19 | import FirebaseDatabaseUI 20 | import MaterialComponents.MaterialSnackbar 21 | 22 | /** 23 | The data source used for the TableView in MyNotesViewController. 24 | 25 | We need to override FUITableViewDataSource in order to allow the user to edit 26 | (and then subsequently delete) rows (i.e. Notes) within the table. 27 | */ 28 | class MyNotesTableViewDataSource: FUITableViewDataSource { 29 | 30 | override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 31 | // Allow the user to edit any row in the table. 32 | return true 33 | } 34 | 35 | override func tableView(_ tableView: UITableView, 36 | commit editingStyle: UITableViewCellEditingStyle, 37 | forRowAt indexPath: IndexPath) { 38 | guard editingStyle == .delete else { return } 39 | 40 | // Attempt to delete the corresponding Note from the Firebase Realtime Database. 41 | if (UInt(indexPath.row) < count) { 42 | snapshot(at: indexPath.row).ref.removeValue { (error, ref) in 43 | guard error == nil else { 44 | MDCSnackbarManager.show(Constants.AppError.couldNotDeleteNote.rawValue) 45 | return 46 | } 47 | } 48 | } 49 | } 50 | } 51 | 52 | /** 53 | These local constants are organized as a private extension to the global Constants struct 54 | for clarity and a cleaner namespace. 55 | */ 56 | private extension Constants { 57 | enum AppError: String, Error { 58 | case couldNotDeleteNote = "Could not delete note. Please try again." 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/MyNotesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import UIKit 18 | import Firebase 19 | import FirebaseDatabaseUI 20 | import MaterialComponents.MaterialButtons 21 | 22 | /** 23 | The ViewController that presents the user with a table of their Notes in Continote. 24 | 25 | From here the user can add, delete, or open to edit Notes. 26 | */ 27 | class MyNotesViewController: BaseViewController { 28 | 29 | // Firebase Realtime Database reference for the current user's Notes within Continote. 30 | private var notesRef: DatabaseReference? 31 | 32 | // The data source to populate the TableView of Notes for the current user. 33 | private var dataSource: MyNotesTableViewDataSource? 34 | 35 | // UI outlets 36 | @IBOutlet var tableView: UITableView! 37 | @IBOutlet var newNoteButton: MDCRaisedButton! 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | 42 | // Set up this screen's AppBar title. 43 | title = Constants.Text.screenTitle 44 | 45 | // Style all buttons. 46 | newNoteButton.applyAppTheme() 47 | } 48 | 49 | override func viewWillDisappear(_ animated: Bool) { 50 | super.viewWillDisappear(animated) 51 | 52 | // Remove all bindings and database observers. 53 | dataSource?.unbind() 54 | dataSource = nil 55 | notesRef?.removeAllObservers() 56 | notesRef = nil 57 | } 58 | 59 | override func viewDidAppear(_ animated: Bool) { 60 | super.viewDidAppear(animated) 61 | 62 | tableView.flashScrollIndicators() 63 | } 64 | 65 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 66 | guard let identifierString = segue.identifier, 67 | let segueIdentifier = Constants.Segue(rawValue: identifierString), 68 | segueIdentifier == .editNote else { return } 69 | 70 | // We need to let the EditNoteViewController know which Note the user wishes to edit 71 | // before the segue can be performed. 72 | let editNoteViewController = segue.destination as! EditNoteViewController 73 | 74 | // Set the databaseKey based on the object passed in. 75 | if let cell = sender as? MyNotesTableViewCell { 76 | editNoteViewController.databaseKey = cell.noteKey 77 | } else if let key = sender as? String { 78 | editNoteViewController.databaseKey = key 79 | } 80 | } 81 | 82 | override func handleUserSignedIn(_ user: User) { 83 | super.handleUserSignedIn(user) 84 | 85 | // Set up our TableView up to sync with the Notes for the current user from the Firebase 86 | // Realtime Database. 87 | notesRef = Database.database().reference(withPath: "notes/\(user.uid)") 88 | dataSource = MyNotesTableViewDataSource( 89 | query: notesRef!, 90 | populateCell: { tableView, indexPath, snapshot in 91 | // Get the data for this Note, as gathered from the Firebase Realtime Database, and parse 92 | // it to create a Note struct for this cell. 93 | let noteKey:String = snapshot.key 94 | let note: Note? = Note(with: snapshot) 95 | 96 | // Get and then populate a cell in the TableView to use for this Note. 97 | let cell = tableView.dequeueReusableCell(withIdentifier: "MyNotesTableViewCell") 98 | as! MyNotesTableViewCell 99 | cell.noteKey = noteKey 100 | cell.note = note 101 | 102 | return cell 103 | }) 104 | 105 | dataSource?.bind(to: tableView) 106 | 107 | // Finally, show this screen's UI since everything is ready. 108 | tableView.isHidden = false 109 | newNoteButton.isHidden = false 110 | } 111 | 112 | override func handleUserSignedOut() { 113 | super.handleUserSignedOut() 114 | 115 | // Hide this screen's UI since the user must be signed in to see any Notes. 116 | tableView.isHidden = true 117 | newNoteButton.isHidden = true 118 | 119 | // The user must be signed in to view this screen, so navigate away from it if the user is 120 | // signed out. 121 | navigationController?.popViewController(animated: true) 122 | } 123 | 124 | /** 125 | Handles when the user taps the newNoteButton. 126 | 127 | Adds a new Note to the Firebase Realtime Database for the current user, 128 | then opens that Note to allow the user to begin writing. 129 | 130 | - Parameter sender: The object that called this action. This should only be the newNoteButton. 131 | */ 132 | @IBAction func newNoteButtonAction(_ sender: Any) { 133 | guard let notesRef = notesRef else { return } 134 | 135 | // Add a new, empty Note to the Firebase Realtime Database for the current user. 136 | let newNote: Note = Note(title: "", content: "") 137 | let newNoteRef: DatabaseReference = notesRef.childByAutoId() 138 | newNoteRef.setValue(newNote.firebaseData) { [weak self] (error, ref) -> Void in 139 | guard error == nil else { 140 | MDCSnackbarManager.show(Constants.AppError.couldNotCreateNewNote.rawValue) 141 | return 142 | } 143 | 144 | // Open the Edit Note screen with this Note. 145 | // We do this so that the user may immediately edit the Note, rather than 146 | // having to wait for the TableView to update from Firebase Realtime Database 147 | // events and then manually tap the cell for the Note. 148 | DispatchQueue.main.async { 149 | self?.performSegue(withIdentifier: Constants.Segue.editNote.rawValue, sender: ref.key) 150 | } 151 | } 152 | } 153 | } 154 | 155 | /** 156 | These local constants are organized as a private extension to the global Constants struct 157 | for clarity and a cleaner namespace. 158 | */ 159 | private extension Constants { 160 | struct Text { 161 | static let screenTitle: String = "My Notes" 162 | } 163 | 164 | enum AppError: String, Error { 165 | case couldNotCreateNewNote = "Could not create a new note. Please try again." 166 | } 167 | 168 | // These segue identifiers must match the identifiers defined in the Main storyboard. 169 | enum Segue: String { 170 | case editNote = "editNote" 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Note.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import FirebaseDatabase 18 | 19 | /** 20 | A Note for the user within Continote. 21 | The schema of each Note is outlined in sample-database.rules.json within the web sample. 22 | 23 | Each Note is considered immutable on the client-side to simplify syncing with the database for 24 | this sample. 25 | */ 26 | struct Note { 27 | 28 | // The title of this Note. 29 | let title: String 30 | 31 | // The main content of this Note. 32 | let content: String 33 | 34 | // The Firebase Realtime Database representation of this Note. 35 | // This could be used to add or set a Note value in the database. 36 | let firebaseData: [String : AnyObject] 37 | 38 | /** 39 | Initializes a Note with the provided values. 40 | 41 | - Parameter title: The title of the Note. 42 | - Parameter content: The main content of the Note. 43 | */ 44 | init(title: String, content: String) { 45 | self.title = title 46 | self.content = content 47 | firebaseData = [ 48 | "title": self.title as AnyObject, 49 | "content": self.content as AnyObject 50 | ] 51 | } 52 | 53 | /** 54 | Attempts to initialize a Note using values from the provided Firebase Realtime Database data 55 | snapshot. This could be more robust, but is sufficient for this sample app. 56 | 57 | - Parameter firebaseData: The Firebase data snapshot to attempt to convert into a Note. 58 | */ 59 | init?(with firebaseData: DataSnapshot?) { 60 | guard let data = firebaseData, 61 | let value = data.value as? [String : AnyObject], 62 | let noteTitle = value["title"] as? String, 63 | let noteContent = value["content"] as? String else { 64 | return nil 65 | } 66 | 67 | self.init(title: noteTitle, content: noteContent) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Sample-Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import MaterialComponents.MaterialTypography 18 | import MaterialComponents.MDCColorScheme 19 | 20 | /** 21 | These constants are organized as part of a struct for clarity and a cleaner namespace. 22 | 23 | The constants predefined below are relevant to more than one screen within the app. 24 | For local constants, use a private extension within the file you need those extra constants. 25 | See the use of "private extension Constants" in MainViewController.swift for an example. 26 | */ 27 | struct Constants { 28 | static let appName: String = "Continote" 29 | 30 | // FirebaseContinue usage related. 31 | struct FirebaseContinue { 32 | static let applicationName: String = "continote" 33 | static let urlToEditNoteWithKey: String = 34 | "[TODO: YOUR-FIREBASE-HOSTING-URL-FOR-CONTINOTE-WEB-HERE]/edit-note.html?noteKey=%@" 35 | } 36 | 37 | // UI appearance related constants. 38 | struct Theme { 39 | 40 | // The color scheme we will apply to Material Components to mimic the look of Firebase. 41 | static let colorScheme: MDCColorScheme & NSObjectProtocol = 42 | MDCBasicColorScheme.init( 43 | primaryColor: UIColor(red: 1.0, green: 0.76, blue: 0.05, alpha: 1.0), 44 | secondaryColor: UIColor(red: 1.0, green: 0.6, blue: 0, alpha: 1.0)) 45 | 46 | struct Button { 47 | // The elevation for buttons to give a raised look. 48 | static let elevation: CGFloat = 4; 49 | } 50 | 51 | // All text-based inputs (i.e. UITextField and UITextView). 52 | struct TextInput { 53 | static let borderColor: CGColor = 54 | UIColor(red: 0.76, green: 0.76, blue: 0.76, alpha: 0.5).cgColor 55 | static let borderWidth: CGFloat = 1 56 | static let borderCornerRadius: CGFloat = 2 57 | } 58 | 59 | enum LabelKind { 60 | 61 | // Labels with text we wish to appear normal/standard (such as longer text content). 62 | case normalText 63 | 64 | // Labels with text we wish to appear as a title. 65 | case titleText 66 | 67 | /** 68 | - Returns: The font to use for this kind of label. 69 | */ 70 | func getFont() -> UIFont { 71 | switch self { 72 | case .normalText: 73 | return MDCTypography.subheadFont() 74 | case .titleText: 75 | return MDCTypography.titleFont() 76 | } 77 | } 78 | 79 | /** 80 | - Returns: The alpha to use for this kind of label. 81 | */ 82 | func getAlpha() -> CGFloat { 83 | switch self { 84 | case .normalText: 85 | return MDCTypography.subheadFontOpacity() 86 | case .titleText: 87 | return MDCTypography.titleFontOpacity() 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import MaterialComponents.MaterialAppBar 18 | import MaterialComponents.MaterialButtons 19 | import MaterialComponents.MaterialSnackbar 20 | import MaterialComponents.MaterialTextFields 21 | import MaterialComponents.MDCAppBarColorThemer 22 | import MaterialComponents.MDCButtonColorThemer 23 | import MaterialComponents.MDCTypography 24 | 25 | /** 26 | This file provides some simple utility functions for use throughout the app. 27 | */ 28 | 29 | extension MDCAppBar { 30 | /** 31 | Applies a standardized visual style to this AppBar. 32 | */ 33 | func applyAppTheme() { 34 | MDCAppBarColorThemer.apply(Constants.Theme.colorScheme, to: self) 35 | } 36 | } 37 | 38 | extension MDCRaisedButton { 39 | /** 40 | Applies a standardized visual style to this button. 41 | */ 42 | func applyAppTheme() { 43 | setElevation(Constants.Theme.Button.elevation, for: .normal) 44 | MDCButtonColorThemer.apply(Constants.Theme.colorScheme, to: self) 45 | } 46 | } 47 | 48 | extension UILabel { 49 | /** 50 | Applies a standardized visual style to this label of a certain kind. 51 | 52 | - Parameter labelKind: The kind of label to appear as. 53 | */ 54 | func applyAppTheme(for labelKind: Constants.Theme.LabelKind) { 55 | font = labelKind.getFont() 56 | alpha = labelKind.getAlpha() 57 | } 58 | 59 | /** 60 | Sets this label's text to the provided value, or the provided placeholder if the value is 61 | nil or empty. 62 | 63 | If the text is set to the provided value, the desiredFont will be applied to the label. 64 | Otherwise, if the placeholder is used, an italicized version of the desiredFont will be applied. 65 | 66 | - Parameter value: The value to set the text to. 67 | - Parameter placeholder: The placeholder text to use if the value above is nil or empty. 68 | - Parameter desiredFont: The font to use if the text is set to the provided value. 69 | */ 70 | func setText(to value: String?, withPlaceholder placeholder: String, using desiredFont: UIFont) { 71 | if !(value ?? "").isEmpty { 72 | text = value; 73 | font = desiredFont 74 | } else { 75 | text = placeholder; 76 | font = MDCTypography.italicFont(from: desiredFont) 77 | } 78 | } 79 | } 80 | 81 | extension MDCTextField { 82 | /** 83 | Applies a standardized visual style to this MDCTextField. 84 | */ 85 | func applyAppTheme() { 86 | font = Constants.Theme.LabelKind.titleText.getFont() 87 | } 88 | } 89 | 90 | extension MDCMultilineTextField { 91 | /** 92 | Applies a standardized visual style to this MDCMultilineTextField. 93 | */ 94 | func applyAppTheme() { 95 | font = Constants.Theme.LabelKind.normalText.getFont() 96 | } 97 | } 98 | 99 | extension MDCSnackbarManager { 100 | /** 101 | Shows the provided text in a snackbar message. 102 | 103 | See: https://material.io/components/ios/catalog/snackbars/ 104 | 105 | - Parameter text: The text to show. 106 | */ 107 | static func show(_ text: String) { 108 | MDCSnackbarManager.show(MDCSnackbarMessage(text: text)) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /samples/ios/Continote/Continote/sample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FacebookAppID 6 | [TODO: YOUR-FACEBOOK-APP-ID-HERE] 7 | FacebookDisplayName 8 | [TODO: YOUR-FACEBOOK-APP-NAME-HERE] 9 | LSApplicationQueriesSchemes 10 | 11 | fbauth2 12 | 13 | CFBundleDevelopmentRegion 14 | en 15 | CFBundleDisplayName 16 | Continote 17 | CFBundleExecutable 18 | $(EXECUTABLE_NAME) 19 | CFBundleIdentifier 20 | $(PRODUCT_BUNDLE_IDENTIFIER) 21 | CFBundleInfoDictionaryVersion 22 | 6.0 23 | CFBundleName 24 | $(PRODUCT_NAME) 25 | CFBundlePackageType 26 | APPL 27 | CFBundleShortVersionString 28 | 1.0 29 | CFBundleURLTypes 30 | 31 | 32 | CFBundleTypeRole 33 | Editor 34 | CFBundleURLSchemes 35 | 36 | [TODO: YOUR-GOOGLESERVICE-INFO.PLIST-RESERVED_CLIENT_ID-HERE] 37 | 38 | 39 | 40 | CFBundleTypeRole 41 | Editor 42 | CFBundleURLSchemes 43 | 44 | fb[TODO: YOUR-FACEBOOK-APP-ID-HERE] 45 | 46 | 47 | 48 | CFBundleVersion 49 | 1 50 | LSRequiresIPhoneOS 51 | 52 | UILaunchStoryboardName 53 | LaunchScreen 54 | UIMainStoryboardFile 55 | Main 56 | UIRequiredDeviceCapabilities 57 | 58 | armv7 59 | 60 | UISupportedInterfaceOrientations 61 | 62 | UIInterfaceOrientationPortrait 63 | 64 | UISupportedInterfaceOrientations~ipad 65 | 66 | UIInterfaceOrientationPortrait 67 | UIInterfaceOrientationPortraitUpsideDown 68 | UIInterfaceOrientationLandscapeLeft 69 | UIInterfaceOrientationLandscapeRight 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /samples/ios/Continote/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | 3 | target 'Continote' do 4 | use_frameworks! 5 | 6 | # Firebase (https://github.com/firebase/firebase-ios-sdk) 7 | pod 'Firebase/Auth', '~> 4.0' 8 | pod 'Firebase/Database', '~> 4.0' 9 | 10 | # FirebaseUI (https://github.com/firebase/FirebaseUI-iOS) 11 | pod 'FirebaseUI/Auth', '~> 4.0' 12 | pod 'FirebaseUI/Database', '~> 4.0' 13 | pod 'FirebaseUI/Google', '~> 4.0' 14 | pod 'FirebaseUI/Facebook', '~> 4.0' 15 | 16 | # Material Components (https://github.com/material-components/material-components-ios/) 17 | pod 'MaterialComponents/AppBar', '~> 31.0' 18 | pod 'MaterialComponents/AppBar/ColorThemer', '~> 31.0' 19 | pod 'MaterialComponents/Buttons', '~> 31.0' 20 | pod 'MaterialComponents/Buttons/ColorThemer', '~> 31.0' 21 | pod 'MaterialComponents/Snackbar', '~> 31.0' 22 | pod 'MaterialComponents/TextFields', '~> 31.0' 23 | pod 'MaterialComponents/Typography', '~> 31.0' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /samples/web/Continote/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "rules": "database.rules.json" 4 | }, 5 | "hosting": { 6 | "public": "public" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/web/Continote/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Continote - Firebase Continue Sample - 404 Page Not Found 27 | 28 | 29 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 |
48 |
49 | 50 | 51 |
52 | Continote — 53 | Firebase Continue Sample — 404 Page Not Found 54 |
55 | 56 | 57 |
58 | 59 | 60 | 66 |
67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 |
75 |
76 |
77 |

78 | 404 Page Not Found 79 |

80 |
81 |
82 |

83 | The page you tried to visit was not found. 84 |

85 |

86 | Navigate back Home at the top of this page and try again. 87 |

88 |
89 |
90 |
91 |
92 |
93 |
94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /samples/web/Continote/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirebaseExtended/firebase-continue/b8c94cad16a80efba152f20a0f652e38050611f9/samples/web/Continote/public/images/favicon.ico -------------------------------------------------------------------------------- /samples/web/Continote/public/my-notes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Continote - Firebase Continue Sample - My Notes 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 | 65 | 66 |
67 |
68 | 69 | 70 |
71 | Continote — 72 | Firebase Continue Sample — My Notes 73 |
74 | 75 | 76 |
77 | 78 | 79 | 90 |
91 |
92 | 93 | 94 |
95 | 96 | 97 | 123 | 124 | 125 | 130 | 131 | 135 |
136 |
137 | 138 |
139 | 140 |
141 |
142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /samples/web/Continote/public/scripts/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a 6 | * copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * This script is loaded and running whenever the index.html page is open. 19 | */ 20 | (function() { 21 | 'use strict'; 22 | 23 | /** 24 | * AuthHelper instance to simplify Firebase Auth usage. 25 | * 26 | * @type {?AuthHelper} 27 | */ 28 | var authHelper_ = null; 29 | 30 | /** 31 | * Various UI elements which will be manipulated through the lifecycle of 32 | * this page. These are organized as part of an object for clarity and a 33 | * cleaner namespace. 34 | * 35 | * @type {!Object} 36 | * @const 37 | */ 38 | var pageUi_ = { 39 | userDisplayName: null, 40 | userEmail: null, 41 | signOutButton: null 42 | }; 43 | 44 | /** 45 | * Handles when the user signs in. 46 | * 47 | * See auth-helper.js for more details. 48 | * 49 | * @type {!UserSignedInCallback} 50 | * @const 51 | */ 52 | var handleUserSignedIn_ = function(user) { 53 | // Set up the UI for signed in users. 54 | pageUi_.userDisplayName.textContent = user.displayName; 55 | pageUi_.userEmail.textContent = user.email; 56 | Utils.enableButtonAndAddClickListener( 57 | pageUi_.signOutButton, handleSignOutButtonClicked_); 58 | }; 59 | 60 | /** 61 | * Handles when the user signs out. 62 | * 63 | * See auth-helper.js for more details. 64 | * 65 | * @type {!UserSignedOutCallback} 66 | * @const 67 | */ 68 | var handleUserSignedOut_ = function() { 69 | // Tear down the UI for signed in users. 70 | Utils.disableButtonAndRemoveClickListener( 71 | pageUi_.signOutButton, handleSignOutButtonClicked_); 72 | }; 73 | 74 | /** 75 | * Handles when the sign out button is clicked. 76 | * 77 | * Signs the user out, if they are signed in. 78 | * 79 | * @type {!ClickEventListener} 80 | * @const 81 | */ 82 | var handleSignOutButtonClicked_ = function(event) { 83 | event.preventDefault(); 84 | 85 | // Since the click event listener is only on the sign out button when the 86 | // user is signed in, we can reasonably assume the user is signed in. 87 | // However, signing out will fail if the user is already signed out, 88 | // so we need to handle that case in the catch function 89 | // below - just in case. 90 | authHelper_.signOut().catch(function(error) { 91 | switch (error) { 92 | case authHelper_.errorMessages.userAlreadySignedOut: 93 | // Do nothing, as the user is already signed out. 94 | break; 95 | 96 | default: 97 | console.error("Error during sign out: " + error); 98 | } 99 | }); 100 | }; 101 | 102 | /** 103 | * Initializes this page. 104 | * 105 | * This is the main entry point of this page's script. 106 | * 107 | * @function 108 | * @const 109 | */ 110 | var init_ = function() { 111 | // Hold references to various UI elements for later manipulation. 112 | pageUi_.userDisplayName = document.getElementById("user-display-name"); 113 | pageUi_.userEmail = document.getElementById("user-email"); 114 | pageUi_.signOutButton = document.getElementById("sign-out-button"); 115 | 116 | // Now that the page is ready, set up the Firebase Auth helper to listen 117 | // for sign in state changes, and to start FirebaseUI for a sign in UI 118 | // when the user is signed out. 119 | authHelper_ = new AuthHelper(handleUserSignedIn_, handleUserSignedOut_); 120 | }; 121 | 122 | // When the page is ready, call the init function. 123 | window.addEventListener("load", init_); 124 | })(); 125 | -------------------------------------------------------------------------------- /samples/web/Continote/public/scripts/sample-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a 6 | * copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * This script sets up Firebase. 19 | * 20 | * Remember to include this script in the of a page if you plan on using 21 | * Firebase within that page. 22 | */ 23 | (function() { 24 | 'use strict'; 25 | 26 | /** 27 | * Firebase will be initialized with this config object. 28 | * 29 | * @type {!Object} 30 | * @const 31 | */ 32 | var config_ = { 33 | apiKey: "[TODO: YOUR-API-KEY-HERE]", 34 | authDomain: "[TODO: YOUR-AUTH-DOMAIN-HERE]", 35 | databaseURL: "[TODO: YOUR-DATABASE-URL-HERE]", 36 | projectId: "[TODO: YOUR-PROJECT-ID-HERE]" 37 | }; 38 | firebase.initializeApp(config_); 39 | })(); 40 | -------------------------------------------------------------------------------- /samples/web/Continote/public/scripts/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a 6 | * copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * This object provides some simple utility functions. 19 | * 20 | * Remember to include this script in the of a page if you plan on 21 | * using any of these utilities within that page. 22 | * 23 | * @type {!Object} 24 | * @const 25 | */ 26 | var Utils = (function() { 27 | 'use strict'; 28 | 29 | /** 30 | * This is the class which, if applied to an element, hides that element. 31 | * 32 | * @type {!string} 33 | * @const 34 | */ 35 | var hiddenClass_ = "hidden"; 36 | 37 | /** 38 | * This is the class which, if applied to an element, means 39 | * the text within the element should be considered a placeholder. 40 | * 41 | * @type {!string} 42 | * @const 43 | */ 44 | var placeholderClass_ = "placeholder"; 45 | 46 | /** 47 | * This is the name of the click event type. 48 | * 49 | * @type {!string} 50 | * @const 51 | */ 52 | var clickEventType_ = "click"; 53 | 54 | /** 55 | * Shows the provided DOM element if it is currently hidden. 56 | * 57 | * @function 58 | * @param {!Element} element 59 | * @const 60 | */ 61 | var showElement_ = function(element) { 62 | element.classList.remove(hiddenClass_); 63 | }; 64 | 65 | /** 66 | * Hides the provided DOM element if it is currently shown. 67 | * 68 | * @function 69 | * @param {!Element} element 70 | * @const 71 | */ 72 | var hideElement_ = function(element) { 73 | element.classList.add(hiddenClass_); 74 | }; 75 | 76 | return { 77 | 78 | /** 79 | * Shows all DOM elements with the provided className. 80 | * 81 | * @function 82 | * @param {!string} className 83 | * @const 84 | */ 85 | showAllElementsWithClassName: function(className) { 86 | var elements = document.getElementsByClassName(className); 87 | for (var i = 0; i < elements.length; i++) { 88 | showElement_(elements[i]); 89 | } 90 | }, 91 | 92 | /** 93 | * Hides all DOM elements with the provided className. 94 | * 95 | * @function 96 | * @param {!string} className 97 | * @const 98 | */ 99 | hideAllElementsWithClassName: function(className) { 100 | var elements = document.getElementsByClassName(className); 101 | for (var i = 0; i < elements.length; i++) { 102 | hideElement_(elements[i]); 103 | } 104 | }, 105 | 106 | /** 107 | * Enables the provided button element if it is currently disabled, 108 | * and adds the provided click event listener to the button 109 | * if the event listener is not already attached to it. 110 | * 111 | * @function 112 | * @param {!Element} button 113 | * @param {?ClickEventListener} clickEventListener 114 | * @const 115 | */ 116 | enableButtonAndAddClickListener: function(button, clickEventListener) { 117 | button.disabled = false; 118 | if (clickEventListener) { 119 | button.addEventListener(clickEventType_, clickEventListener); 120 | } 121 | }, 122 | 123 | /** 124 | * Disables the provided button element if it is currently enabled, 125 | * and removes the provided click event listener from the button 126 | * if the event listener is currently attached to it. 127 | * 128 | * @function 129 | * @param {!Element} button 130 | * @param {?ClickEventListener} clickEventListener 131 | * @const 132 | */ 133 | disableButtonAndRemoveClickListener: function(button, clickEventListener) { 134 | button.disabled = true; 135 | if (clickEventListener) { 136 | button.removeEventListener(clickEventType_, clickEventListener); 137 | } 138 | }, 139 | 140 | /** 141 | * Puts the given text, or the given placeholder if the text 142 | * is null or empty, within the element. 143 | * 144 | * @function 145 | * @param {?string} text 146 | * @param {!string} placeholder 147 | * @param {!Element} element 148 | * @const 149 | */ 150 | putTextOrPlaceholderInElement: function(text, placeholder, element) { 151 | if (text && text.length > 0) { 152 | element.textContent = text; 153 | element.classList.remove(placeholderClass_); 154 | } else { 155 | element.textContent = placeholder; 156 | element.classList.add(placeholderClass_); 157 | } 158 | }, 159 | 160 | /** 161 | * Appends an element based on the provided template to the provided 162 | * container. 163 | * 164 | * @function 165 | * @param {!string} template - The template to create the new element 166 | * based upon. 167 | * @param {!Element} container - The container to append the new element 168 | * (created from the template) to. 169 | * @returns {?Element} - The new element that is now in the container (or 170 | * null if no element could be appended). 171 | * @const 172 | */ 173 | appendElementBasedOnTemplateToContainer: function(template, container) { 174 | if (!template || !container) { 175 | // This should never happen, but just in case. 176 | return null; 177 | } 178 | 179 | // The template will be added to this container 180 | // (which will not be anywhere in the actual page DOM) temporarily, 181 | // and then moved to the final container. 182 | // This is needed so there is an actual element created from the 183 | // template. 184 | var temporaryContainer = document.createElement("div"); 185 | temporaryContainer.innerHTML = template; 186 | 187 | // Get the element to put in the actual container from the temporary 188 | // container, then append that element to said actual container. 189 | var element = temporaryContainer.firstElementChild; 190 | container.appendChild(element); 191 | 192 | return element; 193 | } 194 | } 195 | }()); 196 | 197 | // Below are extra JSDoc definitions to describe the callback functions 198 | // this utility object expects. 199 | 200 | /** 201 | * The standard click event callback. 202 | * 203 | * @callback ClickEventListener 204 | * @param {!Object} event 205 | */ 206 | -------------------------------------------------------------------------------- /samples/web/Continote/public/styles/all-pages.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * These styles apply to all popup pages. 17 | * Thy are based on the Material Design Lite samples provided here: 18 | * https://getmdl.io/templates/index.html 19 | */ 20 | 21 | html, 22 | body { 23 | margin: 0; 24 | padding: 0; 25 | font-family: 'Roboto', 'Helvetica', sans-serif; 26 | } 27 | 28 | .app-title { 29 | font-weight: bold; 30 | } 31 | 32 | .mdl-navigation { 33 | text-transform: uppercase; 34 | } 35 | 36 | .mdl-layout__content { 37 | padding: 32px; 38 | } 39 | 40 | .mdl-layout__content section { 41 | max-width: 960px; 42 | } 43 | 44 | .mdl-layout__content section:not(:last-child) { 45 | margin-bottom: 32px !important; 46 | } 47 | 48 | .mdl-card { 49 | height: auto; 50 | min-height: 0; 51 | display: -webkit-flex; 52 | display: -ms-flexbox; 53 | display: flex; 54 | -webkit-flex-direction: column; 55 | -ms-flex-direction: column; 56 | flex-direction: column; 57 | } 58 | 59 | .mdl-card > * { 60 | height: auto; 61 | } 62 | 63 | .mdl-card .mdl-card__title { 64 | padding: 20px 20px 0; 65 | } 66 | 67 | .mdl-card .mdl-card__supporting-text { 68 | margin: 20px; 69 | -webkit-flex-grow: 1; 70 | flex-grow: 1; 71 | padding: 0; 72 | } 73 | 74 | .mdl-card__actions { 75 | margin: 0; 76 | padding: 12px 20px; 77 | } 78 | 79 | a.current, 80 | a:hover { 81 | font-weight: bold; 82 | } 83 | 84 | #firebaseui-container .firebaseui-idp-google { 85 | background-color: #FFFFFF !important; 86 | } 87 | 88 | #firebaseui-container .firebaseui-idp-facebook { 89 | background-color: #3b5998 !important; 90 | } 91 | 92 | #note-list { 93 | margin: 0; 94 | padding: 0; 95 | } 96 | 97 | #note-list .note-list-item .mdl-list__item-primary-content { 98 | width: 50%; 99 | } 100 | 101 | #note-list .note-list-item { 102 | height: auto; 103 | } 104 | 105 | #note-list .note-list-item .note-title { 106 | font-weight: bold; 107 | } 108 | 109 | #note-list .note-list-item .note-actions { 110 | width: 50%; 111 | text-align: right; 112 | } 113 | 114 | #note-list .note-list-item .note-actions button { 115 | margin-left: 10px; 116 | margin-bottom: 10px; 117 | } 118 | 119 | #note-editor .mdl-textfield { 120 | width: 100%; 121 | } 122 | 123 | #note-editor #note-title-input { 124 | font-weight: bold; 125 | } 126 | 127 | #save-note-button { 128 | margin-left: 10px; 129 | } 130 | 131 | .truncate-to-single-line { 132 | white-space: nowrap !important; 133 | overflow: hidden !important; 134 | text-overflow: ellipsis !important; 135 | } 136 | 137 | .hidden { 138 | display: none !important; 139 | } 140 | 141 | .placeholder { 142 | font-style: italic; 143 | } 144 | -------------------------------------------------------------------------------- /samples/web/Continote/sample-database.rules.json: -------------------------------------------------------------------------------- 1 | // The contents of this file are to be included in another, more complete database 2 | // rules file during the Setup process. See this sample's README. 3 | 4 | // This node stores all notes created by users in Continote. 5 | "notes": { 6 | 7 | // Notes are user specific, so here we store a list of user-private nodes. 8 | "$uid": { 9 | ".read": "$uid === auth.uid", 10 | ".write": "$uid === auth.uid", 11 | 12 | // A user can have many notes, so here we store a list of note nodes. 13 | "$noteid": { 14 | ".validate": "newData.hasChildren(['title', 'content'])", 15 | 16 | // The title of this note. 17 | "title": { 18 | ".validate": "newData.isString()" 19 | }, 20 | 21 | // The main content of this note. 22 | "content": { 23 | ".validate": "newData.isString()" 24 | }, 25 | 26 | // Prevent extraneous data from being added to this note. 27 | "$other": { 28 | ".validate": false 29 | } 30 | } 31 | } 32 | }, 33 | --------------------------------------------------------------------------------