diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf7ff6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.gradle +/local.properties +/.idea +.DS_Store +/build +sample/build +*.iml +*.ipr \ No newline at end of file diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..cd45060 --- /dev/null +++ b/License.txt @@ -0,0 +1,14 @@ +Copyright (c) 2015 Vijay + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..af91502 --- /dev/null +++ b/README.md @@ -0,0 +1,444 @@ +Android Json Wizard +========= + +Android Json Wizard is a library for creating beautiful form based wizards within your app just by defining json in a particular format. + +# Demo + +[Demo Youtube Link](http://youtu.be/0PQD8EA8lEI) + +# Usage + +## Json Structure + +Form json should consist of steps and fields. + +## Steps + +Step directly corresponds to a fragment(or a page) in wizard. It consists of different fields(array of fields), title and next step. + +```json + { + "step1":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Your Name" + }, + { + "key":"email", + "type":"edit_text", + "hint":"Enter email address" + }, + { + "key":"labelBackgroundImage", + "type":"label", + "text":"Choose Background Image" + }, + { + "key":"chooseImage", + "type":"choose_image", + "uploadButtonText":"Choose" + } + ], + "title":"Step 1", + "next":"step2" + } + } +``` + +## Supported fields + +#### EditText +```json + { + "key":"name", + "type":"edit_text", + "hint":"Enter Your Name" + } +``` + +key - must be unique in that particular step. + +type - must be edit_text for EditText. + +hint - hint for EditText. + +value - will be the value present in the editText after completion of wizard + + +#### Label +```json + { + "key":"labelHeaderImage", + "type":"label", + "text":"Choose Background Image" + } +``` +key - must be unique in that particular step. + +type - must be label for Label. + +text - text for Label. + + +#### ImagePicker +```json + { + "key":"chooseImage", + "type":"choose_image", + "uploadButtonText":"Choose" + } +``` +key - must be unique in that particular step. + +type - must be choose_image for ImagePicker. + +uploadButtonText - text for Button of ImagePicker. + +value - will be the path of chosen image on external storage + +#### CheckBox (can be used for single/multiple CheckBoxes) +```json + { + "key":"checkData", + "type":"check_box", + "label":"Select multiple preferences", + "options":[ + { + "key":"awesomeness", + "text":"Are you willing for some awesomeness?", + "value":"false" + }, + { + "key":"newsletter", + "text":"Do you really want to opt out from my newsletter?", + "value":"false" + } + ] + } +``` +key - must be unique in that particular step. + +type - must be check_box for CheckBox. + +label - text for header of CheckBox. + +options - options for CheckBox. + +key(in options) - must be unique in options. + +text(in options) - text fot the CheckBox. + +value(in options) - true/false. + + +#### RadioButton (can be used for single/multiple RadioButtons) + +```json +{ + "key":"radioData", + "type":"radio", + "label":"Select one item from below", + "options":[ + { + "key":"areYouPro", + "text":"Are you pro?" + }, + { + "key":"areYouAmature", + "text":"Are you amature?" + }, + { + "key":"areYouNovice", + "text":"Are you novice?" + } + ], + "value":"areYouNovice" +} +``` +key - must be unique in that particular step. + +type - must be radio for RadioButton. + +label - text for header of RadioButton. + +value - must be key of one of the options which is selected/ or empty if no option is selected. + +options - options for RadioButton. + +key(in options) - must be unique in options. + +text(in options) - text fot the RadioButton. + + +## Demo Input Json (Complete) + +```json +{ + "count":"3", + "step1":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Your Name" + }, + { + "key":"email", + "type":"edit_text", + "hint":"Enter Your Email" + }, + { + "key":"labelBackgroundImage", + "type":"label", + "text":"Choose Background Image" + }, + { + "key":"chooseImage", + "type":"choose_image", + "uploadButtonText":"Choose" + } + ], + "title":"Step 1 of 3", + "next":"step2" + }, + "step2":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Country" + }, + { + "key":"checkData", + "type":"check_box", + "label":"Select multiple preferences", + "options":[ + { + "key":"awesomeness", + "text":"Are you willing for some awesomeness?", + "value":"false" + }, + { + "key":"newsletter", + "text":"Do you really want to opt out from my newsletter?", + "value":"false" + } + ] + }, + { + "key":"radioData", + "type":"radio", + "label":"Select one item from below", + "options":[ + { + "key":"areYouPro", + "text":"Are you pro?" + }, + { + "key":"areYouAmature", + "text":"Are you amature?" + }, + { + "key":"areYouNovice", + "text":"Are you novice?" + } + ], + "value":"areYouNovice" + } + ], + "title":"Step 2 of 3", + "next":"step3" + }, + "step3":{ + "fields":[ + { + "key":"anything", + "type":"edit_text", + "hint":"Enter Anything You Want" + } + ], + "title":"Step 3 of 3" + } +} +``` + +## Starting form activity with your json + +```java + Intent intent = new Intent(context, JsonFormActivity.class); + String json = "Your complete JSON"; + intent.putExtra("json", json); + startActivityForResult(intent, REQUEST_CODE_GET_JSON); +``` + +And receive result populated json in onActivityResult() + +```java +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_GET_JSON && resultCode == RESULT_OK) { + Log.d(TAG, data.getStringExtra("json")); + } + super.onActivityResult(requestCode, resultCode, data); +} +``` + +## Output Json (of demo input json) + +```json +{ + "count":"3", + "step1":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Your Name", + "value":"Vijay" + }, + { + "key":"email", + "type":"edit_text", + "hint":"Enter Your Email", + "value":"dummy@gmail.com" + }, + { + "key":"labelBackgroundImage", + "type":"label", + "text":"Choose Background Image" + }, + { + "key":"chooseImage", + "type":"choose_image", + "uploadButtonText":"Choose", + "value":"\/storage\/emulated\/0\/Pictures\/Wally\/10017.png" + } + ], + "title":"Step 1 of 3", + "next":"step2" + }, + "step2":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Country", + "value":"India" + }, + { + "key":"checkData", + "type":"check_box", + "label":"Select multiple preferences", + "options":[ + { + "key":"awesomeness", + "text":"Are you willing for some awesomeness?", + "value":"true" + }, + { + "key":"newsletter", + "text":"Do you really want to opt out from my newsletter?", + "value":"false" + } + ] + }, + { + "key":"radioData", + "type":"radio", + "label":"Select one item from below", + "options":[ + { + "key":"areYouPro", + "text":"Are you pro?" + }, + { + "key":"areYouAmature", + "text":"Are you amature?" + }, + { + "key":"areYouNovice", + "text":"Are you novice?" + } + ], + "value":"areYouPro" + } + ], + "title":"Step 2 of 3", + "next":"step3" + }, + "step3":{ + "fields":[ + { + "key":"anything", + "type":"edit_text", + "hint":"Enter Anything You Want", + "value":"anything" + } + ], + "title":"Step 3 of 3" + } +} +``` + +# Including in your project + +gradle: + +Step 1. Add the JitPack repository to your build file + +```groovy +repositories { + maven { + url "https://jitpack.io" + } +} +``` + +Step 2. Add the dependency in the form + +```groovy +dependencies { + compile 'com.github.vijayrawatsan:android-json-form-wizard:1.0' +} +``` + +maven: + +Step 1. Add the JitPack repository to your build file + +```xml + + jitpack.io + https://jitpack.io + +``` + +Step 2. Add the dependency in the form + +```xml + + com.github.vijayrawatsan + android-json-form-wizard + 1.0 + +``` +# TODOs + +- Support validation. +- Improve image picker UI. + +# Contributing +Contributions welcome via Github pull requests. + +# Credits + +- [material](https://github.com/rey5137/material) +- [MaterialEditText](https://github.com/rengwuxian/MaterialEditText) + +Thanks! + +# License +This project is licensed under the MIT License. Please refer the [License.txt](https://github.com/vijayrawatsan/android-json-form-wizard/blob/master/License.txt) file. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d3ff69d --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8c0fb64 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c71e76 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library/build.gradle b/library/build.gradle new file mode 100644 index 0000000..555b8b7 --- /dev/null +++ b/library/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.android.library' +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} +repositories { + maven {url "https://clojars.org/repo/"} +} +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.0.0' + compile 'com.github.rey5137:material:1.1.0' + compile 'com.rengwuxian.materialedittext:library:2.0.3' +} diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro new file mode 100644 index 0000000..67d26d7 --- /dev/null +++ b/library/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/vijay/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/library/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java b/library/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java new file mode 100644 index 0000000..4880a9e --- /dev/null +++ b/library/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.vijay.jsonwizard; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml new file mode 100644 index 0000000..bb37c2a --- /dev/null +++ b/library/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/library/src/main/assets/font/LICENSE.txt b/library/src/main/assets/font/LICENSE.txt new file mode 100644 index 0000000..162d2e9 --- /dev/null +++ b/library/src/main/assets/font/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the url of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/library/src/main/assets/font/Roboto-Black.ttf b/library/src/main/assets/font/Roboto-Black.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-BlackItalic.ttf b/library/src/main/assets/font/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Bold.ttf b/library/src/main/assets/font/Roboto-Bold.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-BoldItalic.ttf b/library/src/main/assets/font/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Italic.ttf b/library/src/main/assets/font/Roboto-Italic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Light.ttf b/library/src/main/assets/font/Roboto-Light.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-LightItalic.ttf b/library/src/main/assets/font/Roboto-LightItalic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Medium.ttf b/library/src/main/assets/font/Roboto-Medium.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-MediumItalic.ttf b/library/src/main/assets/font/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Regular.ttf b/library/src/main/assets/font/Roboto-Regular.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-Thin.ttf b/library/src/main/assets/font/Roboto-Thin.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/assets/font/Roboto-ThinItalic.ttf b/library/src/main/assets/font/Roboto-ThinItalic.ttf new file mode 100644 index 0000000..e69de29 diff --git a/library/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java b/library/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java new file mode 100644 index 0000000..5d13a8f --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/activities/JsonFormActivity.java @@ -0,0 +1,124 @@ +package com.vijay.jsonwizard.activities; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; + +import com.vijay.jsonwizard.R; +import com.vijay.jsonwizard.constants.JsonFormConstants; +import com.vijay.jsonwizard.fragments.JsonFormFragment; +import com.vijay.jsonwizard.interfaces.JsonApi; + +public class JsonFormActivity extends ActionBarActivity implements JsonApi { + + private static final String TAG = "JsonFormActivity"; + + private Toolbar mToolbar; + + private JSONObject mJSONObject; + + public void init(String json) { + try { + mJSONObject = new JSONObject(json); + } catch (JSONException e) { + Log.d(TAG, "Initialization error. Json passed is invalid : " + e.getMessage()); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_json_form); + mToolbar = (Toolbar) findViewById(R.id.tb_top); + setSupportActionBar(mToolbar); + if (savedInstanceState == null) { + init(getIntent().getStringExtra("json")); + getSupportFragmentManager().beginTransaction() + .add(R.id.container, JsonFormFragment.getFormFragment(JsonFormConstants.FIRST_STEP_NAME)).commit(); + } else { + init(savedInstanceState.getString("jsonState")); + } + } + + public Toolbar getToolbar() { + return mToolbar; + } + + @Override + public synchronized JSONObject getStep(String name) { + synchronized (mJSONObject) { + try { + return mJSONObject.getJSONObject(name); + } catch (JSONException e) { + e.printStackTrace(); + } + } + return null; + } + + @Override + public void writeValue(String stepName, String key, String value) throws JSONException { + synchronized (mJSONObject) { + JSONObject jsonObject = mJSONObject.getJSONObject(stepName); + JSONArray fields = jsonObject.getJSONArray("fields"); + for (int i = 0; i < fields.length(); i++) { + JSONObject item = fields.getJSONObject(i); + String keyAtIndex = item.getString("key"); + if (key.equals(keyAtIndex)) { + item.put("value", value); + return; + } + } + } + } + + @Override + public void writeValue(String stepName, String parentKey, String childObjectKey, String childKey, String value) + throws JSONException { + synchronized (mJSONObject) { + JSONObject jsonObject = mJSONObject.getJSONObject(stepName); + JSONArray fields = jsonObject.getJSONArray("fields"); + for (int i = 0; i < fields.length(); i++) { + JSONObject item = fields.getJSONObject(i); + String keyAtIndex = item.getString("key"); + if (parentKey.equals(keyAtIndex)) { + JSONArray jsonArray = item.getJSONArray(childObjectKey); + for (int j = 0; j < jsonArray.length(); j++) { + JSONObject innerItem = jsonArray.getJSONObject(j); + String anotherKeyAtIndex = innerItem.getString("key"); + if (childKey.equals(anotherKeyAtIndex)) { + innerItem.put("value", value); + return; + } + } + } + } + } + } + + @Override + public String currentJsonState() { + synchronized (mJSONObject) { + return mJSONObject.toString(); + } + } + + @Override + public String getCount() { + synchronized (mJSONObject) { + return mJSONObject.optString("count"); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("jsonState", mJSONObject.toString()); + } + +} diff --git a/library/src/main/java/com/vijay/jsonwizard/constants/JsonFormConstants.java b/library/src/main/java/com/vijay/jsonwizard/constants/JsonFormConstants.java new file mode 100644 index 0000000..7670a9a --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/constants/JsonFormConstants.java @@ -0,0 +1,15 @@ +package com.vijay.jsonwizard.constants; + +/** + * Created by vijay on 5/7/15. + */ +public class JsonFormConstants { + + public static final String FIRST_STEP_NAME = "step1"; + public static final String EDIT_TEXT = "edit_text"; + public static final String CHECK_BOX = "check_box"; + public static final String RADIO_BUTTON = "radio"; + public static final String LABEL = "label"; + public static final String CHOOSE_IMAGE = "choose_image"; + public static final String OPTIONS_FIELD_NAME = "options"; +} diff --git a/library/src/main/java/com/vijay/jsonwizard/customviews/CheckBox.java b/library/src/main/java/com/vijay/jsonwizard/customviews/CheckBox.java new file mode 100644 index 0000000..1e07137 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/customviews/CheckBox.java @@ -0,0 +1,68 @@ +package com.vijay.jsonwizard.customviews; + +import android.content.Context; +import android.util.AttributeSet; + +import com.rey.material.drawable.CheckBoxDrawable; + +public class CheckBox extends CompoundButton { + + public CheckBox(Context context) { + super(context); + + init(context, null, 0, 0); + } + + public CheckBox(Context context, AttributeSet attrs) { + super(context, attrs); + + init(context, attrs, 0, 0); + } + + public CheckBox(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, 0); + } + + public CheckBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, defStyleRes); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + applyStyle(context, attrs, defStyleAttr, defStyleRes); + } + + public void applyStyle(int resId) { + applyStyle(getContext(), null, 0, resId); + } + + private void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + CheckBoxDrawable drawable = new CheckBoxDrawable.Builder(context, attrs, defStyleAttr, defStyleRes).build(); + drawable.setInEditMode(isInEditMode()); + drawable.setAnimEnable(false); + setButtonDrawable(null); + setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); + drawable.setAnimEnable(true); + } + + /** + * Change the checked state of this button immediately without showing + * animation. + * + * @param checked + * The checked state. + */ + public void setCheckedImmediately(boolean checked) { + if (mButtonDrawable instanceof CheckBoxDrawable) { + CheckBoxDrawable drawable = (CheckBoxDrawable) mButtonDrawable; + drawable.setAnimEnable(false); + setChecked(checked); + drawable.setAnimEnable(true); + } else + setChecked(checked); + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/customviews/CompoundButton.java b/library/src/main/java/com/vijay/jsonwizard/customviews/CompoundButton.java new file mode 100644 index 0000000..bda83f9 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/customviews/CompoundButton.java @@ -0,0 +1,117 @@ +package com.vijay.jsonwizard.customviews; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import com.rey.material.drawable.RippleDrawable; +import com.rey.material.widget.RippleManager; + +public class CompoundButton extends android.widget.CompoundButton { + + private RippleManager mRippleManager = new RippleManager(); + protected Drawable mButtonDrawable; + + public CompoundButton(Context context) { + super(context); + + init(context, null, 0, 0); + } + + public CompoundButton(Context context, AttributeSet attrs) { + super(context, attrs); + + init(context, attrs, 0, 0); + } + + public CompoundButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, 0); + } + + public CompoundButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, defStyleRes); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + // a fix to reset paddingLeft attribute + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + TypedArray a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.padding, + android.R.attr.paddingLeft }, defStyleAttr, defStyleRes); + + if (!a.hasValue(0) && !a.hasValue(1)) + setPadding(0, getPaddingTop(), getPaddingRight(), getPaddingBottom()); + + a.recycle(); + } + + setClickable(true); + applyStyle(context, attrs, defStyleAttr, defStyleRes); + } + + public void applyStyle(int resId) { + applyStyle(getContext(), null, 0, resId); + } + + private void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + mRippleManager.onCreate(this, context, attrs, defStyleAttr, defStyleRes); + } + + @Override + public void setBackgroundDrawable(Drawable drawable) { + Drawable background = getBackground(); + if (background instanceof RippleDrawable && !(drawable instanceof RippleDrawable)) + ((RippleDrawable) background).setBackgroundDrawable(drawable); + else + super.setBackgroundDrawable(drawable); + } + + @Override + public void setOnClickListener(OnClickListener l) { + if (l == mRippleManager) + super.setOnClickListener(l); + else { + mRippleManager.setOnClickListener(l); + setOnClickListener(mRippleManager); + } + } + + @Override + public boolean onTouchEvent(@NonNull MotionEvent event) { + boolean result = super.onTouchEvent(event); + return mRippleManager.onTouchEvent(event) || result; + } + + @Override + public void setButtonDrawable(Drawable d) { + mButtonDrawable = d; + super.setButtonDrawable(d); + } + + @Override + public int getCompoundPaddingLeft() { + int padding = super.getCompoundPaddingLeft(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) + return padding; + + if (mButtonDrawable != null) + padding += mButtonDrawable.getIntrinsicWidth(); + + return padding; + } + + @Override + public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) { + mButtonDrawable = right; + super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom); + } +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/customviews/GenericTextWatcher.java b/library/src/main/java/com/vijay/jsonwizard/customviews/GenericTextWatcher.java new file mode 100644 index 0000000..2687d5b --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/customviews/GenericTextWatcher.java @@ -0,0 +1,39 @@ +package com.vijay.jsonwizard.customviews; + +import org.json.JSONException; + +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; + +import com.vijay.jsonwizard.R; +import com.vijay.jsonwizard.interfaces.JsonApi; + +public class GenericTextWatcher implements TextWatcher { + + private View mView; + private String mStepName; + + public GenericTextWatcher(String stepName, View view) { + mView = view; + mStepName = stepName; + } + + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + public void afterTextChanged(Editable editable) { + String text = editable.toString(); + JsonApi api = (JsonApi) mView.getContext(); + String key = (String) mView.getTag(R.id.key); + try { + api.writeValue(mStepName, key, text); + } catch (JSONException e) { + // TODO- handle + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/customviews/RadioButton.java b/library/src/main/java/com/vijay/jsonwizard/customviews/RadioButton.java new file mode 100644 index 0000000..991f27b --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/customviews/RadioButton.java @@ -0,0 +1,79 @@ +package com.vijay.jsonwizard.customviews; + +import android.content.Context; +import android.util.AttributeSet; + +import com.rey.material.drawable.RadioButtonDrawable; + +/** + * Created by vijay on 5/18/15. + */ +public class RadioButton extends CompoundButton { + public RadioButton(Context context) { + super(context); + + init(context, null, 0, 0); + } + + public RadioButton(Context context, AttributeSet attrs) { + super(context, attrs); + + init(context, attrs, 0, 0); + } + + public RadioButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, 0); + } + + public RadioButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr); + + init(context, attrs, defStyleAttr, defStyleRes); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + applyStyle(context, attrs, defStyleAttr, defStyleRes); + } + + public void applyStyle(int resId) { + applyStyle(getContext(), null, 0, resId); + } + + private void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + RadioButtonDrawable drawable = new RadioButtonDrawable.Builder(context, attrs, defStyleAttr, defStyleRes) + .build(); + drawable.setInEditMode(isInEditMode()); + drawable.setAnimEnable(false); + setButtonDrawable(null); + setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); + drawable.setAnimEnable(true); + } + + @Override + public void toggle() { + // we override to prevent toggle when the radio is already + // checked (as opposed to check boxes widgets) + if (!isChecked()) { + super.toggle(); + } + } + + /** + * Change the checked state of this button immediately without showing + * animation. + * + * @param checked + * The checked state. + */ + public void setCheckedImmediately(boolean checked) { + if (mButtonDrawable instanceof RadioButtonDrawable) { + RadioButtonDrawable drawable = (RadioButtonDrawable) mButtonDrawable; + drawable.setAnimEnable(false); + setChecked(checked); + drawable.setAnimEnable(true); + } else + setChecked(checked); + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/fragments/JsonFormFragment.java b/library/src/main/java/com/vijay/jsonwizard/fragments/JsonFormFragment.java new file mode 100644 index 0000000..50642c5 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/fragments/JsonFormFragment.java @@ -0,0 +1,277 @@ +package com.vijay.jsonwizard.fragments; + +import java.util.List; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.vijay.jsonwizard.R; +import com.vijay.jsonwizard.activities.JsonFormActivity; +import com.vijay.jsonwizard.customviews.RadioButton; +import com.vijay.jsonwizard.interfaces.CommonListener; +import com.vijay.jsonwizard.interfaces.JsonApi; +import com.vijay.jsonwizard.mvp.MvpFragment; +import com.vijay.jsonwizard.presenters.JsonFormFragmentPresenter; +import com.vijay.jsonwizard.views.JsonFormFragmentView; +import com.vijay.jsonwizard.viewstates.JsonFormFragmentViewState; + +/** + * Created by vijay on 5/7/15. + */ +public class JsonFormFragment extends MvpFragment implements + CommonListener, JsonFormFragmentView { + private static final String TAG = "JsonFormFragment"; + private LinearLayout mMainView; + private Menu mMenu; + private JsonApi mJsonApi; + + @Override + public void onAttach(Activity activity) { + mJsonApi = (JsonApi) activity; + super.onAttach(activity); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + setHasOptionsMenu(true); + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_json_wizard, null); + mMainView = (LinearLayout) rootView.findViewById(R.id.main_layout); + return rootView; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + presenter.addFormElements(); + } + + @Override + protected JsonFormFragmentViewState createViewState() { + return new JsonFormFragmentViewState(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + mMenu = menu; + menu.clear(); + inflater.inflate(R.menu.menu_toolbar, menu); + presenter.setUpToolBar(); + } + + @Override + public void setActionBarTitle(String title) { + getSupportActionBar().setTitle(title); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + presenter.onBackClick(); + return true; + } else if (item.getItemId() == R.id.action_next) { + presenter.onNextClick(mMainView); + return true; + } else if (item.getItemId() == R.id.action_save) { + presenter.onSaveClick(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onClick(View v) { + presenter.onClick(v); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + presenter.onActivityResult(requestCode, resultCode, data); + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void onDetach() { + mJsonApi = null; + super.onDetach(); + } + + @Override + public void updateRelevantImageView(Bitmap bitmap, String imagePath, String currentKey) { + int childCount = mMainView.getChildCount(); + for (int i = 0; i < childCount; i++) { + View view = mMainView.getChildAt(i); + if (view instanceof ImageView) { + ImageView imageView = (ImageView) view; + String key = (String) imageView.getTag(R.id.key); + if (key.equals(currentKey)) { + imageView.setImageBitmap(bitmap); + imageView.setVisibility(View.VISIBLE); + imageView.setTag(R.id.imagePath, imagePath); + } + } + } + } + + @Override + public void writeValue(String stepName, String key, String s) { + try { + mJsonApi.writeValue(stepName, key, s); + } catch (JSONException e) { + // TODO - handle + e.printStackTrace(); + } + } + + @Override + public void writeValue(String stepName, String prentKey, String childObjectKey, String childKey, String value) { + try { + mJsonApi.writeValue(stepName, prentKey, childObjectKey, childKey, value); + } catch (JSONException e) { + // TODO - handle + e.printStackTrace(); + } + } + + @Override + public JSONObject getStep(String stepName) { + return mJsonApi.getStep(stepName); + } + + @Override + public String getCurrentJsonState() { + return mJsonApi.currentJsonState(); + } + + @Override + protected JsonFormFragmentPresenter createPresenter() { + return new JsonFormFragmentPresenter(); + } + + @Override + public Context getContext() { + return getActivity(); + } + + @Override + public CommonListener getCommonListener() { + return this; + } + + @Override + public void addFormElements(List views) { + for (View view : views) { + mMainView.addView(view); + } + } + + @Override + public ActionBar getSupportActionBar() { + return ((JsonFormActivity) getActivity()).getSupportActionBar(); + } + + @Override + public Toolbar getToolbar() { + return ((JsonFormActivity) getActivity()).getToolbar(); + } + + @Override + public void setToolbarTitleColor(int colorId) { + getToolbar().setTitleTextColor(getContext().getResources().getColor(colorId)); + } + + @Override + public void updateVisibilityOfNextAndSave(boolean next, boolean save) { + mMenu.findItem(R.id.action_next).setVisible(next); + mMenu.findItem(R.id.action_save).setVisible(save); + } + + @Override + public void hideKeyBoard() { + super.hideSoftKeyboard(); + } + + @Override + public void backClick() { + getActivity().onBackPressed(); + } + + @Override + public void unCheckAllExcept(String parentKey, String childKey) { + int childCount = mMainView.getChildCount(); + for (int i = 0; i < childCount; i++) { + View view = mMainView.getChildAt(i); + if (view instanceof RadioButton) { + RadioButton radio = (RadioButton) view; + String parentKeyAtIndex = (String) radio.getTag(R.id.key); + String childKeyAtIndex = (String) radio.getTag(R.id.childKey); + if (parentKeyAtIndex.equals(parentKey) && !childKeyAtIndex.equals(childKey)) { + radio.setChecked(false); + } + } + } + } + + @Override + public String getCount() { + return mJsonApi.getCount(); + } + + @Override + public void finishWithResult(Intent returnIntent) { + getActivity().setResult(Activity.RESULT_OK, returnIntent); + getActivity().finish(); + } + + @Override + public void setUpBackButton() { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + @Override + public void transactThis(JsonFormFragment next) { + getActivity() + .getSupportFragmentManager() + .beginTransaction() + .setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, + R.anim.exit_to_right).replace(R.id.container, next) + .addToBackStack(next.getClass().getSimpleName()).commit(); + } + + public static JsonFormFragment getFormFragment(String stepName) { + JsonFormFragment jsonFormFragment = new JsonFormFragment(); + Bundle bundle = new Bundle(); + bundle.putString("stepName", stepName); + jsonFormFragment.setArguments(bundle); + return jsonFormFragment; + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + presenter.onCheckedChanged(buttonView, isChecked); + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/interactors/JsonFormInteractor.java b/library/src/main/java/com/vijay/jsonwizard/interactors/JsonFormInteractor.java new file mode 100644 index 0000000..16a1648 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/interactors/JsonFormInteractor.java @@ -0,0 +1,209 @@ +package com.vijay.jsonwizard.interactors; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.Context; +import android.graphics.BitmapFactory; +import android.graphics.Typeface; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.rengwuxian.materialedittext.MaterialEditText; +import com.rey.material.util.ViewUtil; +import com.vijay.jsonwizard.R; +import com.vijay.jsonwizard.constants.JsonFormConstants; +import com.vijay.jsonwizard.customviews.CheckBox; +import com.vijay.jsonwizard.customviews.GenericTextWatcher; +import com.vijay.jsonwizard.customviews.RadioButton; +import com.vijay.jsonwizard.interfaces.CommonListener; + +/** + * Created by vijay on 5/19/15. + */ +public class JsonFormInteractor { + + private static final String TAG = "JsonFormInteractor"; + private static final String FONT_BOLD_PATH = "font/Roboto-Bold.ttf"; + private static final String FONT_REGULAR_PATH = "font/Roboto-Regular.ttf"; + private static final int MATCH_PARENT = -1; + private static final int WRAP_CONTENT = -2; + + private static final JsonFormInteractor INSTANCE = new JsonFormInteractor(); + + private JsonFormInteractor() { + } + + public List fetchFormElements(String stepName, Context context, JSONObject parentJson, CommonListener listener) { + Log.d(TAG, "fetchFormElements called"); + List viewsFromJson = new ArrayList<>(5); + try { + JSONArray fields = parentJson.getJSONArray("fields"); + for (int i = 0; i < fields.length(); i++) { + JSONObject childJson = fields.getJSONObject(i); + try { + List views = getViewsFromJson(stepName, context, childJson, listener); + if (views.size() > 0) { + viewsFromJson.addAll(views); + } + } catch (Exception e) { + Log.d(TAG, + "Exception occurred in making child view at index : " + i + " : Exception is : " + + e.getMessage()); + e.printStackTrace(); + } + } + } catch (JSONException e) { + Log.d(TAG, "Json exception occurred : " + e.getMessage()); + e.printStackTrace(); + } + return viewsFromJson; + } + + public List getViewsFromJson(String stepName, Context context, JSONObject jsonObject, CommonListener listener) + throws Exception { + List views = new ArrayList<>(1); + switch (jsonObject.getString("type")) { + case JsonFormConstants.LABEL: { + LinearLayout.LayoutParams layoutParams = getLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 0, 0, 0, (int) context + .getResources().getDimension(R.dimen.default_bottom_margin)); + views.add(getTextViewWith(context, 16, jsonObject.getString("text"), jsonObject.getString("key"), + jsonObject.getString("type"), layoutParams, FONT_BOLD_PATH)); + break; + } + case JsonFormConstants.CHECK_BOX: { + views.add(getTextViewWith(context, 16, jsonObject.getString("label"), jsonObject.getString("key"), + jsonObject.getString("type"), getLayoutParams(MATCH_PARENT, WRAP_CONTENT, 0, 0, 0, 0), + FONT_BOLD_PATH)); + JSONArray options = jsonObject.getJSONArray(JsonFormConstants.OPTIONS_FIELD_NAME); + for (int i = 0; i < options.length(); i++) { + JSONObject item = options.getJSONObject(i); + CheckBox checkBox = (CheckBox) LayoutInflater.from(context).inflate(R.layout.item_checkbox, null); + checkBox.setText(item.getString("text")); + checkBox.setTag(R.id.key, jsonObject.getString("key")); + checkBox.setTag(R.id.type, jsonObject.getString("type")); + checkBox.setTag(R.id.childKey, item.getString("key")); + checkBox.setGravity(Gravity.CENTER_VERTICAL); + checkBox.setTextSize(16); + checkBox.setTypeface(Typeface.createFromAsset(context.getAssets(), FONT_REGULAR_PATH)); + checkBox.setOnCheckedChangeListener(listener); + if (!TextUtils.isEmpty(item.optString("value"))) { + checkBox.setChecked(Boolean.valueOf(item.optString("value"))); + } + if (i == options.length() - 1) { + checkBox.setLayoutParams(getLayoutParams(MATCH_PARENT, WRAP_CONTENT, 0, 0, 0, (int) context + .getResources().getDimension(R.dimen.extra_bottom_margin))); + } + views.add(checkBox); + } + break; + } + case JsonFormConstants.RADIO_BUTTON: { + views.add(getTextViewWith(context, 16, jsonObject.getString("label"), jsonObject.getString("key"), + jsonObject.getString("type"), getLayoutParams(MATCH_PARENT, WRAP_CONTENT, 0, 0, 0, 0), + FONT_BOLD_PATH)); + JSONArray options = jsonObject.getJSONArray(JsonFormConstants.OPTIONS_FIELD_NAME); + for (int i = 0; i < options.length(); i++) { + JSONObject item = options.getJSONObject(i); + RadioButton radioButton = (RadioButton) LayoutInflater.from(context).inflate(R.layout.item_radiobutton, + null); + radioButton.setText(item.getString("text")); + radioButton.setTag(R.id.key, jsonObject.getString("key")); + radioButton.setTag(R.id.type, jsonObject.getString("type")); + radioButton.setTag(R.id.childKey, item.getString("key")); + radioButton.setGravity(Gravity.CENTER_VERTICAL); + radioButton.setTextSize(16); + radioButton.setTypeface(Typeface.createFromAsset(context.getAssets(), FONT_REGULAR_PATH)); + radioButton.setOnCheckedChangeListener(listener); + if (!TextUtils.isEmpty(jsonObject.optString("value")) + && jsonObject.optString("value").equals(item.getString("key"))) { + radioButton.setChecked(true); + } + if (i == options.length() - 1) { + radioButton.setLayoutParams(getLayoutParams(MATCH_PARENT, WRAP_CONTENT, 0, 0, 0, (int) context + .getResources().getDimension(R.dimen.extra_bottom_margin))); + } + views.add(radioButton); + } + break; + } + case JsonFormConstants.EDIT_TEXT: { + MaterialEditText editText = (MaterialEditText) LayoutInflater.from(context).inflate( + R.layout.item_edit_text, null); + editText.setHint(jsonObject.getString("hint")); + editText.setFloatingLabelText(jsonObject.getString("hint")); + editText.setId(ViewUtil.generateViewId()); + editText.setTag(R.id.key, jsonObject.getString("key")); + editText.setTag(R.id.type, jsonObject.getString("type")); + if (!TextUtils.isEmpty(jsonObject.optString("value"))) { + editText.setText(jsonObject.optString("value")); + } + editText.addTextChangedListener(new GenericTextWatcher(stepName, editText)); + views.add(editText); + break; + } + case JsonFormConstants.CHOOSE_IMAGE: { + ImageView imageView = new ImageView(context); + imageView.setImageDrawable(context.getResources().getDrawable(R.mipmap.grey_bg)); + imageView.setTag(R.id.key, jsonObject.getString("key")); + imageView.setTag(R.id.type, jsonObject.getString("type")); + imageView.setScaleType(ImageView.ScaleType.FIT_XY); + imageView.setLayoutParams(getLayoutParams(MATCH_PARENT, dpToPixels(context, 200), 0, 0, 0, (int) context + .getResources().getDimension(R.dimen.default_bottom_margin))); + if (!TextUtils.isEmpty(jsonObject.optString("value"))) { + imageView.setImageBitmap(BitmapFactory.decodeFile(jsonObject.optString("value"))); + } + views.add(imageView); + Button uploadButton = new Button(context); + uploadButton.setText(jsonObject.getString("uploadButtonText")); + uploadButton.setLayoutParams(getLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 0, 0, 0, (int) context + .getResources().getDimension(R.dimen.default_bottom_margin))); + uploadButton.setOnClickListener(listener); + uploadButton.setTag(R.id.key, jsonObject.getString("key")); + uploadButton.setTag(R.id.type, jsonObject.getString("type")); + views.add(uploadButton); + break; + } + } + return views; + } + + public int dpToPixels(Context context, float dps) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dps * scale + 0.5f); + } + + public LinearLayout.LayoutParams getLayoutParams(int width, int height, int left, int top, int right, int bottom) { + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height); + layoutParams.setMargins(left, top, right, bottom); + return layoutParams; + } + + private TextView getTextViewWith(Context context, int textSizeInSp, String text, String key, String type, + LinearLayout.LayoutParams layoutParams, String fontPath) { + TextView textView = new TextView(context); + textView.setText(text); + textView.setTag(R.id.key, key); + textView.setTag(R.id.type, type); + textView.setId(ViewUtil.generateViewId()); + textView.setTextSize(textSizeInSp); + textView.setLayoutParams(layoutParams); + textView.setTypeface(Typeface.createFromAsset(context.getAssets(), fontPath)); + return textView; + } + + public static JsonFormInteractor getInstance() { + return INSTANCE; + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/interfaces/CommonListener.java b/library/src/main/java/com/vijay/jsonwizard/interfaces/CommonListener.java new file mode 100644 index 0000000..4475427 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/interfaces/CommonListener.java @@ -0,0 +1,10 @@ +package com.vijay.jsonwizard.interfaces; + +import android.view.View; +import android.widget.CompoundButton; + +/** + * Created by vijay on 5/17/15. + */ +public interface CommonListener extends View.OnClickListener, CompoundButton.OnCheckedChangeListener { +} diff --git a/library/src/main/java/com/vijay/jsonwizard/interfaces/JsonApi.java b/library/src/main/java/com/vijay/jsonwizard/interfaces/JsonApi.java new file mode 100644 index 0000000..d5d788f --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/interfaces/JsonApi.java @@ -0,0 +1,20 @@ +package com.vijay.jsonwizard.interfaces; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by vijay on 5/16/15. + */ +public interface JsonApi { + JSONObject getStep(String stepName); + + void writeValue(String stepName, String key, String value) throws JSONException; + + void writeValue(String stepName, String prentKey, String childObjectKey, String childKey, String value) + throws JSONException; + + String currentJsonState(); + + String getCount(); +} diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/BaseActivity.java b/library/src/main/java/com/vijay/jsonwizard/mvp/BaseActivity.java new file mode 100644 index 0000000..e2f14b4 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/BaseActivity.java @@ -0,0 +1,58 @@ +package com.vijay.jsonwizard.mvp; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.View; +import android.view.ViewGroup; + +/** + * Created by vijay on 4/21/15. + */ +public abstract class BaseActivity extends ActionBarActivity { + // @Icicle + VS mViewState; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Icepick.restoreInstanceState(this, savedInstanceState); + if (savedInstanceState == null) { + mViewState = createViewState(); + mViewState.setSavedInstance(false); + } else { + mViewState.setSavedInstance(true); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Icepick.saveInstanceState(this, outState); + } + + @Override + public void setContentView(int layoutResID) { + super.setContentView(layoutResID); + } + + @Override + public void setContentView(View view) { + super.setContentView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + super.setContentView(view, params); + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + super.addContentView(view, params); + } + + protected abstract VS createViewState(); + + public VS getViewState() { + return mViewState; + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/BaseFragment.java b/library/src/main/java/com/vijay/jsonwizard/mvp/BaseFragment.java new file mode 100644 index 0000000..8beb003 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/BaseFragment.java @@ -0,0 +1,73 @@ +package com.vijay.jsonwizard.mvp; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * Created by vijay on 4/19/15. + */ +public abstract class BaseFragment extends Fragment { + + // @Icicle + VS mViewState; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Icepick.restoreInstanceState(this, savedInstanceState); + if (savedInstanceState == null) { + mViewState = createViewState(); + mViewState.setSavedInstance(false); + } else { + mViewState.setSavedInstance(true); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Icepick.saveInstanceState(this, outState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + int layoutRes = getLayoutRes(); + if (layoutRes == 0) { + throw new IllegalArgumentException("getLayoutRes() returned 0, which is not allowed. " + + "If you don't want to use getLayoutRes() but implement your own view for this " + + "fragment manually, then you have to override onCreateView();"); + } else { + View v = inflater.inflate(layoutRes, container, false); + return v; + } + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + + /** + * Return the layout resource like R.layout.my_layout + * + * @return the layout resource or null, if you don't want to have an UI + */ + protected int getLayoutRes() { + return 0; + } + + protected abstract VS createViewState(); + + public VS getViewState() { + return mViewState; + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/MvpActivity.java b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpActivity.java new file mode 100644 index 0000000..2d59808 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpActivity.java @@ -0,0 +1,24 @@ +package com.vijay.jsonwizard.mvp; + +import android.os.Bundle; + +public abstract class MvpActivity

