Add features table on signup

pull/959/merge
Chocobozzz 2018-08-28 17:39:29 +02:00
parent f0d4e7eb24
commit 41a676db39
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
18 changed files with 180 additions and 82 deletions

View File

@ -1,6 +1,6 @@
<div i18n class="about-peertube-title">
<h1 i18n class="about-peertube-title">
About PeerTube
</div>
</h1>
<div class="description">
<p i18n>PeerTube is a federated (ActivityPub) video streaming platform using P2P (WebTorrent) directly in the web browser.</p>
@ -15,14 +15,14 @@
</div>
<div id="p2p-privacy">
<div i18n class="section-title">P2P & Privacy</div>
<h3 i18n class="section-title">P2P & Privacy</h3>
<p i18n>
PeerTube uses the BitTorrent protocol to share bandwidth between users.
This implies that your IP address is stored in the instance's BitTorrent tracker as long as you download or watch the video.
</p>
<h4 i18n class="p2p-privacy-title">What are the consequences?</h4>
<h6 i18n class="p2p-privacy-title">What are the consequences?</h6>
<p i18n>
In theory, someone with enough technical skills could create a script that tracks which IP is downloading which video.
@ -64,7 +64,7 @@
There are much more effective ways to get that kind of information.
</p>
<h4 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h4>
<h6 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h6>
<p i18n>
The threats to privacy in YouTube are different from PeerTube's.
@ -72,7 +72,7 @@
Moreover, YouTube is owned by Google/Alphabet, a company that tracks you across many websites (via AdSense or Google Analytics).
</p>
<h4 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h4>
<h6 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h6>
<p i18n>
Your IP address is public so every time you consult a website, there is a number of actors (in addition to the final website) seeing your IP in their connection logs: ISP/routers/trackers/CDN and more.
@ -80,7 +80,7 @@
Thinking that removing P2P from PeerTube will give you back anonymity doesn't make sense.
</p>
<h4 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h4>
<h6 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h6>
<p i18n>
PeerTube is only in beta, and want to deliver the best countermeasures possible by the time the stable is released.

View File

@ -2,7 +2,7 @@
@import '_mixins';
.about-peertube-title {
font-size: 20px;
font-size: 25px;
font-weight: bold;
margin-bottom: 15px;
}

View File

@ -2,8 +2,7 @@ import { Component } from '@angular/core'
@Component({
selector: 'my-about',
templateUrl: './about.component.html',
styleUrls: [ './about.component.scss' ]
templateUrl: './about.component.html'
})
export class AboutComponent {

View File

@ -64,6 +64,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
super()
}
get videoQuotaOptions () {
return EditCustomConfigComponent.videoQuotaOptions
}
get videoQuotaDailyOptions () {
return EditCustomConfigComponent.videoQuotaDailyOptions
}
getResolutionKey (resolution: string) {
return 'transcodingResolution' + resolution
}

View File

@ -0,0 +1,28 @@
<div class="feature-table">
<table class="table">
<tr>
<td i18n class="label">Video quota</td>
<td class="value">
<ng-container *ngIf="initialUserVideoQuota !== -1">
{{ initialUserVideoQuota | bytes: 0 }}
<my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
</ng-container>
<ng-container i18n *ngIf="initialUserVideoQuota === -1">
Unlimited
</ng-container>
</td>
</tr>
<tr *ngFor="let feature of features">
<td class="label">{{ feature.label }}</td>
<td>
<span *ngIf="feature.value === true" class="glyphicon glyphicon-ok"></span>
<span *ngIf="feature.value === false" class="glyphicon glyphicon-remove"></span>
</td>
</tr>
</table>
</div>

View File

@ -0,0 +1,20 @@
@import '_variables';
@import '_mixins';
table {
font-size: 14px;
max-width: 400px;
.label {
font-weight: $font-semibold;
min-width: 330px;
}
.glyphicon-ok {
color: $green;
}
.glyphicon-remove {
color: $red;
}
}

View File

@ -0,0 +1,84 @@
import { Component, OnInit } from '@angular/core'
import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
selector: 'my-instance-features-table',
templateUrl: './instance-features-table.component.html',
styleUrls: [ './instance-features-table.component.scss' ]
})
export class InstanceFeaturesTableComponent implements OnInit {
features: { label: string, value?: boolean }[] = []
quotaHelpIndication = ''
constructor (
private i18n: I18n,
private serverService: ServerService
) {
}
get initialUserVideoQuota () {
return this.serverService.getConfig().user.videoQuota
}
ngOnInit () {
this.serverService.configLoaded
.subscribe(() => {
this.buildFeatures()
this.buildQuotaHelpIndication()
})
}
private buildFeatures () {
const config = this.serverService.getConfig()
this.features = [
{
label: this.i18n('Transcode your videos in multiple resolutions'),
value: config.transcoding.enabledResolutions.length !== 0
},
{
label: this.i18n('HTTP import (YouTube, Vimeo, direct URL...)'),
value: config.import.videos.http.enabled
},
{
label: this.i18n('Torrent import'),
value: config.import.videos.torrent.enabled
}
]
}
private getApproximateTime (seconds: number) {
const hours = Math.floor(seconds / 3600)
let pluralSuffix = ''
if (hours > 1) pluralSuffix = 's'
if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
const minutes = Math.floor(seconds % 3600 / 60)
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
}
private buildQuotaHelpIndication () {
if (this.initialUserVideoQuota === -1) return
const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
// 1080p: ~ 6Mbps
// 720p: ~ 4Mbps
// 360p: ~ 1.5Mbps
const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
const lines = [
this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
]
this.quotaHelpIndication = lines.join('<br />')
}
}

