first working version

This commit is contained in:
Robin Linus 2015-12-26 13:33:16 +01:00
parent f1ad168e40
commit bda1a15750
24 changed files with 543 additions and 206 deletions

View file

@ -52,12 +52,10 @@
</file-input>
</template>
</div>
<div hidden$="{{buddies.length}}" class="explanation">
Open this page on another device
<wbr>to share files.
<div hidden$="{{buddies.0}}" class="explanation">
Open this page on other devices<br> to send 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';
@ -66,30 +64,11 @@
properties: {
buddies: {
type: Array,
value: []
notify: true
},
me: {
type: String,
}
},
attached: function() {
//Ask server every second for changes
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);
}
}
});
},
},
_fileSelected: function(e) {
var peerId = e.model.item.peerId;

View file

@ -13,11 +13,11 @@
width: 80px;
height: 80px;
color: #4285f4;
margin-bottom: 6px;
}
.paper-font-body1 {
font-size: 13px;
margin-top: 6px;
}
.discover {
@ -26,7 +26,7 @@
</style>
<iron-icon icon="chat:wifi-tethering"></iron-icon>
<div class="paper-font-body1">
SnapDrop lets you share instantly with people near by.
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.

View file

@ -7,7 +7,7 @@
@apply(--layout-vertical);
@apply(--layout-center);
width: 120px;
height: 120px;
height: 152px;
}
paper-icon-button {
@ -45,7 +45,7 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 4px;
margin-top: 4px;
}
</style>
<paper-icon-button icon="{{_displayIcon}}"></paper-icon-button>
@ -85,7 +85,6 @@
if (contact.type === 'tablet') {
return 'chat:tablet-mac';
}
return 'chat:desktop-mac';
},
attached: function() {

View file

@ -2,14 +2,14 @@
<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">
<link rel="import" href="../bower_components/neon-animation/neon-animated-pages.html">
<!-- 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="x-cards/x-card.html">
<link rel="import" href="x-cards/x-cards.html">
<link rel="import" href="buddy-finder/buddy-finder.html">
<link rel="import" href="p2p-network/connection-wrapper.html">
<link rel="import" href="file-sharing/file-receiver.html">

View file

@ -17,13 +17,14 @@
z-index: 101;
}
b {
.filename {
word-break: break-all;
word-break: break-word;
}
</style>
<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>
<p><b class="filename">{{file.name}}</b></p>
<div class="buttons">
<paper-button dialog-dismiss on-tap="_decline">Discard</paper-button>
<paper-button dialog-confirm on-tap="_accept" autofocus>Download</paper-button>
@ -31,11 +32,11 @@
</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>
<p>Open File or 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>
<paper-button dialog-confirm autofocus>Open File</paper-button>
</a>
</div>
</paper-dialog>

File diff suppressed because one or more lines are too long

View file

@ -7,8 +7,11 @@ Chat.FileSelectionBehavior = {
console.log('no files selected...');
return;
}
for (var i = 0; i < files.length; i++) {
var file = files[i];
this._fileSelected(files[0]); //single select
//files.forEach(this._fileSelected.bind(this)); //multi-select
},
_fileSelected: function(file) {
if (file) {
this.fire('file-selected', {
file: file,
name: file.name

View file

@ -8,27 +8,17 @@
<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;
window.webRTCSupported = !!(window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.webkitRTCPeerConnection);
function rtcConnectionSupported(peerId) {
return webRTCSupported && (peerId.indexOf('rtc_') === 0);
return window.webRTCSupported && (peerId.indexOf('rtc_') === 0);
}
Polymer({
is: 'connection-wrapper',
properties: {
me: {
notify: true,
value: (webRTCSupported ? 'rtc_' : 'ws_') + guid()
}
notify: true
},
},
behaviors: [Chat.FileTransferProtocol],
_sendFile: function(toPeer, file) {
@ -50,9 +40,17 @@
if (!rtcConnectionSupported(toPeer)) {
callback();
} else {
this.$.p2p.connectToPeer(toPeer,callback);
this.$.p2p.connectToPeer(toPeer, callback);
}
},
_onHandshake: function(event) {
var me = event.uuid;
console.log('i am');
this.set('me', me);
if (window.webRTCSupported) {
this.$.p2p.initialize();
}
}
});
})();
</script>

View file

@ -22,6 +22,9 @@ Chat.FileTransferProtocol = {
console.log('FTP received sysMsg:', msg);
switch (msg.type) {
case 'handshake':
this._onHandshake(msg);
break;
case 'offer':
this._onOffered(msg);
break;

View file

@ -9,8 +9,7 @@
is: 'p2p-network',
properties: {
me: {
type: String,
notify: true,
type: String
}
},
attached: function() {
@ -22,16 +21,24 @@
this._peer.destroy();
}
}.bind(this);
this._initialize();
},
_initialize: function() {
var options = {
host: 'yawim.com',
port: 443,
path: 'peerjs',
secure: true
};
this._peer = new Peer(this.me,options);
initialize: function() {
var options;
if (window.debug) {
options = {
host: window.location.hostname,
port: 3002,
path: 'peerjs'
};
} else {
options = {
host: 'snapdrop.net',
port: 443,
path: 'peerjs',
secure: true
};
}
this._peer = new Peer(this.me, options);
this._peer.on('open', function(id) {
console.log('My peer ID is: ' + id);
this.set('me', id);
@ -53,12 +60,10 @@
if (err.message.indexOf('Lost connection to server') > -1) {
this._peer.destroy();
this.set('me', this.me);
this._initialize();
this.async(this._initialize, 3000);
return;
}
}.bind(this));
},
connect: function(c) {
@ -140,7 +145,7 @@
conns.forEach(function(conn) {
if (conn.label === 'file') {
conn.send(file);
console.log('file send');
console.log('file send via WebRTC');
}
}.bind(this));
}

View file

@ -15,13 +15,13 @@
this.init();
},
init: function() {
var websocketUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + document.location.hostname + ':9001';
var websocketUrl = (window.debug ? 'ws://' + window.location.hostname + ':3002' : 'wss://snapdrop.net') + '/binary';
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);
//console.log('part received', meta, data);
if (data.isSystemEvent) {
if (meta) {
data.from = meta.from;
@ -45,22 +45,22 @@
}.bind(this));
}.bind(this));
this.client.on('open', function(e) {
this.cancelAsync(this.reconnectTimer);
console.log(e);
this.client.send({}, {
handshake: this.me
serverMsg: 'rtc-support',
rtc: window.webRTCSupported
});
}.bind(this));
this.client.on('error', function(e) {
console.log(e);
});
this._reconnect(e);
}.bind(this));
this.client.on('close', function(e) {
console.log(e);
//try to reconnect after 3s
this.async(this.init, 3000);
this._reconnect(e);
}.bind(this));
},
_sendFile: function(toPeer, file) {
console.log('send file!', file);
console.log('send file via WebSocket', file);
this.client.send(file.file, {
name: file.file.name,
type: file.file.type,
@ -76,6 +76,11 @@
this.client.send(event, {
toPeer: toPeer
});
},
_reconnect: function(e) {
console.log('disconnected', e);
//try to reconnect after 3s
this.reconnectTimer = this.async(this.init, 3000);
}
});
</script>