extends BaseActivity implements + MvpView { + + protected P presenter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + presenter = createPresenter(); + presenter.attachView(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + presenter.detachView(false); + } + + protected abstract P createPresenter(); +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/MvpBasePresenter.java b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpBasePresenter.java new file mode 100644 index 0000000..5ec36ca --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpBasePresenter.java @@ -0,0 +1,37 @@ +package com.vijay.jsonwizard.mvp; + +import java.lang.ref.WeakReference; + +public class MvpBasePresenter implements MvpPresenter { + + private WeakReference viewRef; + + @Override + public void attachView(V view) { + viewRef = new WeakReference(view); + } + + /** + * Get the attached view. You should always call {@link #isViewAttached()} + * to check if the view is attached to avoid NullPointerExceptions + */ + protected V getView() { + return viewRef.get(); + } + + /** + * Checks if a view is attached to this presenter. You should always call + * this method before calling {@link #getView()} to get the view instance. + */ + protected boolean isViewAttached() { + return viewRef != null && viewRef.get() != null; + } + + @Override + public void detachView(boolean retainInstance) { + if (viewRef != null) { + viewRef.clear(); + viewRef = null; + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/MvpFragment.java b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpFragment.java new file mode 100644 index 0000000..8350f5d --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpFragment.java @@ -0,0 +1,48 @@ +package com.vijay.jsonwizard.mvp; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +public abstract class MvpFragment

extends BaseFragment implements + MvpView { + + protected P presenter; + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + // Create the presenter if needed + if (presenter == null) { + presenter = createPresenter(); + } + presenter.attachView(this); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + presenter.detachView(getRetainInstance()); + } + + protected abstract P createPresenter(); + + public void hideSoftKeyboard() { + // Check if no view has focus: + View view = getActivity().getCurrentFocus(); + if (view != null) { + InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService( + Context.INPUT_METHOD_SERVICE); + inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/MvpPresenter.java b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpPresenter.java new file mode 100644 index 0000000..a9508a5 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpPresenter.java @@ -0,0 +1,8 @@ +package com.vijay.jsonwizard.mvp; + +public interface MvpPresenter { + + public void attachView(V view); + + public void detachView(boolean retainInstance); +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/MvpView.java b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpView.java new file mode 100644 index 0000000..9714792 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/MvpView.java @@ -0,0 +1,4 @@ +package com.vijay.jsonwizard.mvp; + +public interface MvpView { +} \ No newline at end of file diff --git a/library/src/main/java/com/vijay/jsonwizard/mvp/ViewState.java b/library/src/main/java/com/vijay/jsonwizard/mvp/ViewState.java new file mode 100644 index 0000000..626cd6a --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/mvp/ViewState.java @@ -0,0 +1,38 @@ +package com.vijay.jsonwizard.mvp; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by vijay on 4/25/15. + */ +public class ViewState implements Parcelable { + + private boolean mIsSavedInstance; + + public boolean isSavedInstance() { + return mIsSavedInstance; + } + + public void setSavedInstance(boolean isSavedInstance) { + mIsSavedInstance = isSavedInstance; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeByte(mIsSavedInstance ? (byte) 1 : (byte) 0); + } + + public ViewState() { + } + + protected ViewState(Parcel in) { + this.mIsSavedInstance = in.readByte() != 0; + } + +} diff --git a/library/src/main/java/com/vijay/jsonwizard/presenters/JsonFormFragmentPresenter.java b/library/src/main/java/com/vijay/jsonwizard/presenters/JsonFormFragmentPresenter.java new file mode 100644 index 0000000..42cfc10 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/presenters/JsonFormFragmentPresenter.java @@ -0,0 +1,152 @@ +package com.vijay.jsonwizard.presenters; + +import java.util.List; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.provider.MediaStore; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.rengwuxian.materialedittext.MaterialEditText; +import com.vijay.jsonwizard.R; +import com.vijay.jsonwizard.constants.JsonFormConstants; +import com.vijay.jsonwizard.customviews.CheckBox; +import com.vijay.jsonwizard.customviews.RadioButton; +import com.vijay.jsonwizard.fragments.JsonFormFragment; +import com.vijay.jsonwizard.interactors.JsonFormInteractor; +import com.vijay.jsonwizard.mvp.MvpBasePresenter; +import com.vijay.jsonwizard.views.JsonFormFragmentView; +import com.vijay.jsonwizard.viewstates.JsonFormFragmentViewState; + +/** + * Created by vijay on 5/14/15. + */ +public class JsonFormFragmentPresenter extends MvpBasePresenter> { + private static final String TAG = "FormFragmentPresenter"; + private static final int RESULT_LOAD_IMG = 1; + private String mStepName; + private JSONObject mStepDetails; + private String mCurrentKey; + private JsonFormInteractor mJsonFormInteractor = JsonFormInteractor.getInstance(); + + public void addFormElements() { + mStepName = getView().getArguments().getString("stepName"); + JSONObject step = getView().getStep(mStepName); + try { + mStepDetails = new JSONObject(step.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + List views = mJsonFormInteractor.fetchFormElements(mStepName, getView().getContext(), mStepDetails, + getView().getCommonListener()); + getView().addFormElements(views); + } + + public void setUpToolBar() { + if (!mStepName.equals(JsonFormConstants.FIRST_STEP_NAME)) { + getView().setUpBackButton(); + } + getView().setActionBarTitle(mStepDetails.optString("title")); + if (mStepDetails.has("next")) { + getView().updateVisibilityOfNextAndSave(true, false); + } else { + getView().updateVisibilityOfNextAndSave(false, true); + } + getView().setToolbarTitleColor(R.color.white); + } + + public void onBackClick() { + getView().hideKeyBoard(); + getView().backClick(); + } + + public void onNextClick(LinearLayout mainView) { + int childCount = mainView.getChildCount(); + for (int i = 0; i < childCount; i++) { + View childAt = mainView.getChildAt(i); + String key = (String) childAt.getTag(R.id.key); + if (childAt instanceof MaterialEditText) { + MaterialEditText editText = (MaterialEditText) childAt; + getView().writeValue(mStepName, key, editText.getText().toString()); + } else if (childAt instanceof ImageView) { + Object imagePath = childAt.getTag(R.id.imagePath); + if (imagePath instanceof String) { + getView().writeValue(mStepName, key, (String) imagePath); + } + } else if (childAt instanceof CheckBox) { + String parentKey = (String) childAt.getTag(R.id.key); + String childKey = (String) childAt.getTag(R.id.childKey); + getView().writeValue(mStepName, parentKey, JsonFormConstants.OPTIONS_FIELD_NAME, childKey, + String.valueOf(((CheckBox) childAt).isChecked())); + } else if (childAt instanceof RadioButton) { + String parentKey = (String) childAt.getTag(R.id.key); + String childKey = (String) childAt.getTag(R.id.childKey); + if (((RadioButton) childAt).isChecked()) { + getView().writeValue(mStepName, parentKey, childKey); + } + } + } + JsonFormFragment next = JsonFormFragment.getFormFragment(mStepDetails.optString("next")); + getView().hideKeyBoard(); + getView().transactThis(next); + } + + public void onSaveClick() { + Intent returnIntent = new Intent(); + returnIntent.putExtra("json", getView().getCurrentJsonState()); + getView().finishWithResult(returnIntent); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == RESULT_LOAD_IMG && resultCode == Activity.RESULT_OK && null != data) { + Uri selectedImage = data.getData(); + String[] filePathColumn = { MediaStore.Images.Media.DATA }; + // No need for null check on cursor + Cursor cursor = getView().getContext().getContentResolver() + .query(selectedImage, filePathColumn, null, null, null); + cursor.moveToFirst(); + + int columnIndex = cursor.getColumnIndex(filePathColumn[0]); + String imagePath = cursor.getString(columnIndex); + getView().updateRelevantImageView(BitmapFactory.decodeFile(imagePath), imagePath, mCurrentKey); + cursor.close(); + } + } + + public void onClick(View v) { + String key = (String) v.getTag(R.id.key); + String type = (String) v.getTag(R.id.type); + if (JsonFormConstants.CHOOSE_IMAGE.equals(type)) { + getView().hideKeyBoard(); + Intent galleryIntent = new Intent(Intent.ACTION_PICK, + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + mCurrentKey = key; + getView().startActivityForResult(galleryIntent, RESULT_LOAD_IMG); + } + } + + public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { + if (compoundButton instanceof CheckBox) { + String parentKey = (String) compoundButton.getTag(R.id.key); + String childKey = (String) compoundButton.getTag(R.id.childKey); + getView().writeValue(mStepName, parentKey, JsonFormConstants.OPTIONS_FIELD_NAME, childKey, + String.valueOf(((CheckBox) compoundButton).isChecked())); + } else if (compoundButton instanceof RadioButton) { + if (isChecked) { + String parentKey = (String) compoundButton.getTag(R.id.key); + String childKey = (String) compoundButton.getTag(R.id.childKey); + getView().unCheckAllExcept(parentKey, childKey); + getView().writeValue(mStepName, parentKey, childKey); + } + } + } +} diff --git a/library/src/main/java/com/vijay/jsonwizard/views/JsonFormFragmentView.java b/library/src/main/java/com/vijay/jsonwizard/views/JsonFormFragmentView.java new file mode 100644 index 0000000..bff8ff6 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/views/JsonFormFragmentView.java @@ -0,0 +1,67 @@ +package com.vijay.jsonwizard.views; + +import java.util.List; + +import org.json.JSONObject; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.view.View; + +import com.vijay.jsonwizard.fragments.JsonFormFragment; +import com.vijay.jsonwizard.interfaces.CommonListener; +import com.vijay.jsonwizard.mvp.MvpView; +import com.vijay.jsonwizard.mvp.ViewState; + +/** + * Created by vijay on 5/14/15. + */ +public interface JsonFormFragmentView extends MvpView { + Bundle getArguments(); + + void setActionBarTitle(String title); + + Context getContext(); + + CommonListener getCommonListener(); + + void addFormElements(List views); + + ActionBar getSupportActionBar(); + + Toolbar getToolbar(); + + void setToolbarTitleColor(int white); + + void updateVisibilityOfNextAndSave(boolean next, boolean save); + + void hideKeyBoard(); + + void transactThis(JsonFormFragment next); + + void startActivityForResult(Intent intent, int requestCode); + + void updateRelevantImageView(Bitmap bitmap, String imagePath, String currentKey); + + void writeValue(String stepName, String key, String value); + + void writeValue(String stepName, String prentKey, String childObjectKey, String childKey, String value); + + JSONObject getStep(String stepName); + + String getCurrentJsonState(); + + void finishWithResult(Intent returnIntent); + + void setUpBackButton(); + + void backClick(); + + void unCheckAllExcept(String parentKey, String childKey); + + String getCount(); +} diff --git a/library/src/main/java/com/vijay/jsonwizard/viewstates/JsonFormFragmentViewState.java b/library/src/main/java/com/vijay/jsonwizard/viewstates/JsonFormFragmentViewState.java new file mode 100644 index 0000000..9e06a11 --- /dev/null +++ b/library/src/main/java/com/vijay/jsonwizard/viewstates/JsonFormFragmentViewState.java @@ -0,0 +1,39 @@ +package com.vijay.jsonwizard.viewstates; + +import android.os.Parcel; + +import com.vijay.jsonwizard.mvp.ViewState; + +/** + * Created by vijay on 5/14/15. + */ +public class JsonFormFragmentViewState extends ViewState implements android.os.Parcelable { + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + public JsonFormFragmentViewState() { + } + + private JsonFormFragmentViewState(Parcel in) { + super(in); + } + + public static final Creator CREATOR = new Creator() { + public JsonFormFragmentViewState createFromParcel( + Parcel source) { + return new JsonFormFragmentViewState(source); + } + + public JsonFormFragmentViewState[] newArray( + int size) { + return new JsonFormFragmentViewState[size]; + } + }; +} diff --git a/library/src/main/res/anim/enter_from_left.xml b/library/src/main/res/anim/enter_from_left.xml new file mode 100644 index 0000000..7a507ee --- /dev/null +++ b/library/src/main/res/anim/enter_from_left.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/library/src/main/res/anim/enter_from_right.xml b/library/src/main/res/anim/enter_from_right.xml new file mode 100644 index 0000000..e0cf6de --- /dev/null +++ b/library/src/main/res/anim/enter_from_right.xml @@ -0,0 +1,6 @@ + + diff --git a/library/src/main/res/anim/exit_to_left.xml b/library/src/main/res/anim/exit_to_left.xml new file mode 100644 index 0000000..893bd0c --- /dev/null +++ b/library/src/main/res/anim/exit_to_left.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/anim/exit_to_right.xml b/library/src/main/res/anim/exit_to_right.xml new file mode 100644 index 0000000..6bf663f --- /dev/null +++ b/library/src/main/res/anim/exit_to_right.xml @@ -0,0 +1,6 @@ + + diff --git a/library/src/main/res/anim/pop_enter_from_left.xml b/library/src/main/res/anim/pop_enter_from_left.xml new file mode 100644 index 0000000..61f1fb6 --- /dev/null +++ b/library/src/main/res/anim/pop_enter_from_left.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/library/src/main/res/anim/pop_exit_to_right.xml b/library/src/main/res/anim/pop_exit_to_right.xml new file mode 100644 index 0000000..6bf663f --- /dev/null +++ b/library/src/main/res/anim/pop_exit_to_right.xml @@ -0,0 +1,6 @@ + + diff --git a/library/src/main/res/layout/activity_json_form.xml b/library/src/main/res/layout/activity_json_form.xml new file mode 100644 index 0000000..b76a6ea --- /dev/null +++ b/library/src/main/res/layout/activity_json_form.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/library/src/main/res/layout/fragment_json_wizard.xml b/library/src/main/res/layout/fragment_json_wizard.xml new file mode 100644 index 0000000..817440c --- /dev/null +++ b/library/src/main/res/layout/fragment_json_wizard.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/layout/item_button.xml b/library/src/main/res/layout/item_button.xml new file mode 100644 index 0000000..1a1c939 --- /dev/null +++ b/library/src/main/res/layout/item_button.xml @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/library/src/main/res/layout/item_checkbox.xml b/library/src/main/res/layout/item_checkbox.xml new file mode 100644 index 0000000..c827a66 --- /dev/null +++ b/library/src/main/res/layout/item_checkbox.xml @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/library/src/main/res/layout/item_edit_text.xml b/library/src/main/res/layout/item_edit_text.xml new file mode 100644 index 0000000..eb84f66 --- /dev/null +++ b/library/src/main/res/layout/item_edit_text.xml @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/library/src/main/res/layout/item_radiobutton.xml b/library/src/main/res/layout/item_radiobutton.xml new file mode 100644 index 0000000..5229e96 --- /dev/null +++ b/library/src/main/res/layout/item_radiobutton.xml @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/library/src/main/res/menu/menu_toolbar.xml b/library/src/main/res/menu/menu_toolbar.xml new file mode 100644 index 0000000..d086bb1 --- /dev/null +++ b/library/src/main/res/menu/menu_toolbar.xml @@ -0,0 +1,17 @@ +

+ + + diff --git a/library/src/main/res/mipmap-hdpi/grey_bg.png b/library/src/main/res/mipmap-hdpi/grey_bg.png new file mode 100644 index 0000000..43c146b Binary files /dev/null and b/library/src/main/res/mipmap-hdpi/grey_bg.png differ diff --git a/library/src/main/res/mipmap-hdpi/ic_launcher.png b/library/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/library/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-mdpi/ic_launcher.png b/library/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/library/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-xhdpi/ic_launcher.png b/library/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/library/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-xxhdpi/ic_launcher.png b/library/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/library/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/library/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/library/src/main/res/values/color.xml b/library/src/main/res/values/color.xml new file mode 100644 index 0000000..4c2bf39 --- /dev/null +++ b/library/src/main/res/values/color.xml @@ -0,0 +1,12 @@ + + + #FFFFFF + #673AB7 + #512DA8 + #D1C4E9 + #FF9800 + #212121 + #727272 + #FFFFFF + #B6B6B6 + \ No newline at end of file diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml new file mode 100644 index 0000000..15f3a2c --- /dev/null +++ b/library/src/main/res/values/dimens.xml @@ -0,0 +1,13 @@ + + + 16dp + 16dp + 16dp + 16dp + 300 + + 16sp + 8sp + 8dp + 16dp + diff --git a/library/src/main/res/values/ids.xml b/library/src/main/res/values/ids.xml new file mode 100644 index 0000000..acbbc80 --- /dev/null +++ b/library/src/main/res/values/ids.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml new file mode 100644 index 0000000..7e3b57d --- /dev/null +++ b/library/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + jsonwizard + + Hello world! + Settings + diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml new file mode 100644 index 0000000..94091c9 --- /dev/null +++ b/library/src/main/res/values/styles.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/sample/build.gradle b/sample/build.gradle new file mode 100644 index 0000000..44f31c7 --- /dev/null +++ b/sample/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.vijay.jsonwizard.demo" + minSdkVersion 9 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} +repositories { + maven {url "https://clojars.org/repo/"} +} +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.0.0' + compile project(':library') +} diff --git a/sample/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java b/sample/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java new file mode 100644 index 0000000..4880a9e --- /dev/null +++ b/sample/src/androidTest/java/com/vijay/jsonwizard/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.vijay.jsonwizard; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fdfd7dc --- /dev/null +++ b/sample/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/sample/src/main/assets/data.json b/sample/src/main/assets/data.json new file mode 100644 index 0000000..ec64f0d --- /dev/null +++ b/sample/src/main/assets/data.json @@ -0,0 +1,87 @@ +{ + "count":"3", + "step1":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Your Name" + }, + { + "key":"email", + "type":"edit_text", + "hint":"Enter Your Email" + }, + { + "key":"labelBackgroundImage", + "type":"label", + "text":"Choose Background Image" + }, + { + "key":"chooseImage", + "type":"choose_image", + "uploadButtonText":"Choose" + } + ], + "title":"Step 1 of 3", + "next":"step2" + }, + "step2":{ + "fields":[ + { + "key":"name", + "type":"edit_text", + "hint":"Enter Country" + }, + { + "key":"checkData", + "type":"check_box", + "label":"Select multiple preferences", + "options":[ + { + "key":"awesomeness", + "text":"Are you willing for some awesomeness?", + "value":"false" + }, + { + "key":"newsletter", + "text":"Do you really want to opt out from my newsletter?", + "value":"false" + } + ] + }, + { + "key":"radioData", + "type":"radio", + "label":"Select one item from below", + "options":[ + { + "key":"areYouPro", + "text":"Are you pro?" + }, + { + "key":"areYouAmature", + "text":"Are you amature?" + }, + { + "key":"areYouNovice", + "text":"Are you novice?" + } + ], + "value":"areYouNovice" + } + ], + "title":"Step 2 of 3", + "next":"step3" + }, + "step3":{ + "fields":[ + { + "key":"anything", + "type":"edit_text", + "hint":"Enter Anything You Want" + } + ], + "title":"Step 3 of 3" + } +} \ No newline at end of file diff --git a/sample/src/main/assets/font/LICENSE.txt b/sample/src/main/assets/font/LICENSE.txt new file mode 100644 index 0000000..162d2e9 --- /dev/null +++ b/sample/src/main/assets/font/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the url of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sample/src/main/assets/font/Roboto-Black.ttf b/sample/src/main/assets/font/Roboto-Black.ttf new file mode 100644 index 0000000..9002aab Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Black.ttf differ diff --git a/sample/src/main/assets/font/Roboto-BlackItalic.ttf b/sample/src/main/assets/font/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..b87e025 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-BlackItalic.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Bold.ttf b/sample/src/main/assets/font/Roboto-Bold.ttf new file mode 100644 index 0000000..072b842 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Bold.ttf differ diff --git a/sample/src/main/assets/font/Roboto-BoldItalic.ttf b/sample/src/main/assets/font/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..74919ff Binary files /dev/null and b/sample/src/main/assets/font/Roboto-BoldItalic.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Italic.ttf b/sample/src/main/assets/font/Roboto-Italic.ttf new file mode 100644 index 0000000..bd57775 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Italic.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Light.ttf b/sample/src/main/assets/font/Roboto-Light.ttf new file mode 100644 index 0000000..13bf13a Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Light.ttf differ diff --git a/sample/src/main/assets/font/Roboto-LightItalic.ttf b/sample/src/main/assets/font/Roboto-LightItalic.ttf new file mode 100644 index 0000000..130672a Binary files /dev/null and b/sample/src/main/assets/font/Roboto-LightItalic.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Medium.ttf b/sample/src/main/assets/font/Roboto-Medium.ttf new file mode 100644 index 0000000..d0f6e2b Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Medium.ttf differ diff --git a/sample/src/main/assets/font/Roboto-MediumItalic.ttf b/sample/src/main/assets/font/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..6153d48 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-MediumItalic.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Regular.ttf b/sample/src/main/assets/font/Roboto-Regular.ttf new file mode 100644 index 0000000..0ba95c9 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Regular.ttf differ diff --git a/sample/src/main/assets/font/Roboto-Thin.ttf b/sample/src/main/assets/font/Roboto-Thin.ttf new file mode 100644 index 0000000..309c22d Binary files /dev/null and b/sample/src/main/assets/font/Roboto-Thin.ttf differ diff --git a/sample/src/main/assets/font/Roboto-ThinItalic.ttf b/sample/src/main/assets/font/Roboto-ThinItalic.ttf new file mode 100644 index 0000000..0b53ba4 Binary files /dev/null and b/sample/src/main/assets/font/Roboto-ThinItalic.ttf differ diff --git a/sample/src/main/java/com/vijay/jsonwizard/demo/activities/MainActivity.java b/sample/src/main/java/com/vijay/jsonwizard/demo/activities/MainActivity.java new file mode 100644 index 0000000..02fb484 --- /dev/null +++ b/sample/src/main/java/com/vijay/jsonwizard/demo/activities/MainActivity.java @@ -0,0 +1,44 @@ +package com.vijay.jsonwizard.demo.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.View; + +import com.vijay.jsonwizard.demo.R; +import com.vijay.jsonwizard.activities.JsonFormActivity; +import com.vijay.jsonwizard.demo.utils.CommonUtils; + +/** + * Created by vijay on 5/16/15. + */ +public class MainActivity extends ActionBarActivity { + + private static final int REQUEST_CODE_GET_JSON = 1; + private static final String TAG = "MainActivity"; + private static final String DATA_JSON_PATH = "data.json"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + findViewById(R.id.button_start).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, JsonFormActivity.class); + String json = CommonUtils.loadJSONFromAsset(getApplicationContext(), DATA_JSON_PATH); + intent.putExtra("json", json); + startActivityForResult(intent, REQUEST_CODE_GET_JSON); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_GET_JSON && resultCode == RESULT_OK) { + Log.d(TAG, data.getStringExtra("json")); + } + super.onActivityResult(requestCode, resultCode, data); + } +} diff --git a/sample/src/main/java/com/vijay/jsonwizard/demo/utils/CommonUtils.java b/sample/src/main/java/com/vijay/jsonwizard/demo/utils/CommonUtils.java new file mode 100644 index 0000000..af9d4bb --- /dev/null +++ b/sample/src/main/java/com/vijay/jsonwizard/demo/utils/CommonUtils.java @@ -0,0 +1,36 @@ +package com.vijay.jsonwizard.demo.utils; + +import java.io.IOException; +import java.io.InputStream; + +import android.content.Context; +import android.util.Log; + +/** + * Created by vijay on 5/16/15. + */ +public class CommonUtils { + + private static final String TAG = "CommonUtils"; + + private CommonUtils() { + } + + public static String loadJSONFromAsset(Context context, String fileName) { + String json = null; + try { + InputStream is = context.getAssets().open(fileName); + int size = is.available(); + byte[] buffer = new byte[size]; + is.read(buffer); + is.close(); + json = new String(buffer, "UTF-8"); + } catch (IOException ex) { + Log.d(TAG, "Exception Occurred : " + ex.getMessage()); + return null; + } + return json; + + } + +} diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..32e92ec --- /dev/null +++ b/sample/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + +