diff --git a/ParseUI-Widget-Sample/build.gradle b/ParseUI-Widget-Sample/build.gradle
new file mode 100644
index 0000000..883e312
--- /dev/null
+++ b/ParseUI-Widget-Sample/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
+
+ defaultConfig {
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ applicationId "com.parse.ui.widget.sample"
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:appcompat-v7:23.1.1'
+ compile project(':ParseUI-Widget')
+
+ testCompile 'junit:junit:4.12'
+}
diff --git a/ParseUI-Widget-Sample/proguard-rules.pro b/ParseUI-Widget-Sample/proguard-rules.pro
new file mode 100644
index 0000000..a965f92
--- /dev/null
+++ b/ParseUI-Widget-Sample/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 /usr/local/opt/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/ParseUI-Widget-Sample/src/main/AndroidManifest.xml b/ParseUI-Widget-Sample/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..37ac933
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/ListActivity.java b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/ListActivity.java
new file mode 100644
index 0000000..cf004bc
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/ListActivity.java
@@ -0,0 +1,53 @@
+package com.parse.ui.widget.sample;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.parse.ParseException;
+import com.parse.ParseObject;
+import com.parse.ParseQuery;
+import com.parse.ParseQueryAdapter;
+
+import java.util.List;
+
+
+public class ListActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_list);
+
+ ListView listView = (ListView) findViewById(R.id.list);
+
+ ParseQueryAdapter adapter = new ParseQueryAdapter<>(this,
+ new ParseQueryAdapter.QueryFactory() {
+ @Override
+ public ParseQuery create() {
+ return ParseQuery.getQuery("Contact")
+ .orderByAscending("name")
+ .setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
+ }
+ }, android.R.layout.simple_list_item_1);
+ adapter.setTextKey("name");
+ adapter.addOnQueryLoadListener(new ParseQueryAdapter.OnQueryLoadListener() {
+ @Override
+ public void onLoading() {
+
+ }
+
+ @Override
+ public void onLoaded(List objects, Exception e) {
+ if (e != null
+ && e instanceof ParseException
+ && ((ParseException) e).getCode() != ParseException.CACHE_MISS) {
+ Toast.makeText(ListActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
+ }
+ }
+ });
+ listView.setAdapter(adapter);
+ }
+}
diff --git a/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MainActivity.java b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MainActivity.java
new file mode 100644
index 0000000..be09b6e
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MainActivity.java
@@ -0,0 +1,33 @@
+package com.parse.ui.widget.sample;
+
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+
+public class MainActivity extends AppCompatActivity implements View.OnClickListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ findViewById(R.id.sample_list).setOnClickListener(this);
+ }
+
+ //region OnClickListener
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ switch (id) {
+ case R.id.sample_list: {
+ Intent intent = new Intent(this, ListActivity.class);
+ startActivity(intent);
+ break;
+ }
+ }
+ }
+
+ //endregion
+}
diff --git a/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MyApplication.java b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MyApplication.java
new file mode 100644
index 0000000..315c5b2
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/java/com/parse/ui/widget/sample/MyApplication.java
@@ -0,0 +1,15 @@
+package com.parse.ui.widget.sample;
+
+import android.app.Application;
+
+import com.parse.Parse;
+
+public class MyApplication extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Parse.initialize(this);
+ }
+}
diff --git a/ParseUI-Widget-Sample/src/main/res/layout/activity_list.xml b/ParseUI-Widget-Sample/src/main/res/layout/activity_list.xml
new file mode 100644
index 0000000..a570070
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/layout/activity_list.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ParseUI-Widget-Sample/src/main/res/layout/activity_main.xml b/ParseUI-Widget-Sample/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..87dc282
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/ParseUI-Widget-Sample/src/main/res/mipmap-hdpi/ic_launcher.png b/ParseUI-Widget-Sample/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/ParseUI-Widget-Sample/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/ParseUI-Widget-Sample/src/main/res/mipmap-mdpi/ic_launcher.png b/ParseUI-Widget-Sample/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/ParseUI-Widget-Sample/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/ParseUI-Widget-Sample/src/main/res/mipmap-xhdpi/ic_launcher.png b/ParseUI-Widget-Sample/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/ParseUI-Widget-Sample/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/ParseUI-Widget-Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ParseUI-Widget-Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/ParseUI-Widget-Sample/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/ParseUI-Widget-Sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ParseUI-Widget-Sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/ParseUI-Widget-Sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/ParseUI-Widget-Sample/src/main/res/values-w820dp/dimens.xml b/ParseUI-Widget-Sample/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/ParseUI-Widget-Sample/src/main/res/values/colors.xml b/ParseUI-Widget-Sample/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/ParseUI-Widget-Sample/src/main/res/values/dimens.xml b/ParseUI-Widget-Sample/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..47c8224
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 16dp
+ 16dp
+
diff --git a/ParseUI-Widget-Sample/src/main/res/values/keys.xml b/ParseUI-Widget-Sample/src/main/res/values/keys.xml
new file mode 100644
index 0000000..5b89549
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values/keys.xml
@@ -0,0 +1,5 @@
+
+
+ YOUR_PARSE_APP_ID
+ YOUR_PARSE_CLIENT_KEY
+
diff --git a/ParseUI-Widget-Sample/src/main/res/values/strings.xml b/ParseUI-Widget-Sample/src/main/res/values/strings.xml
new file mode 100644
index 0000000..07ccf10
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ ParseUI-Widget Sample
+ ListView Sample
+
diff --git a/ParseUI-Widget-Sample/src/main/res/values/styles.xml b/ParseUI-Widget-Sample/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/ParseUI-Widget-Sample/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644
index 0000000..8006b99
--- /dev/null
+++ b/scripts/.gitignore
@@ -0,0 +1,35 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
+node_modules
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
diff --git a/scripts/bootstrap/README.md b/scripts/bootstrap/README.md
new file mode 100644
index 0000000..a94603b
--- /dev/null
+++ b/scripts/bootstrap/README.md
@@ -0,0 +1,13 @@
+# bootstrap.js
+
+Bootstraps a Parse application to be used with the samples in this repository.
+
+# Requirements
+
+* [Node.js](https://nodejs.org)
+
+## Usage
+
+1. Add your keys to `config.js`
+2. `npm install`
+3. `npm bootstrap.js`
diff --git a/scripts/bootstrap/bootstrap.js b/scripts/bootstrap/bootstrap.js
new file mode 100644
index 0000000..592127f
--- /dev/null
+++ b/scripts/bootstrap/bootstrap.js
@@ -0,0 +1,57 @@
+var https = require('https');
+var Parse = require('parse/node');
+var Promise = require('promise');
+var config = require('./config');
+
+Parse.initialize(config.parse.appId, config.parse.jsKey);
+
+var count = 100;
+var className = "Contact";
+
+var args = process.argv.slice(2);
+if (args >= 1) {
+ count = args[0];
+}
+if (args >= 2) {
+ className = args[1];
+}
+
+function toTitleCase(str)
+{
+ return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
+}
+
+console.log('Creating ' + count + ' ' + className + ' objects');
+new Promise(function(resolve, reject) {
+ var options = {
+ hostname: 'randomuser.me',
+ path: '/api/?results=' + count
+ }
+ var req = https.request(options, function(res) {
+ res.setEncoding('utf8');
+ var data = '';
+ res.on('data', function(chunk) {
+ data += chunk;
+ });
+ res.on('end', function() {
+ try {
+ resolve(JSON.parse(data));
+ } catch (ex) {
+ reject(ex);
+ }
+ });
+ });
+ req.end();
+}).then(function(json) {
+ var objects = json.results.map(function(result) {
+ var object = new Parse.Object(className);
+ object.set('name', toTitleCase(result.user.name.first + ' ' + result.user.name.last));
+ return object;
+ });
+
+ return Parse.Object.saveAll(objects);
+}).then(function(result) {
+ console.log('done');
+}, function(error) {
+ console.log('error: ' + error);
+});
diff --git a/scripts/bootstrap/config.js b/scripts/bootstrap/config.js
new file mode 100644
index 0000000..83fda81
--- /dev/null
+++ b/scripts/bootstrap/config.js
@@ -0,0 +1,7 @@
+var config = {};
+
+config.parse = {};
+config.parse.appId = 'YOUR_PARSE_APP_ID';
+config.parse.jsKey = 'YOUR_PARSE_JS_KEY';
+
+module.exports = config;
diff --git a/scripts/bootstrap/package.json b/scripts/bootstrap/package.json
new file mode 100644
index 0000000..0e2540c
--- /dev/null
+++ b/scripts/bootstrap/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "bootstrap",
+ "version": "1.0.0",
+ "description": "",
+ "main": "bootstrap.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Grantland Chew",
+ "license": "Platform License",
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "dependencies": {
+ "parse": "^1.6.13",
+ "promise": "^7.1.1"
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index f8d56a2..2667138 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,12 +1,11 @@
-rootProject.name = 'ParseAndroidUI'
-
-// Parse UI Login Library
+// Parse UI Widget Library
include ':ParseUI-Widget'
-// Parse UI Widget Library
+// Parse UI Login Library
include ':ParseUI-Login'
// Sample Projects
+include ':ParseUI-Widget-Sample'
include ':ParseLoginSampleBasic'
include ':ParseLoginSampleWithDispatchActivity'
include ':ParseLoginSampleCodeCustomization'