├── hooks ├── .gitignore └── README.md ├── www ├── .gitignore ├── templates │ ├── layout.html │ └── snaps │ │ └── stream.html ├── js │ ├── controllers │ │ ├── app_ctrl.js │ │ └── snaps_ctrl.js │ ├── modules.js │ ├── app.js │ └── strftime.js ├── css │ └── style.css └── index.html ├── .bowerrc ├── .gitignore ├── ionic.project ├── README.md ├── firebase.json ├── bower.json ├── package.json ├── scss └── ionic.app.scss ├── config.xml └── gulpfile.js /hooks/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "www/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | www/lib/* 3 | plugins/* 4 | platforms/* 5 | merges/* 6 | -------------------------------------------------------------------------------- /www/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | -------------------------------------------------------------------------------- /ionic.project: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snap", 3 | "email": "brentvatne@gmail.com", 4 | "app_id": "", 5 | "package_name": "" 6 | } 7 | -------------------------------------------------------------------------------- /www/js/controllers/app_ctrl.js: -------------------------------------------------------------------------------- 1 | angular.module('snap.controllers') 2 | .controller('AppCtrl', function($scope, $state) { 3 | }) 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hey look an image feed! Neato! 2 | 3 | Make this into something like Instagram or Snapchat if you like, as an 4 | exercise! 5 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "firebase": "snap-ruby-db", 3 | "public": "www", 4 | "ignore": [ 5 | "firebase.json", 6 | ".*", 7 | "**/node_modules/**" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /www/js/modules.js: -------------------------------------------------------------------------------- 1 | angular.module('snap.controllers', []) 2 | angular.module('snap.services', []) 3 | angular.module('snap.directives', []) 4 | angular.module('snap', ['ionic', 'ngCordova', 'firebase', 'snap.controllers']) 5 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Snap!", 3 | "private": "true", 4 | "devDependencies": { 5 | "ionic": "driftyco/ionic-bower#1.0.0-beta.8" 6 | }, 7 | "dependencies": { 8 | "angular-local-storage": "~0.0.5", 9 | "ngCordova": "~0.1.2-alpha", 10 | "angularfire": "~0.7.1", 11 | "firebase": "~1.0.17" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-project", 3 | "version": "1.0.0", 4 | "description": "An Ionic project", 5 | "dependencies": { 6 | "gulp": "^3.5.6", 7 | "gulp-sass": "^0.7.1", 8 | "gulp-concat": "^2.2.0", 9 | "gulp-minify-css": "^0.3.0", 10 | "gulp-rename": "^1.2.0" 11 | }, 12 | "devDependencies": { 13 | "bower": "^1.3.3", 14 | "gulp-util": "^2.2.14", 15 | "shelljs": "^0.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /www/templates/snaps/stream.html: -------------------------------------------------------------------------------- 1 | 2 |

Snaps!

3 |
4 | 6 |
7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 | 16 | 17 |
18 | {{formattedDate(snap.created)}} 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /scss/ionic.app.scss: -------------------------------------------------------------------------------- 1 | /* 2 | To customize the look and feel of Ionic, you can override the variables 3 | in ionic's _variables.scss file. 4 | 5 | For example, you might change some of the default colors: 6 | 7 | $light: #fff !default; 8 | $stable: #f8f8f8 !default; 9 | $positive: #4a87ee !default; 10 | $calm: #43cee6 !default; 11 | $balanced: #66cc33 !default; 12 | $energized: #f0b840 !default; 13 | $assertive: #ef4e3a !default; 14 | $royal: #8a6de9 !default; 15 | $dark: #444 !default; 16 | */ 17 | 18 | // The path for our ionicons font files, relative to the built CSS in www/css 19 | $ionicons-font-path: "../lib/ionic/fonts" !default; 20 | 21 | // Include all of Ionic 22 | @import "www/lib/ionic/scss/ionic"; 23 | 24 | -------------------------------------------------------------------------------- /www/js/app.js: -------------------------------------------------------------------------------- 1 | angular.module('snap') 2 | .constant('FirebaseUrl', "https://snap-ruby-db.firebaseio.com") 3 | 4 | .run(function($ionicPlatform) { 5 | $ionicPlatform.ready(function() { 6 | // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard 7 | // for form inputs) 8 | if(window.cordova && window.cordova.plugins.Keyboard) { 9 | cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 10 | } 11 | if(window.StatusBar) { 12 | // org.apache.cordova.statusbar required 13 | StatusBar.styleDefault(); 14 | } 15 | }); 16 | }) 17 | 18 | .config(function($stateProvider, $urlRouterProvider) { 19 | $stateProvider 20 | .state('snaps', { 21 | url: "/snaps", 22 | abstract: true, 23 | templateUrl: "templates/layout.html" 24 | }) 25 | 26 | .state('snaps.stream', { 27 | url: "/stream", 28 | templateUrl: 'templates/snaps/stream.html', 29 | controller: 'SnapsCtrl' 30 | }) 31 | 32 | $urlRouterProvider.otherwise('/snaps/stream'); 33 | }); 34 | -------------------------------------------------------------------------------- /www/css/style.css: -------------------------------------------------------------------------------- 1 | /* Empty. Add your own CSS if you like */ 2 | 3 | .loading-spinner { 4 | font-size: 30px; 5 | color: #ccc; 6 | } 7 | 8 | .loading-wrapper { 9 | text-align: center; 10 | padding-top: 40px; 11 | } 12 | 13 | @media all and (min-width: 600px) { 14 | .card { 15 | width: 48%; 16 | display: inline-block; 17 | vertical-align: top; 18 | margin: 0; 19 | margin-left: 12px; 20 | margin-top: 10px; 21 | } 22 | 23 | .list { 24 | padding-top: 25px; 25 | } 26 | } 27 | 28 | .bar-header { 29 | height: 54px; 30 | } 31 | 32 | .list { 33 | text-align: center; 34 | } 35 | 36 | .bar-header .title { 37 | line-height: 54px; 38 | font-size: 20px; 39 | padding-left: 10px; 40 | } 41 | 42 | .bar-header .button { 43 | border: none; 44 | font-size: 20px; 45 | } 46 | 47 | .bar .button.button-icon:before, .bar .button .icon:before, .bar .button.icon:before, .bar .button.icon-left:before, .bar .button.icon-right:before { 48 | font-size: 25px; 49 | } 50 | 51 | .platform-browser .camera-button { 52 | display: none; 53 | } 54 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Snap! 4 | 5 | Snap! 6 | 7 | 8 | Brent 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Snaps! 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var bower = require('bower'); 4 | var concat = require('gulp-concat'); 5 | var sass = require('gulp-sass'); 6 | var minifyCss = require('gulp-minify-css'); 7 | var rename = require('gulp-rename'); 8 | var sh = require('shelljs'); 9 | 10 | var paths = { 11 | sass: ['./scss/**/*.scss'] 12 | }; 13 | 14 | gulp.task('default', ['sass']); 15 | 16 | gulp.task('sass', function(done) { 17 | gulp.src('./scss/ionic.app.scss') 18 | .pipe(sass()) 19 | .pipe(gulp.dest('./www/css/')) 20 | .pipe(minifyCss({ 21 | keepSpecialComments: 0 22 | })) 23 | .pipe(rename({ extname: '.min.css' })) 24 | .pipe(gulp.dest('./www/css/')) 25 | .on('end', done); 26 | }); 27 | 28 | gulp.task('watch', function() { 29 | gulp.watch(paths.sass, ['sass']); 30 | }); 31 | 32 | gulp.task('install', ['git-check'], function() { 33 | return bower.commands.install() 34 | .on('log', function(data) { 35 | gutil.log('bower', gutil.colors.cyan(data.id), data.message); 36 | }); 37 | }); 38 | 39 | gulp.task('git-check', function(done) { 40 | if (!sh.which('git')) { 41 | console.log( 42 | ' ' + gutil.colors.red('Git is not installed.'), 43 | '\n Git, the version control system, is required to download Ionic.', 44 | '\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.', 45 | '\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.' 46 | ); 47 | process.exit(1); 48 | } 49 | done(); 50 | }); 51 | -------------------------------------------------------------------------------- /www/js/controllers/snaps_ctrl.js: -------------------------------------------------------------------------------- 1 | angular.module('snap.controllers') 2 | .controller('SnapsCtrl', function($scope, $rootScope, $state, $ionicLoading, 3 | $cordovaDialogs, $cordovaVibration, 4 | $cordovaCamera, FirebaseUrl, $firebase) { 5 | 6 | $scope.isLoading = true; 7 | var snapsRef = new Firebase(FirebaseUrl + "/snaps"); 8 | $scope.snaps = $firebase(snapsRef); 9 | $scope.snaps.$on('loaded', function() { 10 | $scope.isLoading = false; 11 | }); 12 | 13 | $scope.formattedDate = function(dateInteger) { 14 | return strftime('%B %d, %Y %H:%M:%S', new Date(dateInteger)); 15 | } 16 | 17 | $scope.takePicture = function() { 18 | var options = { 19 | quality : 75, 20 | destinationType : Camera.DestinationType.DATA_URL, 21 | sourceType : Camera.PictureSourceType.CAMERA, 22 | allowEdit : true, 23 | encodingType: Camera.EncodingType.JPEG, 24 | targetWidth: 600, 25 | targetHeight: 600, 26 | popoverOptions: CameraPopoverOptions, 27 | saveToPhotoAlbum: false 28 | }; 29 | 30 | $cordovaCamera.getPicture(options).then(function(imageData) { 31 | $ionicLoading.show({ 32 | template: 'Uploading...' 33 | }); 34 | 35 | $scope.snaps.$add({data: imageData, created: (new Date().getTime())}). 36 | then(function(data) { 37 | $ionicLoading.hide(); 38 | }); 39 | }, function(err) { 40 | // If you cancel or there is an error for some reason, 41 | // it goes here. 42 | }); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /hooks/README.md: -------------------------------------------------------------------------------- 1 | 21 | # Cordova Hooks 22 | 23 | This directory may contain scripts used to customize cordova commands. This 24 | directory used to exist at `.cordova/hooks`, but has now been moved to the 25 | project root. Any scripts you add to these directories will be executed before 26 | and after the commands corresponding to the directory name. Useful for 27 | integrating your own build systems or integrating with version control systems. 28 | 29 | __Remember__: Make your scripts executable. 30 | 31 | ## Hook Directories 32 | The following subdirectories will be used for hooks: 33 | 34 | after_build/ 35 | after_compile/ 36 | after_docs/ 37 | after_emulate/ 38 | after_platform_add/ 39 | after_platform_rm/ 40 | after_platform_ls/ 41 | after_plugin_add/ 42 | after_plugin_ls/ 43 | after_plugin_rm/ 44 | after_plugin_search/ 45 | after_prepare/ 46 | after_run/ 47 | after_serve/ 48 | before_build/ 49 | before_compile/ 50 | before_docs/ 51 | before_emulate/ 52 | before_platform_add/ 53 | before_platform_rm/ 54 | before_platform_ls/ 55 | before_plugin_add/ 56 | before_plugin_ls/ 57 | before_plugin_rm/ 58 | before_plugin_search/ 59 | before_prepare/ 60 | before_run/ 61 | before_serve/ 62 | pre_package/ <-- Windows 8 and Windows Phone only. 63 | 64 | ## Script Interface 65 | 66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: 67 | 68 | * CORDOVA_VERSION - The version of the Cordova-CLI. 69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). 70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) 71 | * CORDOVA_HOOK - Path to the hook that is being executed. 72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) 73 | 74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted. 75 | 76 | 77 | ## Writing hooks 78 | 79 | We highly recommend writting your hooks using Node.js so that they are 80 | cross-platform. Some good examples are shown here: 81 | 82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) 83 | 84 | -------------------------------------------------------------------------------- /www/js/strftime.js: -------------------------------------------------------------------------------- 1 | (function(){function i(c,a,b){return g(c,a,b)}function g(c,a,b,j){j=j||{};a&&!n(a)&&(b=a,a=void 0);a=a||new Date;b=b||o;b.formats=b.formats||{};var i=a.getTime(),h=j.timezone,e=typeof h;if(j.utc||e=="number"||e=="string")a=p(a);if(h){if(e=="string")var k=h[0]=="-"?-1:1,q=parseInt(h.slice(1,3),10),r=parseInt(h.slice(3,5),10),h=k*(60*q+r);e&&(a=new Date(a.getTime()+h*6E4))}return c.replace(/%([-_0]?.)/g,function(c,e){var d;if(e.length==2){d=e[0];if(d=="-")d="";else if(d=="_")d=" ";else if(d=="0")d= 2 | "0";else return c;e=e[1]}switch(e){case "A":return b.days[a.getDay()];case "a":return b.shortDays[a.getDay()];case "B":return b.months[a.getMonth()];case "b":return b.shortMonths[a.getMonth()];case "C":return f(Math.floor(a.getFullYear()/100),d);case "D":return g(b.formats.D||"%m/%d/%y",a,b);case "d":return f(a.getDate(),d);case "e":return a.getDate();case "F":return g(b.formats.F||"%Y-%m-%d",a,b);case "H":return f(a.getHours(),d);case "h":return b.shortMonths[a.getMonth()];case "I":return f(l(a), 3 | d);case "j":return d=new Date(a.getFullYear(),0,1),d=Math.ceil((a.getTime()-d.getTime())/864E5),f(d,3);case "k":return f(a.getHours(),d==null?" ":d);case "L":return f(Math.floor(i%1E3),3);case "l":return f(l(a),d==null?" ":d);case "M":return f(a.getMinutes(),d);case "m":return f(a.getMonth()+1,d);case "n":return"\n";case "o":return String(a.getDate())+s(a.getDate());case "P":return a.getHours()<12?b.am:b.pm;case "p":return a.getHours()<12?b.AM:b.PM;case "R":return g(b.formats.R||"%H:%M",a,b);case "r":return g(b.formats.r|| 4 | "%I:%M:%S %p",a,b);case "S":return f(a.getSeconds(),d);case "s":return Math.floor(i/1E3);case "T":return g(b.formats.T||"%H:%M:%S",a,b);case "t":return"\t";case "U":return f(m(a,"sunday"),d);case "u":return d=a.getDay(),d==0?7:d;case "v":return g(b.formats.v||"%e-%b-%Y",a,b);case "W":return f(m(a,"monday"),d);case "w":return a.getDay();case "Y":return a.getFullYear();case "y":return d=String(a.getFullYear()),d.slice(d.length-2);case "Z":return j.utc?"GMT":(d=a.toString().match(/\(([\w\s]+)\)/))&& 5 | d[1]||"";case "z":return j.utc?"+0000":(d=typeof h=="number"?h:-a.getTimezoneOffset(),(d<0?"-":"+")+f(Math.floor(Math.abs(d)/60))+f(Math.abs(d)%60));default:return e}})}function p(c){var a=(c.getTimezoneOffset()||0)*6E4;return new Date(c.getTime()+a)}function n(c){for(var a=0,b=k.length,a=0;a12&&(c-=12);return c}function s(c){var a=c%10;c%=100;if(c>=11&&c<=13||a===0||a>=4)return"th";switch(a){case 1:return"st";case 2:return"nd";case 3:return"rd"}}function m(c,a){var a=a||"sunday",b=c.getDay();a=="monday"&&(b==0?b=6:b--);var e=new Date(c.getFullYear(),0,1);return Math.floor(((c-e)/864E5+7-b)/7)}var e;e=typeof module!=="undefined"?module.exports=i:function(){return this||(0,eval)("this")}();var o={days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),shortDays:"Sun Mon Tue Wed Thu Fri Sat".split(" "), 7 | months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),AM:"AM",PM:"PM",am:"am",pm:"pm"};e.strftime=i;e.strftimeTZ=i.strftimeTZ=function(c,a,b,e){if((typeof b=="number"||typeof b=="string")&&e==null)e=b,b=void 0;return g(c,a,b,{timezone:e})};e.strftimeUTC=i.strftimeUTC=function(c,a,b){return g(c,a,b,{utc:!0})};e.localizedStrftime=i.localizedStrftime=function(c){return function(a, 8 | b){return g(a,b,c)}};var k=["getTime","getTimezoneOffset","getDay","getDate","getMonth","getFullYear","getYear","getHours","getMinutes","getSeconds"]})(); 9 | --------------------------------------------------------------------------------