fix: made ui better for Downloads section, files, search etc

This commit is contained in:
zelfroster 2023-06-17 23:15:54 +05:30
parent ef6c1e241f
commit 69935d431a
13 changed files with 254 additions and 236 deletions

View File

@ -8,11 +8,7 @@ const Downloads = {
hashes: [],
async loadHashes() {
const res = await rs.rsJsonApiRequest(
'/rsFiles/FileDownloads',
{},
(d) => (Downloads.hashes = d.hashs)
);
await rs.rsJsonApiRequest('/rsFiles/FileDownloads', {}, (d) => (Downloads.hashes = d.hashs));
},
async loadStatus() {
@ -137,33 +133,38 @@ const Component = () => {
});
Downloads.resetSearch();
},
view: () =>
m('.widget', [
m('h3', 'Downloads (' + Downloads.hashes.length + ' files)'),
m('hr'),
m(
'button',
{
onclick: () => widget.popupMessage(m(NewFileDialog)),
},
'Add new file'
),
m(
'button',
{
onclick: () => rs.rsJsonApiRequest('/rsFiles/FileClearCompleted'),
},
'Clear completed'
),
Object.keys(Downloads.statusMap).map((hash) =>
m(util.File, {
info: Downloads.statusMap[hash],
direction: 'down',
transferred: Downloads.statusMap[hash].transfered.xint64,
parts: [],
})
),
view: () => [
m('.widget__body-heading', [
m('h3', 'Downloads (' + (Downloads.hashes && Downloads.hashes.length) + ' files)'),
m('.action', [
m(
'button',
{
onclick: () => widget.popupMessage(m(NewFileDialog)),
},
'Add new file'
),
m(
'button',
{
onclick: () => rs.rsJsonApiRequest('/rsFiles/FileClearCompleted'),
},
'Clear completed'
),
]),
]),
m('.widget__body-content', [
Downloads.statusMap &&
Object.keys(Downloads.statusMap).map((hash) =>
m(util.File, {
info: Downloads.statusMap[hash],
direction: 'down',
transferred: Downloads.statusMap[hash].transfered.xint64,
parts: [],
})
),
]),
],
};
};

View File