View file

@ -0,0 +1,138 @@
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../bower_components/neon-animation/neon-shared-element-animatable-behavior.html">
<link rel="import" href="../../bower_components/neon-animation/neon-animations.html">
<link rel="import" href="../../bower_components/paper-styles/paper-styles-classes.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<dom-module id="x-card">
<template>
<style>
:host {
display: block;
overflow: hidden;
color: white;
z-index: 3
}
#placeholder {
opacity: 0;
background-color: #4285f4;
@apply(--layout-fit);
}
paper-icon-button {
position: absolute;
top: 16px;
right: 16px;
z-index: 2;
}
#container {
@apply(--layout-fit);
@apply(--layout-vertical);
@apply(--layout-center-center);
background-color: #4285f4;
padding: 64px 32px 64px 32px;
box-sizing: border-box;
}
iron-icon {
width: 80px;
height: 80px;
}
.paper-font-subhead {
text-align: center;
}
a {
text-decoration: none;
color: white;
@apply(--layout-self-end);
}
.center {
@apply(--layout-vertical);
@apply(--layout-center-center);
}
#footer {
position: absolute;
left: 50%;
margin-left: -160px;
width: 320px;
bottom: 24px;
text-align: center;
}
</style>
<paper-icon-button id="btn" icon="chat:close" on-tap="_switch"></paper-icon-button>
<div id="placeholder"></div>
<div id="container">
<div class="center">
<iron-icon icon="chat:wifi-tethering"></iron-icon>
<div class="paper-font-headline">Snapdrop</div>
<div class="paper-font-subhead">The easiest way to send files across devices.</div>
</div>
<span id="footer">Built with &#9829; by <a href="mailto:robin@capira.de">Robin Linus</a></span>
</div>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'x-card',
behaviors: [
Polymer.NeonSharedElementAnimatableBehavior
],
properties: {
animationConfig: {
value: function() {
return {
'entry': [{
name: 'ripple-animation',
id: 'ripple',
toPage: this
}, {
name: 'fade-out-animation',
node: this.$.placeholder,
timing: {
delay: 250
}
}, {
name: 'fade-in-animation',
node: this.$.container,
timing: {
delay: 50
}
}],
'exit': [{
name: 'opaque-animation',
node: this.$.placeholder
}, {
name: 'fade-out-animation',
node: this.$.container,
timing: {
duration: 0
}
}, {
name: 'reverse-ripple-animation',
id: 'reverse-ripple',
fromPage: this
}]
};
}
},
sharedElements: {
value: function() {
return {
'ripple': this.$.placeholder,
'reverse-ripple': this.$.placeholder
};
}
}
},
_switch: function() {
document.querySelector('#pages').select(0);
}
});
})();
</script>

