mirror of
https://github.com/AzuraCast/AzuraCast.git
synced 2024-06-18 06:57:05 +00:00
Add support for per-user 24-hour clock display setting.
This commit is contained in:
parent
d5fb9edf61
commit
f6c363163f
|
@ -10,6 +10,9 @@ release channel, you can take advantage of these new features and fixes.
|
||||||
media. Because cover art files are often named a variety of things, we currently will use _any_ image file that exists
|
media. Because cover art files are often named a variety of things, we currently will use _any_ image file that exists
|
||||||
alongside media. You can also now view cover art via the Media Manager UI.
|
alongside media. You can also now view cover art via the Media Manager UI.
|
||||||
|
|
||||||
|
- **24-Hour Time Display Support**: You can now choose whether to view time in 12 or 24 hour format from your user
|
||||||
|
profile, or use the default settings for your locale.
|
||||||
|
|
||||||
## Code Quality/Technical Changes
|
## Code Quality/Technical Changes
|
||||||
|
|
||||||
- Because both our Docker and Ansible installations are managed by Supervisor now, we can view the realtime status of
|
- Because both our Docker and Ansible installations are managed by Supervisor now, we can view the realtime status of
|
||||||
|
|
|
@ -80,14 +80,26 @@ return [
|
||||||
$localeShort = substr($locale, 0, 2);
|
$localeShort = substr($locale, 0, 2);
|
||||||
$localeWithDashes = str_replace('_', '-', $locale);
|
$localeWithDashes = str_replace('_', '-', $locale);
|
||||||
|
|
||||||
|
// User profile-specific 24-hour display setting.
|
||||||
|
$userObj = $request->getAttribute(ServerRequest::ATTR_USER);
|
||||||
|
$show24Hours = ($userObj instanceof App\Entity\User)
|
||||||
|
? $userObj->getShow24HourTime()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$timeConfig = new \stdClass();
|
||||||
|
if (null !== $show24Hours) {
|
||||||
|
$timeConfig->hour12 = !$show24Hours;
|
||||||
|
}
|
||||||
|
|
||||||
$app = [
|
$app = [
|
||||||
'lang' => [
|
'lang' => [
|
||||||
'confirm' => __('Are you sure?'),
|
'confirm' => __('Are you sure?'),
|
||||||
'advanced' => __('Advanced'),
|
'advanced' => __('Advanced'),
|
||||||
],
|
],
|
||||||
'locale' => $locale,
|
'locale' => $locale,
|
||||||
'locale_short' => $localeShort,
|
'locale_short' => $localeShort,
|
||||||
'locale_with_dashes' => $localeWithDashes,
|
'locale_with_dashes' => $localeWithDashes,
|
||||||
|
'time_config' => $timeConfig,
|
||||||
'api_csrf' => null,
|
'api_csrf' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -22,30 +22,44 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<b-form-row>
|
<b-form-row>
|
||||||
<b-wrapped-form-group class="col-md-6" id="edit_form_locale"
|
<b-col md="6">
|
||||||
:field="form.locale">
|
<b-wrapped-form-group class="col-md-6" id="edit_form_locale"
|
||||||
<template #label="{lang}">
|
:field="form.locale">
|
||||||
<translate :key="lang">Language</translate>
|
<template #label="{lang}">
|
||||||
</template>
|
<translate :key="lang">Language</translate>
|
||||||
<template #default="props">
|
</template>
|
||||||
<b-form-radio-group stacked :id="props.id" :options="localeOptions"
|
<template #default="props">
|
||||||
v-model="props.field.$model">
|
<b-form-radio-group stacked :id="props.id" :options="localeOptions"
|
||||||
</b-form-radio-group>
|
v-model="props.field.$model">
|
||||||
</template>
|
</b-form-radio-group>
|
||||||
</b-wrapped-form-group>
|
</template>
|
||||||
|
</b-wrapped-form-group>
|
||||||
<b-wrapped-form-group class="col-md-6" id="edit_form_theme"
|
</b-col>
|
||||||
:field="form.theme">
|
<b-col md="6">
|
||||||
<template #label="{lang}">
|
<b-wrapped-form-group id="edit_form_theme"
|
||||||
<translate :key="lang">Site Theme</translate>
|
:field="form.theme">
|
||||||
</template>
|
<template #label="{lang}">
|
||||||
<template #default="props">
|
<translate :key="lang">Site Theme</translate>
|
||||||
<b-form-radio-group stacked :id="props.id" :options="themeOptions"
|
</template>
|
||||||
v-model="props.field.$model">
|
<template #default="props">
|
||||||
</b-form-radio-group>
|
<b-form-radio-group stacked :id="props.id" :options="themeOptions"
|
||||||
</template>
|
v-model="props.field.$model">
|
||||||
</b-wrapped-form-group>
|
</b-form-radio-group>
|
||||||
|
</template>
|
||||||
|
</b-wrapped-form-group>
|
||||||
|
|
||||||
|
<b-wrapped-form-group id="edit_form_show_24_hour_time"
|
||||||
|
:field="form.show_24_hour_time">
|
||||||
|
<template #label="{lang}">
|
||||||
|
<translate :key="lang">Time Display</translate>
|
||||||
|
</template>
|
||||||
|
<template #default="props">
|
||||||
|
<b-form-radio-group stacked :id="props.id" :options="show24hourOptions"
|
||||||
|
v-model="props.field.$model">
|
||||||
|
</b-form-radio-group>
|
||||||
|
</template>
|
||||||
|
</b-wrapped-form-group>
|
||||||
|
</b-col>
|
||||||
</b-form-row>
|
</b-form-row>
|
||||||
</b-form-fieldset>
|
</b-form-fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
@ -87,6 +101,22 @@ export default {
|
||||||
value: 'dark'
|
value: 'dark'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
},
|
||||||
|
show24hourOptions() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: this.$gettext('Prefer System Default'),
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$gettext('12 Hour'),
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.$gettext('24 Hour'),
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@ export default {
|
||||||
name: {},
|
name: {},
|
||||||
email: {required, email},
|
email: {required, email},
|
||||||
locale: {required},
|
locale: {required},
|
||||||
theme: {required}
|
theme: {required},
|
||||||
|
show_24_hour_time: {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -52,7 +53,8 @@ export default {
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
locale: 'default',
|
locale: 'default',
|
||||||
theme: 'browser'
|
theme: 'browser',
|
||||||
|
show_24_hour_time: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
open() {
|
open() {
|
||||||
|
|
|
@ -143,7 +143,9 @@ export default {
|
||||||
this.$refs.datatable.relist();
|
this.$refs.datatable.relist();
|
||||||
},
|
},
|
||||||
formatTimestamp(unix_timestamp) {
|
formatTimestamp(unix_timestamp) {
|
||||||
return DateTime.fromSeconds(unix_timestamp).toLocaleString(DateTime.DATETIME_SHORT);
|
return DateTime.fromSeconds(unix_timestamp).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_SHORT, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,7 +183,9 @@ export default {
|
||||||
return DateTime.fromSeconds(timestamp).toRelative();
|
return DateTime.fromSeconds(timestamp).toRelative();
|
||||||
},
|
},
|
||||||
toLocaleTime(timestamp) {
|
toLocaleTime(timestamp) {
|
||||||
return DateTime.fromSeconds(timestamp).toLocaleString(DateTime.DATETIME_SHORT);
|
return DateTime.fromSeconds(timestamp).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_SHORT, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formatFileSize(size) {
|
formatFileSize(size) {
|
||||||
return formatFileSize(size);
|
return formatFileSize(size);
|
||||||
|
|
|
@ -267,7 +267,9 @@ export default {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return DateTime.fromSeconds(value).setZone(this.stationTimeZone).toLocaleString(DateTime.DATETIME_MED);
|
return DateTime.fromSeconds(value).setZone(this.stationTimeZone).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
selectable: true,
|
selectable: true,
|
||||||
visible: true
|
visible: true
|
||||||
|
|
|
@ -192,7 +192,9 @@ export default {
|
||||||
: this.$gettext('Enable');
|
: this.$gettext('Enable');
|
||||||
},
|
},
|
||||||
formatTime (time) {
|
formatTime (time) {
|
||||||
return DateTime.fromSeconds(time).setZone(this.stationTimeZone).toLocaleString(DateTime.DATETIME_MED);
|
return DateTime.fromSeconds(time).setZone(this.stationTimeZone).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formatLength (length) {
|
formatLength (length) {
|
||||||
return humanizeDuration(length * 1000, {
|
return humanizeDuration(length * 1000, {
|
||||||
|
|
|
@ -60,15 +60,23 @@ export default {
|
||||||
row.time_until = start_moment.toRelative();
|
row.time_until = start_moment.toRelative();
|
||||||
|
|
||||||
if (start_moment.hasSame(now, 'day')) {
|
if (start_moment.hasSame(now, 'day')) {
|
||||||
row.start_formatted = start_moment.toLocaleString(DateTime.TIME_SIMPLE);
|
row.start_formatted = start_moment.toLocaleString(
|
||||||
|
{...DateTime.TIME_SIMPLE, ...App.time_config}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
row.start_formatted = start_moment.toLocaleString(DateTime.DATETIME_MED);
|
row.start_formatted = start_moment.toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_moment.hasSame(start_moment, 'day')) {
|
if (end_moment.hasSame(start_moment, 'day')) {
|
||||||
row.end_formatted = end_moment.toLocaleString(DateTime.TIME_SIMPLE);
|
row.end_formatted = end_moment.toLocaleString(
|
||||||
|
{...DateTime.TIME_SIMPLE, ...App.time_config}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
row.end_formatted = end_moment.toLocaleString(DateTime.DATETIME_MED);
|
row.end_formatted = end_moment.toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
|
|
|
@ -81,7 +81,9 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTime(time) {
|
formatTime(time) {
|
||||||
return this.getDateTime(time).toLocaleString(DateTime.TIME_WITH_SECONDS);
|
return this.getDateTime(time).toLocaleString(
|
||||||
|
{...DateTime.TIME_WITH_SECONDS, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formatRelativeTime(time) {
|
formatRelativeTime(time) {
|
||||||
return this.getDateTime(time).toRelative();
|
return this.getDateTime(time).toRelative();
|
||||||
|
|
|
@ -104,7 +104,9 @@ export default {
|
||||||
this.$refs.datatable.refresh();
|
this.$refs.datatable.refresh();
|
||||||
},
|
},
|
||||||
formatTime(time) {
|
formatTime(time) {
|
||||||
return DateTime.fromSeconds(time).setZone(this.stationTimeZone).toLocaleString(DateTime.DATETIME_MED);
|
return DateTime.fromSeconds(time).setZone(this.stationTimeZone).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
doDelete(url) {
|
doDelete(url) {
|
||||||
this.$confirmDelete({
|
this.$confirmDelete({
|
||||||
|
|
|
@ -165,10 +165,14 @@ export default {
|
||||||
return Math.abs(val);
|
return Math.abs(val);
|
||||||
},
|
},
|
||||||
formatTimestamp(unix_timestamp) {
|
formatTimestamp(unix_timestamp) {
|
||||||
return DateTime.fromSeconds(unix_timestamp).toLocaleString(DateTime.DATETIME_SHORT);
|
return DateTime.fromSeconds(unix_timestamp).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_SHORT, ...App.time_config}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
formatTimestampStation(unix_timestamp) {
|
formatTimestampStation(unix_timestamp) {
|
||||||
return DateTime.fromSeconds(unix_timestamp).setZone(this.stationTimeZone).toLocaleString(DateTime.DATETIME_SHORT);
|
return DateTime.fromSeconds(unix_timestamp).setZone(this.stationTimeZone).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_SHORT, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,9 @@ export default {
|
||||||
label: this.$gettext('Start Time'),
|
label: this.$gettext('Start Time'),
|
||||||
sortable: false,
|
sortable: false,
|
||||||
formatter: (value, key, item) => {
|
formatter: (value, key, item) => {
|
||||||
return DateTime.fromSeconds(value).toLocaleString(DateTime.DATETIME_MED);
|
return DateTime.fromSeconds(value).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -72,7 +74,9 @@ export default {
|
||||||
if (value === 0) {
|
if (value === 0) {
|
||||||
return this.$gettext('Live');
|
return this.$gettext('Live');
|
||||||
}
|
}
|
||||||
return DateTime.fromSeconds(value).toLocaleString(DateTime.DATETIME_MED);
|
return DateTime.fromSeconds(value).toLocaleString(
|
||||||
|
{...DateTime.DATETIME_MED, ...App.time_config}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
26
src/Entity/Migration/Version20221102125558.php
Normal file
26
src/Entity/Migration/Version20221102125558.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity\Migration;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20221102125558 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add user-level 24-hour time setting.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE users ADD show_24_hour_time TINYINT(1) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE users DROP show_24_hour_time');
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,6 +81,14 @@ class User implements Stringable, IdentifiableEntityInterface
|
||||||
]
|
]
|
||||||
protected ?string $theme = null;
|
protected ?string $theme = null;
|
||||||
|
|
||||||
|
#[
|
||||||
|
OA\Property(example: true),
|
||||||
|
ORM\Column(nullable: true),
|
||||||
|
Attributes\AuditIgnore,
|
||||||
|
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
|
||||||
|
]
|
||||||
|
protected ?bool $show_24_hour_time = null;
|
||||||
|
|
||||||
#[
|
#[
|
||||||
OA\Property(example: "A1B2C3D4"),
|
OA\Property(example: "A1B2C3D4"),
|
||||||
ORM\Column(length: 255, nullable: true),
|
ORM\Column(length: 255, nullable: true),
|
||||||
|
@ -234,6 +242,16 @@ class User implements Stringable, IdentifiableEntityInterface
|
||||||
$this->theme = $theme;
|
$this->theme = $theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getShow24HourTime(): ?bool
|
||||||
|
{
|
||||||
|
return $this->show_24_hour_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setShow24HourTime(?bool $show_24_hour_time): void
|
||||||
|
{
|
||||||
|
$this->show_24_hour_time = $show_24_hour_time;
|
||||||
|
}
|
||||||
|
|
||||||
public function getTwoFactorSecret(): ?string
|
public function getTwoFactorSecret(): ?string
|
||||||
{
|
{
|
||||||
return $this->two_factor_secret;
|
return $this->two_factor_secret;
|
||||||
|
|
|
@ -49,10 +49,12 @@ $(document).on('click', '.api-call', function (e) {
|
||||||
$(function () {
|
$(function () {
|
||||||
function updateClock() {
|
function updateClock() {
|
||||||
let d = new Date();
|
let d = new Date();
|
||||||
let time = d.toLocaleString(App.locale_with_dashes, {
|
|
||||||
timeZone: <?=$this->escapeJs($station->getTimezone()) ?>,
|
let timeConfig = App.time_config;
|
||||||
timeStyle: 'long'
|
timeConfig.timeZone = <?=$this->escapeJs($station->getTimezone()) ?>;
|
||||||
})
|
timeConfig.timeStyle = 'long';
|
||||||
|
|
||||||
|
let time = d.toLocaleString(App.locale_with_dashes, timeConfig);
|
||||||
|
|
||||||
$('#station-time').text(time);
|
$('#station-time').text(time);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user