fix: creates form for user media preferences
This commit is contained in:
11
assets/bootstrap.js
vendored
11
assets/bootstrap.js
vendored
@@ -1,11 +1,14 @@
|
|||||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
||||||
import Popover from '@stimulus-components/popover'
|
import Popover from '@stimulus-components/popover';
|
||||||
import Dialog from '@stimulus-components/dialog'
|
import Dialog from '@stimulus-components/dialog';
|
||||||
import Dropdown from '@stimulus-components/dropdown'
|
import Dropdown from '@stimulus-components/dropdown';
|
||||||
import 'animate.css'
|
import 'animate.css';
|
||||||
|
import Brock from './components/brock.js';
|
||||||
|
|
||||||
const app = startStimulusApp();
|
const app = startStimulusApp();
|
||||||
// register any custom, 3rd party controllers here
|
// register any custom, 3rd party controllers here
|
||||||
app.register('popover', Popover);
|
app.register('popover', Popover);
|
||||||
app.register('dialog', Dialog);
|
app.register('dialog', Dialog);
|
||||||
app.register('dropdown', Dropdown);
|
app.register('dropdown', Dropdown);
|
||||||
|
|
||||||
|
customElements.define('brock-app', Brock);
|
||||||
|
|||||||
25
assets/components/brock.js
Normal file
25
assets/components/brock.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export default class Brock extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.innerHTML = `
|
||||||
|
Yo, yo, yo! Waddup ${this.name}, doe, it's Brocky fresh!
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attribute change
|
||||||
|
attributeChangedCallback(property, oldValue, newValue) {
|
||||||
|
if (oldValue === newValue) return;
|
||||||
|
this[ property ] = newValue;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ dialog[data-dialog-target="dialog"][closing] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text-input {
|
.text-input {
|
||||||
@apply bg-gray-50 text-gray-50 p-1 bg-transparent border-b-2 border-orange-400
|
@apply bg-gray-50 text-gray-50 px-2 py-1 bg-transparent border-b-2 border-orange-400
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class QualityList
|
|||||||
|
|
||||||
public static function asSelectOptions(): array
|
public static function asSelectOptions(): array
|
||||||
{
|
{
|
||||||
$result = [];
|
$result = ['n/a' => null];
|
||||||
foreach (array_keys(static::$qualities) as $quality) {
|
foreach (array_keys(static::$qualities) as $quality) {
|
||||||
$result[$quality] = $quality;
|
$result[$quality] = $quality;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ class UserPreferencesFactory
|
|||||||
private static function getNestedValue(UserInterface $user, string $preferenceId): ?string
|
private static function getNestedValue(UserInterface $user, string $preferenceId): ?string
|
||||||
{
|
{
|
||||||
$preference = $user->getUserPreference($preferenceId);
|
$preference = $user->getUserPreference($preferenceId);
|
||||||
if (null === $preference) {
|
if (null === $preference || "" === $preference || null === $preference->getPreferenceValue() || "" === $preference->getPreferenceValue()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return $preference->getPreference()
|
return $preference->getPreference()
|
||||||
->getPreferenceOptions()
|
->getPreferenceOptions()
|
||||||
->filter(fn (PreferenceOption $option) => (string) $option->getId() === $preference->getPreferenceValue())
|
->filter(fn (PreferenceOption $option) => (string) $option->getId() === $preference->getPreferenceValue())
|
||||||
->first()
|
->first()
|
||||||
->getValue()
|
->getId()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\User\Framework\Controller\Web;
|
namespace App\User\Framework\Controller\Web;
|
||||||
|
|
||||||
use App\Base\Service\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
|
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
|
||||||
use App\User\Action\Handler\SaveUserDownloadPreferencesHandler;
|
use App\User\Action\Handler\SaveUserDownloadPreferencesHandler;
|
||||||
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
||||||
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
|
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
|
||||||
@@ -14,8 +15,10 @@ use App\User\Database\ProviderList;
|
|||||||
use App\User\Database\QualityList;
|
use App\User\Database\QualityList;
|
||||||
use App\User\Dto\UserPreferencesFactory;
|
use App\User\Dto\UserPreferencesFactory;
|
||||||
use App\User\Framework\Form\GettingStartedFilterForm;
|
use App\User\Framework\Form\GettingStartedFilterForm;
|
||||||
|
use App\User\Framework\Form\UserMediaPreferencesForm;
|
||||||
use App\User\Framework\Repository\PreferencesRepository;
|
use App\User\Framework\Repository\PreferencesRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
@@ -26,24 +29,35 @@ class PreferencesController extends AbstractController
|
|||||||
private readonly Broadcaster $broadcaster,
|
private readonly Broadcaster $broadcaster,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
#[Route('/user/preferences', 'app_user_preferences', methods: ['GET'])]
|
#[Route('/user/preferences', 'app_user_preferences', methods: ['GET', 'POST'])]
|
||||||
public function mediaPreferences(): Response
|
public function mediaPreferences(Request $request, SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler): Response
|
||||||
{
|
{
|
||||||
$mediaPreferences = $this->getUser()->getMediaPreferences();
|
|
||||||
$downloadPreferences = $this->getUser()->getDownloadPreferences();
|
$downloadPreferences = $this->getUser()->getDownloadPreferences();
|
||||||
$languages = CountryLanguages::$languages;
|
$formData = (array) UserPreferencesFactory::createFromUser($this->getUser());
|
||||||
sort($languages);
|
$form = $this->createForm(UserMediaPreferencesForm::class, $formData);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$saveUserMediaPreferencesHandler->handle(new SaveUserMediaPreferencesCommand(
|
||||||
|
resolution: (string) $form->get('resolution')->getData(),
|
||||||
|
codec: (string) $form->get('codec')->getData(),
|
||||||
|
quality: (string) $form->get('quality')->getData(),
|
||||||
|
language: (string) $form->get('language')->getData(),
|
||||||
|
provider: (string) $form->get('provider')->getData(),
|
||||||
|
));
|
||||||
|
$this->broadcaster->alert(
|
||||||
|
title: 'Success',
|
||||||
|
message: 'Your media preferences have been saved.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->render(
|
return $this->render(
|
||||||
'user/preferences.html.twig',
|
'user/preferences.html.twig',
|
||||||
[
|
[
|
||||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
|
||||||
'languages' => $languages,
|
|
||||||
'providers' => ProviderList::getProviders(),
|
|
||||||
'qualities' => QualityList::getBaseQualities(),
|
|
||||||
'mediaPreferences' => $mediaPreferences,
|
|
||||||
'downloadPreferences' => $downloadPreferences,
|
'downloadPreferences' => $downloadPreferences,
|
||||||
'filterForm' => $this->createForm(GettingStartedFilterForm::class, (array) UserPreferencesFactory::createFromUser($this->getUser())),
|
'preferences_form' => $form,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
60
src/User/Framework/Form/UserMediaPreferencesForm.php
Normal file
60
src/User/Framework/Form/UserMediaPreferencesForm.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Framework\Form;
|
||||||
|
|
||||||
|
use Aimeos\Map;
|
||||||
|
use App\User\Database\CountryLanguages;
|
||||||
|
use App\User\Database\ProviderList;
|
||||||
|
use App\User\Database\QualityList;
|
||||||
|
use App\User\Framework\Repository\PreferenceOptionRepository;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class UserMediaPreferencesForm extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly PreferenceOptionRepository $preferenceOptionRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$this->addChoiceField($builder, 'language', CountryLanguages::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'quality', QualityList::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'provider', ProviderList::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'resolution', $this->getPreferenceChoices('resolution'));
|
||||||
|
$this->addChoiceField($builder, 'codec', $this->getPreferenceChoices('codec'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addChoiceField(FormBuilderInterface $builder, string $fieldName, array $choices): void
|
||||||
|
{
|
||||||
|
$question = [
|
||||||
|
'attr' => ['class' => 'w-64 text-input mb-4'],
|
||||||
|
'label_attr' => ['class' => 'w-64 text-white block font-semibold mb-2'],
|
||||||
|
'choices' => $this->addDefaultChoice($choices),
|
||||||
|
'required' => false,
|
||||||
|
];
|
||||||
|
$builder->add($fieldName, ChoiceType::class, $question);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPreferenceChoices(string $preference): array
|
||||||
|
{
|
||||||
|
$options = $this->preferenceOptionRepository->findBy(['preference' => $preference]);
|
||||||
|
$result = [];
|
||||||
|
foreach ($options as $item) {
|
||||||
|
$result[$item->getName()] = $item->getId();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addDefaultChoice(array $choices): iterable
|
||||||
|
{
|
||||||
|
return ['n/a' => ''] + $choices;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ module.exports = {
|
|||||||
"flex-row",
|
"flex-row",
|
||||||
"p-2",
|
"p-2",
|
||||||
"p-4",
|
"p-4",
|
||||||
|
"w-32",
|
||||||
|
"w-64",
|
||||||
"bg-blue-300",
|
"bg-blue-300",
|
||||||
"bg-orange-300",
|
"bg-orange-300",
|
||||||
"bg-fuchsia-300",
|
"bg-fuchsia-300",
|
||||||
|
|||||||
17
templates/components/field/select.html.twig
Normal file
17
templates/components/field/select.html.twig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<div{{ attributes }}>
|
||||||
|
<label class="text-gray-50" for="quality">{{ label }}</label>
|
||||||
|
<select class="p-1.5 rounded-md mb-2" name="quality" id="quality" value="{{ value }}">
|
||||||
|
{% if true == show_na %}
|
||||||
|
<option class="text-gray-800"
|
||||||
|
value=""
|
||||||
|
{{ value is null ? "selected" }}
|
||||||
|
>n/a</option>
|
||||||
|
{% endif %}
|
||||||
|
{% for option in options %}
|
||||||
|
<option class="text-gray-800"
|
||||||
|
value="{{ option.value }}"
|
||||||
|
{{ quality == option.value ? "selected" }}
|
||||||
|
>{{ option.label }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
@@ -5,84 +5,19 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="p-4 flex flex-col md:flex-row gap-2">
|
<div class="p-4 flex flex-col md:flex-row gap-2">
|
||||||
<twig:Card title="Media Preferences" class="w-full">
|
<twig:Card title="Media Preferences" class="w-full">
|
||||||
<p class="text-gray-50 mb-2">Define a filter to be pre-applied to your download options.</p>
|
<p class="text-gray-50 mb-4">Define a filter to be pre-applied to your download options.</p>
|
||||||
<form id="media_preferences" class="flex flex-col max-w-64" name="media_preferences" method="post" action="{{ path('app_save_media_preferences') }}">
|
{{ form_start(preferences_form) }}
|
||||||
<label class="text-gray-50" for="quality">Quality</label>
|
{{ form_row(preferences_form.language) }}
|
||||||
<select class="p-1.5 rounded-md mb-2" name="quality" id="quality" value="{{ mediaPreferences['quality'].getPreferenceValue() }}">
|
{{ form_row(preferences_form.quality) }}
|
||||||
<option class="text-gray-800"
|
{{ form_row(preferences_form.provider) }}
|
||||||
value=""
|
{{ form_row(preferences_form.resolution) }}
|
||||||
{{ mediaPreferences['quality'].getPreferenceValue() is null ? "selected" }}
|
{{ form_row(preferences_form.codec) }}
|
||||||
>n/a</option>
|
<button class="submit-button">Save</button>
|
||||||
{% for quality in qualities %}
|
{{ form_end(preferences_form) }}
|
||||||
<option class="text-gray-800"
|
|
||||||
value="{{ quality }}"
|
|
||||||
{{ quality == mediaPreferences['quality'].getPreferenceValue() ? "selected" }}
|
|
||||||
>{{ quality }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="text-gray-50" for="resolution">Resolution</label>
|
|
||||||
<select class="p-1.5 rounded-md mb-2" name="resolution" id="resolution" value="{{ mediaPreferences['resolution'].getPreferenceValue() }}">
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value=""
|
|
||||||
{{ mediaPreferences['resolution'] is null ? "selected" }}
|
|
||||||
>n/a</option>
|
|
||||||
|
|
||||||
{% for pref in mediaPreferences['resolution'].getPreference().getPreferenceOptions() %}
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value="{{ pref.id }}"
|
|
||||||
{{ pref.id == mediaPreferences['resolution'].getPreferenceValue() ? "selected" }}
|
|
||||||
>{{ pref.name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="text-gray-50" for="codec">Codec</label>
|
|
||||||
<select class="p-1.5 rounded-md mb-2" name="codec" id="codec" value="{{ mediaPreferences['codec'].getPreferenceValue() }}">
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value=""
|
|
||||||
{{ mediaPreferences['codec'].getPreferenceValue() is null ? "selected" }}
|
|
||||||
>n/a</option>
|
|
||||||
{% for pref in mediaPreferences['codec'].getPreference().getPreferenceOptions() %}
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value="{{ pref.id }}"
|
|
||||||
{{ pref.id == mediaPreferences['codec'].getPreferenceValue() ? "selected" }}
|
|
||||||
>{{ pref.name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="text-gray-50" for="provider">Provider</label>
|
|
||||||
<select class="p-1.5 rounded-md mb-2" name="provider" id="provider" value="{{ mediaPreferences['provider'].getPreferenceValue() }}">
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value=""
|
|
||||||
{{ "" == mediaPreferences['provider'].getPreferenceValue() ? "selected" }}
|
|
||||||
>n/a</option>
|
|
||||||
{% for provider in providers %}
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value="{{ provider }}"
|
|
||||||
{{ provider == mediaPreferences['provider'].getPreferenceValue() ? "selected" }}
|
|
||||||
>{{ provider }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label class="text-gray-50" for="language">Language</label>
|
|
||||||
<select class="p-1.5 rounded-md mb-2" name="language" id="language" value="{{ mediaPreferences['language'].getPreferenceValue() }}">
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value=""
|
|
||||||
{{ mediaPreferences['language'].getPreferenceValue() is null ? "selected" }}
|
|
||||||
>n/a</option>
|
|
||||||
{% for language in languages %}
|
|
||||||
<option class="text-gray-800"
|
|
||||||
value="{{ language }}"
|
|
||||||
{{ language == mediaPreferences['language'].getPreferenceValue() ? "selected" }}
|
|
||||||
>{{ language }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
<button class="px-1.5 py-1 max-w-20 rounded-md bg-green-600 text-white" type="submit">Submit</button>
|
|
||||||
</form>
|
|
||||||
</twig:Card>
|
</twig:Card>
|
||||||
|
|
||||||
<twig:Card title="Download Preferences" class="w-full">
|
<twig:Card title="Download Preferences" class="w-full">
|
||||||
<p class="text-gray-50 mb-2">Change how your downloads are stored.</p>
|
<p class="text-gray-50 mb-4">Change how your downloads are stored.</p>
|
||||||
<form id="download_preferences" class="flex flex-col" name="download_preferences" method="post" action="{{ path('app_save_download_preferences') }}">
|
<form id="download_preferences" class="flex flex-col" name="download_preferences" method="post" action="{{ path('app_save_download_preferences') }}">
|
||||||
<div class="flex flex-row gap-2 mb-2">
|
<div class="flex flex-row gap-2 mb-2">
|
||||||
<input type="hidden" name="movie_folder" id="movie_folder_hidden" value="0" />
|
<input type="hidden" name="movie_folder" id="movie_folder_hidden" value="0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user