View file

@ -0,0 +1,83 @@
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../bower_components/neon-animation/neon-shared-element-animatable-behavior.html">
<link rel="import" href="../../bower_components/neon-animation/neon-animations.html">
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<dom-module id="x-cards">
<template>
<style>
:host {
display: block;
overflow: hidden;
}
#placeholder {
opacity: 0;
background-color: grey;
@apply(--layout-fit);
}
paper-icon-button {
position: absolute;
top: 16px;
right: 16px;
z-index: 2;
color: #313131;
}
paper-icon-button:hover {
color: #4285f4;
}
</style>
<div id="placeholder"></div>
<div id="container">
<paper-icon-button id="btn" icon="chat:info-outline" on-tap="_switch"></paper-icon-button>
<content select="div"></content>
</div>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'x-cards',
behaviors: [
Polymer.NeonSharedElementAnimatableBehavior
],
properties: {
animationConfig: {
value: function() {
return {
'entry': [{
name: 'reverse-ripple-animation',
id: 'reverse-ripple',
toPage: this
}],
'exit': [{
name: 'fade-out-animation',
node: this.$.container,
timing: {
delay: 150,
duration: 0
}
}, {
name: 'ripple-animation',
id: 'ripple',
fromPage: this
}]
};
}
},
sharedElements: {
value: function() {
return {
'ripple': this.$.btn,
'reverse-ripple': this.$.btn
};
}
}
},
_switch: function() {
document.querySelector('#pages').select(1);
}
});
})();
</script>

View file

