mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-27 10:16:16 -04:00
Lots of small improvements, websockets fallback
This commit is contained in:
parent
e5eab64c6b
commit
22be7c5cb9
35 changed files with 2672 additions and 916 deletions
|
@ -1,97 +1,100 @@
|
|||
<link rel="import" href="../../../bower_components/iron-ajax/iron-ajax.html">
|
||||
<link rel="import" href="../../../bower_components/paper-styles/paper-styles.html">
|
||||
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
|
||||
<link rel="import" href="../../bower_components/paper-styles/paper-styles.html">
|
||||
<link rel="import" href="../file-sharing/file-input.html">
|
||||
<link rel="import" href="user-avatar.html">
|
||||
<link rel="import" href="personal-avatar.html">
|
||||
<dom-module id="buddy-finder">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
background-color: white;
|
||||
background-color: transparent;
|
||||
@apply(--layout-fit);
|
||||
@apply(--layout-horizontal);
|
||||
@apply(--layout-center-center);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.paper-font-display1 {
|
||||
color: black;
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
display: none;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.buddies {
|
||||
z-index: 1;
|
||||
@apply(--layout-horizontal);
|
||||
@apply(--layout-center-center);
|
||||
@apply(--layout-wrap);
|
||||
}
|
||||
|
||||
.buddy {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.circles {
|
||||
position: absolute;
|
||||
bottom: -50px;
|
||||
left: 50%;
|
||||
width: 1140px;
|
||||
margin-left: -570px;
|
||||
height: 700px;
|
||||
transform-origin: 570px 570px;
|
||||
animation: grow 1.5s ease-out;
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
.me {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
bottom: 24px;
|
||||
left: 50%;
|
||||
margin-left: -60px;
|
||||
margin-left: -180px;
|
||||
}
|
||||
|
||||
.explanation {
|
||||
@apply(--paper-font-headline);
|
||||
color: #4285f4;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<div class="paper-font-display1">People near by</div>
|
||||
<div class="buddies">
|
||||
<template is="dom-repeat" items="{{buddies}}">
|
||||
<file-input on-file-selected="_fileDropped">
|
||||
<user-avatar contact="{{item.peerId}}" class="buddy"></user-avatar>
|
||||
<file-input on-file-selected="_fileSelected">
|
||||
<user-avatar contact="{{item}}" class="buddy"></user-avatar>
|
||||
</file-input>
|
||||
</template>
|
||||
</div>
|
||||
<user-avatar contact="{{me}}" class="me"></user-avatar>
|
||||
<svg class="circles" viewBox="-0.5 -0.5 1140 700">
|
||||
<circle class="circle" cx="570" cy="570" r="120" stroke="rgba(160,160,160,.15)"></circle>
|
||||
<circle class="circle" cx="570" cy="570" r="210" stroke="rgba(160,160,160,.2)"></circle>
|
||||
<circle class="circle" cx="570" cy="570" r="300" stroke="rgba(160,160,160,.3)"></circle>
|
||||
<circle class="circle" cx="570" cy="570" r="390" stroke="rgba(160,160,160,.35)"></circle>
|
||||
<circle class="circle" cx="570" cy="570" r="480" stroke="rgba(160,160,160,.4)"></circle>
|
||||
<circle class="circle" cx="570" cy="570" r="570" stroke="rgba(160,160,160,.43)"></circle>
|
||||
</svg>
|
||||
<iron-ajax id="ajax" auto url="https://yawim.com/findbuddies/{{me}}" handle-as="json" last-response="{{buddies}}"></iron-ajax>
|
||||
<div hidden$="{{buddies.length}}" class="explanation">
|
||||
Open this page on another device
|
||||
<wbr>to share files.
|
||||
</div>
|
||||
<personal-avatar class="me"></personal-avatar>
|
||||
<!-- <iron-ajax id="ajax" auto url="https://yawim.com/findbuddies/{{me}}" handle-as="json" last-response="{{buddies}}"></iron-ajax> -->
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'buddy-finder',
|
||||
properties: {
|
||||
buddies: Array,
|
||||
buddies: {
|
||||
type: Array,
|
||||
value: []
|
||||
},
|
||||
me: {
|
||||
type: String,
|
||||
}
|
||||
},
|
||||
attached: function() {
|
||||
//Ask server every second for changes
|
||||
setInterval(function() {
|
||||
this.$.ajax.generateRequest();
|
||||
}.bind(this), 1000);
|
||||
var ajax = this.$.ajax;
|
||||
|
||||
function request() {
|
||||
//ajax.generateRequest();
|
||||
}
|
||||
var intervalId = setInterval(request, 1000);
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.hidden) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = 0;
|
||||
} else {
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(request, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
_fileDropped: function(e) {
|
||||
_fileSelected: function(e) {
|
||||
var peerId = e.model.item.peerId;
|
||||
var file = e.detail;
|
||||
app.p2p.connectToPeer(peerId, function() {
|
||||
app.p2p.sendFile(peerId, file);
|
||||
});
|
||||
console.log('Send:', file);
|
||||
console.log('To:', peerId);
|
||||
app.p2p.sendFile(peerId, file);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
41
app/elements/buddy-finder/personal-avatar.html
Normal file
41
app/elements/buddy-finder/personal-avatar.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
|
||||
<link rel="import" href="../../styles/icons.html">
|
||||
<dom-module id="personal-avatar">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
@apply(--layout-vertical);
|
||||
@apply(--layout-center);
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
iron-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
color: #4285f4;
|
||||
}
|
||||
|
||||
.paper-font-body1 {
|
||||
font-size: 13px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.discover {
|
||||
color: #4285f4;
|
||||
}
|
||||
</style>
|
||||
<iron-icon icon="chat:wifi-tethering"></iron-icon>
|
||||
<div class="paper-font-body1">
|
||||
SnapDrop lets you share instantly with people near by.
|
||||
</div>
|
||||
<div class="paper-font-body1 discover">
|
||||
Allow me to be discovered by: Everyone in this network.
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'personal-avatar'
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
|
@ -1,4 +1,4 @@
|
|||
<link rel="import" href="../contact-item/anonymous-contact-behavior.html">
|
||||
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<dom-module id="user-avatar">
|
||||
<template>
|
||||
<style>
|
||||
|
@ -9,35 +9,121 @@
|
|||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
|
||||
paper-icon-button {
|
||||
display: inline-block;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
width: 64px !important;
|
||||
height: 64px !important;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: #ccc;
|
||||
@apply(--shadow-elevation-2dp);
|
||||
padding: 12px;
|
||||
margin-bottom: 4px;
|
||||
background-color: #4285f4;
|
||||
color: white;
|
||||
}
|
||||
.paper-font-subhead{
|
||||
text-align: center;
|
||||
|
||||
:host:hover paper-icon-button {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.paper-font-subhead {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.paper-font-body1 {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
color: grey;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
:host,
|
||||
.paper-font-subhead,
|
||||
.paper-font-body1 {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
margin: 4px;
|
||||
}
|
||||
</style>
|
||||
<div class="avatar" id="avatar" item-icon></div>
|
||||
<paper-icon-button icon="{{_displayIcon}}"></paper-icon-button>
|
||||
<div class="paper-font-subhead">{{_displayName}}</div>
|
||||
<div class="paper-font-body1">{{status}}</div>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'user-avatar',
|
||||
behaviors:[Chat.AnonymousContactBehavior],
|
||||
observers:['_computeBackgroundImg(contact.*)'],
|
||||
_computeBackgroundImg:function(){
|
||||
console.log('avatar changed');
|
||||
var avatar = this.anonymousAccount(this.contact).avatar;
|
||||
var style = this.$.avatar.style;
|
||||
style.backgroundImage='url('+avatar.url+')';
|
||||
style.backgroundPosition=avatar.left+'px '+avatar.top+'px';
|
||||
properties: {
|
||||
contact: Object,
|
||||
_displayName: {
|
||||
computed: '_computeDisplayName(contact)'
|
||||
},
|
||||
_displayIcon: {
|
||||
computed: '_computeDisplayIcon(contact)'
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
_computeDisplayName: function(contact) {
|
||||
contact = contact.name;
|
||||
if (contact.model) {
|
||||
return contact.os + ' ' + contact.model;
|
||||
}
|
||||
contact.os = contact.os.replace('Mac OS', 'Mac');
|
||||
return contact.os + ' ' + contact.browser;
|
||||
},
|
||||
_computeDisplayIcon: function(contact) {
|
||||
contact = contact.name;
|
||||
if (contact.type === 'mobile') {
|
||||
return 'chat:phone-iphone';
|
||||
}
|
||||
if (contact.type === 'tablet') {
|
||||
return 'chat:tablet-mac';
|
||||
}
|
||||
|
||||
return 'chat:desktop-mac';
|
||||
},
|
||||
attached: function() {
|
||||
this.async(function() {
|
||||
app.p2p.addEventListener('file-offered', function(e) {
|
||||
if (e.detail.to === this.contact.peerId) {
|
||||
this.status = 'Waiting to accept...';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('upload-started', function(e) {
|
||||
if (e.detail.to === this.contact.peerId) {
|
||||
this.status = 'Uploading...';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('download-started', function(e) {
|
||||
if (e.detail.from === this.contact.peerId) {
|
||||
this.status = 'Downloading...';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('upload-complete', function(e) {
|
||||
if (e.detail.from === this.contact.peerId) {
|
||||
this.status = '';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('download-complete', function(e) {
|
||||
if (e.detail.from === this.contact.peerId) {
|
||||
this.status = '';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('file-declined', function(e) {
|
||||
if (e.detail.from === this.contact.peerId) {
|
||||
this.status = '';
|
||||
}
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('upload-error', function(e) {
|
||||
this.status = '';
|
||||
}.bind(this), false);
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,337 +0,0 @@
|
|||
<script>
|
||||
'use strict';
|
||||
window.Chat = window.Chat || {};
|
||||
var djb2Code = function(str) {
|
||||
var hash = 5381;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var character = str.charCodeAt(i);
|
||||
hash = ((hash << 5) + hash) + character; /* hash * 33 + c */
|
||||
}
|
||||
return hash > 0 ? hash : -hash;
|
||||
};
|
||||
var animals = [
|
||||
'Adelie',
|
||||
'Penguin',
|
||||
'Akita',
|
||||
'Bulldog',
|
||||
'Ant',
|
||||
'Fox',
|
||||
'Hare',
|
||||
'Wolf',
|
||||
'Terrier',
|
||||
'Avocet',
|
||||
'Baboon',
|
||||
'Camel',
|
||||
'Badger',
|
||||
'Barb',
|
||||
'Basenji',
|
||||
'Basking',
|
||||
'Bat',
|
||||
'Beagle',
|
||||
'Bear',
|
||||
'Collie',
|
||||
'Beaver',
|
||||
'Beetle',
|
||||
'Bichon',
|
||||
'Bird',
|
||||
'Birman',
|
||||
'Bison',
|
||||
'Bobcat',
|
||||
'Bombay',
|
||||
'Bongo',
|
||||
'Bonobo',
|
||||
'Booby',
|
||||
'Boykin',
|
||||
'Budgie',
|
||||
'Buffalo',
|
||||
'Burmese',
|
||||
'Fish',
|
||||
'Caiman',
|
||||
'Lizard',
|
||||
'Canaan',
|
||||
'Caracal',
|
||||
'Cat',
|
||||
'Catfish',
|
||||
'Cesky',
|
||||
'Fousek',
|
||||
'Chamois',
|
||||
'Cheetah',
|
||||
'Chicken',
|
||||
'Chinook',
|
||||
'Cichlid',
|
||||
'Leopard',
|
||||
'Clumber',
|
||||
'Coati',
|
||||
'Coral',
|
||||
'Tamarin',
|
||||
'Cougar',
|
||||
'Cow',
|
||||
'Coyote',
|
||||
'Crab',
|
||||
'Macaque',
|
||||
'Crane',
|
||||
'Cuscus',
|
||||
'Frog',
|
||||
'Deer',
|
||||
'Bracke',
|
||||
'Dhole',
|
||||
'Dingo',
|
||||
'Discus',
|
||||
'Dodo',
|
||||
'Dog',
|
||||
'Dogo',
|
||||
'Dolphin',
|
||||
'Donkey',
|
||||
'Drever',
|
||||
'Duck',
|
||||
'Dugong',
|
||||
'Dunker',
|
||||
'Dusky',
|
||||
'Eagle',
|
||||
'Earwig ',
|
||||
'Gorilla',
|
||||
'Echidna',
|
||||
'Emu',
|
||||
'Falcon',
|
||||
'Fennec',
|
||||
'Ferret',
|
||||
'Spitz',
|
||||
'Fly',
|
||||
'Fossa',
|
||||
'Gecko',
|
||||
'Gerbil',
|
||||
'Gharial',
|
||||
'Gibbon',
|
||||
'Giraffe',
|
||||
'Goat',
|
||||
'Oriole',
|
||||
'Goose',
|
||||
'Gopher',
|
||||
'Grouse',
|
||||
'Guppy',
|
||||
'Shark',
|
||||
'Hamster',
|
||||
'Harrier',
|
||||
'Heron',
|
||||
'Horse',
|
||||
'Human',
|
||||
'Hyena',
|
||||
'Ibis',
|
||||
'Iguana',
|
||||
'Impala',
|
||||
'Indri',
|
||||
'Insect',
|
||||
'Setter',
|
||||
'Jackal',
|
||||
'Jaguar',
|
||||
'Kakapo',
|
||||
'Kiwi',
|
||||
'Koala',
|
||||
'Lemming',
|
||||
'Lemur',
|
||||
'Liger',
|
||||
'Lion',
|
||||
'Llama',
|
||||
'Lobster',
|
||||
'Owl',
|
||||
'Lynx',
|
||||
'Mayfly',
|
||||
'Meerkat',
|
||||
'Molly',
|
||||
'Mongrel',
|
||||
'Monkey',
|
||||
'Moorhen',
|
||||
'Moose',
|
||||
'Mouse',
|
||||
'Mule',
|
||||
'Numbat',
|
||||
'Ocelot',
|
||||
'Octopus',
|
||||
'Okapi',
|
||||
'Opossum',
|
||||
'Ostrich',
|
||||
'Otter',
|
||||
'Oyster',
|
||||
'Panther',
|
||||
'Parrot',
|
||||
'Peacock',
|
||||
'Pelican',
|
||||
'Persian',
|
||||
'Pig',
|
||||
'Piranha',
|
||||
'Pointer',
|
||||
'Poodle',
|
||||
'Possum',
|
||||
'Prawn',
|
||||
'Puffin',
|
||||
'Pug',
|
||||
'Puma',
|
||||
'Pygmy',
|
||||
'Quail',
|
||||
'Quetzal',
|
||||
'Quokka',
|
||||
'Quoll',
|
||||
'Rabbit',
|
||||
'Raccoon',
|
||||
'Ragdoll',
|
||||
'Rat',
|
||||
'Robin',
|
||||
'Saola',
|
||||
'Seal',
|
||||
'Serval',
|
||||
'Sheep',
|
||||
'Shrimp',
|
||||
'Siamese',
|
||||
'Skunk',
|
||||
'Sloth',
|
||||
'Snail',
|
||||
'Snake',
|
||||
'Somali',
|
||||
'Sparrow',
|
||||
'Dogfish',
|
||||
'Sponge',
|
||||
'Squid',
|
||||
'Stoat',
|
||||
'Swan',
|
||||
'Tang',
|
||||
'Tapir',
|
||||
'Tarsier',
|
||||
'Termite',
|
||||
'Tetra',
|
||||
'Tiffany',
|
||||
'Tiger',
|
||||
'Toucan',
|
||||
'Tuatara',
|
||||
'Turkey',
|
||||
'Uakari',
|
||||
'Uguisu',
|
||||
'Vulture',
|
||||
'Wallaby',
|
||||
'Walrus',
|
||||
'Warthog',
|
||||
'Wasp',
|
||||
'Weasel',
|
||||
'Whippet',
|
||||
'Wombat',
|
||||
'Wrasse',
|
||||
'Yak',
|
||||
'Yorkie',
|
||||
'Zebra',
|
||||
'Zebu',
|
||||
'Zonkey',
|
||||
'Zorse'
|
||||
];
|
||||
var bb = [
|
||||
'Walter White',
|
||||
'Skyler White',
|
||||
'Jesse Pinkman',
|
||||
'Hank Schrader',
|
||||
'Marie Schrader',
|
||||
'Walter White, Jr.',
|
||||
'Saul Goodman',
|
||||
'Gustavo Fring',
|
||||
'Mike Ehrmantraut',
|
||||
'Lydia Rodarte-Quayle',
|
||||
'Todd Alquist',
|
||||
'Steven Gomez',
|
||||
'Detectives Kalanchoe & Munn',
|
||||
'George Merkert',
|
||||
'Sac Ramey',
|
||||
'Tim Roberts',
|
||||
'Maximino Arciniega',
|
||||
'Gale Boetticher',
|
||||
'Duane Chow',
|
||||
'Ron Forenall',
|
||||
'Barry Goodman',
|
||||
'Tyrus Kitt',
|
||||
'Chris Mara',
|
||||
'Dennis Markowski',
|
||||
'Victor',
|
||||
'Dan Wachsberger',
|
||||
'Don Eladio Vuente',
|
||||
'Juan Bolsa',
|
||||
'Hector Salamanca',
|
||||
'Tuco Salamanca',
|
||||
'Leonel Salamanca',
|
||||
'Marco Salamanca',
|
||||
'Gonzo',
|
||||
'Emilio Koyama',
|
||||
'Krazy-8 Molina',
|
||||
'Jack Welker',
|
||||
'Andrea Cantillo',
|
||||
'Brock Cantillo',
|
||||
'Jane Margolis',
|
||||
'Brandon Mayhew',
|
||||
'Combo Ortega',
|
||||
'Skinny Pete',
|
||||
'Adam Pinkman',
|
||||
'Mrs. Pinkman',
|
||||
'Jake Pinkman',
|
||||
'Wendy',
|
||||
'Huell Babineaux',
|
||||
'Ed',
|
||||
'Francesca',
|
||||
'Patrick Kuby',
|
||||
'Hugo Archuleta',
|
||||
'Ted Beneke',
|
||||
'Clovis',
|
||||
'Louis Corbett',
|
||||
'Dr. Delcavoli',
|
||||
'Lawson',
|
||||
'Donald Margolis',
|
||||
'Carmen Molina',
|
||||
'Old Joe',
|
||||
'Pamela',
|
||||
'Gretchen Schwartz',
|
||||
'Elliott Schwartz',
|
||||
'Drew Sharp',
|
||||
'Spooge',
|
||||
'Holly White',
|
||||
'Bogdan Wolynetz'
|
||||
];
|
||||
Chat.AnonymousContactBehavior = {
|
||||
properties: {
|
||||
contact: {
|
||||
type: Object,
|
||||
notify: true
|
||||
},
|
||||
_displayName: {
|
||||
computed: '_computeDisplayName(contact)'
|
||||
}
|
||||
},
|
||||
_computeDisplayName: function(contact) {
|
||||
if (contact === undefined || contact === null) {
|
||||
return 'connecting...';
|
||||
}
|
||||
if (contact === 'error' || contact === 'invite') {
|
||||
return '';
|
||||
}
|
||||
if (!contact.name) {
|
||||
return this.anonymousAccount(contact).name;
|
||||
}
|
||||
return contact.name;
|
||||
},
|
||||
get names() {
|
||||
return bb;
|
||||
},
|
||||
anonymousAccount: function(contact) {
|
||||
if (contact && !contact.name) {
|
||||
var peer = contact.peer || contact;
|
||||
var hash = djb2Code(peer);
|
||||
var i = hash % this.names.length;
|
||||
var name = this.names[i];
|
||||
var marginTop = i % 2;
|
||||
var marginLeft = Math.floor(i / 2) % 5;
|
||||
return {
|
||||
name: name,
|
||||
peer: peer,
|
||||
avatar: {
|
||||
url: 'images/avatars.jpg',
|
||||
left: -14 + 80 * marginLeft,
|
||||
top: -19 + 95 * marginTop
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,15 +1,15 @@
|
|||
<link rel="import" href="../bower_components/platinum-sw/platinum-sw-cache.html">
|
||||
<link rel="import" href="../bower_components/platinum-sw/platinum-sw-register.html">
|
||||
<link rel="import" href="../bower_components/paper-toast/paper-toast.html">
|
||||
<link rel="import" href="../bower_components/paper-progress/paper-progress.html">
|
||||
|
||||
|
||||
<!-- Configure your routes here -->
|
||||
<!-- Configure your routes here
|
||||
<link rel="import" href="routing.html">
|
||||
|
||||
-->
|
||||
<!-- Add your elements here -->
|
||||
<link rel="import" href="../styles/app-theme.html">
|
||||
<link rel="import" href="../styles/shared-styles.html">
|
||||
<link rel="import" href="buddy-finder/buddy-finder.html">
|
||||
<link rel="import" href="p2p-network/p2p-network.html">
|
||||
<link rel="import" href="p2p-network/connection-wrapper.html">
|
||||
<link rel="import" href="file-sharing/file-receiver.html">
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ Chat.FileButtonBehaviorImpl = {
|
|||
if (!fileInput) {
|
||||
fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.multiple = 'true';
|
||||
fileInput.className = 'fileInput';
|
||||
fileInput.style.position = 'fixed';
|
||||
fileInput.style.top = '-10000px';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<link rel="import" href="file-button-behavior.html">
|
||||
<dom-module id="file-button">
|
||||
<template>
|
||||
|
|
|
@ -25,7 +25,7 @@ Chat.FileDropBehaviorImpl = {
|
|||
dropZone.addEventListener('drop', function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
|
||||
//call dragend
|
||||
dragEnd();
|
||||
|
||||
|
@ -36,5 +36,13 @@ Chat.FileDropBehaviorImpl = {
|
|||
});
|
||||
}
|
||||
};
|
||||
document.body.addEventListener('dragover', function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
document.body.addEventListener('drop', function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
Chat.FileDropBehavior = [Chat.FileDropBehaviorImpl, Chat.FileSelectionBehavior];
|
||||
</script>
|
||||
|
|
|
@ -2,51 +2,94 @@
|
|||
<link rel="import" href="../../bower_components/paper-button/paper-button.html">
|
||||
<link rel="import" href="../../bower_components/neon-animation/animations/scale-up-animation.html">
|
||||
<link rel="import" href="../../bower_components/neon-animation/animations/fade-out-animation.html">
|
||||
<link rel="import" href="../../bower_components/iron-pages/iron-pages.html">
|
||||
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html">
|
||||
<dom-module id="file-receiver">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#dialog,
|
||||
#download {
|
||||
width: 300px;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
b {
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
||||
<paper-dialog id="dialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdro>
|
||||
<h2>File Received</h2>
|
||||
<p>You received file {{file.name}}</p>
|
||||
<paper-dialog id="dialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop modal>
|
||||
<h2>Download File</h2>
|
||||
<p><b>{{file.name}}</b></p>
|
||||
<div class="buttons">
|
||||
<paper-button dialog-dismiss>Dismiss</paper-button>
|
||||
<paper-button dialog-confirm on-tap="_download">Download</paper-button>
|
||||
<paper-button dialog-dismiss on-tap="_decline">Discard</paper-button>
|
||||
<paper-button dialog-confirm on-tap="_accept" autofocus>Download</paper-button>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
<paper-dialog id="download" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop modal>
|
||||
<h2>File Received</h2>
|
||||
<p>Right Click and "Save as"...</p>
|
||||
<div class="buttons">
|
||||
<paper-button dialog-dismiss>Discard</paper-button>
|
||||
<a href="{{dataUri}}" target="_blank">
|
||||
<paper-button dialog-confirm autofocus>Download</paper-button>
|
||||
</a>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'file-receiver',
|
||||
attached: function() {
|
||||
this.async(function() {
|
||||
app.p2p.addEventListener('file-received', function(e) {
|
||||
this.fileReceived(e.detail);
|
||||
}.bind(this), false);
|
||||
},200);
|
||||
},
|
||||
fileReceived: function(file) {
|
||||
this.set('file', file);
|
||||
this.$.dialog.open();
|
||||
},
|
||||
_download: function() {
|
||||
var link = document.createElement('a');
|
||||
link.download = this.file.name;
|
||||
// Construct the uri
|
||||
var uri = this.file.dataURI;
|
||||
link.href = uri;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// Cleanup the DOM
|
||||
document.body.removeChild(link);
|
||||
//delete link;
|
||||
}
|
||||
});
|
||||
(function() {
|
||||
Polymer({
|
||||
is: 'file-receiver',
|
||||
attached: function() {
|
||||
this.async(function() {
|
||||
app.p2p.addEventListener('file-offer', function(e) {
|
||||
this.file = e.detail;
|
||||
this.$.dialog.open();
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('file-received', function(e) {
|
||||
this._fileReceived(e.detail);
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('file-declined', function(e) {
|
||||
app.displayToast('User declined file ' + e.detail.name);
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('upload-complete', function(e) {
|
||||
app.displayToast('User received file ' + e.detail.name);
|
||||
}.bind(this), false);
|
||||
app.p2p.addEventListener('upload-error', function(e) {
|
||||
app.displayToast('The other device did not respond. Please try again.');
|
||||
}.bind(this), false);
|
||||
}, 200);
|
||||
},
|
||||
_fileReceived: function(file) {
|
||||
this.downloadURI(file);
|
||||
},
|
||||
_decline: function() {
|
||||
app.p2p.decline(this.file);
|
||||
},
|
||||
_accept: function() {
|
||||
app.p2p.accept(this.file);
|
||||
},
|
||||
downloadURI: function(file) {
|
||||
var link = document.createElement('a');
|
||||
var uri = (window.URL || window.webkitURL).createObjectURL(file.blob);
|
||||
if (typeof link.download !== 'undefined') {
|
||||
//download attribute is supported
|
||||
link.href = uri;
|
||||
link.download = file.name || 'blank';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
} else {
|
||||
this.dataUri = uri;
|
||||
this.$.download.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
</dom-module>
|
||||
|
|
4
app/elements/file-sharing/file-saver.html
Normal file
4
app/elements/file-sharing/file-saver.html
Normal file
File diff suppressed because one or more lines are too long
|
@ -3,22 +3,16 @@
|
|||
window.Chat = window.Chat || {};
|
||||
Chat.FileSelectionBehavior = {
|
||||
notifyFilesSelection: function(files) {
|
||||
if(!files){
|
||||
if (!files) {
|
||||
console.log('no files selected...');
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e2) {
|
||||
// finished reading file data.
|
||||
console.log('file dropped');
|
||||
this.fire('file-selected', {
|
||||
dataURI: e2.target.result,
|
||||
name: file.name
|
||||
});
|
||||
}.bind(this);
|
||||
reader.readAsDataURL(file); // start reading the file data.
|
||||
this.fire('file-selected', {
|
||||
file: file,
|
||||
name: file.name
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
1572
app/elements/p2p-network/binaryjs.html
Normal file
1572
app/elements/p2p-network/binaryjs.html
Normal file
File diff suppressed because it is too large
Load diff
59
app/elements/p2p-network/connection-wrapper.html
Normal file
59
app/elements/p2p-network/connection-wrapper.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
<link rel="import" href="p2p-network.html">
|
||||
<link rel="import" href="web-socket.html">
|
||||
<dom-module id="connection-wrapper">
|
||||
<template>
|
||||
<p2p-network id="p2p" me="{{me}}"></p2p-network>
|
||||
<web-socket id="ws" me="{{me}}"></web-socket>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
(function() {
|
||||
function guid() {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
}
|
||||
var webRTCSupported = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.webkitRTCPeerConnection;
|
||||
|
||||
function rtcConnectionSupported(peerId) {
|
||||
return webRTCSupported && (peerId.indexOf('rtc_') === 0);
|
||||
}
|
||||
Polymer({
|
||||
is: 'connection-wrapper',
|
||||
properties: {
|
||||
me: {
|
||||
notify: true,
|
||||
value: (webRTCSupported ? 'rtc_' : 'ws_') + guid()
|
||||
}
|
||||
},
|
||||
behaviors: [Chat.FileTransferProtocol],
|
||||
_sendFile: function(toPeer, file) {
|
||||
if (!rtcConnectionSupported(toPeer)) {
|
||||
this.$.ws._sendFile(toPeer, file);
|
||||
} else {
|
||||
this.$.p2p._sendFile(toPeer, file);
|
||||
}
|
||||
},
|
||||
_sendSystemEvent: function(toPeer, event) {
|
||||
console.log('system event', toPeer, event);
|
||||
if (!rtcConnectionSupported(toPeer)) {
|
||||
this.$.ws._sendSystemEvent(toPeer, event);
|
||||
} else {
|
||||
this.$.p2p._sendSystemEvent(toPeer, event);
|
||||
}
|
||||
},
|
||||
connectToPeer: function(toPeer, callback) {
|
||||
if (!rtcConnectionSupported(toPeer)) {
|
||||
callback();
|
||||
} else {
|
||||
this.$.p2p.connectToPeer(toPeer,callback);
|
||||
}
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
137
app/elements/p2p-network/file-transfer-protocol.html
Normal file
137
app/elements/p2p-network/file-transfer-protocol.html
Normal file
|
@ -0,0 +1,137 @@
|
|||
<script>
|
||||
'use strict';
|
||||
window.Chat = window.Chat || {};
|
||||
Chat.FileTransferProtocol = {
|
||||
properties: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
value: false,
|
||||
observer: '_loadingChanged'
|
||||
},
|
||||
buddies: {
|
||||
notify: true
|
||||
}
|
||||
},
|
||||
listeners: {
|
||||
'system-event': '_onSystemMsg',
|
||||
'file-received': '_onFileReceived',
|
||||
},
|
||||
_onSystemMsg: function(event) {
|
||||
var msg = event.detail;
|
||||
console.log('FTP received sysMsg:', msg);
|
||||
|
||||
switch (msg.type) {
|
||||
case 'offer':
|
||||
this._onOffered(msg);
|
||||
break;
|
||||
case 'decline':
|
||||
this._onDeclined(msg);
|
||||
break;
|
||||
case 'accept':
|
||||
this._onAccepted(msg);
|
||||
break;
|
||||
case 'transfer':
|
||||
this._onTransfer(msg);
|
||||
break;
|
||||
case 'received':
|
||||
this._onReceived(msg);
|
||||
break;
|
||||
case 'buddies':
|
||||
this._onBuddies(msg);
|
||||
break;
|
||||
}
|
||||
},
|
||||
sendFile: function(peerId, file) {
|
||||
this.set('loading', true);
|
||||
this.fileToSend = file;
|
||||
this.fire('file-offered', {
|
||||
to: peerId
|
||||
});
|
||||
this.connectToPeer(peerId, function() {
|
||||
this._offer(peerId, file);
|
||||
}.bind(this));
|
||||
|
||||
//set 15sec timeout
|
||||
this._timeoutTimer = this.async(function() {
|
||||
this._onError();
|
||||
}, 15000);
|
||||
},
|
||||
_offer: function(toPeer, file) {
|
||||
console.log('FTP offer file:', file, 'To:', toPeer);
|
||||
|
||||
this._sendSystemEvent(toPeer, {
|
||||
type: 'offer',
|
||||
name: file.name
|
||||
});
|
||||
},
|
||||
_onOffered: function(offer) {
|
||||
console.log('FTP offered file:', offer.name, 'From:', offer.from);
|
||||
this.fire('file-offer', {
|
||||
from: offer.from,
|
||||
name: offer.name
|
||||
});
|
||||
},
|
||||
decline: function(offer) {
|
||||
this._sendSystemEvent(offer.from, {
|
||||
type: 'decline',
|
||||
name: offer.name
|
||||
});
|
||||
},
|
||||
_onDeclined: function(offer) {
|
||||
this.cancelAsync(this._timeoutTimer);
|
||||
delete this.fileToSend;
|
||||
this.set('loading', false);
|
||||
this.fire('file-declined', offer);
|
||||
},
|
||||
accept: function(offer) {
|
||||
this._sendSystemEvent(offer.from, {
|
||||
type: 'accept',
|
||||
name: offer.name
|
||||
});
|
||||
this.fire('download-started', {
|
||||
from: offer.from
|
||||
});
|
||||
},
|
||||
_onAccepted: function(offer) {
|
||||
this.cancelAsync(this._timeoutTimer);
|
||||
this._sendSystemEvent(offer.from, {
|
||||
type: 'transfer',
|
||||
name: offer.name
|
||||
});
|
||||
this.fire('upload-started', {
|
||||
to: offer.from
|
||||
});
|
||||
this._sendFile(offer.from, this.fileToSend);
|
||||
},
|
||||
_onTransfer: function() {
|
||||
this.loading = true;
|
||||
},
|
||||
_onFileReceived: function(event) {
|
||||
var file = event.detail;
|
||||
this.loading = false;
|
||||
this._sendSystemEvent(file.from, {
|
||||
type: 'received',
|
||||
name: file.name
|
||||
});
|
||||
this.fire('download-complete', {
|
||||
from: file.from
|
||||
});
|
||||
console.log('FTP received:', file);
|
||||
},
|
||||
_onReceived: function(offer) {
|
||||
this.loading = false;
|
||||
this.fire('upload-complete', offer);
|
||||
},
|
||||
_onError: function() {
|
||||
this.loading = false;
|
||||
this.fire('upload-error');
|
||||
},
|
||||
_loadingChanged: function(loading) {
|
||||
window.anim(loading);
|
||||
},
|
||||
_onBuddies: function(msg) {
|
||||
this.set('buddies', msg.buddies);
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,4 +1,5 @@
|
|||
<script src="../../../bower_components/peerjs/peer.min.js"></script>
|
||||
<script src="../../bower_components/peerjs/peer.min.js"></script>
|
||||
<link rel="import" href="file-transfer-protocol.html">
|
||||
<dom-module id="p2p-network">
|
||||
<template>
|
||||
</template>
|
||||
|
@ -30,7 +31,7 @@
|
|||
path: 'peerjs',
|
||||
secure: true
|
||||
};
|
||||
this._peer = new Peer(options);
|
||||
this._peer = new Peer(this.me,options);
|
||||
this._peer.on('open', function(id) {
|
||||
console.log('My peer ID is: ' + id);
|
||||
this.set('me', id);
|
||||
|
@ -65,12 +66,22 @@
|
|||
|
||||
if (c.label === 'file') {
|
||||
c.on('data', function(data) {
|
||||
console.log('received!', data);
|
||||
console.log(data);
|
||||
var dataView = new Uint8Array(data.file);
|
||||
var dataBlob = new Blob([dataView]);
|
||||
this.fire('file-received', {
|
||||
peer: peer,
|
||||
dataURI: data.dataURI,
|
||||
from: peer,
|
||||
blob: dataBlob,
|
||||
name: data.name,
|
||||
});
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
if (c.label === 'system') {
|
||||
c.on('data', function(data) {
|
||||
data.from = peer;
|
||||
this.fire('system-event', data);
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
@ -78,15 +89,32 @@
|
|||
function request(requestedPeer, callback) {
|
||||
return function() {
|
||||
|
||||
//system messages channel
|
||||
var s = this._peer.connect(requestedPeer, {
|
||||
label: 'system'
|
||||
});
|
||||
|
||||
s.on('open', function() {
|
||||
this.connect(s);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}.bind(this));
|
||||
s.on('error', function(err) {
|
||||
console.log(err);
|
||||
if (err.message.indexOf('Connection is not open') > -1) {
|
||||
console.err('Handle this error!!');
|
||||
}
|
||||
});
|
||||
|
||||
//files channel
|
||||
var f = this._peer.connect(requestedPeer, {
|
||||
label: 'file',
|
||||
reliable: true
|
||||
});
|
||||
f.on('open', function() {
|
||||
this.connect(f);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
f.on('error', function(err) {
|
||||
console.log(err);
|
||||
|
@ -98,7 +126,6 @@
|
|||
callback();
|
||||
return;
|
||||
}
|
||||
this.set('loading', true);
|
||||
if (this._peerOpen) {
|
||||
request(requestedPeer, callback).bind(this)();
|
||||
} else {
|
||||
|
@ -107,7 +134,7 @@
|
|||
|
||||
};
|
||||
}()),
|
||||
sendFile: function(peerId, file) {
|
||||
_sendFile: function(peerId, file) {
|
||||
var conns = this._peer.connections[peerId];
|
||||
if (conns) {
|
||||
conns.forEach(function(conn) {
|
||||
|
@ -115,7 +142,17 @@
|
|||
conn.send(file);
|
||||
console.log('file send');
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
_sendSystemEvent: function(peerId, msg) {
|
||||
var conns = this._peer.connections[peerId];
|
||||
if (conns) {
|
||||
conns.forEach(function(conn) {
|
||||
if (conn.label === 'system') {
|
||||
conn.send(msg);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
82
app/elements/p2p-network/web-socket.html
Normal file
82
app/elements/p2p-network/web-socket.html
Normal file
|
@ -0,0 +1,82 @@
|
|||
<link rel="import" href="binaryjs.html">
|
||||
<dom-module id="web-socket">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</template>
|
||||
<script>
|
||||
'use strict';
|
||||
Polymer({
|
||||
is: 'web-socket',
|
||||
attached: function() {
|
||||
this.init();
|
||||
},
|
||||
init: function() {
|
||||
var websocketUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + document.location.hostname + ':9001';
|
||||
this.client = new BinaryClient(websocketUrl);
|
||||
this.client.on('stream', function(stream, meta) {
|
||||
// collect stream data
|
||||
var parts = [];
|
||||
stream.on('data', function(data) {
|
||||
console.log('part received', meta, data);
|
||||
if (data.isSystemEvent) {
|
||||
if (meta) {
|
||||
data.from = meta.from;
|
||||
}
|
||||
this.fire('system-event', data);
|
||||
} else {
|
||||
parts.push(data);
|
||||
}
|
||||
}.bind(this));
|
||||
// when finished, set it as the background image
|
||||
stream.on('end', function() {
|
||||
var blob = new Blob(parts, {
|
||||
type: meta.type
|
||||
});
|
||||
console.log('file received', blob, meta);
|
||||
this.fire('file-received', {
|
||||
blob: blob,
|
||||
name: meta.name,
|
||||
from: meta.from
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
this.client.on('open', function(e) {
|
||||
console.log(e);
|
||||
this.client.send({}, {
|
||||
handshake: this.me
|
||||
});
|
||||
}.bind(this));
|
||||
this.client.on('error', function(e) {
|
||||
console.log(e);
|
||||
});
|
||||
this.client.on('close', function(e) {
|
||||
console.log(e);
|
||||
//try to reconnect after 3s
|
||||
this.async(this.init, 3000);
|
||||
}.bind(this));
|
||||
},
|
||||
_sendFile: function(toPeer, file) {
|
||||
console.log('send file!', file);
|
||||
this.client.send(file.file, {
|
||||
name: file.file.name,
|
||||
type: file.file.type,
|
||||
toPeer: toPeer
|
||||
});
|
||||
},
|
||||
connectToPeer: function(peer, callback) {
|
||||
callback();
|
||||
},
|
||||
_sendSystemEvent: function(toPeer, event) {
|
||||
console.log('system event', toPeer, event);
|
||||
event.isSystemEvent = true;
|
||||
this.client.send(event, {
|
||||
toPeer: toPeer
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
Loading…
Add table
Add a link
Reference in a new issue