├── vendor └── .gitkeep ├── app ├── components │ ├── .gitkeep │ ├── radial-progress-indicator.js │ ├── instance-holder.js │ ├── action-bar.js │ ├── profile-pic.js │ ├── reveal-modal.js │ ├── file-select-drop.js │ └── thumbnail-slider.js ├── helpers │ ├── .gitkeep │ └── extension-mapping.js ├── models │ ├── .gitkeep │ └── user.js ├── routes │ ├── .gitkeep │ ├── signin.js │ ├── signup.js │ ├── users.js │ ├── about.js │ ├── people.js │ ├── profile.js │ ├── home │ │ └── sidebar.js │ ├── application.js │ ├── notifications.js │ ├── people │ │ ├── find.js │ │ └── detail.js │ └── home.js ├── controllers │ ├── .gitkeep │ ├── users.js │ ├── signin.js │ ├── application.js │ ├── header-nav.js │ ├── home.js │ ├── people │ │ ├── find.js │ │ └── detail.js │ ├── profile.js │ ├── home │ │ ├── sidebar.js │ │ └── dropzone.js │ ├── notifications.js │ └── signup.js ├── templates │ ├── components │ │ ├── .gitkeep │ │ ├── radial-progress-indicator.hbs │ │ ├── instance-holder.hbs │ │ ├── file-select-drop.hbs │ │ ├── profile-pic.hbs │ │ ├── action-bar.hbs │ │ ├── reveal-modal.hbs │ │ └── thumbnail-slider.hbs │ ├── people.hbs │ ├── users.hbs │ ├── about.hbs │ ├── application.hbs │ ├── people │ │ ├── find.hbs │ │ └── detail.hbs │ ├── signin.hbs │ ├── home │ │ ├── dropzone.hbs │ │ └── sidebar.hbs │ ├── notifications.hbs │ ├── header-nav.hbs │ ├── home.hbs │ ├── profile.hbs │ └── signup.hbs ├── styles │ ├── mixins.scss │ ├── pages │ │ ├── notifications.scss │ │ ├── signin.scss │ │ ├── about.scss │ │ ├── profile.scss │ │ ├── signup.scss │ │ ├── people.scss │ │ └── home.scss │ ├── bootstrap-variables.scss │ ├── app.scss │ └── components │ │ ├── reveal-modal.scss │ │ └── radial-progress-indicator.scss ├── adapters │ └── application.js ├── app.js ├── router.js ├── mixins │ ├── pretty-bytes.js │ └── signin-user.js ├── services │ ├── blob.js │ ├── webtorrent.js │ ├── file.js │ ├── users.js │ ├── ips.js │ ├── webrtc.js │ └── webrtc-v1.js ├── index.html ├── utils │ ├── context-menu.js │ └── window-menu.js └── transitions.js ├── tests ├── unit │ ├── .gitkeep │ ├── routes │ │ ├── signin-test.js │ │ ├── signup-test.js │ │ ├── users-test.js │ │ ├── profile-test.js │ │ ├── application-test.js │ │ └── notifications-test.js │ ├── models │ │ └── user-test.js │ ├── controllers │ │ ├── signin-test.js │ │ ├── signup-test.js │ │ ├── users-test.js │ │ └── application-test.js │ └── mixins │ │ ├── signin-user-test.js │ │ └── pretty-bytes-test.js ├── .eslintrc.js ├── package.json ├── test-helper.js ├── helpers │ ├── resolver.js │ └── start-app.js ├── integration │ └── components │ │ ├── profile-pic-test.js │ │ ├── reveal-modal-test.js │ │ └── instance-holder-test.js ├── electron.js ├── .jshintrc └── index.html ├── .watchmanconfig ├── .eslintrc ├── public ├── robots.txt ├── images │ ├── favicon.ico │ ├── icons │ │ ├── doc.png │ │ ├── pdf.png │ │ ├── ppt.png │ │ ├── txt.png │ │ ├── movie.png │ │ ├── music.png │ │ ├── photo.png │ │ ├── contacts.png │ │ ├── network.png │ │ ├── search.png │ │ ├── unknown.png │ │ ├── compressed.png │ │ └── photoshop.png │ ├── dummy │ │ ├── ajain.png │ │ ├── suganthi.png │ │ └── szymon.jpeg │ ├── placeholder_profile.png │ ├── logo │ │ ├── p2pdrop-logo-128.png │ │ ├── p2pdrop-logo-256.png │ │ ├── p2pdrop-logo-32.png │ │ ├── p2pdrop-logo-512.png │ │ ├── p2pdrop-logo-64.png │ │ ├── p2pdrop-logo-green-128.png │ │ ├── p2pdrop-logo-green-256.png │ │ ├── p2pdrop-logo-green-512.png │ │ ├── p2pdrop-logo-white-128.png │ │ ├── p2pdrop-logo-white-256.png │ │ └── p2pdrop-logo-white-512.png │ └── apple-touch-icon-precomposed.png └── crossdomain.xml ├── .bowerrc ├── assets ├── icons │ ├── ghost.ico │ ├── ghost.icns │ ├── ghost2.icns │ ├── ghost2.ico │ ├── ghost-osx.png │ ├── Ghost-Icons.sketch │ └── ghost-windows.png ├── dmg │ └── background.png ├── icons_1 │ ├── p2pdrop.icns │ ├── p2pdrop.ico │ ├── p2pdrop-osx.png │ └── p2pdrop-windows.png └── win │ └── installer-dev.gif ├── testem.json ├── .eslintrc.js ├── .ember-cli ├── .gitignore ├── .travis.yml ├── .jshintrc ├── .editorconfig ├── _appdmg.json ├── .sass-lint.yml ├── bower.json ├── electron.js ├── main ├── load-error │ └── error.html ├── squirrel.js ├── window-state.js ├── entry.js └── preload.js ├── ember-cli-build.js ├── package.json ├── config └── environment.js └── README.md /vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/templates/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/components/radial-progress-indicator.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./config/eslint.js" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/components/radial-progress-indicator.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /app/templates/components/instance-holder.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /assets/icons/ghost.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost.ico -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | 'embertest': true 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-electron-test", 3 | "main": "electron.js" 4 | } 5 | -------------------------------------------------------------------------------- /assets/icons/ghost.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost.icns -------------------------------------------------------------------------------- /assets/icons/ghost2.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost2.icns -------------------------------------------------------------------------------- /assets/icons/ghost2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost2.ico -------------------------------------------------------------------------------- /app/routes/signin.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | }); 5 | -------------------------------------------------------------------------------- /app/routes/signup.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | }); 5 | -------------------------------------------------------------------------------- /assets/dmg/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/dmg/background.png -------------------------------------------------------------------------------- /assets/icons/ghost-osx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost-osx.png -------------------------------------------------------------------------------- /assets/icons_1/p2pdrop.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons_1/p2pdrop.icns -------------------------------------------------------------------------------- /assets/icons_1/p2pdrop.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons_1/p2pdrop.ico -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/icons/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/doc.png -------------------------------------------------------------------------------- /public/images/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/pdf.png -------------------------------------------------------------------------------- /public/images/icons/ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/ppt.png -------------------------------------------------------------------------------- /public/images/icons/txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/txt.png -------------------------------------------------------------------------------- /assets/win/installer-dev.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/win/installer-dev.gif -------------------------------------------------------------------------------- /public/images/dummy/ajain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/dummy/ajain.png -------------------------------------------------------------------------------- /public/images/icons/movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/movie.png -------------------------------------------------------------------------------- /public/images/icons/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/music.png -------------------------------------------------------------------------------- /public/images/icons/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/photo.png -------------------------------------------------------------------------------- /app/styles/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin max-height($max) { 2 | @media (max-height: $max){ 3 | @content; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /assets/icons/Ghost-Icons.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/Ghost-Icons.sketch -------------------------------------------------------------------------------- /assets/icons/ghost-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons/ghost-windows.png -------------------------------------------------------------------------------- /assets/icons_1/p2pdrop-osx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons_1/p2pdrop-osx.png -------------------------------------------------------------------------------- /public/images/dummy/suganthi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/dummy/suganthi.png -------------------------------------------------------------------------------- /public/images/dummy/szymon.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/dummy/szymon.jpeg -------------------------------------------------------------------------------- /public/images/icons/contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/contacts.png -------------------------------------------------------------------------------- /public/images/icons/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/network.png -------------------------------------------------------------------------------- /public/images/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/search.png -------------------------------------------------------------------------------- /public/images/icons/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/unknown.png -------------------------------------------------------------------------------- /app/templates/people.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{liquid-outlet}} 4 |
5 |
-------------------------------------------------------------------------------- /assets/icons_1/p2pdrop-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/assets/icons_1/p2pdrop-windows.png -------------------------------------------------------------------------------- /public/images/icons/compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/compressed.png -------------------------------------------------------------------------------- /public/images/icons/photoshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/icons/photoshop.png -------------------------------------------------------------------------------- /public/images/placeholder_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/placeholder_profile.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-128.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-256.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-32.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-512.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-64.png -------------------------------------------------------------------------------- /public/images/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-green-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-green-128.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-green-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-green-256.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-green-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-green-512.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-white-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-white-128.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-white-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-white-256.png -------------------------------------------------------------------------------- /public/images/logo/p2pdrop-logo-white-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajainvivek/P2PDrop/HEAD/public/images/logo/p2pdrop-logo-white-512.png -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import { 3 | setResolver 4 | } from 'ember-qunit'; 5 | 6 | setResolver(resolver); 7 | -------------------------------------------------------------------------------- /app/routes/users.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | const {Route} = Ember; 3 | 4 | export default Route.extend({ 5 | model(){ 6 | return this.store.findAll('user'); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /app/routes/about.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 5 | }); 6 | -------------------------------------------------------------------------------- /app/routes/people.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 5 | }); 6 | -------------------------------------------------------------------------------- /app/routes/profile.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 5 | }); 6 | -------------------------------------------------------------------------------- /app/adapters/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import FirebaseAdapter from 'emberfire/adapters/firebase'; 3 | 4 | const { inject } = Ember; 5 | 6 | export default FirebaseAdapter.extend({ 7 | firebase: inject.service() 8 | }); 9 | -------------------------------------------------------------------------------- /testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "framework": "qunit", 3 | "test_page": "tests/index.html?hidepassed", 4 | "disable_watching": true, 5 | "launch_in_ci": [ 6 | "PhantomJS" 7 | ], 8 | "launch_in_dev": [ 9 | "PhantomJS", 10 | "Chrome" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /app/styles/pages/notifications.scss: -------------------------------------------------------------------------------- 1 | #notification { 2 | width: 80%; 3 | margin: 0px auto; 4 | padding: 10px; 5 | background: #fafafa; 6 | border: 1px solid #ebebeb; 7 | box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px; 8 | } 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "babel-eslint", 4 | parserOptions: { 5 | ecmaVersion: 6, 6 | sourceType: 'module' 7 | }, 8 | extends: 'eslint:recommended', 9 | env: { 10 | 'browser': true 11 | }, 12 | rules: { 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember/resolver'; 2 | import config from '../../config/environment'; 3 | 4 | var resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /app/templates/components/file-select-drop.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log 17 | testem.log 18 | /.idea 19 | -------------------------------------------------------------------------------- /app/routes/home/sidebar.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const { 5 | Route, 6 | inject 7 | } = Ember; 8 | 9 | export default Route.extend(AuthenticatedRouteMixin, { 10 | setupController: function(controller, model, queryParams) { 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /app/templates/components/profile-pic.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

CHANGE

5 |
6 | 7 |
8 | -------------------------------------------------------------------------------- /tests/unit/routes/signin-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:signin', 'Unit | Route | signin', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/signup-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:signup', 'Unit | Route | signup', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/users-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:users', 'Unit | Route | users', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/profile-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:profile', 'Unit | Route | profile', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/routes/application-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:application', 'Unit | Route | application', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | const { 3 | attr, 4 | hasMany, 5 | Model 6 | } = DS; 7 | 8 | export default Model.extend({ 9 | profilePic: attr(), 10 | name: attr('string'), 11 | online: attr('string'), 12 | gender: attr('string'), 13 | email: attr('string'), 14 | friends: attr(), 15 | networks: attr(), 16 | isVerified: attr() 17 | }); 18 | -------------------------------------------------------------------------------- /tests/unit/models/user-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForModel, test } from 'ember-qunit'; 2 | 3 | moduleForModel('user', 'Unit | Model | user', { 4 | // Specify the other units that are required for this test. 5 | needs: [] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var model = this.subject(); 10 | // var store = this.store(); 11 | assert.ok(!!model); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/routes/notifications-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('route:notifications', 'Unit | Route | notifications', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | test('it exists', function(assert) { 9 | var route = this.subject(); 10 | assert.ok(route); 11 | }); 12 | -------------------------------------------------------------------------------- /app/routes/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin'; 3 | const { 4 | Route, 5 | RSVP 6 | } = Ember; 7 | 8 | export default Route.extend( 9 | ApplicationRouteMixin, { 10 | model(){ 11 | return RSVP.hash({ 12 | users: this.store.findAll('user') 13 | }); 14 | } 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /tests/unit/controllers/signin-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('controller:signin', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | // Replace this with your real tests. 9 | test('it exists', function(assert) { 10 | var controller = this.subject(); 11 | assert.ok(controller); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/controllers/signup-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('controller:signup', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | // Replace this with your real tests. 9 | test('it exists', function(assert) { 10 | var controller = this.subject(); 11 | assert.ok(controller); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/controllers/users-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('controller:users', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | // Replace this with your real tests. 9 | test('it exists', function(assert) { 10 | var controller = this.subject(); 11 | assert.ok(controller); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/controllers/application-test.js: -------------------------------------------------------------------------------- 1 | import { moduleFor, test } from 'ember-qunit'; 2 | 3 | moduleFor('controller:application', { 4 | // Specify the other units that are required for this test. 5 | // needs: ['controller:foo'] 6 | }); 7 | 8 | // Replace this with your real tests. 9 | test('it exists', function(assert) { 10 | var controller = this.subject(); 11 | assert.ok(controller); 12 | }); 13 | -------------------------------------------------------------------------------- /app/templates/components/action-bar.hbs: -------------------------------------------------------------------------------- 1 | {{#liquid-if isFileSelected class="action-bar"}} 2 |
3 | Preview 4 | Download 5 |
6 | {{else}} 7 |
8 |

{{localIp}}

9 |
10 | {{/liquid-if}} 11 | -------------------------------------------------------------------------------- /app/routes/notifications.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | export default Ember.Route.extend(AuthenticatedRouteMixin, { 5 | setupController: function (controller, model, queryParams) { 6 | controller.getPendingApprovals().then(function (data) { 7 | controller.set("pendingApprovals", data); 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /app/routes/people/find.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const { 5 | Route, 6 | inject 7 | } = Ember; 8 | 9 | export default Route.extend(AuthenticatedRouteMixin, { 10 | users : inject.service("users"), 11 | setupController: function(controller, model, queryParams) { 12 | controller.fetchUsers(); 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - "0.12" 5 | 6 | sudo: false 7 | 8 | cache: 9 | directories: 10 | - node_modules 11 | 12 | before_install: 13 | - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH 14 | - "npm config set spin false" 15 | - "npm install -g npm@^2" 16 | 17 | install: 18 | - npm install -g bower 19 | - npm install 20 | - bower install 21 | 22 | script: 23 | - npm test 24 | -------------------------------------------------------------------------------- /app/components/instance-holder.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from '../config/environment'; 3 | import contextMenu from '../utils/context-menu'; 4 | import windowMenu from '../utils/window-menu'; 5 | 6 | export default Ember.Component.extend({ 7 | setup : function () { 8 | if (config.isDesktop) { 9 | contextMenu.setup(); 10 | windowMenu.setup(); 11 | } 12 | }.on("didInsertElement") 13 | }); 14 | -------------------------------------------------------------------------------- /tests/unit/mixins/signin-user-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import SigninUserMixin from '../../../mixins/signin-user'; 3 | import { module, test } from 'qunit'; 4 | 5 | module('Unit | Mixin | signin user'); 6 | 7 | // Replace this with your real tests. 8 | test('it works', function(assert) { 9 | var SigninUserObject = Ember.Object.extend(SigninUserMixin); 10 | var subject = SigninUserObject.create(); 11 | assert.ok(subject); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/unit/mixins/pretty-bytes-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import PrettyBytesMixin from '../../../mixins/pretty-bytes'; 3 | import { module, test } from 'qunit'; 4 | 5 | module('Unit | Mixin | pretty bytes'); 6 | 7 | // Replace this with your real tests. 8 | test('it works', function(assert) { 9 | var PrettyBytesObject = Ember.Object.extend(PrettyBytesMixin); 10 | var subject = PrettyBytesObject.create(); 11 | assert.ok(subject); 12 | }); 13 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from 'ember/resolver'; 3 | import loadInitializers from 'ember/load-initializers'; 4 | import config from './config/environment'; 5 | 6 | var App; 7 | 8 | Ember.MODEL_FACTORY_INJECTIONS = true; 9 | 10 | App = Ember.Application.extend({ 11 | modulePrefix: config.modulePrefix, 12 | podModulePrefix: config.podModulePrefix, 13 | Resolver: Resolver 14 | }); 15 | 16 | loadInitializers(App, config.modulePrefix); 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /app/styles/pages/signin.scss: -------------------------------------------------------------------------------- 1 | .signin-wrapper { 2 | width: 380px; 3 | margin: 0px auto; 4 | padding: 10px; 5 | background: #fafafa; 6 | border: 1px solid #ebebeb; 7 | box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px; 8 | 9 | .center { 10 | margin: 0px auto; 11 | text-align: center; 12 | display: table; 13 | } 14 | 15 | .btn-width { 16 | width: 300px; 17 | } 18 | 19 | md-input-container.md-default-theme > md-icon { 20 | color: rgba(0, 0, 0, 0.54); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Application from '../../app'; 3 | import config from '../../config/environment'; 4 | 5 | export default function startApp(attrs) { 6 | var application; 7 | 8 | var attributes = Ember.merge({}, config.APP); 9 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 10 | 11 | Ember.run(function() { 12 | application = Application.create(attributes); 13 | application.setupForTesting(); 14 | application.injectTestHelpers(); 15 | }); 16 | 17 | return application; 18 | } 19 | -------------------------------------------------------------------------------- /app/templates/users.hbs: -------------------------------------------------------------------------------- 1 |
2 |

Online Users

3 |
4 | {{#each onlineUsers as |user|}} 5 | {{user-display user=user}} 6 | {{else}} 7 | There's no users online right now. 8 | {{/each}} 9 |
10 | 11 |

Offline Users

12 |
13 | {{#each offlineUsers as |user|}} 14 | {{user-display user=user}} 15 | {{else}} 16 | There's no users offline right now. 17 | {{/each}} 18 |
19 |
20 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from './config/environment'; 3 | import googlePageview from './mixins/google-pageview'; 4 | 5 | var Router = Ember.Router.extend(googlePageview, { 6 | location: config.locationType 7 | }); 8 | 9 | Router.map(function() { 10 | this.route('home'); 11 | this.route('about'); 12 | this.route('people', function () { 13 | this.route('find'); 14 | this.route('detail'); 15 | }); 16 | this.route('users'); 17 | this.route('signup'); 18 | this.route('signin', {path : "/"}); 19 | this.route('notifications'); 20 | this.route('profile'); 21 | }); 22 | 23 | export default Router; 24 | -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "-Promise" 6 | ], 7 | "browser": true, 8 | "boss": true, 9 | "curly": true, 10 | "debug": false, 11 | "devel": true, 12 | "eqeqeq": true, 13 | "evil": true, 14 | "forin": false, 15 | "immed": false, 16 | "laxbreak": false, 17 | "newcap": true, 18 | "noarg": true, 19 | "noempty": false, 20 | "nonew": false, 21 | "nomen": false, 22 | "onevar": false, 23 | "plusplus": false, 24 | "regexp": false, 25 | "undef": true, 26 | "sub": true, 27 | "strict": false, 28 | "white": false, 29 | "eqnull": true, 30 | "esnext": true, 31 | "unused": true 32 | } 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.js] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.hbs] 21 | insert_final_newline = false 22 | indent_style = space 23 | indent_size = 2 24 | 25 | [*.css] 26 | indent_style = space 27 | indent_size = 2 28 | 29 | [*.html] 30 | indent_style = space 31 | indent_size = 2 32 | 33 | [*.{diff,md}] 34 | trim_trailing_whitespace = false 35 | -------------------------------------------------------------------------------- /app/templates/about.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

5 | P2PDrop 6 |

7 |

8 | Version 0.1.1 9 |

10 |

11 | Official free Peer to Peer File Sharing Application. 12 |

13 |

14 | This application is licensed under MIT, source code is available on Github 15 |

16 |
17 |
18 | Powered by Chaicode 19 |
20 |
21 | -------------------------------------------------------------------------------- /_appdmg.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Ghost", 3 | "background": "assets/dmg/background.png", 4 | "icon": "assets/icons/p2pdrop.icns", 5 | "icon-size": 80, 6 | "contents": [ 7 | { 8 | "x": 448, 9 | "y": 344, 10 | "type": "link", 11 | "path": "/Applications" 12 | }, 13 | { 14 | "x": 192, 15 | "y": 344, 16 | "type": "file", 17 | "path": "electron-builds/p2pdrop-darwin-x64/p2pdrop.app" 18 | }, 19 | { 20 | "x": 512, 21 | "y": 128, 22 | "type": "file", 23 | "path": "electron-builds/p2pdrop-darwin-x64/LICENSES.chromium.html" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.sass-lint.yml: -------------------------------------------------------------------------------- 1 | # Rule Configuration 2 | rules: 3 | extends-before-mixins: 2 4 | extends-before-declarations: 2 5 | placeholder-in-extend: 2 6 | mixins-before-declarations: 7 | - 2 8 | - 9 | exclude: 10 | - breakpoint 11 | - mq 12 | 13 | no-warn: 1 14 | no-debug: 1 15 | no-ids: 2 16 | no-important: 2 17 | hex-notation: 18 | - 2 19 | - 20 | style: uppercase 21 | indentation: 22 | - 2 23 | - 24 | size: 2 25 | property-sort-order: 26 | - 1 27 | - 28 | order: 29 | - display 30 | - margin 31 | ignore-custom-properties: true 32 | variable-for-property: 33 | - 2 34 | - 35 | properties: 36 | - margin 37 | - content 38 | -------------------------------------------------------------------------------- /app/styles/bootstrap-variables.scss: -------------------------------------------------------------------------------- 1 | $drop-blue: #04A9EB; 2 | $drop-grey: #EDEDED; 3 | $drop-dark-grey: #9d9d9d; 4 | $drop-light-grey: #F5F5F5; 5 | $drop-white: #FFFFFF; 6 | $drop-green: #76bd27; 7 | 8 | $primary: "blue"; 9 | 10 | $sidebar-padding: 300px; 11 | 12 | /** Navbar Styles ****/ 13 | $navbar-default-bg: $drop-blue; 14 | $navbar-default-color: $drop-white; 15 | $navbar-border-radius: 0px; 16 | $navbar-default-color: $drop-white; 17 | $navbar-default-brand-color: $drop-white; 18 | $navbar-default-toggle-border-color: $drop-white; 19 | $nav-tabs-border-color: $drop-white; 20 | $navbar-default-toggle-icon-bar-bg: $drop-white; 21 | $navbar-margin-bottom: 0px; 22 | $navbar-default-brand-hover-bg: rgba(0, 0, 0, 0.4); 23 | $navbar-default-border: $drop-blue; 24 | -------------------------------------------------------------------------------- /app/routes/people/detail.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | 4 | const { 5 | Route, 6 | inject 7 | } = Ember; 8 | 9 | export default Route.extend(AuthenticatedRouteMixin, { 10 | users : inject.service("users"), 11 | setupController: function(controller, model, queryParams) { 12 | let user = this.get("users").getUser(queryParams.queryParams.email); 13 | if (user) { 14 | controller.set("user", user); 15 | controller.set("isAvailable", false); 16 | controller.set("isPending", false); 17 | controller.set("isConnected", false); 18 | controller.checkStatus(); 19 | } else { 20 | controller.traverseBack(); 21 | } 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#if currentUser}} 3 | {{render 'header-nav'}} 4 | {{else}} 5 |
6 | 7 |

8 | P2PDROP 9 |

10 |
11 | {{/if}} 12 | 13 |
14 | {{#if currentUser}} 15 | {{liquid-outlet class="p2pdrop-liquid-wrapper"}} 16 | {{else}} 17 | {{liquid-outlet}} 18 | {{/if}} 19 |
20 |
21 | 22 | {{ember-notify messageStyle='foundation-5'}} 23 | {{ember-cli-spinner id="app-spinner" type="double-bounce" height="60px" width="60px" color="blue" bgColor="rgba(230, 230, 230, 0.5)"}} 24 | {{instance-holder}} 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "p2pdrop", 3 | "dependencies": { 4 | "ember": "1.13.7", 5 | "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", 6 | "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", 7 | "ember-data": "1.13.8", 8 | "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", 9 | "ember-qunit": "0.4.9", 10 | "ember-qunit-notifications": "0.0.7", 11 | "ember-resolver": "~0.1.18", 12 | "jquery": "^1.11.3", 13 | "loader.js": "ember-cli/loader.js#3.2.1", 14 | "qunit": "~1.18.0", 15 | "moment": ">= 2.8.0", 16 | "moment-timezone": ">= 0.1.0", 17 | "bootstrap-sass": "~3.3.6", 18 | "firebase": "^2.1.0", 19 | "ember-simple-auth": "0.8.0", 20 | "hammerjs": "~2.0.6", 21 | "matchMedia": "0.2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/components/action-bar.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | var inject = Ember.inject; 3 | 4 | export default Ember.Component.extend({ 5 | isFileSelected: false, 6 | name: "", 7 | url: "", 8 | ips: inject.service(), 9 | localIp: "", 10 | didInsertElement : function () { 11 | var self = this; 12 | this.set("actionContext", this); 13 | this.get("ips").getLocalIps().then(function (data) { 14 | console.log(data); 15 | self.set("localIp", data[0]); 16 | }); 17 | }, 18 | notifyFileSelect : function (data) { 19 | this.set("isFileSelected", true); 20 | this.set("name", data.name); 21 | this.set("url", data.url); 22 | }, 23 | resetSelected : function (boolean) { 24 | this.set("isFileSelected", boolean); 25 | }, 26 | actions: { 27 | 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /app/templates/components/reveal-modal.hbs: -------------------------------------------------------------------------------- 1 | {{#if showModalDialog}} 2 | {{#liquid-tether 3 | to="modal-dialog" 4 | target="document.body" 5 | targetModifier="visible" 6 | attachment="middle center" 7 | tetherClass="modal-dialog" 8 | overlayClass="modal-backdrop"}} 9 | 23 | {{/liquid-tether}} 24 | {{/if}} 25 | -------------------------------------------------------------------------------- /tests/integration/components/profile-pic-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('profile-pic', 'Integration | Component | profile pic', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | assert.expect(2); 10 | 11 | // Set any properties with this.set('myProperty', 'value'); 12 | // Handle any actions with this.on('myAction', function(val) { ... }); 13 | 14 | this.render(hbs`{{profile-pic}}`); 15 | 16 | assert.equal(this.$().text().trim(), ''); 17 | 18 | // Template block usage: 19 | this.render(hbs` 20 | {{#profile-pic}} 21 | template block text 22 | {{/profile-pic}} 23 | `); 24 | 25 | assert.equal(this.$().text().trim(), 'template block text'); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/integration/components/reveal-modal-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('reveal-modal', 'Integration | Component | reveal modal', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | assert.expect(2); 10 | 11 | // Set any properties with this.set('myProperty', 'value'); 12 | // Handle any actions with this.on('myAction', function(val) { ... }); 13 | 14 | this.render(hbs`{{reveal-modal}}`); 15 | 16 | assert.equal(this.$().text().trim(), ''); 17 | 18 | // Template block usage: 19 | this.render(hbs` 20 | {{#reveal-modal}} 21 | template block text 22 | {{/reveal-modal}} 23 | `); 24 | 25 | assert.equal(this.$().text().trim(), 'template block text'); 26 | }); 27 | -------------------------------------------------------------------------------- /app/mixins/pretty-bytes.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | const { 4 | Mixin 5 | } = Ember; 6 | 7 | export default Mixin.create({ 8 | prettyBytes : function (num) { 9 | if (typeof num !== 'number') { 10 | throw new TypeError('Expected a number, got ' + typeof num); 11 | } 12 | 13 | var exponent; 14 | var unit; 15 | var neg = num < 0; 16 | var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 17 | 18 | if (neg) { 19 | num = -num; 20 | } 21 | 22 | if (num < 1) { 23 | return (neg ? '-' : '') + num + ' B'; 24 | } 25 | 26 | exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1); 27 | num = Number((num / Math.pow(1000, exponent)).toFixed(2)); 28 | unit = units[exponent]; 29 | 30 | return (neg ? '-' : '') + num + ' ' + unit; 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /app/templates/people/find.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{input type="text" value=name class="search-query form-control" placeholder="Search" }} 4 | 5 | 8 | 9 |
10 |
11 | 12 |
13 | {{#each filteredUsers as |user|}} 14 |
15 | 16 |

17 | {{user.name}} 18 |

19 |
20 | {{/each}} 21 |
22 | -------------------------------------------------------------------------------- /app/controllers/users.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | const { 3 | Controller, 4 | computed, 5 | inject 6 | } = Ember; 7 | 8 | const { alias } = computed; 9 | 10 | export default Controller.extend({ 11 | application: inject.controller(), 12 | currentUser: alias('application.currentUser'), 13 | users: alias('application.model'), 14 | 15 | onlineUsers: computed('model.@each.online', function(){ 16 | let onlineUsers = this.get('model').filter( (user) => { 17 | return user.get('online') === 'true'; 18 | }); 19 | return onlineUsers.sortBy('name'); 20 | }), 21 | 22 | offlineUsers: computed('model.@each.online', function(){ 23 | let offlineUsers = this.get('model').filter( (user) => { 24 | return user.get('online') !== 'true'; 25 | }); 26 | return offlineUsers.sortBy('name'); 27 | }) 28 | }); 29 | -------------------------------------------------------------------------------- /tests/integration/components/instance-holder-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('instance-holder', 'Integration | Component | instance holder', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | assert.expect(2); 10 | 11 | // Set any properties with this.set('myProperty', 'value'); 12 | // Handle any actions with this.on('myAction', function(val) { ... }); 13 | 14 | this.render(hbs`{{instance-holder}}`); 15 | 16 | assert.equal(this.$().text().trim(), ''); 17 | 18 | // Template block usage: 19 | this.render(hbs` 20 | {{#instance-holder}} 21 | template block text 22 | {{/instance-holder}} 23 | `); 24 | 25 | assert.equal(this.$().text().trim(), 'template block text'); 26 | }); 27 | -------------------------------------------------------------------------------- /app/styles/pages/about.scss: -------------------------------------------------------------------------------- 1 | /******** About Styles ********/ 2 | #about { 3 | height: 100%; 4 | width: 100%; 5 | 6 | .about-content { 7 | width: 400px; 8 | height: 400px; 9 | position: absolute; 10 | top:0; 11 | bottom: 0; 12 | left: 0; 13 | right: 0; 14 | margin: auto; 15 | text-align: center; 16 | 17 | .logo { 18 | margin: 0px auto; 19 | display: block; 20 | } 21 | 22 | h1 { 23 | margin: 10px 0px; 24 | } 25 | 26 | .highlight { 27 | color: $drop-blue; 28 | font-size: 14px; 29 | } 30 | } 31 | .bottom-right { 32 | position: absolute; 33 | bottom: 50px; 34 | right: 50px; 35 | text-decoration: none; 36 | color: $drop-dark-grey; 37 | 38 | .highlight { 39 | color: $drop-green; 40 | font-size: 20px; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/templates/signin.hbs: -------------------------------------------------------------------------------- 1 | {{#paper-card class="md-whiteframe-z1 signin-wrapper"}} 2 | {{#paper-card-content}} 3 |
4 | {{paper-input label="Email (required)" type="email" value=email icon="email" icon-class="email" required=true customValidation=emailValidation}} 5 | {{paper-input value=password label="Password (required)" type="password" icon="https" icon-class="https" required=true}} 6 |
7 | {{#paper-button raised=true type="submit" class="btn-width"}}Log In{{/paper-button}} 8 |
9 |

OR

10 |
11 | {{#paper-button raised=true action="goToSignUp" class="btn-width" primary=true}}Register Now{{/paper-button}} 12 |
13 |
14 | {{/paper-card-content}} 15 | {{/paper-card}} 16 | -------------------------------------------------------------------------------- /tests/electron.js: -------------------------------------------------------------------------------- 1 | /* jshint undef: false */ 2 | 3 | var BrowserWindow = require('browser-window'); 4 | var app = require('app'); 5 | var mainWindow = null; 6 | 7 | app.on('window-all-closed', function onWindowAllClosed() { 8 | if (process.platform !== 'darwin') { 9 | app.quit(); 10 | } 11 | }); 12 | 13 | app.on('ready', function onReady() { 14 | mainWindow = new BrowserWindow({ 15 | width: 800, 16 | height: 600 17 | }); 18 | 19 | delete mainWindow.module; 20 | 21 | if (process.env.EMBER_ENV === 'test') { 22 | mainWindow.loadUrl('file://' + __dirname + '/index.html'); 23 | } else { 24 | mainWindow.loadUrl('file://' + __dirname + '/dist/index.html'); 25 | } 26 | 27 | mainWindow.on('closed', function onClosed() { 28 | mainWindow = null; 29 | }); 30 | }); 31 | 32 | /* jshint undef: true */ 33 | -------------------------------------------------------------------------------- /app/controllers/signin.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import LoginUser from '../mixins/signin-user'; 3 | const { 4 | Controller, 5 | inject 6 | } = Ember; 7 | 8 | export default Controller.extend( 9 | LoginUser, { 10 | spinner: inject.service("spinner"), 11 | emailValidation: { 12 | 'errorMessage': 'Please provide email in a valid format', 13 | 'isError': (inputValue) => { 14 | var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; 15 | return !emailPattern.test(inputValue); 16 | } 17 | }, 18 | actions: { 19 | signin(e) { 20 | e.preventDefault(); 21 | this.get('spinner').show('app-spinner'); 22 | this.authenticateUser(this.get('email'), this.get('password')); 23 | }, 24 | goToSignUp() { 25 | this.transitionToRoute("signup"); 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /app/services/blob.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Service.extend({ 4 | b64toBlob: function (b64Data, contentType, sliceSize) { 5 | contentType = contentType || ''; 6 | sliceSize = sliceSize || 512; 7 | 8 | var byteCharacters = atob(b64Data); 9 | var byteArrays = []; 10 | 11 | for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) { 12 | var slice = byteCharacters.slice(offset, offset + sliceSize); 13 | 14 | var byteNumbers = new Array(slice.length); 15 | for (var i = 0; i < slice.length; i++) { 16 | byteNumbers[i] = slice.charCodeAt(i); 17 | } 18 | 19 | var byteArray = new Uint8Array(byteNumbers); 20 | 21 | byteArrays.push(byteArray); 22 | } 23 | 24 | var blob = new Blob(byteArrays, {type: contentType}); 25 | return blob; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /app/templates/components/thumbnail-slider.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#each files as |file|}} 3 |
4 |
5 | {{paper-icon "clear" size="sm" class="delete-icon-btn"}} 6 |
7 | {{#if file.isDownloading}} 8 |
9 |
10 |
11 | {{liquid-bind file.progress}} 12 |
13 |
14 |
15 | {{/if}} 16 |
17 | 18 |

{{file.name}}

19 |
20 |
21 | {{/each}} 22 |
23 | -------------------------------------------------------------------------------- /app/templates/home/dropzone.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{thumbnail-slider class="thumbnail-slider-wrapper" thumbnailContext=thumbnailContext fileChange=(action "changeSelectedFile") resetSelected=(action "resetSelected")}} 3 |
4 |
5 |

6 | DROP FILES HERE 7 |

8 | 9 |
10 |
11 | {{file-select-drop class="dropzone-widget" onFileSelect=(action "sendFile") triggerFileSelect=(action "triggerFileSelect")}} 12 | {{action-bar class="action-bar-wrapper" actionContext=actionContext}} 13 |
14 | {{#reveal-modal rightBtnText="Download" leftBtnText="Cancel" title="Notification" self=modalContext}} 15 |

{{senderName}} has shared you a file.

16 | {{/reveal-modal}} 17 | -------------------------------------------------------------------------------- /app/mixins/signin-user.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | const { 3 | Mixin, 4 | inject 5 | } = Ember; 6 | 7 | export default Mixin.create({ 8 | notify: inject.service('notify'), 9 | spinner: inject.service('spinner'), 10 | home: inject.controller('home'), 11 | authenticateUser(email, password, callback) { 12 | let self = this; 13 | this.get('session').authenticate('authenticator:firebase', { 14 | 'email': email, 15 | 'password': password 16 | }).then( () => { 17 | if (typeof callback === "function") { 18 | callback(function (guid) { 19 | self.get('spinner').hide('app-spinner'); 20 | self.transitionToRoute('home'); 21 | self.get('home').setVerification(guid); 22 | }); 23 | } else { 24 | self.get('spinner').hide('app-spinner'); 25 | self.transitionToRoute('home'); 26 | } 27 | 28 | }, (error) => { 29 | self.get('spinner').hide('app-spinner'); 30 | self.get('notify').alert(error.toString()); 31 | }); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /electron.js: -------------------------------------------------------------------------------- 1 | var BrowserWindow = require('browser-window'); 2 | var app = require('app'); 3 | var mainWindow = null; 4 | 5 | app.on('window-all-closed', function onWindowAllClosed() { 6 | if (process.platform !== 'darwin') { 7 | app.quit(); 8 | } 9 | }); 10 | 11 | app.on('ready', function onReady() { 12 | mainWindow = new BrowserWindow({ 13 | width: 800, 14 | height: 600 15 | }); 16 | 17 | delete mainWindow.module; 18 | 19 | // If you want to open up dev tools programmatically, call 20 | // mainWindow.openDevTools(); 21 | 22 | // By default, we'll open the Ember App by directly going to the 23 | // file system. 24 | // 25 | // Please ensure that you have set the locationType option in the 26 | // config/environment.js file to 'hash'. For more information, 27 | // please consult the ember-electron readme. 28 | mainWindow.loadURL('file://' + __dirname + '/dist/index.html'); 29 | 30 | mainWindow.on('closed', function onClosed() { 31 | mainWindow = null; 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "define", 10 | "console", 11 | "visit", 12 | "exists", 13 | "fillIn", 14 | "click", 15 | "keyEvent", 16 | "triggerEvent", 17 | "find", 18 | "findWithAssert", 19 | "wait", 20 | "DS", 21 | "andThen", 22 | "currentURL", 23 | "currentPath", 24 | "currentRouteName" 25 | ], 26 | "node": false, 27 | "browser": false, 28 | "boss": true, 29 | "curly": true, 30 | "debug": false, 31 | "devel": false, 32 | "eqeqeq": true, 33 | "evil": true, 34 | "forin": false, 35 | "immed": false, 36 | "laxbreak": false, 37 | "newcap": true, 38 | "noarg": true, 39 | "noempty": false, 40 | "nonew": false, 41 | "nomen": false, 42 | "onevar": false, 43 | "plusplus": false, 44 | "regexp": false, 45 | "undef": true, 46 | "sub": true, 47 | "strict": false, 48 | "white": false, 49 | "eqnull": true, 50 | "esnext": true, 51 | "unused": true 52 | } 53 | -------------------------------------------------------------------------------- /app/services/webtorrent.js: -------------------------------------------------------------------------------- 1 | /**** WebTorrent Service Layer ******/ 2 | 3 | import Ember from "ember"; 4 | 5 | const { 6 | Service, 7 | RSVP 8 | } = Ember; 9 | 10 | export default Service.extend({ 11 | torrentClient : function () { 12 | if (!this.get("client")) { 13 | this.set("client", new WebTorrent()); 14 | } 15 | return this.get("client"); 16 | }, 17 | download : function (data, callback) { 18 | let client = this.torrentClient(); 19 | 20 | return new RSVP.Promise(function (resolve, reject) { 21 | client.add(data.magnetURI, function (torrent) { 22 | // Got torrent metadata! 23 | console.log('Client is downloading:', torrent.infoHash) 24 | callback(torrent, data.name); 25 | resolve(torrent.files); 26 | }); 27 | }); 28 | }, 29 | seed : function (files) { 30 | var client = this.torrentClient(); 31 | 32 | return new RSVP.Promise(function (resolve, reject) { 33 | client.seed(files, function (torrent) { 34 | console.log('Client is seeding:', torrent.infoHash); 35 | resolve(torrent); 36 | }); 37 | }); 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /app/templates/notifications.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#if isPendingApprovals}} 3 | {{#paper-list}} 4 | {{#paper-subheader class="md-no-sticky"}}Pending Approvals{{/paper-subheader}} 5 | 6 | {{#each pendingApprovals as |pendingApproval|}} 7 | {{#paper-item}} 8 | {{paper-icon "thumbs-up-down"}} 9 |

{{pendingApproval.name}}

10 |
11 | {{#paper-button raised=true primary=true }}Approve{{/paper-button}} 12 |
13 |
14 | {{#paper-button raised=true warn=true}}Reject{{/paper-button}} 15 |
16 | {{/paper-item}} 17 | {{/each}} 18 | 19 | {{/paper-list}} 20 | {{else}} 21 | {{#paper-list}} 22 | {{#paper-subheader class="md-no-sticky"}}Pending Approvals{{/paper-subheader}} 23 | {{#paper-item}} 24 |

None

25 | {{/paper-item}} 26 | {{/paper-list}} 27 | {{/if}} 28 | 29 |
30 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | P2PDrop Tests 7 | 8 | 9 | 10 | {{content-for 'head'}} 11 | {{content-for 'test-head'}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for 'head-footer'}} 18 | {{content-for 'test-head-footer'}} 19 | 20 | 21 | 22 | {{content-for 'body'}} 23 | {{content-for 'test-body'}} 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for 'body-footer'}} 31 | {{content-for 'test-body-footer'}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/routes/home.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 3 | import config from '../config/environment'; 4 | 5 | const { 6 | Route, 7 | inject 8 | } = Ember; 9 | 10 | export default Route.extend(AuthenticatedRouteMixin, { 11 | ips : inject.service("ips"), 12 | users : inject.service("users"), 13 | setupController : function (controller, model, queryParams) { 14 | let self = this; 15 | const uid = this.get('session.secure.uid'); 16 | //on complete state change the state of btn 17 | let onComplete = function (error) { 18 | if (error) { 19 | console.log('Synchronization failed'); 20 | } else { 21 | console.log('Synchronized'); 22 | } 23 | }; 24 | //Inject users network ip 25 | this.get("ips").getLocalIps().then(function (data) { 26 | let userRef = new Firebase(config.firebase + '/users/' + uid + "/networks"); 27 | 28 | self.get("users").getCurrentUser(uid).then(function (currentUser) { 29 | userRef.set(data[1], onComplete); 30 | }); 31 | 32 | }); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /app/controllers/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from '../config/environment'; 3 | const { 4 | Controller, 5 | computed, 6 | inject 7 | } = Ember; 8 | 9 | export default Controller.extend({ 10 | ips : inject.service("ips"), 11 | users : inject.service("users"), 12 | init : function () { 13 | if (this.get("currentUser")) { 14 | this.transitionToRoute("home"); 15 | } 16 | }, 17 | 18 | currentUser: computed('session.secure.uid', function(){ 19 | const uid = this.get('session.secure.uid'); 20 | if (uid !== undefined) { 21 | this.setUpPresenceCheck(uid); 22 | return this.store.find('user', uid); 23 | } else { 24 | return null; 25 | } 26 | }), 27 | 28 | setUpPresenceCheck(uid){ 29 | const isConnected = new Firebase(config.firebase + '/.info/connected'); 30 | isConnected.on('value', function(snapshot){ 31 | if (snapshot.val()){ 32 | let userRef = new Firebase(config.firebase + '/users/' + uid + '/online'); 33 | userRef.onDisconnect().set(Firebase.ServerValue.TIMESTAMP); 34 | userRef.set(true); 35 | } 36 | }); 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /app/helpers/extension-mapping.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import _ from 'lodash'; 3 | 4 | export default Ember.Helper.helper(function(params, hash) { 5 | let fileName = params[0]; 6 | let extension = fileName.replace(/^.*\./, ''); 7 | let extensionMap = [{ 8 | key: "photo", 9 | value: ["jpeg", "jpg", "png", "gif"] 10 | }, { 11 | key: "pdf", 12 | value: ["pdf"] 13 | }, { 14 | key: "txt", 15 | value: ["txt"] 16 | }, { 17 | key: "doc", 18 | value: ["doc", "docx"] 19 | }, { 20 | key: "photoshop", 21 | value: ["psd"] 22 | }, { 23 | key: "movie", 24 | value: ["mpeg4", "mpeg", "mp4", "avi"] 25 | }, { 26 | key: "ppt", 27 | value: ["ppt"] 28 | }, { 29 | key: "music", 30 | value: ["mp3", "ogg"] 31 | }, { 32 | key: "compressed", 33 | value: ["zip", "rar", "7z"] 34 | }]; 35 | 36 | let type = _.filter(extensionMap, _.matches({ value: [extension]})); 37 | let typeName; 38 | 39 | if (type.length) {//if exists 40 | typeName = type[0].key; 41 | } else { 42 | typeName = 'unknown'; 43 | } 44 | 45 | return typeName; 46 | }); 47 | -------------------------------------------------------------------------------- /app/templates/header-nav.hbs: -------------------------------------------------------------------------------- 1 |
2 | 25 |
26 | -------------------------------------------------------------------------------- /app/components/profile-pic.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | const { 3 | Component, 4 | inject 5 | } = Ember; 6 | 7 | export default Component.extend({ 8 | imgur: inject.service(), 9 | file: inject.service(), 10 | spinner: inject.service('spinner'), 11 | profilePic : { 12 | link : 'https://i.imgur.com/DAgl4rz.png' 13 | }, 14 | didInsertElement: function () { 15 | $("body").on("click", "#imgSelector", function (evt) { 16 | evt.stopPropagation(); 17 | }); 18 | }, 19 | actions: { 20 | //Trigger File Select 21 | triggerFileSelect(){ 22 | $("#imgSelector").trigger("click"); 23 | }, 24 | //Upload Image 25 | uploadImage(){ 26 | event.stopPropagation(); 27 | let self = this; 28 | this.get('spinner').show('app-spinner'); 29 | this.get("file").read(event).then(function (imageData) { 30 | self.get('imgur').imagePost(imageData[0].result.split(',')[1]).then((result) => { 31 | self.get('spinner').hide('app-spinner'); 32 | self.sendAction("imageUploaded", result.data); 33 | }).catch((result) => { 34 | console.error(result); 35 | }); 36 | }); 37 | } 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /main/load-error/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | P2PDrop failed to load 5 | 17 | 18 | 19 | 20 | 21 |
22 |

😦

23 |

Loading the P2PDrop failed.

24 | No error details. 25 |
26 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* global require, module */ 2 | var EmberApp = require('ember-cli/lib/broccoli/ember-app'); 3 | 4 | module.exports = function(defaults) { 5 | var app = new EmberApp(defaults, { 6 | fingerprint: { 7 | enabled: false 8 | }, 9 | sassLint: { 10 | configPath: '.sass-lint.yml', 11 | shouldThrowExceptions: true, 12 | shouldLog: false 13 | } 14 | }); 15 | 16 | app.import('vendor/simplewebrtc-v2.js'); 17 | app.import('vendor/webtorrent.min.js'); 18 | app.import('bower_components/firebase/firebase.js'); 19 | //app.import('vendor/webrtc/adapter.js'); 20 | 21 | // Use `app.import` to add additional libraries to the generated 22 | // output files. 23 | // 24 | // If you need to use different assets in different 25 | // environments, specify an object as the first parameter. That 26 | // object's keys should be the environment name and the values 27 | // should be the asset to use in that environment. 28 | // 29 | // If the library that you are including contains AMD or ES6 30 | // modules that you would like to import into your application 31 | // please specify an object with the list of modules as keys 32 | // along with the exports of each module as its value. 33 | 34 | return app.toTree(); 35 | }; 36 | -------------------------------------------------------------------------------- /app/templates/home.hbs: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | {{render 'home/dropzone'}} 7 |
8 | {{#if isNotVerified}} 9 | {{#liquid-tether 10 | to="modal-dialog" 11 | target="document.body" 12 | targetModifier="visible" 13 | attachment="middle center" 14 | tetherClass="modal-dialog" 15 | overlayClass="modal-backdrop"}} 16 | {{#paper-card class="md-whiteframe-z1 signin-wrapper"}} 17 | {{#paper-card-content}} 18 |
19 | {{paper-input value=code label="Verification Code (required)" type="text" icon="https" icon-class="https" required=true}} 20 |
21 | {{#paper-button raised=true type="submit" class="btn-width"}}Verify{{/paper-button}} 22 |
23 |

OR

24 |
25 | {{#paper-button raised=true action="resend" class="btn-width" primary=true}}Resend{{/paper-button}} 26 |
27 |
28 | {{/paper-card-content}} 29 | {{/paper-card}} 30 | {{/liquid-tether}} 31 | {{/if}} 32 |
33 | -------------------------------------------------------------------------------- /app/components/reveal-modal.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | const { Component } = Ember; 4 | 5 | export default Component.extend({ 6 | showModalDialog : false, 7 | title : "", 8 | leftBtnText : "", 9 | rightBtnText : "", 10 | callback : function () {}, 11 | self : {}, 12 | setSelf : function () { 13 | let self = this; 14 | let context = this.get("self"); 15 | if (!Ember.isEmpty(context)) { //To ensure the DOM doesnt get rendered 16 | this.set("self", { 17 | open : self.open.bind(self), 18 | close : self.close.bind(self), 19 | toggle : self.toggle.bind(self) 20 | }); 21 | } 22 | }.on("didInsertElement"), 23 | open : function (callback) { 24 | this.set("showModalDialog", true); 25 | if (typeof callback === "function") { 26 | this.set("callback", callback); 27 | } 28 | }, 29 | close : function () { 30 | this.set("showModalDialog", false); 31 | }, 32 | toggle : function () { 33 | let showModalDialog = this.get("showModalDialog"); 34 | this.set("showModalDialog", !showModalDialog); 35 | }, 36 | actions: { 37 | open() { 38 | this.open(); 39 | }, 40 | close() { 41 | this.close(); 42 | }, 43 | callback() { 44 | this.callback(); 45 | this.close(); 46 | } 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /app/templates/profile.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{profile-pic profilePic=profilePic imageUploaded=(action 'setProfilePic')}} 4 |
5 |
6 | {{#paper-list}} 7 | {{#paper-item class="col-xs-12 col-md-12"}} 8 |
9 | {{paper-input label="Name (required)" value=currentUser.name icon="person" icon-class="name" required=true}} 10 |
11 | {{/paper-item}} 12 | {{#paper-item class="col-xs-12 col-md-12"}} 13 |
14 | {{paper-input label="Email (required)" type="email" value=currentUser.email icon="email" icon-class="email" required=true customValidation=emailValidation disabled="disabled"}} 15 |
16 | {{/paper-item}} 17 | {{#paper-item class="col-xs-12 col-md-12"}} 18 |
19 |
20 | {{paper-icon "face"}} 21 |
22 |
23 | {{#paper-switch checked=isMale}} {{currentUser.gender}} {{/paper-switch}} 24 |
25 |
26 | {{/paper-item}} 27 | {{/paper-list}} 28 |
29 |
30 | {{#paper-button raised=true action="update"}}Update{{/paper-button}} 31 |
32 |
33 | -------------------------------------------------------------------------------- /app/styles/pages/profile.scss: -------------------------------------------------------------------------------- 1 | #profile { 2 | width: 80%; 3 | margin: 0px auto; 4 | padding: 10px; 5 | background: #fafafa; 6 | border: 1px solid #ebebeb; 7 | box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px; 8 | 9 | .center { 10 | margin: 0px auto; 11 | text-align: center; 12 | display: table; 13 | } 14 | 15 | .profile-pic { 16 | margin: 10px; 17 | 18 | img { 19 | border: 1px solid $drop-green; 20 | } 21 | 22 | h4 { 23 | background: #ccc; 24 | padding: 3px; 25 | } 26 | 27 | input { 28 | display: none; 29 | } 30 | } 31 | 32 | .form-wrapper { 33 | 34 | .label-text { 35 | margin-left: 12px; 36 | color: rgba(0, 0, 0, 0.26); 37 | font-weight: bold; 38 | } 39 | 40 | md-input-container.md-default-theme > md-icon { 41 | color: rgba(0, 0, 0, 0.54); 42 | } 43 | 44 | .misc { 45 | margin-bottom: 26px; 46 | 47 | .right { 48 | float: left; 49 | margin: 5px 0; 50 | } 51 | 52 | .left { 53 | margin-left: 35px; 54 | border-bottom: 1px solid #ccc; 55 | text-shadow: none; 56 | color: rgba(0, 0, 0, 0.26); 57 | font-weight: bold; 58 | .paper-switch { 59 | margin: 5px !important; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/styles/pages/signup.scss: -------------------------------------------------------------------------------- 1 | #signup { 2 | width: 80%; 3 | margin: 0px auto; 4 | padding: 10px; 5 | background: #fafafa; 6 | border: 1px solid #ebebeb; 7 | box-shadow: rgba(0,0,0,0.14902) 0px 1px 1px 0px,rgba(0,0,0,0.09804) 0px 1px 2px 0px; 8 | 9 | .center { 10 | margin: 0px auto; 11 | text-align: center; 12 | display: table; 13 | } 14 | 15 | .profile-pic { 16 | margin: 10px; 17 | 18 | img { 19 | border: 1px solid $drop-green; 20 | } 21 | 22 | h4 { 23 | background: #ccc; 24 | padding: 3px; 25 | } 26 | 27 | input { 28 | display: none; 29 | } 30 | } 31 | 32 | .form-wrapper { 33 | 34 | .label-text { 35 | margin-left: 12px; 36 | color: rgba(0, 0, 0, 0.26); 37 | font-weight: bold; 38 | } 39 | 40 | md-input-container.md-default-theme > md-icon { 41 | color: rgba(0, 0, 0, 0.54); 42 | } 43 | 44 | .misc { 45 | margin-bottom: 26px; 46 | 47 | .right { 48 | float: left; 49 | margin: 5px 0; 50 | } 51 | 52 | .left { 53 | margin-left: 35px; 54 | border-bottom: 1px solid #ccc; 55 | text-shadow: none; 56 | color: rgba(0, 0, 0, 0.26); 57 | font-weight: bold; 58 | .paper-switch { 59 | margin: 5px !important; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /main/squirrel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * This file is responsible for handling Squirrel events. 4 | * ⚠ Remember: It needs to load ASAP, execute ASAP, exit ASAP! ⚠ 5 | */ 6 | 7 | const path = require('path'); 8 | const spawn = require('child_process').spawn; 9 | const app = require('app'); 10 | 11 | function run(args, done) { 12 | let updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); 13 | 14 | spawn(updateExe, args, { 15 | detached: true 16 | }).on('close', done); 17 | }; 18 | 19 | const check = function() { 20 | if (process.platform === 'win32') { 21 | let cmd = process.argv[1]; 22 | let target = path.basename(process.execPath); 23 | 24 | if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { 25 | run(['--createShortcut=' + target + ''], app.quit); 26 | return true; 27 | } 28 | 29 | if (cmd === '--squirrel-uninstall') { 30 | run(['--removeShortcut=' + target + ''], app.quit); 31 | return true; 32 | } 33 | 34 | if (cmd === '--squirrel-obsolete') { 35 | app.quit(); 36 | return true; 37 | } 38 | 39 | if (cmd === '--squirrel-updated') { 40 | app.quit(); 41 | return true; 42 | } 43 | } 44 | return false; 45 | }; 46 | 47 | module.exports = check; 48 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | P2PDrop - Securely share files between peers 7 | 8 | 9 | 10 | 11 | {{content-for 'head'}} 12 | 13 | 14 | 15 | 16 | {{content-for 'head-footer'}} 17 | 18 | 19 | 31 | {{content-for 'body'}} 32 | 33 | 34 | 35 | 36 | 37 | {{content-for 'body-footer'}} 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/services/file.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import _ from 'lodash/lodash'; 3 | 4 | export default Ember.Service.extend({ 5 | getFiles : function (evt) { 6 | evt.stopPropagation(); 7 | evt.preventDefault(); 8 | 9 | var files = evt.target.files || evt.dataTransfer.files; // FileList object 10 | 11 | // files is a FileList of File objects. List some properties. 12 | var output = []; 13 | for (var i = 0, f; f = files[i]; i++) { 14 | output.push({ 15 | name : escape(f.name), 16 | type : f.type || 'n/a', 17 | size : f.size, 18 | lastModifiedDate : f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a', 19 | file: f 20 | }); 21 | } 22 | return output; 23 | }, 24 | 25 | read : function (evt) { 26 | var reader = new FileReader(); 27 | var files = this.getFiles(evt); 28 | 29 | return new Ember.RSVP.Promise(function (resolve, reject) { 30 | _.each(files, function (item, index) { 31 | // Closure to capture the file information. 32 | reader.onload = (function(file) { 33 | return function(e) { 34 | item.result = e.target.result; 35 | if (index === files.length - 1) { 36 | resolve(files); 37 | } 38 | }; 39 | })(item.file); 40 | 41 | // Read in the image file as a data URL. 42 | reader.readAsDataURL(item.file); 43 | }); 44 | }); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /app/services/users.js: -------------------------------------------------------------------------------- 1 | import Ember from "ember"; 2 | import _object from 'lodash/object'; 3 | import _collection from 'lodash/collection'; 4 | import config from '../config/environment'; 5 | 6 | const { 7 | Service, 8 | inject 9 | } = Ember; 10 | 11 | export default Service.extend({ 12 | users : [], 13 | setUsers : function (users) { 14 | this.set("users", users); 15 | }, 16 | getUsers : function () { 17 | return this.get("users"); 18 | }, 19 | getUser : function (email) { 20 | let users = this.get("users"); 21 | let user = _collection.filter(users, { 22 | email : email 23 | })[0]; 24 | return user; 25 | }, 26 | getCurrentUser : function (uid) { 27 | let userRef = new Firebase(config.firebase + '/users/' + uid); 28 | let self = this; 29 | 30 | return new Promise(function (resolve, reject) { 31 | userRef.once("value", function(snapshot) { 32 | let user = snapshot.val(); 33 | resolve(user); 34 | }); 35 | }); 36 | }, 37 | sendVerificationCode : function (uid, email) { 38 | return new Promise(function (resolve, reject) { 39 | $.ajax({ 40 | method: "POST", 41 | url: config.emailServer, 42 | dataType: "json", 43 | data: { uid : uid, email: email }, 44 | success: function (data) { 45 | resolve(data); 46 | }, 47 | fail: function (error) { 48 | reject(error); 49 | } 50 | }); 51 | }); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /app/components/file-select-drop.js: -------------------------------------------------------------------------------- 1 | import Ember from "ember"; 2 | const { 3 | Component, 4 | inject 5 | } = Ember; 6 | 7 | export default Component.extend({ 8 | file: inject.service(), 9 | didInsertElement: function () { 10 | $("#p2p-files").on("click", function (evt) { 11 | evt.stopPropagation(); 12 | }); 13 | }, 14 | actions : { 15 | //Trigger File Select 16 | triggerFileSelect: function () { 17 | this.sendAction("triggerFileSelect", function () { 18 | $("#p2p-files").trigger("click"); 19 | }); 20 | }, 21 | //Handle File Select Event 22 | onFileSelect : function () { 23 | event.stopPropagation(); 24 | let self = this; 25 | this.get("file").read(event).then(function (data) { 26 | self.sendAction("onFileSelect", data); 27 | }); 28 | }, 29 | //On Drag Over 30 | onDragOver : function () { 31 | event.preventDefault(); 32 | event.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy. 33 | $(".dropzone-content").css({ 34 | border: "2px dashed #04A9EB" 35 | }); 36 | }, 37 | //On Drag Leave 38 | onDragLeave : function () { 39 | $(".dropzone-content").css({ 40 | border: "2px dashed #CCC" 41 | }); 42 | }, 43 | //On Drop Of File 44 | onDrop : function () { 45 | event.preventDefault(); 46 | let self = this; 47 | 48 | $(".dropzone-content").css({ 49 | border: "2px dashed #CCC" 50 | }); 51 | 52 | this.get("file").read(event).then(function (data) { 53 | self.sendAction("onFileSelect", data); 54 | }); 55 | } 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /app/templates/people/detail.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{link-to 'Back' 'people.find' class="back-btn"}} 4 |
5 |
6 |
7 | 8 |

{{user.name}}

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 |
17 |

{{user.name}}

18 |
19 |
20 | 21 |
22 | 23 |
24 |

{{user.gender}}

25 |
26 |
27 | 28 | 34 | 35 |
36 | {{#if isConnected}} 37 |
38 | Connected 39 |
40 | {{else if isPending}} 41 |
42 | Pending Connect Request 43 |
44 | {{else}} 45 |
46 | Send Connect Request 47 |
48 | {{/if}} 49 |
50 |
51 | 52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /app/utils/context-menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handles the contextmenu event for the whole window, checking if 3 | * an input element has been selected - if so, a cut/copy/paste 4 | * menu will be opened 5 | * 6 | * @param e - MouseEvent 7 | */ 8 | function handleContextMenu(e) { 9 | let {remote} = requireNode('electron'); 10 | let {BrowserWindow, Menu} = remote; 11 | let template = [{ 12 | label: 'Undo', 13 | role: 'undo' 14 | }, { 15 | label: 'Redo', 16 | role: 'redo' 17 | }, { 18 | type: 'separator' 19 | }, { 20 | label: 'Cut', 21 | role: 'cut' 22 | }, { 23 | label: 'Copy', 24 | role: 'copy' 25 | }, { 26 | label: 'Paste', 27 | role: 'paste' 28 | }, { 29 | label: 'Paste and Match Style', 30 | click: () => BrowserWindow.getFocusedWindow().webContents.pasteAndMatchStyle() 31 | }, { 32 | label: 'Select All', 33 | role: 'selectall' 34 | }]; 35 | 36 | e.preventDefault(); 37 | e.stopPropagation(); 38 | 39 | let node = e.target; 40 | let editorMenu = Menu.buildFromTemplate(template); 41 | 42 | while (node) { 43 | if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) { 44 | editorMenu.popup(remote.getCurrentWindow()); 45 | break; 46 | } 47 | 48 | node = node.parentNode; 49 | } 50 | 51 | /** 52 | * We cannot, with pure JavaScript, confirm that this event handler works. 53 | * A little hack to ensure that this method becomes testable. 54 | */ 55 | if (window && window.QUnit && editorMenu) { 56 | window.CONTEXTMENU_OPENED = true; 57 | } 58 | } 59 | 60 | /** 61 | * Creates the conextmenu event listener 62 | * 63 | * @export 64 | */ 65 | export function setup() { 66 | window.addEventListener('contextmenu', handleContextMenu); 67 | }; 68 | -------------------------------------------------------------------------------- /app/templates/signup.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{profile-pic profilePic=profilePic imageUploaded=(action 'setProfilePic')}} 4 |
5 |
6 | {{#paper-list}} 7 | {{#paper-item class="col-xs-12 col-md-12"}} 8 |
9 | {{paper-input label="Name (required)" value=name icon="person" icon-class="name" required=true}} 10 |
11 | {{/paper-item}} 12 | {{#paper-item class="col-xs-12 col-md-12"}} 13 |
14 | {{paper-input label="Email (required)" type="email" value=email icon="email" icon-class="email" required=true customValidation=emailValidation}} 15 |
16 | {{/paper-item}} 17 | {{#paper-item class="col-xs-12 col-md-12"}} 18 |
19 |
20 | {{paper-icon "face"}} 21 |
22 |
23 | {{#paper-switch checked=isMale}} {{gender}} {{/paper-switch}} 24 |
25 |
26 | {{/paper-item}} 27 | {{#paper-item class="col-xs-12 col-md-12"}} 28 |
29 | {{paper-input value=password label="Password (required)" type="password" icon="https" icon-class="https" required=true}} 30 |
31 | {{/paper-item}} 32 | {{#paper-item class="col-xs-12 col-md-12"}} 33 |
34 | {{paper-input value=passwordConfirmation label="Retype Password (required)" type="password" icon="https" icon-class="https" required=true}} 35 |
36 | {{/paper-item}} 37 | {{/paper-list}} 38 |
39 |
40 | {{#paper-button raised=true action="signup"}}Sign Up{{/paper-button}} 41 |

OR

42 |
43 | {{#paper-button raised=true action="goToLogin" class="btn-width" primary=true}}Login{{/paper-button}} 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /app/transitions.js: -------------------------------------------------------------------------------- 1 | import { target, onOpenTether } from 'liquid-tether'; 2 | 3 | const options = { 4 | duration: 500, 5 | easing: 'easeInOutQuint' 6 | }; 7 | 8 | export default function () { 9 | let duration = 500; 10 | 11 | this.transition( 12 | this.fromRoute('signin'), 13 | this.toRoute('signup'), 14 | this.use('toLeft', {duration: duration/2}), 15 | this.reverse('toRight', {duration: duration/2}) 16 | ); 17 | 18 | this.transition( 19 | this.fromRoute('home'), 20 | this.toRoute('about'), 21 | this.use('fade', {duration: duration/2}), 22 | this.reverse('fade', {duration: duration/2}) 23 | ); 24 | 25 | this.transition( 26 | this.fromRoute('home'), 27 | this.toRoute('people'), 28 | this.use('fade', {duration: duration/2}), 29 | this.reverse('fade', {duration: duration/2}) 30 | ); 31 | 32 | this.transition( 33 | this.fromRoute('people'), 34 | this.toRoute('about'), 35 | this.use('fade', {duration: duration/2}), 36 | this.reverse('fade', {duration: duration/2}) 37 | ); 38 | 39 | this.transition( 40 | this.fromRoute('people.find'), 41 | this.toRoute('people.detail'), 42 | this.useAndReverse('explode', { 43 | matchBy: 'data-profile-email', 44 | use: ['fly-to', {duration}] 45 | },{ 46 | use: "fade" 47 | }) 48 | ); 49 | 50 | this.transition( 51 | this.hasClass('action-bar'), 52 | this.toValue(true), 53 | this.use('toUp', {duration}), 54 | this.reverse('toDown', {duration}) 55 | ); 56 | 57 | this.transition( 58 | this.hasClass('slide'), 59 | this.toValue(true), 60 | this.use('toLeft', {duration}), 61 | this.reverse('toRight', {duration}) 62 | ); 63 | 64 | this.transition( 65 | this.childOf('#liquid-bind-progress'), 66 | this.use('toUp') 67 | ); 68 | 69 | /**** Liquid Tether Modal Transition ****/ 70 | this.transition( 71 | target('modal-dialog'), 72 | onOpenTether(), 73 | this.use('tether', ['to-up', options]), 74 | this.reverse('tether', ['to-down', options]) 75 | ); 76 | 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /main/window-state.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const electron = require('electron'); 3 | const winStateKeeper = require('electron-window-state'); 4 | 5 | /** 6 | * This file provides basic window state management 7 | */ 8 | 9 | /** 10 | * Builds an returns an object consisting of two objects, with the following keys: 11 | * usableState: an object describing how to layout the app window given screen real estate 12 | * stateKeeper: an object that keeps track of window state change events. 13 | */ 14 | function fetchWindowState() { 15 | const screen = electron.screen; 16 | const defaultWidth = 1000; 17 | const defaultHeight = 800; 18 | 19 | // Instantiate the state keeper with a default state. 20 | const stateKeeper = winStateKeeper({ 21 | defaultWidth: defaultWidth, 22 | defaultHeight: defaultHeight 23 | }); 24 | 25 | // Get the display nearest to the window's saved position, if it exists. 26 | const nearestDisplay = screen.getDisplayNearestPoint({ 27 | x: stateKeeper.x, 28 | y: stateKeeper.y 29 | }); 30 | 31 | // Get the usable screen area. 32 | const displaySize = nearestDisplay.workAreaSize; 33 | 34 | // Build an object consisting of window offset, usable width/height, and 35 | // usable minWidth/minHeight. 36 | // We want to avoid the following situations: 37 | // 1. the *minimum* width/height larger than the usable screen estate 38 | // 2. the window width/height larger than the usable screen real estate. 39 | const usableState = { 40 | x: stateKeeper.x, 41 | y: stateKeeper.y, 42 | width: displaySize.width < stateKeeper.width ? displaySize.width : stateKeeper.width, 43 | height: displaySize.height < stateKeeper.height ? displaySize.height : stateKeeper.height, 44 | minWidth: displaySize.width < defaultWidth ? displaySize.width : defaultWidth, 45 | minHeight: displaySize.height < defaultHeight ? displaySize.height : defaultHeight 46 | }; 47 | 48 | return { 49 | usableState: usableState, 50 | stateKeeper: stateKeeper 51 | }; 52 | }; 53 | 54 | module.exports = fetchWindowState; 55 | -------------------------------------------------------------------------------- /app/controllers/header-nav.js: -------------------------------------------------------------------------------- 1 | import Ember from "ember"; 2 | import config from '../config/environment'; 3 | 4 | const { 5 | Controller, 6 | inject 7 | } = Ember; 8 | 9 | export default Controller.extend({ 10 | session: inject.service('session'), 11 | spinner: inject.service('spinner'), 12 | pendingApprovals: 0, 13 | isPendingApprovals: false, 14 | init : function () { 15 | let self = this; 16 | this.get("session").on('invalidationSucceeded', function() { //TODO: Not Routing On Desktop App 17 | window.location.reload(); 18 | }); 19 | this.getPendingApprovals().then(function (data) { 20 | if (data.length > 0) { 21 | self.set("pendingApprovals", data.length); 22 | self.set("isPendingApprovals", true); 23 | } else { 24 | self.set("pendingApprovals", data.length); 25 | self.set("isPendingApprovals", false); 26 | } 27 | }); 28 | }, 29 | getPendingApprovals : function () { 30 | const uid = this.get('session.secure.uid'); 31 | let userRef = new Firebase(config.firebase + '/users/' + uid); 32 | let self = this; 33 | 34 | return new Promise(function (resolve, reject) { 35 | userRef.on("value", function(snapshot) { 36 | let user = snapshot.val(); 37 | let friends = user.friends || {}; 38 | let pending = friends.pending || []; 39 | if (user.friends && user.friends.pending && user.friends.pending.length) { 40 | self.set("pendingApprovals", pending.length); 41 | self.set("isPendingApprovals", true); 42 | } else { 43 | self.set("isPendingApprovals", false); 44 | } 45 | resolve(pending); 46 | }); 47 | }); 48 | }, 49 | actions: { 50 | logout: function() { 51 | this.get("spinner").show("app-spinner"); 52 | this.get('session').invalidate().then(function() { 53 | this.get("spinner").hide("app-spinner"); 54 | this.transitionToRoute('signin'); 55 | if (config.isDesktop) { //Refresh for desktop application 56 | window.location.reload(false); 57 | } 58 | }.bind(this)); 59 | } 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /app/templates/home/sidebar.hbs: -------------------------------------------------------------------------------- 1 | 55 | -------------------------------------------------------------------------------- /app/controllers/home.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from '../config/environment'; 3 | 4 | const { 5 | Controller, 6 | inject 7 | } = Ember; 8 | 9 | export default Controller.extend({ 10 | users: inject.service('users'), 11 | spinner: inject.service('spinner'), 12 | notify: inject.service('notify'), 13 | isNotVerified : false, 14 | verificationCode : null, 15 | code: null, 16 | init : function () { 17 | this.setVerification(); 18 | }, 19 | setVerification: function (guid) { 20 | const uid = this.get('session.secure.uid'); 21 | let self = this; 22 | this.get("users").getCurrentUser(uid).then(function (currentUser) { 23 | self.set("isNotVerified", !currentUser.isVerified); 24 | self.set("verificationCode", currentUser.verificationCode || guid); 25 | }); 26 | }, 27 | actions: { 28 | verify(e) { 29 | e.preventDefault(); 30 | const uid = this.get('session.secure.uid'); 31 | let self = this; 32 | let isVerifiedRef = new Firebase(config.firebase + '/users/' + uid + '/isVerified'); 33 | let verificationCode = this.get('verificationCode'); 34 | let code = this.get('code'); 35 | 36 | if (verificationCode && (verificationCode === code)) { 37 | isVerifiedRef.set(true, function (error) { 38 | if (error) { 39 | console.log('Synchronization failed'); 40 | } else { 41 | self.set("isNotVerified", false); 42 | console.log('Synchronization succeeded'); 43 | } 44 | }); 45 | } 46 | }, 47 | resend() { 48 | const uid = this.get('session.secure.uid'); 49 | let self = this; 50 | self.get('spinner').show('app-spinner'); 51 | this.get("users").sendVerificationCode(uid).then(function (data) { 52 | if (data.status === "success") { 53 | self.set("verificationCode", data.guid); 54 | self.get('notify').info("Verification mail sent!"); 55 | } else { 56 | self.get('notify').info("Verification mail not sent!"); 57 | } 58 | self.get('spinner').hide('app-spinner'); 59 | }, function () { 60 | self.get('notify').info("Verification mail not sent!"); 61 | self.get('spinner').hide('app-spinner'); 62 | }); 63 | } 64 | } 65 | }); 66 | -------------------------------------------------------------------------------- /main/entry.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const electron = require('electron'); 4 | const fetchWindowState = require('./window-state'); 5 | const app = electron.app; 6 | const BrowserWindow = electron.BrowserWindow; 7 | const emberAppLocation = `file://${__dirname}/../dist/index.html`; 8 | 9 | 10 | // Before we do anything else, handle Squirrel Events 11 | if (require('./squirrel')()) { 12 | return; 13 | } 14 | 15 | let mainWindow = null; 16 | 17 | app.on('ready', function onReady() { 18 | let windowState, usableState, stateKeeper; 19 | 20 | // Greetings 21 | console.log('Welcome to P2PDrop 👻'); 22 | 23 | // Instantiate the window with the existing size and position. 24 | try { 25 | windowState = fetchWindowState(); 26 | usableState = windowState.usableState; 27 | stateKeeper = windowState.stateKeeper; 28 | 29 | mainWindow = new BrowserWindow( 30 | Object.assign(usableState, {show: false}) 31 | ); 32 | } catch (error) { 33 | // Window state keeper failed, let's still open a window 34 | console.log(error); 35 | mainWindow = new BrowserWindow({ 36 | show: false, 37 | height: 600, 38 | width: 800 39 | }); 40 | } 41 | 42 | delete mainWindow.module; 43 | 44 | // Letting the state keeper listen to window resizing and window moving 45 | // event, and save them accordingly. 46 | if (stateKeeper) { 47 | stateKeeper.manage(mainWindow); 48 | } 49 | 50 | // If you want to open up dev tools programmatically, call 51 | // mainWindow.openDevTools(); 52 | mainWindow.loadURL(emberAppLocation); 53 | 54 | // If a loading operation goes wrong, we'll send Electron back to 55 | // Ember App entry point 56 | mainWindow.webContents.on('did-fail-load', () => mainWindow.loadURL(emberAppLocation)); 57 | mainWindow.webContents.on('did-finish-load', () => mainWindow.show()); 58 | 59 | // Chromium drag and drop events tend to navigate the app away, making the 60 | // app impossible to use without restarting. These events should be prevented. 61 | mainWindow.webContents.on('will-navigate', (event) => event.preventDefault()); 62 | 63 | mainWindow.on('closed', () => app.quit()); 64 | }); 65 | -------------------------------------------------------------------------------- /app/controllers/people/find.js: -------------------------------------------------------------------------------- 1 | import Ember from "ember"; 2 | import config from '../../config/environment'; 3 | import _object from 'lodash/object'; 4 | import _collection from 'lodash/collection'; 5 | import _array from 'lodash/array'; 6 | 7 | const { 8 | Controller, 9 | inject 10 | } = Ember; 11 | 12 | export default Controller.extend({ 13 | session: inject.service('session'), 14 | users : inject.service('users'), 15 | filteredUsers : [], 16 | name : "", 17 | //Get Users 18 | fetchUsers : function () { 19 | let self = this; 20 | const uid = this.get('session.secure.uid'); 21 | 22 | this.get("users").getCurrentUser(uid).then(function (user) { 23 | let email = user.email; 24 | new Firebase(config.firebase + "users").orderByChild('name') 25 | .on('value', function(snap){ 26 | let usersList = snap.val(); 27 | let users = _object.transform(usersList, function(memo, val, key) { 28 | if (val.name && val.email !== email) { 29 | memo.push(val); 30 | } 31 | }, []); 32 | self.get("users").setUsers(users); 33 | self.set("filteredUsers", _collection.sample(users, 10)); 34 | }); 35 | }); 36 | }.on("init"), 37 | //Search Query 38 | searchQuery(query) { 39 | let users = this.get("users").getUsers(); 40 | let chars = query.toLowerCase(); 41 | let filteredName = _collection.filter(users, function (user) { 42 | let name = user.name.toLowerCase(); 43 | if (name.search(chars) >= 0) { 44 | user.index = user.name.search(chars); 45 | return true; 46 | } else { 47 | return false; 48 | } 49 | }); 50 | let filteredEmail = _collection.filter(users, function (user) { 51 | let name = user.email.toLowerCase(); 52 | if (name.search(chars) >= 0) { 53 | user.index = user.name.search(chars); 54 | return true; 55 | } else { 56 | return false; 57 | } 58 | }); 59 | let filtered = _array.union(filteredName, filteredEmail); 60 | let ordered = _collection.sortBy(filtered, ['index']); 61 | return ordered; 62 | }, 63 | postKey: function(){ 64 | let users = this.searchQuery(this.get('name')); 65 | this.set("filteredUsers", _array.take(users, 10)); 66 | }.observes('name'), 67 | actions: { 68 | goToDetail(user) { 69 | this.transitionToRoute("people.detail", { queryParams: { email: user.email }}); 70 | } 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap-variables"; 2 | @import "bootstrap"; 3 | @import "ember-paper"; 4 | @import "hover"; 5 | @import "mixins"; 6 | @import "components/reveal-modal.scss"; 7 | @import "pages/home"; 8 | @import "pages/about"; 9 | @import "pages/people"; 10 | @import "pages/signup"; 11 | @import "pages/signin"; 12 | @import "pages/profile"; 13 | @import "pages/notifications"; 14 | 15 | /** Override Styles **/ 16 | 17 | html, body { 18 | background: $drop-grey; 19 | height: 100%; 20 | width: 100%; 21 | position: relative; 22 | } 23 | 24 | h1, h2, h3, h4 { 25 | padding: 0px; 26 | margin: 0px; 27 | } 28 | 29 | .container-fluid { 30 | padding-left: 0px; 31 | padding-right: 0px; 32 | } 33 | 34 | .navbar-brand { 35 | background: rgba(0, 0, 0, 0.2); 36 | padding: 8px 15px; 37 | } 38 | 39 | .navbar-default .navbar-nav > li > a { 40 | color: $drop-white; 41 | } 42 | 43 | .navbar-default .navbar-nav > li > a:hover { 44 | color: $drop-grey; 45 | } 46 | 47 | .navbar-toggle:hover, .navbar-toggle:focus { 48 | background-color: rgba(0, 0, 0, 0.2) !important; 49 | } 50 | /********************/ 51 | 52 | /**** Hero Wrapper *******/ 53 | 54 | .align-left { 55 | text-align: left !important; 56 | } 57 | 58 | .align-right { 59 | text-align: right !important; 60 | } 61 | 62 | .align-center { 63 | text-align: center !important; 64 | } 65 | 66 | .header { 67 | position: absolute; 68 | top: 0px; 69 | left: 0px; 70 | width: 100%; 71 | z-index: 999; 72 | } 73 | 74 | .p2pdrop-liquid-wrapper { 75 | position: absolute; 76 | height: 100%; 77 | width: 100%; 78 | padding-top: 52px; 79 | } 80 | 81 | .hero-wrapper { 82 | background: $drop-grey; 83 | } 84 | 85 | .form-wrapper { 86 | margin: 20px auto; 87 | width: 80%; 88 | } 89 | 90 | .fill-width { 91 | width: 100%; 92 | } 93 | 94 | .header-banner { 95 | margin: 10px auto; 96 | display: table; 97 | color: $drop-dark-grey; 98 | 99 | h4 { 100 | margin-top: 10px; 101 | margin-left: -12px; 102 | } 103 | } 104 | 105 | .alert-box.alert { 106 | background-color: #f04124; 107 | border-color: #de2d0f; 108 | color: #FFF; 109 | } 110 | 111 | .alert-box.info { 112 | background-color: #a0d3e8; 113 | border-color: #74bfdd; 114 | color: #4f4f4f; 115 | } 116 | 117 | 118 | .badge.red { 119 | background: #fa623f; 120 | border-color: #fa5a35; 121 | background-image: -webkit-linear-gradient(top, #fc9f8a, #fa623f); 122 | background-image: -moz-linear-gradient(top, #fc9f8a, #fa623f); 123 | background-image: -o-linear-gradient(top, #fc9f8a, #fa623f); 124 | background-image: linear-gradient(to bottom, #fc9f8a, #fa623f); 125 | position: absolute; 126 | top: 0px; 127 | left: 39px; 128 | } 129 | 130 | /************************/ 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "p2pdrop", 3 | "version": "0.0.1", 4 | "description": "Small description for p2pdrop goes here", 5 | "private": true, 6 | "directories": { 7 | "doc": "doc", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "build": "ember build", 12 | "start": "ember server", 13 | "test": "ember test" 14 | }, 15 | "repository": "", 16 | "engines": { 17 | "node": ">= 0.10.0" 18 | }, 19 | "author": "", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "babel-eslint": "^6.0.4", 23 | "broccoli-asset-rev": "^2.1.2", 24 | "broccoli-manifest": "0.0.7", 25 | "broccoli-serviceworker": "0.1.0", 26 | "ember-cli": "1.13.8", 27 | "ember-cli-app-version": "0.5.0", 28 | "ember-cli-babel": "^5.1.3", 29 | "ember-cli-bootstrap-sassy": "0.5.1", 30 | "ember-cli-content-security-policy": "0.4.0", 31 | "ember-cli-dependency-checker": "^1.0.1", 32 | "ember-cli-eslint": "1.4.0", 33 | "ember-cli-github-pages": "0.0.8", 34 | "ember-cli-google-analytics": "^1.5.0", 35 | "ember-cli-htmlbars": "0.7.9", 36 | "ember-cli-htmlbars-inline-precompile": "^0.2.0", 37 | "ember-cli-ic-ajax": "0.2.1", 38 | "ember-cli-inject-live-reload": "^1.3.1", 39 | "ember-cli-moment-shim": "0.7.1", 40 | "ember-cli-notifications": "2.1.4", 41 | "ember-cli-qunit": "^1.0.0", 42 | "ember-cli-release": "0.2.3", 43 | "ember-cli-sass": "5.3.0", 44 | "ember-cli-sass-lint": "1.0.1", 45 | "ember-cli-simple-auth": "0.8.0", 46 | "ember-cli-simple-auth-firebase": "1.0.5", 47 | "ember-cli-spinner": "0.0.7", 48 | "ember-cli-sri": "^1.0.3", 49 | "ember-cli-uglify": "^1.2.0", 50 | "ember-data": "1.13.8", 51 | "ember-disable-proxy-controllers": "^1.0.0", 52 | "ember-export-application-global": "^1.0.3", 53 | "ember-imgur": "0.1.0", 54 | "ember-lodash": "0.0.6", 55 | "ember-moment": "4.1.0", 56 | "ember-notify": "5.0.2", 57 | "ember-paper": "0.2.11", 58 | "ember-watson": "0.7.0", 59 | "emberfire": "1.6.4", 60 | "eslint": "^2.10.2", 61 | "liquid-fire": "0.22.0", 62 | "liquid-tether": "1.0.0" 63 | }, 64 | "ember-electron": { 65 | "copy-files": [ 66 | "package.json", 67 | "main/*" 68 | ], 69 | "name": "P2PDrop", 70 | "app-bundle-id": "com.chaicode.p2pdrop", 71 | "app-category-type": null, 72 | "app-copyright": "Copyright (c) 2016 Chaicode", 73 | "helper-bundle-id": null, 74 | "icon": "assets/icons/ghost", 75 | "overwrite": true, 76 | "sign": null, 77 | "osx-sign": { 78 | "identity": "Ajain Vivek" 79 | }, 80 | "version-string": { 81 | "CompanyName": "Chaicode", 82 | "FileDescription": "P2PDROP for Desktops", 83 | "ProductName": "P2PDrop", 84 | "InternalName": "Chaicode" 85 | }, 86 | "version": "0.37.7" 87 | }, 88 | "main": "main/entry.js", 89 | "dependencies": { 90 | "electron-prebuilt": "^0.37.7", 91 | "electron-rebuild": "^1.1.3", 92 | "ember-electron": "^1.4.1", 93 | "electron-window-state": "^2.0.0" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/services/ips.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Service.extend({ 4 | getLocalIps : function () { 5 | return new Ember.RSVP.Promise(function (resolve, reject) { 6 | var ip_dups = {}; 7 | 8 | //compatibility for firefox and chrome 9 | var RTCPeerConnection = window.RTCPeerConnection 10 | || window.mozRTCPeerConnection 11 | || window.webkitRTCPeerConnection; 12 | var useWebKit = !!window.webkitRTCPeerConnection; 13 | 14 | //bypass naive webrtc blocking using an iframe 15 | if(!RTCPeerConnection){ 16 | //NOTE: you need to have an iframe in the page right above the script tag 17 | // 18 | // 19 | //