Compare commits
5 Commits
v0.25.6
...
dev-user-p
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a9bacea8c | |||
| 0988517bd0 | |||
| d1ae26db45 | |||
| 75e9c1e8c3 | |||
| 93f5b716b2 |
11
assets/bootstrap.js
vendored
11
assets/bootstrap.js
vendored
@@ -1,11 +1,14 @@
|
||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
||||
import Popover from '@stimulus-components/popover'
|
||||
import Dialog from '@stimulus-components/dialog'
|
||||
import Dropdown from '@stimulus-components/dropdown'
|
||||
import 'animate.css'
|
||||
import Popover from '@stimulus-components/popover';
|
||||
import Dialog from '@stimulus-components/dialog';
|
||||
import Dropdown from '@stimulus-components/dropdown';
|
||||
import 'animate.css';
|
||||
import Brock from './components/brock.js';
|
||||
|
||||
const app = startStimulusApp();
|
||||
// register any custom, 3rd party controllers here
|
||||
app.register('popover', Popover);
|
||||
app.register('dialog', Dialog);
|
||||
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 {
|
||||
@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 {
|
||||
|
||||
41
migrations/Version20250724042107.php
Normal file
41
migrations/Version20250724042107.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250724042107 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE preference_option DROP FOREIGN KEY FK_607C52FD81022C0
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE preference_option
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE preference_option (id INT AUTO_INCREMENT NOT NULL, preference_id VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, name VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, value VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, enabled TINYINT(1) NOT NULL, INDEX IDX_607C52FD81022C0 (preference_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = ''
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE preference_option ADD CONSTRAINT FK_607C52FD81022C0 FOREIGN KEY (preference_id) REFERENCES preference (id)
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,15 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
class SeedDatabaseCommand extends Command
|
||||
{
|
||||
private PreferencesRepository $preferenceRepository;
|
||||
private PreferenceOptionRepository $preferenceOptionRepository;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
PreferencesRepository $preferenceRepository,
|
||||
PreferenceOptionRepository $preferenceOptionRepository,
|
||||
UserRepository $userRepository,
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->preferenceRepository = $preferenceRepository;
|
||||
$this->preferenceOptionRepository = $preferenceOptionRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
@@ -39,7 +37,6 @@ class SeedDatabaseCommand extends Command
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$this->seedPreferences($io);
|
||||
$this->seedPreferenceOptions($io);
|
||||
$this->updateUserPreferences($io);
|
||||
|
||||
return Command::SUCCESS;
|
||||
@@ -140,72 +137,4 @@ class SeedDatabaseCommand extends Command
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function seedPreferenceOptions(SymfonyStyle $io)
|
||||
{
|
||||
$io->info('[SeedDatabaseCommand] > Seeding preference options...');
|
||||
$options = $this->getPreferenceOptions();
|
||||
|
||||
foreach ($options as $option) {
|
||||
if ($this->preferenceOptionRepository->findBy([
|
||||
'preference' => $option['preference_id'],
|
||||
'name' => $option['name'],
|
||||
'value' => $option['value'],
|
||||
'enabled' => $option['enabled'],
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
$this->preferenceOptionRepository->getEntityManager()->persist(
|
||||
(new \App\User\Framework\Entity\PreferenceOption())
|
||||
->setPreference($this->preferenceRepository->find($option['preference_id']))
|
||||
->setName($option['name'])
|
||||
->setValue($option['value'])
|
||||
->setEnabled($option['enabled'])
|
||||
);
|
||||
}
|
||||
|
||||
$this->preferenceOptionRepository->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
private function getPreferenceOptions(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'preference_id' => 'resolution',
|
||||
'name' => '720p',
|
||||
'value' => '720p',
|
||||
'enabled' => true
|
||||
],
|
||||
[
|
||||
'preference_id' => 'resolution',
|
||||
'name' => '1080p',
|
||||
'value' => '1080p',
|
||||
'enabled' => true
|
||||
],
|
||||
[
|
||||
'preference_id' => 'resolution',
|
||||
'name' => '2160p',
|
||||
'value' => '2160p',
|
||||
'enabled' => true
|
||||
],
|
||||
[
|
||||
'preference_id' => 'codec',
|
||||
'name' => '-',
|
||||
'value' => '-',
|
||||
'enabled' => true
|
||||
],
|
||||
[
|
||||
'preference_id' => 'codec',
|
||||
'name' => 'h264',
|
||||
'value' => 'h264',
|
||||
'enabled' => true
|
||||
],
|
||||
[
|
||||
'preference_id' => 'codec',
|
||||
'name' => 'h265/HEVC',
|
||||
'value' => 'h265',
|
||||
'enabled' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
namespace App\Twig\Components;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\User\Database\CodecList;
|
||||
use App\User\Database\QualityList;
|
||||
use App\User\Database\ResolutionList;
|
||||
use App\User\Dto\PreferenceOptions;
|
||||
use App\User\Dto\PreferenceOptionsFactory;
|
||||
use App\User\Dto\UserPreferencesFactory;
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
|
||||
use Symfony\UX\LiveComponent\DefaultActionTrait;
|
||||
|
||||
#[AsLiveComponent]
|
||||
final class Filter
|
||||
final class Filter extends AbstractController
|
||||
{
|
||||
use DefaultActionTrait;
|
||||
|
||||
@@ -21,15 +27,20 @@ final class Filter
|
||||
public array $reverseMappedQualities = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly PreferencesRepository $preferencesRepository,
|
||||
private readonly Security $security,
|
||||
) {
|
||||
$this->preferences = Map::from($this->preferencesRepository->findEnabled())
|
||||
->rekey(fn($element) => $element->getId())
|
||||
->map(fn($element) => $element->getPreferenceOptions()->toArray())
|
||||
->toArray();
|
||||
$this->userPreferences = Map::from($this->security->getUser()->getUserPreferenceValues())
|
||||
->toArray();
|
||||
$this->preferences = (array) PreferenceOptionsFactory::createSelectOptions();
|
||||
$this->userPreferences = (array) UserPreferencesFactory::createFromUser($security->getUser());
|
||||
$this->reverseMappedQualities = QualityList::getAsReverseMap();
|
||||
}
|
||||
|
||||
public function getResolutionOptions()
|
||||
{
|
||||
return ResolutionList::asSelectOptions();
|
||||
}
|
||||
|
||||
public function getCodecOptions()
|
||||
{
|
||||
return CodecList::asSelectOptions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\User\Action\Command;
|
||||
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
/** @implements CommandInterface<SaveUserMediaPreferencesCommand> */
|
||||
class SaveUserMediaPreferencesCommand implements CommandInterface
|
||||
@@ -14,4 +15,15 @@ class SaveUserMediaPreferencesCommand implements CommandInterface
|
||||
public string $language,
|
||||
public string $provider,
|
||||
) {}
|
||||
|
||||
public static function fromUserMediaPreferencesForm(FormInterface $form): self
|
||||
{
|
||||
return new static(
|
||||
resolution: $form->get('resolution')->getData(),
|
||||
codec: $form->get('codec')->getData(),
|
||||
quality: $form->get('quality')->getData(),
|
||||
language: $form->get('language')->getData(),
|
||||
provider: $form->get('provider')->getData(),
|
||||
);
|
||||
}
|
||||
}
|
||||
25
src/User/Database/CodecList.php
Normal file
25
src/User/Database/CodecList.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Database;
|
||||
|
||||
class CodecList
|
||||
{
|
||||
public static $codecs = [
|
||||
'h264',
|
||||
'h265/HEVC',
|
||||
];
|
||||
|
||||
public static function getCodecs()
|
||||
{
|
||||
return self::$codecs;
|
||||
}
|
||||
|
||||
public static function asSelectOptions(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (static::$codecs as $codec) {
|
||||
$result[$codec] = $codec;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ class QualityList
|
||||
|
||||
public static function asSelectOptions(): array
|
||||
{
|
||||
$result = [];
|
||||
$result = ['n/a' => null];
|
||||
foreach (array_keys(static::$qualities) as $quality) {
|
||||
$result[$quality] = $quality;
|
||||
}
|
||||
|
||||
27
src/User/Database/ResolutionList.php
Normal file
27
src/User/Database/ResolutionList.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Database;
|
||||
|
||||
class ResolutionList
|
||||
{
|
||||
public static $resolutions = [
|
||||
'480p',
|
||||
'720p',
|
||||
'1080p',
|
||||
'2160p',
|
||||
];
|
||||
|
||||
public static function getResolutions()
|
||||
{
|
||||
return self::$resolutions;
|
||||
}
|
||||
|
||||
public static function asSelectOptions(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (static::$resolutions as $resolution) {
|
||||
$result[$resolution] = $resolution;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
14
src/User/Dto/PreferenceOptions.php
Normal file
14
src/User/Dto/PreferenceOptions.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Dto;
|
||||
|
||||
class PreferenceOptions
|
||||
{
|
||||
public function __construct(
|
||||
public readonly array $resolutions,
|
||||
public readonly array $codecs,
|
||||
public readonly array $languages,
|
||||
public readonly array $providers,
|
||||
public readonly array $qualities,
|
||||
) {}
|
||||
}
|
||||
23
src/User/Dto/PreferenceOptionsFactory.php
Normal file
23
src/User/Dto/PreferenceOptionsFactory.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Dto;
|
||||
|
||||
use App\User\Database\CodecList;
|
||||
use App\User\Database\CountryLanguages;
|
||||
use App\User\Database\ProviderList;
|
||||
use App\User\Database\QualityList;
|
||||
use App\User\Database\ResolutionList;
|
||||
|
||||
class PreferenceOptionsFactory
|
||||
{
|
||||
public static function createSelectOptions(): PreferenceOptions
|
||||
{
|
||||
return new PreferenceOptions(
|
||||
resolutions: ResolutionList::asSelectOptions(),
|
||||
codecs: CodecList::asSelectOptions(),
|
||||
languages: CountryLanguages::asSelectOptions(),
|
||||
providers: ProviderList::asSelectOptions(),
|
||||
qualities: QualityList::asSelectOptions(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ class UserPreferencesFactory
|
||||
public static function createFromUser(UserInterface $user): UserPreferences
|
||||
{
|
||||
return new UserPreferences(
|
||||
resolution: self::getNestedValue($user, 'resolution'),
|
||||
codec: self::getNestedValue($user, 'codec'),
|
||||
resolution: self::getValue($user, 'resolution'),
|
||||
codec: self::getValue($user, 'codec'),
|
||||
language: self::getValue($user, 'language'),
|
||||
provider: self::getValue($user, 'provider'),
|
||||
quality: self::getValue($user, 'quality'),
|
||||
@@ -29,19 +29,4 @@ class UserPreferencesFactory
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @param User $user */
|
||||
private static function getNestedValue(UserInterface $user, string $preferenceId): ?string
|
||||
{
|
||||
$preference = $user->getUserPreference($preferenceId);
|
||||
if (null === $preference) {
|
||||
return null;
|
||||
}
|
||||
return $preference->getPreference()
|
||||
->getPreferenceOptions()
|
||||
->filter(fn (PreferenceOption $option) => (string) $option->getId() === $preference->getPreferenceValue())
|
||||
->first()
|
||||
->getValue()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\User\Framework\Controller\Web;
|
||||
|
||||
use App\Base\Service\Broadcaster;
|
||||
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
|
||||
use App\User\Action\Handler\SaveUserDownloadPreferencesHandler;
|
||||
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
||||
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
|
||||
@@ -14,8 +15,10 @@ use App\User\Database\ProviderList;
|
||||
use App\User\Database\QualityList;
|
||||
use App\User\Dto\UserPreferencesFactory;
|
||||
use App\User\Framework\Form\GettingStartedFilterForm;
|
||||
use App\User\Framework\Form\UserMediaPreferencesForm;
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
@@ -29,53 +32,43 @@ class PreferencesController extends AbstractController
|
||||
#[Route('/user/preferences', 'app_user_preferences', methods: ['GET'])]
|
||||
public function mediaPreferences(): Response
|
||||
{
|
||||
$mediaPreferences = $this->getUser()->getMediaPreferences();
|
||||
$downloadPreferences = $this->getUser()->getDownloadPreferences();
|
||||
$languages = CountryLanguages::$languages;
|
||||
sort($languages);
|
||||
$formData = (array) UserPreferencesFactory::createFromUser($this->getUser());
|
||||
$form = $this->createForm(UserMediaPreferencesForm::class, $formData);
|
||||
|
||||
return $this->render(
|
||||
'user/preferences.html.twig',
|
||||
[
|
||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
||||
'languages' => $languages,
|
||||
'providers' => ProviderList::getProviders(),
|
||||
'qualities' => QualityList::getBaseQualities(),
|
||||
'mediaPreferences' => $mediaPreferences,
|
||||
'downloadPreferences' => $downloadPreferences,
|
||||
'filterForm' => $this->createForm(GettingStartedFilterForm::class, (array) UserPreferencesFactory::createFromUser($this->getUser())),
|
||||
'preferences_form' => $form,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Route('/user/preferences/media', 'app_save_media_preferences', methods: ['POST'])]
|
||||
public function saveMediaPreferences(
|
||||
SaveUserMediaPreferencesInput $input,
|
||||
SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler,
|
||||
#[Route('/user/preferences/media', 'app_user_media_preferences_submit', methods: ['POST'])]
|
||||
public function mediaPreferencesSubmit(
|
||||
Request $request,
|
||||
SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler
|
||||
): Response
|
||||
{
|
||||
$saveUserMediaPreferencesHandler->handle($input->toCommand());
|
||||
$mediaPreferences = $this->getUser()->getMediaPreferences();
|
||||
$downloadPreferences = $this->getUser()->getDownloadPreferences();
|
||||
$formData = (array) UserPreferencesFactory::createFromUser($this->getUser());
|
||||
$form = $this->createForm(UserMediaPreferencesForm::class, $formData);
|
||||
|
||||
$languages = CountryLanguages::$languages;
|
||||
sort($languages);
|
||||
$form->handleRequest($request);
|
||||
|
||||
$this->broadcaster->alert(
|
||||
title: 'Success',
|
||||
message: 'Your media preferences have been saved.'
|
||||
);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$saveUserMediaPreferencesHandler->handle(
|
||||
SaveUserMediaPreferencesCommand::fromUserMediaPreferencesForm($form)
|
||||
);
|
||||
$this->broadcaster->alert('Success', 'Your media preferences have been saved.');
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'user/preferences.html.twig',
|
||||
[
|
||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
||||
'languages' => $languages,
|
||||
'providers' => ProviderList::$providers,
|
||||
'qualities' => QualityList::getBaseQualities(),
|
||||
'mediaPreferences' => $mediaPreferences,
|
||||
'downloadPreferences' => $downloadPreferences,
|
||||
'filterForm' => $this->createForm(GettingStartedFilterForm::class ?? null),
|
||||
'preferences_form' => $form,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -86,11 +79,11 @@ class PreferencesController extends AbstractController
|
||||
SaveUserDownloadPreferencesHandler $saveUserDownloadPreferencesHandler,
|
||||
): Response
|
||||
{
|
||||
$downloadPreferences = $saveUserDownloadPreferencesHandler->handle($input->toCommand())->downloadPreferences;
|
||||
$mediaPreferences = $this->getUser()->getMediaPreferences();
|
||||
$downloadPreferences = $this->getUser()->getDownloadPreferences();
|
||||
$formData = (array) UserPreferencesFactory::createFromUser($this->getUser());
|
||||
$form = $this->createForm(UserMediaPreferencesForm::class, $formData);
|
||||
|
||||
$languages = CountryLanguages::$languages;
|
||||
sort($languages);
|
||||
$saveUserDownloadPreferencesHandler->handle($input->toCommand());
|
||||
|
||||
$this->broadcaster->alert(
|
||||
title: 'Success',
|
||||
@@ -100,12 +93,8 @@ class PreferencesController extends AbstractController
|
||||
return $this->render(
|
||||
'user/preferences.html.twig',
|
||||
[
|
||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
||||
'languages' => $languages,
|
||||
'providers' => ProviderList::getProviders(),
|
||||
'qualities' => QualityList::getBaseQualities(),
|
||||
'mediaPreferences' => $mediaPreferences,
|
||||
'downloadPreferences' => $downloadPreferences,
|
||||
'preferences_form' => $form,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,17 +26,6 @@ class Preference
|
||||
#[ORM\Column]
|
||||
private ?bool $enabled = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, PreferenceOption>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: PreferenceOption::class, mappedBy: 'preference', fetch: 'EAGER')]
|
||||
private Collection $preferenceOptions;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->preferenceOptions = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
@@ -94,34 +83,4 @@ class Preference
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, PreferenceOption>
|
||||
*/
|
||||
public function getPreferenceOptions(): Collection
|
||||
{
|
||||
return $this->preferenceOptions;
|
||||
}
|
||||
|
||||
public function addPreferenceOption(PreferenceOption $preferenceOption): static
|
||||
{
|
||||
if (!$this->preferenceOptions->contains($preferenceOption)) {
|
||||
$this->preferenceOptions->add($preferenceOption);
|
||||
$preferenceOption->setPreference($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removePreferenceOption(PreferenceOption $preferenceOption): static
|
||||
{
|
||||
if ($this->preferenceOptions->removeElement($preferenceOption)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($preferenceOption->getPreference() === $this) {
|
||||
$preferenceOption->setPreference(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Framework\Entity;
|
||||
|
||||
use App\User\Framework\Repository\PreferenceOptionRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Ignore;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PreferenceOptionRepository::class)]
|
||||
class PreferenceOption
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $value = null;
|
||||
|
||||
#[Ignore]
|
||||
#[ORM\ManyToOne(inversedBy: 'preferenceOptions')]
|
||||
private ?Preference $preference = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $enabled = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValue(): ?string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function setValue(?string $value): static
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreference(): ?Preference
|
||||
{
|
||||
return $this->preference;
|
||||
}
|
||||
|
||||
public function setPreference(?Preference $preference): static
|
||||
{
|
||||
$this->preference = $preference;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isEnabled(): ?bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
public function setEnabled(bool $enabled): static
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -215,11 +215,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
if (in_array($userPreference->getPreference()->getId(), ['language', 'provider', 'quality'])) {
|
||||
return $userPreference->getPreferenceValue();
|
||||
}
|
||||
foreach ($userPreference->getPreference()->getPreferenceOptions() as $preferenceOption) {
|
||||
if ($preferenceOption->getId() === (int) $userPreference->getPreferenceValue()) {
|
||||
return $preferenceOption->getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})
|
||||
->toArray();
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace App\User\Framework\Form;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\User\Database\CodecList;
|
||||
use App\User\Database\CountryLanguages;
|
||||
use App\User\Database\ProviderList;
|
||||
use App\User\Database\QualityList;
|
||||
use App\User\Framework\Repository\PreferenceOptionRepository;
|
||||
use App\User\Database\ResolutionList;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -14,17 +14,14 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class GettingStartedFilterForm 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'));
|
||||
$this->addChoiceField($builder, 'resolution', ResolutionList::asSelectOptions());
|
||||
$this->addChoiceField($builder, 'codec', CodecList::asSelectOptions());;
|
||||
}
|
||||
|
||||
private function addChoiceField(FormBuilderInterface $builder, string $fieldName, array $choices): void
|
||||
@@ -42,16 +39,6 @@ class GettingStartedFilterForm extends AbstractType
|
||||
$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' => null] + $choices;
|
||||
|
||||
56
src/User/Framework/Form/UserMediaPreferencesForm.php
Normal file
56
src/User/Framework/Form/UserMediaPreferencesForm.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Framework\Form;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\User\Database\CodecList;
|
||||
use App\User\Database\CountryLanguages;
|
||||
use App\User\Database\ProviderList;
|
||||
use App\User\Database\QualityList;
|
||||
use App\User\Database\ResolutionList;
|
||||
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;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
class UserMediaPreferencesForm extends AbstractType
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UrlGeneratorInterface $urlGenerator,
|
||||
) {}
|
||||
|
||||
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', ResolutionList::asSelectOptions());
|
||||
$this->addChoiceField($builder, 'codec', CodecList::asSelectOptions());
|
||||
}
|
||||
|
||||
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([
|
||||
'action' => $this->urlGenerator->generate('app_user_media_preferences_submit'),
|
||||
]);
|
||||
}
|
||||
|
||||
private function addDefaultChoice(array $choices): iterable
|
||||
{
|
||||
return ['n/a' => ''] + $choices;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Framework\Repository;
|
||||
|
||||
use App\User\Framework\Entity\PreferenceOption;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<PreferenceOption>
|
||||
*/
|
||||
class PreferenceOptionRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, PreferenceOption::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return PreferenceOption[] Returns an array of PreferenceOption objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('p')
|
||||
// ->andWhere('p.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('p.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?PreferenceOption
|
||||
// {
|
||||
// return $this->createQueryBuilder('p')
|
||||
// ->andWhere('p.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -10,6 +10,8 @@ module.exports = {
|
||||
"flex-row",
|
||||
"p-2",
|
||||
"p-4",
|
||||
"w-32",
|
||||
"w-64",
|
||||
"bg-blue-300",
|
||||
"bg-orange-300",
|
||||
"bg-fuchsia-300",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<li {{ attributes }} id="alert_{{ alert_id }}"
|
||||
class="alert alert-{{ type|default('success') }}"
|
||||
role="alert"
|
||||
role="alert"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<svg class="shrink-0 w-4 h-4 me-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
@@ -9,7 +9,7 @@
|
||||
<span class="sr-only">Info</span>
|
||||
<h3 class="text-lg font-medium font-bold">{{ title|default('') }}</h3>
|
||||
</div>
|
||||
<div class="mt-2 text-sm w-[350px] font-bold">
|
||||
<div class="mt-2 text-sm w-[300px] font-bold overflow-hidden text-wrap">
|
||||
{{ message }}
|
||||
</div>
|
||||
</li>
|
||||
@@ -15,10 +15,10 @@
|
||||
value="{{ app.user.userPreferenceValues["resolution"] }}"
|
||||
>
|
||||
<option value="">n/a</option>
|
||||
{% for option in this.preferences['resolution'] %}
|
||||
<option value="{{ option.value }}"
|
||||
{{ option.value == this.userPreferences['resolution'] ? 'selected' }}
|
||||
>{{ option.name }}</option>
|
||||
{% for name, value in this.resolutionOptions %}
|
||||
<option value="{{ value }}"
|
||||
{{ value == this.userPreferences['resolution'] ? 'selected' }}
|
||||
>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
@@ -26,10 +26,10 @@
|
||||
Codec
|
||||
<select id="codec" data-result-filter-target="codec" class="px-1 py-0.5 bg-stone-100 text-sm text-gray-800 rounded-md">
|
||||
<option value="">n/a</option>
|
||||
{% for option in this.preferences['codec'] %}
|
||||
<option value="{{ option.value }}"
|
||||
{{ option.value == this.userPreferences['codec'] ? 'selected' }}
|
||||
>{{ option.name }}</option>
|
||||
{% for name, value in this.codecOptions %}
|
||||
<option value="{{ value }}"
|
||||
{{ value == this.userPreferences['codec'] ? 'selected' }}
|
||||
>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div {{ turbo_stream_listen(app.session.get('mercure_alert_topic')) }} class="fixed z-40 top-10 right-10">
|
||||
<div {{ turbo_stream_listen(app.session.get('mercure_alert_topic')) }} class="fixed z-40 top-4 right-3 md:top-10 md:right-10">
|
||||
<div class="z-40">
|
||||
<ul id="alert_list" class="flex flex-col gap-2">
|
||||
{% for message in app.flashes('warning') %}
|
||||
|
||||
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 %}
|
||||
<div class="p-4 flex flex-col md:flex-row gap-2">
|
||||
<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>
|
||||
<form id="media_preferences" class="flex flex-col max-w-64" name="media_preferences" method="post" action="{{ path('app_save_media_preferences') }}">
|
||||
<label class="text-gray-50" for="quality">Quality</label>
|
||||
<select class="p-1.5 rounded-md mb-2" name="quality" id="quality" value="{{ mediaPreferences['quality'].getPreferenceValue() }}">
|
||||
<option class="text-gray-800"
|
||||
value=""
|
||||
{{ mediaPreferences['quality'].getPreferenceValue() is null ? "selected" }}
|
||||
>n/a</option>
|
||||
{% for quality in qualities %}
|
||||
<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>
|
||||
<p class="text-gray-50 mb-4">Define a filter to be pre-applied to your download options.</p>
|
||||
{{ form_start(preferences_form) }}
|
||||
{{ form_row(preferences_form.language) }}
|
||||
{{ form_row(preferences_form.quality) }}
|
||||
{{ form_row(preferences_form.provider) }}
|
||||
{{ form_row(preferences_form.resolution) }}
|
||||
{{ form_row(preferences_form.codec) }}
|
||||
<button class="submit-button">Save</button>
|
||||
{{ form_end(preferences_form) }}
|
||||
</twig:Card>
|
||||
|
||||
<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') }}">
|
||||
<div class="flex flex-row gap-2 mb-2">
|
||||
<input type="hidden" name="movie_folder" id="movie_folder_hidden" value="0" />
|
||||
|
||||
Reference in New Issue
Block a user