mirror of
https://gitlab.com/timvisee/send.git
synced 2024-11-08 20:22:45 +01:00
Implement section 2.1 and parts of section 4.1 from the Send Android spec (#901)
* Fix #877 Implement Start page (Empty State) Design * Update some kotlin and android sdk things, and update to the latest code in vnext * Begin implementing the card ui which shows after uploading. * Implement a progress bar.
This commit is contained in:
parent
29bafe1bae
commit
071e283f87
@ -1,6 +1,6 @@
|
|||||||
/* global window, document, fetch */
|
/* global window, document, fetch */
|
||||||
|
|
||||||
const MAXFILESIZE = 1024 * 1024 * 1024 * 2;
|
window.MAXFILESIZE = 1024 * 1024 * 1024 * 2;
|
||||||
|
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
@ -32,41 +32,58 @@ function dom(tagName, attributes, children = []) {
|
|||||||
|
|
||||||
function uploadComplete(file) {
|
function uploadComplete(file) {
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
const input = dom('input', { id: 'url', value: file.url });
|
const input = dom('input', { id: 'url', value: file.url, readonly: 'true' });
|
||||||
const copy = dom(
|
const copyText = dom('span', {}, 'Copy link');
|
||||||
'button',
|
const copyImage = dom('img', { id: 'copy-image', src: 'copy-link.png' });
|
||||||
{
|
|
||||||
id: 'copy-button',
|
|
||||||
className: 'button',
|
|
||||||
onclick: () => {
|
|
||||||
input.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
input.blur();
|
|
||||||
copy.textContent = 'Copied!';
|
|
||||||
setTimeout(function() {
|
|
||||||
copy.textContent = 'Copy to clipboard';
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'Copy to clipboard'
|
|
||||||
);
|
|
||||||
const node = dom(
|
const node = dom(
|
||||||
'div',
|
'div',
|
||||||
{ id: 'striped' },
|
{ id: 'white' },
|
||||||
dom('div', { id: 'white' }, [
|
dom('div', { className: 'card' }, [
|
||||||
|
dom('div', {}, 'The card contents will be here.'),
|
||||||
|
dom('div', {}, [
|
||||||
|
'Expires after: ',
|
||||||
|
dom('span', { className: 'expiresAfter' }, 'exp')
|
||||||
|
]),
|
||||||
input,
|
input,
|
||||||
copy,
|
|
||||||
dom(
|
dom(
|
||||||
'button',
|
'div',
|
||||||
{ id: 'send-another', className: 'button', onclick: render },
|
{
|
||||||
'Send another file'
|
id: 'copy-link',
|
||||||
)
|
onclick: e => {
|
||||||
|
e.preventDefault();
|
||||||
|
input.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
input.selectionEnd = input.selectionStart;
|
||||||
|
copyText.textContent = 'Copied!';
|
||||||
|
setTimeout(function() {
|
||||||
|
copyText.textContent = 'Copy link';
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[copyImage, copyText]
|
||||||
|
),
|
||||||
|
dom('img', {
|
||||||
|
id: 'send-another',
|
||||||
|
src: 'cloud-upload.png',
|
||||||
|
onclick: () => {
|
||||||
|
render();
|
||||||
|
document.getElementById('label').click();
|
||||||
|
}
|
||||||
|
})
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
document.body.appendChild(node);
|
document.body.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
translate: (...toTranslate) => {
|
||||||
|
return toTranslate.map(o => JSON.stringify(o)).toString();
|
||||||
|
},
|
||||||
|
raven: {
|
||||||
|
captureException: e => {
|
||||||
|
console.error('ERROR ' + e + ' ' + e.stack);
|
||||||
|
}
|
||||||
|
},
|
||||||
storage: {
|
storage: {
|
||||||
files: [],
|
files: [],
|
||||||
remove: function(fileId) {
|
remove: function(fileId) {
|
||||||
@ -92,21 +109,30 @@ function upload(event) {
|
|||||||
if (file.size === 0) {
|
if (file.size === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (file.size > MAXFILESIZE) {
|
|
||||||
console.log('file too big (no bigger than ' + MAXFILESIZE + ')');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitter.emit('upload', { file: file, type: 'click' });
|
emitter.emit('addFiles', { files: [file] });
|
||||||
|
emitter.emit('upload', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
const striped = dom(
|
const node = dom(
|
||||||
'div',
|
'div',
|
||||||
{ id: 'striped' },
|
{ id: 'white' },
|
||||||
dom('div', { id: 'white' }, [
|
dom('div', { id: 'centering' }, [
|
||||||
dom('label', { id: 'label', htmlFor: 'input' }, 'Choose file'),
|
dom('img', { src: 'encrypted-envelope.png' }),
|
||||||
|
dom('h4', {}, 'Private, Encrypted File Sharing'),
|
||||||
|
dom(
|
||||||
|
'div',
|
||||||
|
{},
|
||||||
|
'Send files through a safe, private, and encrypted link that automatically expires to ensure your stuff does not remain online forever.'
|
||||||
|
),
|
||||||
|
dom('div', { id: 'spacer' }),
|
||||||
|
dom(
|
||||||
|
'label',
|
||||||
|
{ id: 'label', htmlFor: 'input' },
|
||||||
|
dom('img', { src: 'cloud-upload.png' }, [])
|
||||||
|
),
|
||||||
dom('input', {
|
dom('input', {
|
||||||
id: 'input',
|
id: 'input',
|
||||||
type: 'file',
|
type: 'file',
|
||||||
@ -115,19 +141,42 @@ function render() {
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
document.body.appendChild(striped);
|
document.body.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitter.on('render', function() {
|
emitter.on('render', function() {
|
||||||
|
if (!state.transfer || !state.transfer.progress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
const percent =
|
const percent = Math.floor(state.transfer.progressRatio * 100);
|
||||||
(state.transfer.progress[0] / state.transfer.progress[1]) * 100;
|
|
||||||
const node = dom(
|
const node = dom(
|
||||||
'div',
|
'div',
|
||||||
{ style: 'background-color: white; width: 100%' },
|
{ id: 'white', style: 'width: 90%' },
|
||||||
dom('span', {
|
dom('div', { className: 'card' }, [
|
||||||
style: `display: inline-block; width: ${percent}%; background-color: blue`
|
dom('div', {}, `${percent}%`),
|
||||||
})
|
dom(
|
||||||
|
'span',
|
||||||
|
{
|
||||||
|
style: `display: inline-block; height: 4px; border-radius: 2px; width: ${percent}%; background-color: #1b96ef; color: white`
|
||||||
|
},
|
||||||
|
'.'
|
||||||
|
),
|
||||||
|
dom(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
style: 'text-align: right',
|
||||||
|
onclick: e => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (state.uploading) {
|
||||||
|
emitter.emit('cancel');
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'CANCEL'
|
||||||
|
)
|
||||||
|
])
|
||||||
);
|
);
|
||||||
document.body.appendChild(node);
|
document.body.appendChild(node);
|
||||||
});
|
});
|
||||||
@ -150,8 +199,10 @@ window.addEventListener(
|
|||||||
fetch(event.data)
|
fetch(event.data)
|
||||||
.then(res => res.blob())
|
.then(res => res.blob())
|
||||||
.then(blob => {
|
.then(blob => {
|
||||||
emitter.emit('upload', { file: blob, type: 'share' });
|
emitter.emit('addFiles', { files: [blob] });
|
||||||
});
|
emitter.emit('upload', {});
|
||||||
|
})
|
||||||
|
.catch(e => console.error('ERROR ' + e + ' ' + e.stack));
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="pluginClasspaths">
|
<option name="pluginClasspaths">
|
||||||
<array>
|
<array>
|
||||||
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.2.50/a5309d96fd097320a75947d2e9673a86c948f605/kotlin-android-extensions-1.2.50.jar" />
|
<option value="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-android-extensions/1.2.60/69596054ff0e04bb3f38cd906dce6854a9d3438d/kotlin-android-extensions-1.2.60.jar" />
|
||||||
</array>
|
</array>
|
||||||
</option>
|
</option>
|
||||||
</compilerArguments>
|
</compilerArguments>
|
||||||
@ -150,15 +150,12 @@
|
|||||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-27.1.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:support-compat-27.1.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.50@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
|
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel-1.1.0" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: com.squareup:javawriter:2.1.1@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-27.1.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-27.1.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-1.1.2" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.50@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils-27.1.1" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.2.50@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
|
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: com.google.code.findbugs:jsr305:2.0.1@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.github.delight-im:Android-AdvancedWebView-v3.0.0" level="project" />
|
<orderEntry type="library" name="Gradle: com.github.delight-im:Android-AdvancedWebView-v3.0.0" level="project" />
|
||||||
@ -172,10 +169,13 @@
|
|||||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.1" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-27.1.1" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: com.android.support.test.espresso:espresso-idling-resource-3.0.2" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.2@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.2.60@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core-1.1.0" level="project" />
|
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core-1.1.0" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-library:1.3@jar" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-integration:1.3@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
|
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.60@jar" level="project" />
|
||||||
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
|
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.1.0" level="project" />
|
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.1.0" level="project" />
|
||||||
</component>
|
</component>
|
||||||
|
@ -8,7 +8,7 @@ android {
|
|||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.mozilla.send.sendandroid"
|
applicationId "com.mozilla.send.sendandroid"
|
||||||
minSdkVersion 24
|
minSdkVersion 26
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" />
|
||||||
<activity android:name=".MainActivity" android:screenOrientation="portrait">
|
<activity android:name=".MainActivity" android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
BIN
android/app/src/main/assets/cloud-upload.png
Normal file
BIN
android/app/src/main/assets/cloud-upload.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
BIN
android/app/src/main/assets/copy-link.png
Normal file
BIN
android/app/src/main/assets/copy-link.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
android/app/src/main/assets/encrypted-envelope.png
Normal file
BIN
android/app/src/main/assets/encrypted-envelope.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@ -1,20 +1,11 @@
|
|||||||
body {
|
html {
|
||||||
background: url('background_1.jpg');
|
height: 100vh;
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex: auto;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 20px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#striped {
|
body {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(
|
||||||
45deg,
|
45deg,
|
||||||
white,
|
white,
|
||||||
@ -26,32 +17,37 @@ body {
|
|||||||
#0083ff 30px,
|
#0083ff 30px,
|
||||||
#0083ff 50px
|
#0083ff 50px
|
||||||
);
|
);
|
||||||
height: 350px;
|
|
||||||
width: 480px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#white {
|
#white {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: white;
|
||||||
|
margin: 0 10px;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#centering {
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: white;
|
width: 100%;
|
||||||
margin: 0 10px;
|
|
||||||
padding: 1px 10px 0 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#label {
|
#label {
|
||||||
background: #0297f8;
|
position: fixed;
|
||||||
border: 1px solid #0297f8;
|
right: 2em;
|
||||||
color: white;
|
bottom: 1em;
|
||||||
font-size: 24px;
|
}
|
||||||
font-weight: 500;
|
|
||||||
|
#label img {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
width: 200px;
|
width: 60px;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#input {
|
#input {
|
||||||
@ -59,26 +55,38 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#url {
|
#url {
|
||||||
flex: 1;
|
display: none;
|
||||||
width: 100%;
|
|
||||||
height: 32px;
|
|
||||||
font-size: 24px;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
#copy-link {
|
||||||
flex: 1;
|
text-align: right;
|
||||||
display: block;
|
}
|
||||||
background: #0297f8;
|
|
||||||
border: 1px solid #0297f8;
|
#copy-image {
|
||||||
color: white;
|
position: relative;
|
||||||
font-size: 24px;
|
top: 6px;
|
||||||
font-weight: 500;
|
height: 30px;
|
||||||
width: 95%;
|
width: 30px;
|
||||||
height: 32px;
|
}
|
||||||
margin-top: 1em;
|
|
||||||
|
.spacer {
|
||||||
|
height: 12em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#send-another {
|
#send-another {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
height: 60px;
|
||||||
|
width: 60px;
|
||||||
|
position: fixed;
|
||||||
|
right: 2em;
|
||||||
|
bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin: 6px;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid white;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 5px 5px 5px 5px #d5d5d5;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.50'
|
ext.kotlin_version = '1.2.60'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
Loading…
Reference in New Issue
Block a user