@ -3,10 +3,11 @@
<head>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="description" content="Snapdrop lets you instantly share files with people near by. It is a web-based clone of Apple's Airdrop.">
<meta name="viewport" content="initial-scale=1,user-scalable=no,maximum-scale=1">
<meta name="generator" content="SnapDrop!">
<title>SnapDrop!</title>
<meta name="generator" content="Snapdrop">
<title>Snapdrop</title>
<link rel="shortcut icon" href="favicon.ico?v=2" />
<!-- Place favicon.ico in the `app/` directory -->
<!-- Chrome for Android theme color -->
<meta name="theme-color" content="#3367d6">
@ -18,10 +19,12 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="PSK">
<link rel="icon" sizes="192x192" href="images/touch/chrome-touch-icon-192x192.png">
<link rel="fluid-icon" type="image/png" href="images/touch/chrome-touch-icon-192x192.png">
<meta property="og:image" content="https://snapdrop.net/images/touch/chrome-touch-icon-192x192.png" />
<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="SnapDrop!">
<meta name="apple-mobile-web-app-title" content="Snapdrop">
<link rel="apple-touch-icon" href="images/touch/apple-touch-icon.png">
<!-- Tile icon for Win8 (144x144) -->
<meta name="msapplication-TileImage" content="images/touch/ms-touch-icon-144x144-precomposed.png">
@ -29,25 +32,34 @@
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild-->
<!-- build:js bower_components/webcomponentsjs/webcomponents-lite.min.js -->
<script src="bower_components/webcomponentsjs/webcomponents-lite.js" async></script>
<script src="bower_components/webcomponentsjs/webcomponents-lite.js" async="1"></script>
<!-- endbuild -->
<!-- Because this project uses vulcanize this should be your only html import
in this file. All other imports should go in elements.html -->
<link rel="import" href="elements/elements.html" async>
<meta name="description" content="SnapDrop lets you instantly share files with people near by. It is a web-based clone of Apple's Airdrop.">
</head>
<body class="fullbleed layout vertical" loading>
<script src="scripts/animated-bg.js" inline></script>
<script>
window.debug = true;
</script>
<span id="browser-sync-binding"></span>
<template is="dom-bind" id="app">
<paper-progress indeterminate hidden$="{{!loading}}"></paper-progress>
<buddy-finder me="{{me}}" active$="{{loading}}" buddies="{{buddies}}"></buddy-finder>
<connection-wrapper me="{{me}}" loading="{{loading}}" buddies="{{buddies}}"></connection-wrapper>
<neon-animated-pages id="pages" selected="0">
<x-cards on-switch="_showAbout">
<div>
<paper-progress indeterminate hidden$="{{!loading}}"></paper-progress>
<buddy-finder me="{{me}}" active$="{{loading}}" buddies="{{buddies}}"></buddy-finder>
</div>
</x-cards>
<x-card on-switch="_showApp">
</x-card>
</neon-animated-pages>
<file-receiver></file-receiver>
<paper-toast id="toast" duration="6000">
</paper-toast>
<!-- Uncomment next block to enable Service Worker support (1/2) -->
<paper-toast id="caching-complete" duration="6000" text="Caching complete! This app will work offline.">
</paper-toast>
<platinum-sw-register auto-register clients-claim skip-waiting base-uri="bower_components/platinum-sw/bootstrap" on-service-worker-installed="displayInstalledToast">
@ -58,6 +70,22 @@
<!-- build:js scripts/app.js -->
<script src="scripts/app.js"></script>
<!-- endbuild-->
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-71686975-1', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>

View file

@ -1,6 +1,6 @@
{
"name": "SnapDrop",
"short_name": "SnapDrop",
"name": "Snapdrop",
"short_name": "Snapdrop",
"icons": [{
"src": "images/touch/icon-128x128.png",
"sizes": "128x128",

View file

@ -40,6 +40,10 @@
});
app._showAbout=function(){
document.querySelector('#pages').select(1);
};
app._showAbout=function(){
document.querySelector('#pages').select(0);
};
})(document);

View file

@ -28,4 +28,7 @@ paper-progress {
position: absolute;
top: 0;
}
neon-animated-pages{
height: 100%;
}
</style>

View file

@ -32,6 +32,12 @@
<g id="tablet-mac">
<path d="M18.5 0h-14C3.12 0 2 1.12 2 2.5v19C2 22.88 3.12 24 4.5 24h14c1.38 0 2.5-1.12 2.5-2.5v-19C21 1.12 19.88 0 18.5 0zm-7 23c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm7.5-4H4V3h15v16z" />
</g>
<g id="info-outline">
<path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z" />
</g>
<g id="close">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
</g>
</defs>
</svg>
</iron-iconset-svg>