@ -11,12 +11,13 @@ const friendfile = require('files/friends_files');
const MyFiles = () => {
return {
view: (vnode) => [
m(util.SearchBar, {
list: Object.assign({}, downloads.list, uploads.list),
}),
m(downloads.Component),
m(uploads.Component),
view: () => [
m('.widget__heading', [
m(util.SearchBar, {
list: Object.assign({}, downloads.list, uploads.list),
}),
]),
m('.widget__body', [m(downloads.Component), m(uploads.Component)]),
],
};
};
@ -29,14 +30,13 @@ const sections = {
};
const Layout = {
view: (vnode) =>
m('.tab-page', [
m(widget.Sidebar, {
tabs: Object.keys(sections),
baseRoute: '/files/',
}),
m('.file-node-panel', vnode.children),
]),
view: (vnode) => [
m(widget.Sidebar, {
tabs: Object.keys(sections),
baseRoute: '/files/',
}),
m('.node-panel', m('.widget', vnode.children)),
],
};
module.exports = {

View File

@ -4,13 +4,13 @@ const futil = require('files/files_util');
const widget = require('widgets');
let matchString = '';
const reqObj = {};
let currentItem = 0;
const reqObj = {};
async function handleSubmit() {
await rs
.rsJsonApiRequest('/rsFiles/turtleSearch', { matchString })
function handleSubmit() {
rs.rsJsonApiRequest('/rsFiles/turtleSearch', { matchString })
.then((res) => {
// Add prefix to obj keys so that javascript doesn't sort them
reqObj['_' + res.body.retval] = matchString;
currentItem = '_' + res.body.retval;
})
@ -21,16 +21,16 @@ const SearchBar = () => {
return {
view: () =>
m(
'form',
'form.search-form',
{
onsubmit: handleSubmit,
},
[
m('input[type=text][placeholder=search]', {
m('input[type=text][placeholder=search keyword]', {
value: matchString,
oninput: (e) => (matchString = e.target.value),
}),
m('button[type=submit]', 'Submit'),
m('button[type=submit]', m('i.fas.fa-search')),
]
),
};
@ -39,14 +39,12 @@ const SearchBar = () => {
const Layout = () => {
let active = 0;
return {
view: (vnode) =>
m('.widget', [
m('h3', 'Search'),
m('hr'),
m(SearchBar),
view: () => [
m('.widget__heading', [m('h3', 'Search'), m(SearchBar)]),
m('.widget__body', [
m('div.file-search-container', [
m('div.file-search-container__keywords', [
m('h4', 'Keywords'),
m('h5.bold', 'Keywords'),
m(
'div.keywords-container',
Object.keys(reqObj)
@ -69,7 +67,7 @@ const Layout = () => {
]),
m('div.file-search-container__results', [
Object.keys(futil.proxyObj).length === 0
? m('h4', 'Results')
? m('h5.bold', 'Results')
: m('table.results-container', [
m(
'thead.results-header',
@ -96,32 +94,28 @@ const Layout = () => {
'button',
{
onclick: () => {
try {
rs.rsJsonApiRequest(
'/rsFiles/FileRequest',
{
fileName: item.fName,
hash: item.fHash,
flags: futil.RS_FILE_REQ_ANONYMOUS_ROUTING,
size: {
xstr64: item.fSize.xstr64,
},
},
(status) => {
status.retval
? widget.popupMessage([
m('i.fas.fa-file-medical'),
m('h3', 'File is being downloaded!'),
])
: widget.popupMessage([
m('i.fas.fa-file-medical'),
m('h3', 'File is already downloaded!'),
]);
}
);
} catch (error) {
console.log('error in sending download request: ', error);
}
rs.rsJsonApiRequest('/rsFiles/FileRequest', {
fileName: item.fName,
hash: item.fHash,
flags: futil.RS_FILE_REQ_ANONYMOUS_ROUTING,
size: {
xstr64: item.fSize.xstr64,
},
})
.then((res) => {
res.retval
? widget.popupMessage([
m('i.fas.fa-file-medical'),
m('h3', 'File is being downloaded!'),
])
: widget.popupMessage([
m('i.fas.fa-file-medical'),
m('h3', 'File is already downloaded!'),
]);
})
.catch((error) => {
console.log('error in sending download request: ', error);
});
},
},
'Download'
@ -134,6 +128,7 @@ const Layout = () => {
]),
]),
]),
],
};
};

View File

@ -192,23 +192,14 @@ function actionButton(file, action) {
const ProgressBar = () => {
return {
view: (v) =>
m(
'.progressbar',
{
m('.progressbar', [
m('span.progressbar-status', {
style: {
content: v.attrs.rate + '%',
width: v.attrs.rate + '%',
},
},
m(
'span.progress-status',
{
style: {
width: v.attrs.rate + '%',
},
},
v.attrs.rate.toPrecision(3) + '%'
)
),
}),
m('span.progressbar-percent', v.attrs.rate.toPrecision(3) + '%'),
]),
};
};
@ -233,23 +224,18 @@ const File = () => {
},
},
[
m('p', v.attrs.info.fname),
v.attrs.direction === 'up' || v.attrs.info.downloadStatus === FT_STATE_COMPLETE
? []
: [
actionButton(v.attrs.info, 'cancel'),
actionButton(
v.attrs.info,
v.attrs.info.downloadStatus === FT_STATE_PAUSED ? 'resume' : 'pause'
),
m('.file-view__heading', [
m('h6', v.attrs.info.fname),
!(v.attrs.direction === 'up') && [
m('.file-view__heading-chunk', [
m('label[for=chunkTag]', 'Set Chunk Strategy: '),
m(
'select[id=chunkTag]',
{
value: chunkStrat,
onchange: async (e) => {
onchange: (e) => {
chunkStrat = chunkStrats[e.target.selectedIndex];
const res = await rs.rsJsonApiRequest('/rsFiles/setChunkStrategy', {
rs.rsJsonApiRequest('/rsFiles/setChunkStrategy', {
hash: v.attrs.info.hash,
newStrategy: chunkStrat,
});
@ -257,36 +243,54 @@ const File = () => {
},
[chunkStratsOptions.map((opt) => m('option', { value: opt }, opt))]
),
m('label[for=chunkTag]', 'Set Chunk Strategy: '),
],
v.attrs.direction === 'up'
? []
: m(ProgressBar, {
rate: (v.attrs.transferred / v.attrs.info.size.xint64) * 100,
}),
m('span.filestat', m('i.fas.fa-download'), makeFriendlyUnit(v.attrs.transferred)),
]),
],
]),
m('.file-view__body', [
m(
'.file-view__body-progress',
!(v.attrs.direction === 'up') &&
m(ProgressBar, {
rate: (v.attrs.transferred / v.attrs.info.size.xint64) * 100,
})
),
m('.file-view__body-details', [
m('.file-view__body-details-stat', [
m('span', m('i.fas.fa-download'), makeFriendlyUnit(v.attrs.transferred)),
m('span.filestat', m('i.fas.fa-file'), makeFriendlyUnit(v.attrs.info.size.xint64)),
m(
'span.filestat',
m('i.fas.fa-arrow-circle-' + v.attrs.direction),
makeFriendlyUnit(v.attrs.info.tfRate * 1024) + '/s'
),
v.attrs.direction === 'up'
? []
: m('span.filestat', { title: 'time remaining' }, [
m('i.fas.fa-clock'),
calcRemainingTime(
v.attrs.info.size.xint64 - v.attrs.transferred,
v.attrs.info.tfRate
m('span', m('i.fas.fa-file'), makeFriendlyUnit(v.attrs.info.size.xint64)),
m(
'span',
m('i.fas.fa-arrow-circle-' + v.attrs.direction),
makeFriendlyUnit(v.attrs.info.tfRate * 1024) + '/s'
),
!(v.attrs.direction === 'up') &&
m('span', { title: 'time remaining' }, [
m('i.fas.fa-clock'),
calcRemainingTime(
v.attrs.info.size.xint64 - v.attrs.transferred,
v.attrs.info.tfRate
),
]),
m(
'span',
{ title: 'peers' },
[m('i.fas.fa-users'), v.attrs.info.peers.length],
v.attrs.parts.reduce((a, e) => [...a, ' - ' + makeFriendlyUnit(e)], [])
),
]),
m(
'span.filestat',
{ title: 'peers' },
[m('i.fas.fa-users'), v.attrs.info.peers.length],
v.attrs.parts.reduce((a, e) => [...a, ' - ' + makeFriendlyUnit(e)], [])
),
m(
'.file-view__body-details-action',
!(v.attrs.info.downloadStatus === FT_STATE_COMPLETE) && [
actionButton(
v.attrs.info,
v.attrs.info.downloadStatus === FT_STATE_PAUSED ? 'resume' : 'pause'
),
actionButton(v.attrs.info, 'cancel'),
]
),
]),
]),
]
),
};

View File

@ -145,15 +145,14 @@ const Layout = () => {
// let root_handle;
let parent;
return {
oninit: async () => {
const res = await rs.rsJsonApiRequest('/rsfiles/requestDirDetails', {
oninit: () => {
rs.rsJsonApiRequest('/rsfiles/requestDirDetails', {
flags: util.RS_FILE_HINTS_REMOTE,
});
parent = res;
}).then((res) => (parent = res));
},
view: (v) => [
m('.widget', [
m('h3', 'Friends Files'),
view: () => [
m('.widget__heading', [m('h3', 'Friends Files')]),
m('.widget__body', [
m(
util.FriendsFilesTable,
m(

View File

@ -21,7 +21,8 @@ function displayfiles() {
class: 'fa-rotate-' + (parStruct.showChild ? '90' : '0'),
style: 'margin-top:12px',
onclick: () => {
if (!loaded) { // if it is not already retrieved
if (!loaded) {
// if it is not already retrieved
parStruct.details.children.map(async (child) => {
const res = await rs.rsJsonApiRequest('/rsfiles/requestDirDetails', {
handle: child.handle.xint64,
@ -43,7 +44,6 @@ function displayfiles() {
position: 'relative',
'--replyDepth': v.attrs.replyDepth,
left: `calc(30px*${v.attrs.replyDepth})`,
},
},
parStruct.details.name
@ -52,7 +52,8 @@ function displayfiles() {
]),
parStruct.showChild &&
childrenList.map((child) =>
m(displayfiles, { // recursive call
m(displayfiles, {
// recursive call
par_directory: { details: child, showChild: false },
replyDepth: v.attrs.replyDepth + 1,
})
@ -65,13 +66,12 @@ const Layout = () => {
// let root_handle;
let parent;
return {
oninit: async () => {
const res = await rs.rsJsonApiRequest('/rsfiles/requestDirDetails', {});
parent = res;
oninit: () => {
rs.rsJsonApiRequest('/rsfiles/requestDirDetails', {}).then((res) => (parent = res));
},
view: (v) => [
m('.widget', [
m('h3', 'My Files'),
view: () => [
m('.widget__heading', [m('h3', 'My Files')]),
m('.widget__body', [
m(
util.MyFilesTable,
m(

View File

@ -6,8 +6,8 @@
@mixin button($bg-color) {
color: white;
background: $bg-color;
font-size: 1.2em;
padding: 5px 10px;
font-size: 1rem;
padding: 0.4rem 1rem;
border: 0;
border-radius: 5px;
cursor: pointer;

View File

@ -40,6 +40,7 @@ h2,
h3,
h4,
h5,
h6,
p {
font-weight: normal;
}

View File

@ -35,7 +35,7 @@ textarea {
font-weight: 400;
border: 1px solid #ccc;
border-radius: 5px;
padding: 0.5rem;
padding: 0.4rem 0.8rem;
/* Disable chromium's focused element hinting*/
outline: transparent;
}
@ -49,11 +49,10 @@ input {
}
&.small {
max-width: 70%;
font-size: 1em;
padding: 0.1em;
padding: 0.1rem;
}
&.searchbar {
display: block;
width: 40%;
}
}

View File

@ -1,23 +1,26 @@
@use '../abstracts/colors' as *;
.progressbar {
width: 100%;
border-radius: 500px;
background-color: #eef3f6;
height: 2rem;
position: relative;
text-align: left;
}
.progressbar:before {
position: absolute;
text-align: center;
left: 0;
right: 0;
background-color: $light-color;
border-radius: 20px;
overflow: hidden;
&-status {
position: absolute;
top: 0;
left: 0;
height: 100%;
color: $dark-color;
background-color: $primary-color;
}
&-percent {
position: absolute;
inset: 0;
margin: auto;
width: fit-content;
height: fit-content;
}
}
.progress-status {
display: inline-block;
height: 100%;
padding: 5px;
border-radius: 500px;
color: #000;
background-color: #3ba4d7;
text-align: center;
}

View File

@ -16,7 +16,22 @@
}
&__body {
height: 100%;
display: flex;
flex-direction: column;
overflow: scroll;
&-heading {
display: flex;
justify-content: space-between;
align-items: center;
& .action {
display: flex;
gap: 0.5rem;
}
}
&-content {
height: 100%;
overflow: scroll;
}
}
& > p {
font-size: 0.9em;

View File

@ -1,56 +1,47 @@
@use '../abstracts/colors' as *;
.file-view {
width: 90%;
border-radius: 10px;
width: 100%;
padding: 1rem;
margin-top: 1.5rem;
border-radius: 8px;
border: 1px solid #ccc;
margin-top: 2em;
padding: 1em;
animation: fadein 0.5s;
}
.file-view > p {
margin: 0.5em;
font-size: 1.1em;
}
.file-view > span {
margin: 0 1em;
font-size: 0.9em;
}
.file-view > .progressbar {
width: 70%;
margin-bottom: 5px;
}
.file-view button {
float: right;
margin-left: 15px;
}
.file-view select {
float: right;
margin-left: 15px;
}
.file-view label {
float: right;
margin-left: 15px;
}
span > i {
margin-right: 5px;
}
.filestat {
min-width: 7em;
display: inline-block;
}
.searchbar {
margin: 5px;
width: 40%;
box-shadow: 0 0 3px #aaa;
}
.file-node-panel {
position: relative;
bottom: 200px;
margin-left: 200px;
animation: fadein 0.5s;
&__heading {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
&-chunk {
display: flex;
gap: 1rem;
}
}
&__body {
display: flex;
flex-direction: column;
gap: 0.5rem;
&-details {
display: flex;
align-items: center;
&-stat {
width: 100%;
display: grid;
grid-template-columns: repeat(5, 1fr);
& span > i {
margin-right: 0.5rem;
}
}
&-action {
display: flex;
height: 100%;
gap: 1rem;
& button,
& button.red {
padding: 0.25rem 0.75rem;
}
}
}
}
}
table.myfiles td {
@ -89,10 +80,8 @@ table.friendsfiles td:nth-child(2) {
gap: 8px;
border: 1px solid transparentize($dark-color, 0.8);
border-radius: 6px;
h4 {
font-size: 1.25rem;
}
height: 100%;
overflow: scroll;
&__keywords {
flex-basis: 15%;
@ -116,6 +105,8 @@ table.friendsfiles td:nth-child(2) {
&__results {
flex-basis: 85%;
height: 100%;
overflow: scroll;
& .results-container {
& .results-header {
@ -144,6 +135,8 @@ table.friendsfiles td:nth-child(2) {
}
}
& .results {
height: 100%;
overflow: scroll;
& tr {
display: flex;
& .results {
@ -171,9 +164,17 @@ table.friendsfiles td:nth-child(2) {
}
}
}
& button {
font-size: 1rem;
}
}
}
}
.search-form {
display: flex;
width: 40%;
input {
width: 100%;
}
button {
margin-left: 0.5rem;
}
}

File diff suppressed because one or more lines are too long