View File

@ -51,6 +51,7 @@ import { VideoImportService } from '@app/shared/video-import/video-import.servic
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
@NgModule({
imports: [
@ -86,7 +87,8 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
HelpComponent,
ReactiveFileComponent,
PeertubeCheckboxComponent,
SubscribeButtonComponent
SubscribeButtonComponent,
InstanceFeaturesTableComponent
],
exports: [
@ -119,6 +121,7 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
ReactiveFileComponent,
PeertubeCheckboxComponent,
SubscribeButtonComponent,
InstanceFeaturesTableComponent,
NumberFormatterPipe,
ObjectLengthPipe,

View File

@ -4,19 +4,7 @@
Create an account
</div>
<div class="initial-user-quota">
<span i18n class="initial-user-quota-label">Initial video quota:</span>
<span *ngIf="initialUserVideoQuota !== -1">
{{ initialUserVideoQuota | bytes: 0 }}
<my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
</span>
<ng-container i18n *ngIf="initialUserVideoQuota === -1">
Unlimited
</ng-container>
</div>
<my-instance-features-table></my-instance-features-table>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>

View File

@ -1,13 +1,10 @@
@import '_variables';
@import '_mixins';
.initial-user-quota {
font-size: 15px;
margin-bottom: 20px;
my-instance-features-table {
display: block;
.initial-user-quota-label {
font-weight: $font-semibold;
}
margin-bottom: 40px;
}
.form-group-terms {
@ -15,11 +12,11 @@
}
.input-group {
@include peertube-input-group(340px);
@include peertube-input-group(400px);
}
input:not([type=submit]) {
@include peertube-input-text(340px);
@include peertube-input-text(400px);
display: block;
&#username {

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core'
import { Router } from '@angular/router'
import { ServerService } from '@app/core/server'
import { NotificationsService } from 'angular2-notifications'
import { UserCreate } from '../../../../shared'
import { FormReactive, UserService, UserValidatorsService } from '../shared'
@ -15,7 +14,6 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
})
export class SignupComponent extends FormReactive implements OnInit {
error: string = null
quotaHelpIndication = ''
constructor (
protected formValidatorService: FormValidatorService,
@ -24,16 +22,11 @@ export class SignupComponent extends FormReactive implements OnInit {
private notificationsService: NotificationsService,
private userService: UserService,
private redirectService: RedirectService,
private serverService: ServerService,
private i18n: I18n
) {
super()
}
get initialUserVideoQuota () {
return this.serverService.getConfig().user.videoQuota
}
get instanceHost () {
return window.location.host
}
@ -45,9 +38,6 @@ export class SignupComponent extends FormReactive implements OnInit {
email: this.userValidatorsService.USER_EMAIL,
terms: this.userValidatorsService.USER_TERMS
})
this.serverService.configLoaded
.subscribe(() => this.buildQuotaHelpIndication())
}
signup () {
@ -67,37 +57,4 @@ export class SignupComponent extends FormReactive implements OnInit {
err => this.error = err.message
)
}
private getApproximateTime (seconds: number) {
const hours = Math.floor(seconds / 3600)
let pluralSuffix = ''
if (hours > 1) pluralSuffix = 's'
if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
const minutes = Math.floor(seconds % 3600 / 60)
if (minutes > 1) pluralSuffix = 's'
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
}
private buildQuotaHelpIndication () {
if (this.initialUserVideoQuota === -1) return
const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
// 1080p: ~ 6Mbps
// 720p: ~ 4Mbps
// 360p: ~ 1.5Mbps
const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
const lines = [
this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
]
this.quotaHelpIndication = lines.join('<br />')
}
}

View File

@ -226,7 +226,7 @@
}
&.action-button-like.activated {
background-color: #39CC0B;
background-color: $green;
.icon-like {
background-image: url('../../../assets/images/video/like-white.svg');
@ -234,7 +234,7 @@
}
&.action-button-dislike.activated {
background-color: #FF0000;
background-color: $red;
.icon-dislike {
background-image: url('../../../assets/images/video/dislike-white.svg');

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="Artboard-4" transform="translate(-356.000000, -115.000000)" stroke="#585858" stroke-width="2">
<g id="8" transform="translate(356.000000, 115.000000)">
<path d="M21,6 L9,18" id="Path-14"></path>
<path d="M9,13 L4,18" id="Path-14" transform="translate(6.500000, 15.500000) scale(-1, 1) translate(-6.500000, -15.500000) "></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 741 B

View File

@ -53,12 +53,12 @@ label {
.form-error {
display: block;
color: $red-error;
color: $red;
margin-top: 5px;
}
.input-error {
border-color: $red-error !important;
border-color: $red !important;
}
.glyphicon-black {

View File

@ -21,7 +21,7 @@ $nav-pills-link-active-color: #000;
//@import '~bootstrap/scss/images';
//@import '~bootstrap/scss/code';
@import '~bootstrap/scss/grid';
//@import '~bootstrap/scss/tables';
@import '~bootstrap/scss/tables';
@import '~bootstrap/scss/forms';
@import '~bootstrap/scss/buttons';
//@import '~bootstrap/scss/transitions';

View File

@ -10,7 +10,9 @@ $orange-hoover-color: #F97D46;
$black-background: #000;
$grey-background: #f6f2f2;
$red-error: #FF0000;
$red: #FF0000;
$green: #39CC0B;
$grey-actor-name: #777272;

View File

@ -43,7 +43,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
.filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
.filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
.map(r => parseInt(r, 10))
const json: ServerConfig = {