mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 23:18:10 +00:00
parent
ed9d03d0b8
commit
56638b26e8
28 changed files with 1067 additions and 346 deletions
172
app/Console/Commands/MashupCreateCommand.php
Normal file
172
app/Console/Commands/MashupCreateCommand.php
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Device;
|
||||||
|
use App\Models\Playlist;
|
||||||
|
use App\Models\PlaylistItem;
|
||||||
|
use App\Models\Plugin;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
use function Laravel\Prompts\select;
|
||||||
|
use function Laravel\Prompts\text;
|
||||||
|
|
||||||
|
class MashupCreateCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'mashup:create';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Create a new mashup and add it to a playlist';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// Select device
|
||||||
|
$device = $this->selectDevice();
|
||||||
|
if (! $device) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select playlist
|
||||||
|
$playlist = $this->selectPlaylist($device);
|
||||||
|
if (! $playlist) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select mashup layout
|
||||||
|
$layout = $this->selectLayout();
|
||||||
|
if (! $layout) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mashup name
|
||||||
|
$name = $this->getMashupName();
|
||||||
|
if (! $name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select plugins
|
||||||
|
$plugins = $this->selectPlugins($layout);
|
||||||
|
if ($plugins->isEmpty()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxOrder = $playlist->items()->max('order') ?? 0;
|
||||||
|
|
||||||
|
// Create playlist item with mashup
|
||||||
|
PlaylistItem::createMashup(
|
||||||
|
playlist: $playlist,
|
||||||
|
layout: $layout,
|
||||||
|
pluginIds: $plugins->pluck('id')->toArray(),
|
||||||
|
name: $name,
|
||||||
|
order: $maxOrder + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->info('Mashup created successfully!');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function selectDevice(): ?Device
|
||||||
|
{
|
||||||
|
$devices = Device::all();
|
||||||
|
if ($devices->isEmpty()) {
|
||||||
|
$this->error('No devices found. Please create a device first.');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$deviceId = select(
|
||||||
|
label: 'Select a device',
|
||||||
|
options: $devices->mapWithKeys(fn ($device) => [$device->id => $device->name])->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $devices->firstWhere('id', $deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function selectPlaylist(Device $device): ?Playlist
|
||||||
|
{
|
||||||
|
$playlists = $device->playlists;
|
||||||
|
if ($playlists->isEmpty()) {
|
||||||
|
$this->error('No playlists found for this device. Please create a playlist first.');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$playlistId = select(
|
||||||
|
label: 'Select a playlist',
|
||||||
|
options: $playlists->mapWithKeys(fn ($playlist) => [$playlist->id => $playlist->name])->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $playlists->firstWhere('id', $playlistId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function selectLayout(): ?string
|
||||||
|
{
|
||||||
|
return select(
|
||||||
|
label: 'Select a layout',
|
||||||
|
options: PlaylistItem::getAvailableLayouts()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMashupName(): ?string
|
||||||
|
{
|
||||||
|
return text(
|
||||||
|
label: 'Enter a name for this mashup',
|
||||||
|
required: true,
|
||||||
|
default: 'Mashup',
|
||||||
|
validate: fn (string $value) => match (true) {
|
||||||
|
strlen($value) < 1 => 'The name must be at least 2 characters.',
|
||||||
|
strlen($value) > 50 => 'The name must not exceed 50 characters.',
|
||||||
|
default => null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function selectPlugins(string $layout): Collection
|
||||||
|
{
|
||||||
|
$requiredCount = PlaylistItem::getRequiredPluginCountForLayout($layout);
|
||||||
|
|
||||||
|
$plugins = Plugin::all();
|
||||||
|
if ($plugins->isEmpty()) {
|
||||||
|
$this->error('No plugins found. Please create some plugins first.');
|
||||||
|
|
||||||
|
return collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectedPlugins = collect();
|
||||||
|
$availablePlugins = $plugins->mapWithKeys(fn ($plugin) => [$plugin->id => $plugin->name])->toArray();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $requiredCount; $i++) {
|
||||||
|
$position = match ($i) {
|
||||||
|
0 => 'first',
|
||||||
|
1 => 'second',
|
||||||
|
2 => 'third',
|
||||||
|
3 => 'fourth',
|
||||||
|
default => ($i + 1).'th'
|
||||||
|
};
|
||||||
|
|
||||||
|
$pluginId = select(
|
||||||
|
label: "Select the $position plugin",
|
||||||
|
options: $availablePlugins
|
||||||
|
);
|
||||||
|
|
||||||
|
$selectedPlugins->push($plugins->firstWhere('id', $pluginId));
|
||||||
|
unset($availablePlugins[$pluginId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $selectedPlugins;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ class PlaylistItem extends Model
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'is_active' => 'boolean',
|
'is_active' => 'boolean',
|
||||||
'last_displayed_at' => 'datetime',
|
'last_displayed_at' => 'datetime',
|
||||||
|
'mashup' => 'json',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function playlist(): BelongsTo
|
public function playlist(): BelongsTo
|
||||||
|
|
@ -26,4 +27,179 @@ class PlaylistItem extends Model
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Plugin::class);
|
return $this->belongsTo(Plugin::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this playlist item is a mashup
|
||||||
|
*/
|
||||||
|
public function isMashup(): bool
|
||||||
|
{
|
||||||
|
return ! is_null($this->mashup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mashup name if this is a mashup
|
||||||
|
*/
|
||||||
|
public function getMashupName(): ?string
|
||||||
|
{
|
||||||
|
return $this->mashup['mashup_name'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mashup layout type if this is a mashup
|
||||||
|
*/
|
||||||
|
public function getMashupLayoutType(): ?string
|
||||||
|
{
|
||||||
|
return $this->mashup['mashup_layout'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all plugin IDs for this mashup
|
||||||
|
*/
|
||||||
|
public function getMashupPluginIds(): array
|
||||||
|
{
|
||||||
|
return $this->mashup['plugin_ids'] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of plugins required for the current layout
|
||||||
|
*/
|
||||||
|
public function getRequiredPluginCount(): int
|
||||||
|
{
|
||||||
|
if (! $this->isMashup()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($this->getMashupLayoutType()) {
|
||||||
|
'1Lx1R', '1Tx1B' => 2, // Left-Right or Top-Bottom split
|
||||||
|
'1Lx2R', '2Lx1R', '2Tx1B', '1Tx2B' => 3, // Two on one side, one on other
|
||||||
|
'2x2' => 4, // Quadrant
|
||||||
|
default => 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the layout type (horizontal, vertical, or grid)
|
||||||
|
*/
|
||||||
|
public function getLayoutType(): string
|
||||||
|
{
|
||||||
|
if (! $this->isMashup()) {
|
||||||
|
return 'single';
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($this->getMashupLayoutType()) {
|
||||||
|
'1Lx1R', '1Lx2R', '2Lx1R' => 'vertical',
|
||||||
|
'1Tx1B', '2Tx1B', '1Tx2B' => 'horizontal',
|
||||||
|
'2x2' => 'grid',
|
||||||
|
default => 'single',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the layout size for a plugin based on its position
|
||||||
|
*/
|
||||||
|
public function getLayoutSize(int $position = 0): string
|
||||||
|
{
|
||||||
|
if (! $this->isMashup()) {
|
||||||
|
return 'full';
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($this->getMashupLayoutType()) {
|
||||||
|
'1Lx1R' => 'half_vertical', // Both sides are single plugins
|
||||||
|
'1Tx1B' => 'half_horizontal', // Both sides are single plugins
|
||||||
|
'2Lx1R' => match ($position) {
|
||||||
|
0, 1 => 'quadrant', // Left side has 2 plugins
|
||||||
|
2 => 'half_vertical', // Right side has 1 plugin
|
||||||
|
default => 'full'
|
||||||
|
},
|
||||||
|
'1Lx2R' => match ($position) {
|
||||||
|
0 => 'half_vertical', // Left side has 1 plugin
|
||||||
|
1, 2 => 'quadrant', // Right side has 2 plugins
|
||||||
|
default => 'full'
|
||||||
|
},
|
||||||
|
'2Tx1B' => match ($position) {
|
||||||
|
0, 1 => 'quadrant', // Top side has 2 plugins
|
||||||
|
2 => 'half_horizontal', // Bottom side has 1 plugin
|
||||||
|
default => 'full'
|
||||||
|
},
|
||||||
|
'1Tx2B' => match ($position) {
|
||||||
|
0 => 'half_horizontal', // Top side has 1 plugin
|
||||||
|
1, 2 => 'quadrant', // Bottom side has 2 plugins
|
||||||
|
default => 'full'
|
||||||
|
},
|
||||||
|
'2x2' => 'quadrant', // All positions are quadrants
|
||||||
|
default => 'full'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render all plugins with appropriate layout
|
||||||
|
*/
|
||||||
|
public function render(): string
|
||||||
|
{
|
||||||
|
if (! $this->isMashup()) {
|
||||||
|
return view('trmnl-layouts.single', [
|
||||||
|
'slot' => $this->plugin->render('full', false),
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pluginMarkups = [];
|
||||||
|
$plugins = Plugin::whereIn('id', $this->getMashupPluginIds())->get();
|
||||||
|
|
||||||
|
foreach ($plugins as $index => $plugin) {
|
||||||
|
$size = $this->getLayoutSize($index);
|
||||||
|
$pluginMarkups[] = $plugin->render($size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('trmnl-layouts.mashup', [
|
||||||
|
'mashupLayout' => $this->getMashupLayoutType(),
|
||||||
|
'slot' => implode('', $pluginMarkups),
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available mashup layouts with their descriptions
|
||||||
|
*/
|
||||||
|
public static function getAvailableLayouts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'1Lx1R' => '1 Left - 1 Right (2 plugins)',
|
||||||
|
'1Lx2R' => '1 Left - 2 Right (3 plugins)',
|
||||||
|
'2Lx1R' => '2 Left - 1 Right (3 plugins)',
|
||||||
|
'1Tx1B' => '1 Top - 1 Bottom (2 plugins)',
|
||||||
|
'2Tx1B' => '2 Top - 1 Bottom (3 plugins)',
|
||||||
|
'1Tx2B' => '1 Top - 2 Bottom (3 plugins)',
|
||||||
|
'2x2' => 'Quadrant (4 plugins)',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required number of plugins for a given layout
|
||||||
|
*/
|
||||||
|
public static function getRequiredPluginCountForLayout(string $layout): int
|
||||||
|
{
|
||||||
|
return match ($layout) {
|
||||||
|
'1Lx1R', '1Tx1B' => 2,
|
||||||
|
'1Lx2R', '2Lx1R', '2Tx1B', '1Tx2B' => 3,
|
||||||
|
'2x2' => 4,
|
||||||
|
default => 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new mashup with the given layout and plugins
|
||||||
|
*/
|
||||||
|
public static function createMashup(Playlist $playlist, string $layout, array $pluginIds, string $name, $order): self
|
||||||
|
{
|
||||||
|
return static::create([
|
||||||
|
'playlist_id' => $playlist->id,
|
||||||
|
'plugin_id' => $pluginIds[0], // First plugin is the main plugin
|
||||||
|
'mashup' => [
|
||||||
|
'mashup_layout' => $layout,
|
||||||
|
'mashup_name' => $name,
|
||||||
|
'plugin_ids' => $pluginIds,
|
||||||
|
],
|
||||||
|
'is_active' => true,
|
||||||
|
'order' => $order,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Blade;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
|
@ -65,4 +66,38 @@ class Plugin extends Model
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the plugin's markup
|
||||||
|
*/
|
||||||
|
public function render(string $size = 'full', bool $standalone = true): string
|
||||||
|
{
|
||||||
|
if ($this->render_markup) {
|
||||||
|
if ($standalone) {
|
||||||
|
return view('trmnl-layouts.single', [
|
||||||
|
'slot' => Blade::render($this->render_markup, ['size' => $size, 'data' => $this->data_payload]),
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Blade::render($this->render_markup, ['size' => $size, 'data' => $this->data_payload]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->render_markup_view) {
|
||||||
|
if ($standalone) {
|
||||||
|
return view('trmnl-layouts.single', [
|
||||||
|
'slot' => view($this->render_markup_view, [
|
||||||
|
'size' => $size,
|
||||||
|
'data' => $this->data_payload,
|
||||||
|
])->render(),
|
||||||
|
])->render();
|
||||||
|
} else {
|
||||||
|
return view($this->render_markup_view, [
|
||||||
|
'size' => $size,
|
||||||
|
'data' => $this->data_payload,
|
||||||
|
])->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<p>No render markup yet defined for this plugin.</p>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"ext-imagick": "*",
|
"ext-imagick": "*",
|
||||||
"bnussbau/laravel-trmnl-blade": "1.0.*",
|
"bnussbau/laravel-trmnl-blade": "1.1.*",
|
||||||
"intervention/image": "^3.11",
|
"intervention/image": "^3.11",
|
||||||
"keepsuit/laravel-liquid": "^0.5.2",
|
"keepsuit/laravel-liquid": "^0.5.2",
|
||||||
"laravel/framework": "^12.1",
|
"laravel/framework": "^12.1",
|
||||||
|
|
|
||||||
39
composer.lock
generated
39
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "abffc30d88cd79c676be64cb30b8cfb1",
|
"content-hash": "63075a49e79059d81034658d332d9dd8",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-crt-php",
|
"name": "aws/aws-crt-php",
|
||||||
|
|
@ -62,16 +62,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.343.24",
|
"version": "3.344.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
"reference": "5308e15ca92655906d04d5945613ab9046b4f79f"
|
"reference": "3a6aaaea75f4605f89aa57ad63b9a077bf01e1e5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5308e15ca92655906d04d5945613ab9046b4f79f",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3a6aaaea75f4605f89aa57ad63b9a077bf01e1e5",
|
||||||
"reference": "5308e15ca92655906d04d5945613ab9046b4f79f",
|
"reference": "3a6aaaea75f4605f89aa57ad63b9a077bf01e1e5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -153,22 +153,22 @@
|
||||||
"support": {
|
"support": {
|
||||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.343.24"
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.344.2"
|
||||||
},
|
},
|
||||||
"time": "2025-06-03T18:04:18+00:00"
|
"time": "2025-06-06T18:14:42+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bnussbau/laravel-trmnl-blade",
|
"name": "bnussbau/laravel-trmnl-blade",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bnussbau/laravel-trmnl-blade.git",
|
"url": "https://github.com/bnussbau/laravel-trmnl-blade.git",
|
||||||
"reference": "9e23a83c2dbb33286d0940c5282eaa8b142cd218"
|
"reference": "f57a7e2f855d882364e9ce2bb1a239b9387cdd75"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/bnussbau/laravel-trmnl-blade/zipball/9e23a83c2dbb33286d0940c5282eaa8b142cd218",
|
"url": "https://api.github.com/repos/bnussbau/laravel-trmnl-blade/zipball/f57a7e2f855d882364e9ce2bb1a239b9387cdd75",
|
||||||
"reference": "9e23a83c2dbb33286d0940c5282eaa8b142cd218",
|
"reference": "f57a7e2f855d882364e9ce2bb1a239b9387cdd75",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -223,7 +223,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/bnussbau/laravel-trmnl-blade/issues",
|
"issues": "https://github.com/bnussbau/laravel-trmnl-blade/issues",
|
||||||
"source": "https://github.com/bnussbau/laravel-trmnl-blade/tree/1.0.0"
|
"source": "https://github.com/bnussbau/laravel-trmnl-blade/tree/1.1.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -235,7 +235,7 @@
|
||||||
"type": "custom"
|
"type": "custom"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-06-04T15:52:22+00:00"
|
"time": "2025-06-10T13:05:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
|
|
@ -7571,16 +7571,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pail",
|
"name": "laravel/pail",
|
||||||
"version": "v1.2.2",
|
"version": "v1.2.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/pail.git",
|
"url": "https://github.com/laravel/pail.git",
|
||||||
"reference": "f31f4980f52be17c4667f3eafe034e6826787db2"
|
"reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2",
|
"url": "https://api.github.com/repos/laravel/pail/zipball/8cc3d575c1f0e57eeb923f366a37528c50d2385a",
|
||||||
"reference": "f31f4980f52be17c4667f3eafe034e6826787db2",
|
"reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -7600,7 +7600,7 @@
|
||||||
"orchestra/testbench-core": "^8.13|^9.0|^10.0",
|
"orchestra/testbench-core": "^8.13|^9.0|^10.0",
|
||||||
"pestphp/pest": "^2.20|^3.0",
|
"pestphp/pest": "^2.20|^3.0",
|
||||||
"pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
|
"pestphp/pest-plugin-type-coverage": "^2.3|^3.0",
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.12.27",
|
||||||
"symfony/var-dumper": "^6.3|^7.0"
|
"symfony/var-dumper": "^6.3|^7.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
|
@ -7636,6 +7636,7 @@
|
||||||
"description": "Easily delve into your Laravel application's log files directly from the command line.",
|
"description": "Easily delve into your Laravel application's log files directly from the command line.",
|
||||||
"homepage": "https://github.com/laravel/pail",
|
"homepage": "https://github.com/laravel/pail",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
"dev",
|
||||||
"laravel",
|
"laravel",
|
||||||
"logs",
|
"logs",
|
||||||
"php",
|
"php",
|
||||||
|
|
@ -7645,7 +7646,7 @@
|
||||||
"issues": "https://github.com/laravel/pail/issues",
|
"issues": "https://github.com/laravel/pail/issues",
|
||||||
"source": "https://github.com/laravel/pail"
|
"source": "https://github.com/laravel/pail"
|
||||||
},
|
},
|
||||||
"time": "2025-01-28T15:15:15+00:00"
|
"time": "2025-06-05T13:55:57+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pint",
|
"name": "laravel/pint",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class PlaylistItemFactory extends Factory
|
||||||
return [
|
return [
|
||||||
'playlist_id' => Playlist::factory(),
|
'playlist_id' => Playlist::factory(),
|
||||||
'plugin_id' => Plugin::factory(),
|
'plugin_id' => Plugin::factory(),
|
||||||
|
'mashup' => null,
|
||||||
'order' => $this->faker->numberBetween(0, 100),
|
'order' => $this->faker->numberBetween(0, 100),
|
||||||
'is_active' => $this->faker->boolean(80), // 80% chance of being active
|
'is_active' => $this->faker->boolean(80), // 80% chance of being active
|
||||||
'last_displayed_at' => null,
|
'last_displayed_at' => null,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('playlist_items', function (Blueprint $table) {
|
||||||
|
$table->json('mashup')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('playlist_items', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('mashup');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -34,6 +34,7 @@ class DatabaseSeeder extends Seeder
|
||||||
|
|
||||||
$this->call([
|
$this->call([
|
||||||
ExampleRecipesSeeder::class,
|
ExampleRecipesSeeder::class,
|
||||||
|
MashupPocSeeder::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
database/seeders/MashupPocSeeder.php
Normal file
50
database/seeders/MashupPocSeeder.php
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Playlist;
|
||||||
|
use App\Models\PlaylistItem;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class MashupPocSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// Create a playlist
|
||||||
|
$playlist = Playlist::create([
|
||||||
|
'device_id' => 1,
|
||||||
|
'name' => 'Mashup Test Playlist',
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create a playlist item with 1Tx1B layout using the new JSON structure
|
||||||
|
PlaylistItem::createMashup(
|
||||||
|
playlist: $playlist,
|
||||||
|
layout: '1Tx1B',
|
||||||
|
pluginIds: [2, 3], // Top and bottom plugins
|
||||||
|
name: 'Mashup 1Tx1B',
|
||||||
|
order: 1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create another playlist item with 2x2 layout
|
||||||
|
PlaylistItem::createMashup(
|
||||||
|
playlist: $playlist,
|
||||||
|
layout: '1Lx1R',
|
||||||
|
pluginIds: [2, 6], // All four quadrants
|
||||||
|
name: 'Mashup Quadrant',
|
||||||
|
order: 2
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a single plugin item (no mashup)
|
||||||
|
PlaylistItem::create([
|
||||||
|
'playlist_id' => $playlist->id,
|
||||||
|
'plugin_id' => 1,
|
||||||
|
'mashup' => null,
|
||||||
|
'is_active' => true,
|
||||||
|
'order' => 3,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
resources/views/flux/icon/mashup-1Lx1R.blade.php
Normal file
39
resources/views/flux/icon/mashup-1Lx1R.blade.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect width="36.5" height="44" rx="3"/>
|
||||||
|
<rect x="39.5" width="36.5" height="44" rx="3"/>
|
||||||
|
</svg>
|
||||||
40
resources/views/flux/icon/mashup-1Lx2R.blade.php
Normal file
40
resources/views/flux/icon/mashup-1Lx2R.blade.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect width="36.5" height="44" rx="3"/>
|
||||||
|
<rect x="39.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
<rect x="39.5" y="23.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
</svg>
|
||||||
39
resources/views/flux/icon/mashup-1Tx1B.blade.php
Normal file
39
resources/views/flux/icon/mashup-1Tx1B.blade.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect y="23.5" width="76" height="20.5" rx="3"/>
|
||||||
|
<rect width="76" height="20.5" rx="3"/>
|
||||||
|
</svg>
|
||||||
38
resources/views/flux/icon/mashup-1x1.blade.php
Normal file
38
resources/views/flux/icon/mashup-1x1.blade.php
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect width="76" height="44" rx="3"/>
|
||||||
|
</svg>
|
||||||
40
resources/views/flux/icon/mashup-2Lx1R.blade.php
Normal file
40
resources/views/flux/icon/mashup-2Lx1R.blade.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect x="39.5" width="36.5" height="44" rx="3"/>
|
||||||
|
<rect width="36.5" height="20.5" rx="3"/>
|
||||||
|
<rect y="23.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
</svg>
|
||||||
41
resources/views/flux/icon/mashup-2x2.blade.php
Normal file
41
resources/views/flux/icon/mashup-2x2.blade.php
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{{-- Credit: Lucide (https://lucide.dev) --}}
|
||||||
|
|
||||||
|
@props([
|
||||||
|
'variant' => 'outline',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$classes = Flux::classes('shrink-0')
|
||||||
|
->add(match($variant) {
|
||||||
|
'outline' => '[:where(&)]:size-6',
|
||||||
|
'solid' => '[:where(&)]:size-6',
|
||||||
|
'mini' => '[:where(&)]:size-5',
|
||||||
|
'micro' => '[:where(&)]:size-4',
|
||||||
|
});
|
||||||
|
|
||||||
|
$strokeWidth = match ($variant) {
|
||||||
|
'outline' => 2,
|
||||||
|
'mini' => 2.25,
|
||||||
|
'micro' => 2.5,
|
||||||
|
default => 2,
|
||||||
|
};
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{{ $attributes->class($classes) }}
|
||||||
|
data-flux-icon
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 76 44"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="{{ $strokeWidth }}"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-slot="icon"
|
||||||
|
>
|
||||||
|
<rect x="39.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
<rect x="39.5" y="23.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
<rect width="36.5" height="20.5" rx="3"/>
|
||||||
|
<rect y="23.5" width="36.5" height="20.5" rx="3"/>
|
||||||
|
</svg>
|
||||||
|
|
@ -195,7 +195,19 @@ new class extends Component {
|
||||||
@foreach($playlist->items->sortBy('order') as $item)
|
@foreach($playlist->items->sortBy('order') as $item)
|
||||||
<tr data-flux-row>
|
<tr data-flux-row>
|
||||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300">
|
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300">
|
||||||
{{ $item->plugin->name }}
|
@if($item->isMashup())
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div>
|
||||||
|
<div class="font-medium">{{ $item->getMashupName() }}</div>
|
||||||
|
<div class="text-xs text-zinc-500 dark:text-zinc-400">
|
||||||
|
<flux:icon name="mashup-{{ $item->getMashupLayoutType() }}" class="inline-block pb-1" variant="mini" />
|
||||||
|
{{ collect($item->getMashupPluginIds())->map(fn($id) => App\Models\Plugin::find($id)->name)->join(' | ') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="font-medium">{{ $item->plugin->name }}</div>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300">
|
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300">
|
||||||
<flux:switch wire:model.live="item.is_active"
|
<flux:switch wire:model.live="item.is_active"
|
||||||
|
|
@ -219,8 +231,20 @@ new class extends Component {
|
||||||
|
|
||||||
<flux:modal name="delete-playlist-item-{{ $item->id }}" class="min-w-[22rem] space-y-6">
|
<flux:modal name="delete-playlist-item-{{ $item->id }}" class="min-w-[22rem] space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<flux:heading size="lg">Delete {{ $item->plugin->name }}?</flux:heading>
|
<flux:heading size="lg">
|
||||||
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">This will remove this item from the playlist.</p>
|
@if($item->isMashup())
|
||||||
|
Delete {{ $item->getMashupName() }}?
|
||||||
|
@else
|
||||||
|
Delete {{ $item->plugin->name }}?
|
||||||
|
@endif
|
||||||
|
</flux:heading>
|
||||||
|
<p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
|
||||||
|
@if($item->isMashup())
|
||||||
|
This will remove this mashup from the playlist.
|
||||||
|
@else
|
||||||
|
This will remove this item from the playlist.
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ new class extends Component {
|
||||||
'plugin_id' => $this->plugin->id,
|
'plugin_id' => $this->plugin->id,
|
||||||
'order' => $maxOrder + 1,
|
'order' => $maxOrder + 1,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->reset(['checked_devices', 'playlist_name', 'selected_weekdays', 'active_from', 'active_until', 'selected_playlist']);
|
$this->reset(['checked_devices', 'playlist_name', 'selected_weekdays', 'active_from', 'active_until', 'selected_playlist']);
|
||||||
|
|
@ -200,16 +201,12 @@ HTML;
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderPreview(): void
|
public function renderPreview($size = 'full'): void
|
||||||
{
|
{
|
||||||
abort_unless(auth()->user()->plugins->contains($this->plugin), 403);
|
abort_unless(auth()->user()->plugins->contains($this->plugin), 403);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->plugin->render_markup_view) {
|
$previewMarkup = $this->plugin->render($size);
|
||||||
$previewMarkup = view($this->plugin->render_markup_view, ['data' => $this->plugin->data_payload])->render();
|
|
||||||
} else {
|
|
||||||
$previewMarkup = Blade::render($this->plugin->render_markup, ['data' => $this->plugin->data_payload]);
|
|
||||||
}
|
|
||||||
$this->dispatch('preview-updated', preview: $previewMarkup);
|
$this->dispatch('preview-updated', preview: $previewMarkup);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->dispatch('preview-error', message: $e->getMessage());
|
$this->dispatch('preview-error', message: $e->getMessage());
|
||||||
|
|
@ -237,6 +234,27 @@ HTML;
|
||||||
<flux:modal.trigger name="preview-plugin">
|
<flux:modal.trigger name="preview-plugin">
|
||||||
<flux:button icon="eye" wire:click="renderPreview">Preview</flux:button>
|
<flux:button icon="eye" wire:click="renderPreview">Preview</flux:button>
|
||||||
</flux:modal.trigger>
|
</flux:modal.trigger>
|
||||||
|
<flux:dropdown>
|
||||||
|
<flux:button icon="chevron-down"></flux:button>
|
||||||
|
<flux:menu>
|
||||||
|
<flux:modal.trigger name="preview-plugin">
|
||||||
|
<flux:menu.item icon="mashup-1Tx1B" wire:click="renderPreview('half_horizontal')">Half-Horizontal
|
||||||
|
</flux:menu.item>
|
||||||
|
</flux:modal.trigger>
|
||||||
|
|
||||||
|
<flux:modal.trigger name="preview-plugin">
|
||||||
|
<flux:menu.item icon="mashup-1Lx1R" wire:click="renderPreview('half_vertical')">Half-Vertical
|
||||||
|
</flux:menu.item>
|
||||||
|
</flux:modal.trigger>
|
||||||
|
|
||||||
|
<flux:modal.trigger name="preview-plugin">
|
||||||
|
<flux:menu.item icon="mashup-2x2" wire:click="renderPreview('quadrant')">Quadrant</flux:menu.item>
|
||||||
|
</flux:modal.trigger>
|
||||||
|
</flux:menu>
|
||||||
|
</flux:dropdown>
|
||||||
|
|
||||||
|
</flux:button.group>
|
||||||
|
<flux:button.group>
|
||||||
<flux:modal.trigger name="add-to-playlist">
|
<flux:modal.trigger name="add-to-playlist">
|
||||||
<flux:button icon="play" variant="primary">Add to Playlist</flux:button>
|
<flux:button icon="play" variant="primary">Add to Playlist</flux:button>
|
||||||
</flux:modal.trigger>
|
</flux:modal.trigger>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<div class="view view--{{ size }}">
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
|
||||||
<link href="https://fonts.bunny.net/css?family=Inter:300,400,500" rel="stylesheet"/>
|
|
||||||
<link rel="stylesheet" href="https://usetrmnl.com/css/latest/plugins.css">
|
|
||||||
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>
|
|
||||||
<title>plugin</title>
|
|
||||||
<style>
|
|
||||||
.trmnl .content .description {
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="environment trmnl">
|
|
||||||
<div class="screen">
|
|
||||||
<div class="view view--full">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column"
|
<div class="column"
|
||||||
|
|
@ -74,6 +55,3 @@
|
||||||
<span class="instance">{{ data.metadata.current_date }}</span>
|
<span class="instance">{{ data.metadata.current_date }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
});
|
});
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<x-trmnl::view>
|
@props(['size' => 'full'])
|
||||||
|
<x-trmnl::view size="{{$size}}">
|
||||||
<x-trmnl::layout class="layout--col gap--space-between">
|
<x-trmnl::layout class="layout--col gap--space-between">
|
||||||
@if($weatherEntity)
|
@if($weatherEntity)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,7 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
|
||||||
<link href="https://fonts.bunny.net/css?family=Inter:300,400,500" rel="stylesheet"/>
|
|
||||||
<link rel="stylesheet" href="https://usetrmnl.com/css/latest/plugins.css">
|
|
||||||
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>
|
|
||||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1/dist/chartkick.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1/dist/chartkick.min.js"></script>
|
||||||
<title>plugin</title>
|
|
||||||
<style>
|
<div class="view view--{{ size }}">
|
||||||
.trmnl .content .description {
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="environment trmnl">
|
|
||||||
<div class="screen">
|
|
||||||
<div class="view view--full">
|
|
||||||
<div class="layout layout--col gap--space-between">
|
<div class="layout layout--col gap--space-between">
|
||||||
<!-- Current Pollen Stats -->
|
<!-- Current Pollen Stats -->
|
||||||
<div class="grid grid--cols-5">
|
<div class="grid grid--cols-5">
|
||||||
|
|
@ -68,7 +52,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="title_bar">
|
<div class="title_bar">
|
||||||
<svg width="30px" fill="currentColor" xmlns="http://www.w3.org/2000/svg" id="mdi-flower-pollen" viewBox="0 0 24 24"><path d="M18.4 12.75C18.4 11.37 17.28 10.25 15.9 10.25C15.37 10.25 14.88 10.41 14.5 10.69V10.5C14.5 9.12 13.38 8 12 8S9.5 9.12 9.5 10.5V10.69C9.12 10.41 8.63 10.25 8.1 10.25C6.72 10.25 5.6 11.37 5.6 12.75C5.6 13.74 6.19 14.6 7.03 15C6.19 15.4 5.6 16.25 5.6 17.25C5.6 18.63 6.72 19.75 8.1 19.75C8.63 19.75 9.12 19.58 9.5 19.31V19.5C9.5 20.88 10.62 22 12 22S14.5 20.88 14.5 19.5V19.31C14.88 19.58 15.37 19.75 15.9 19.75C17.28 19.75 18.4 18.63 18.4 17.25C18.4 16.25 17.81 15.4 16.97 15C17.81 14.6 18.4 13.74 18.4 12.75M12 17.5C10.62 17.5 9.5 16.38 9.5 15S10.62 12.5 12 12.5 14.5 13.62 14.5 15 13.38 17.5 12 17.5M11 6C11 5.45 11.45 5 12 5S13 5.45 13 6 12.55 7 12 7 11 6.55 11 6M7 8C7 7.45 7.45 7 8 7S9 7.45 9 8 8.55 9 8 9 7 8.55 7 8M5 6C4.45 6 4 5.55 4 5S4.45 4 5 4 6 4.45 6 5 5.55 6 5 6M8 3C8 2.45 8.45 2 9 2S10 2.45 10 3 9.55 4 9 4 8 3.55 8 3M14 3C14 2.45 14.45 2 15 2S16 2.45 16 3 15.55 4 15 4 14 3.55 14 3M20 5C20 5.55 19.55 6 19 6S18 5.55 18 5 18.45 4 19 4 20 4.45 20 5M16 7C16.55 7 17 7.45 17 8S16.55 9 16 9 15 8.55 15 8 15.45 7 16 7Z"></path></svg>
|
<svg width="30px" fill="currentColor" xmlns="http://www.w3.org/2000/svg" id="mdi-flower-pollen"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
d="M18.4 12.75C18.4 11.37 17.28 10.25 15.9 10.25C15.37 10.25 14.88 10.41 14.5 10.69V10.5C14.5 9.12 13.38 8 12 8S9.5 9.12 9.5 10.5V10.69C9.12 10.41 8.63 10.25 8.1 10.25C6.72 10.25 5.6 11.37 5.6 12.75C5.6 13.74 6.19 14.6 7.03 15C6.19 15.4 5.6 16.25 5.6 17.25C5.6 18.63 6.72 19.75 8.1 19.75C8.63 19.75 9.12 19.58 9.5 19.31V19.5C9.5 20.88 10.62 22 12 22S14.5 20.88 14.5 19.5V19.31C14.88 19.58 15.37 19.75 15.9 19.75C17.28 19.75 18.4 18.63 18.4 17.25C18.4 16.25 17.81 15.4 16.97 15C17.81 14.6 18.4 13.74 18.4 12.75M12 17.5C10.62 17.5 9.5 16.38 9.5 15S10.62 12.5 12 12.5 14.5 13.62 14.5 15 13.38 17.5 12 17.5M11 6C11 5.45 11.45 5 12 5S13 5.45 13 6 12.55 7 12 7 11 6.55 11 6M7 8C7 7.45 7.45 7 8 7S9 7.45 9 8 8.55 9 8 9 7 8.55 7 8M5 6C4.45 6 4 5.55 4 5S4.45 4 5 4 6 4.45 6 5 5.55 6 5 6M8 3C8 2.45 8.45 2 9 2S10 2.45 10 3 9.55 4 9 4 8 3.55 8 3M14 3C14 2.45 14.45 2 15 2S16 2.45 16 3 15.55 4 15 4 14 3.55 14 3M20 5C20 5.55 19.55 6 19 6S18 5.55 18 5 18.45 4 19 4 20 4.45 20 5M16 7C16.55 7 17 7.45 17 8S16.55 9 16 9 15 8.55 15 8 15.45 7 16 7Z"></path>
|
||||||
|
</svg>
|
||||||
<span class="title">Pollen Forecast Vienna</span>
|
<span class="title">Pollen Forecast Vienna</span>
|
||||||
<span class="instance">Data provided by: Open-Meteo.com</span>
|
<span class="instance">Data provided by: Open-Meteo.com</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -177,6 +165,3 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<div class="view view--{{ size }}">
|
||||||
<html lang="de">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
|
||||||
<link href="https://fonts.bunny.net/css?family=Inter:300,400,500" rel="stylesheet"/>
|
|
||||||
<link rel="stylesheet" href="https://usetrmnl.com/css/latest/plugins.css">
|
|
||||||
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>
|
|
||||||
<title>plugin</title>
|
|
||||||
<style>
|
|
||||||
.trmnl .content .description {
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="environment trmnl">
|
|
||||||
<div class="screen">
|
|
||||||
<div class="view view--full">
|
|
||||||
<div class="layout layout--col gap--space-between">
|
<div class="layout layout--col gap--space-between">
|
||||||
<!-- Top row: 2 columns -->
|
<!-- Top row: 2 columns -->
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
|
|
@ -38,7 +21,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if size == 'full' or size == 'half_vertical' %}
|
||||||
<!-- Bottom row: 2 columns -->
|
<!-- Bottom row: 2 columns -->
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<!-- Day Progress - Left column -->
|
<!-- Day Progress - Left column -->
|
||||||
|
|
@ -58,12 +41,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<!-- Title Bar -->
|
<!-- Title Bar -->
|
||||||
<div class="title_bar">
|
<div class="title_bar">
|
||||||
<span class="title">Sunrise & Sunset</span>
|
<span class="title">Sunrise & Sunset</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<x-trmnl::view>
|
@props(['size' => 'full'])
|
||||||
|
<x-trmnl::view size="{{$size}}">
|
||||||
<x-trmnl::layout>
|
<x-trmnl::layout>
|
||||||
<x-trmnl::table>
|
<x-trmnl::table>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<x-trmnl::view>
|
@props(['size' => 'full'])
|
||||||
|
<x-trmnl::view size="{{$size}}">
|
||||||
<x-trmnl::layout>
|
<x-trmnl::layout>
|
||||||
<x-trmnl::table>
|
<x-trmnl::table>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -28,7 +29,7 @@
|
||||||
</td>
|
</td>
|
||||||
@if($journey['isCancelled'])
|
@if($journey['isCancelled'])
|
||||||
<td>
|
<td>
|
||||||
<x-trmnl::label variant="inverted">Cancelled</x-trmnl::label>
|
<x-trmnl::label variant="inverted">Ausfall</x-trmnl::label>
|
||||||
</td>
|
</td>
|
||||||
@else
|
@else
|
||||||
<td>
|
<td>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
{{--@dump($data)--}}
|
{{--@dump($data)--}}
|
||||||
<x-trmnl::view>
|
@props(['size' => 'full'])
|
||||||
|
<x-trmnl::view size="{{$size}}">
|
||||||
<x-trmnl::layout class="layout--col gap--space-between">
|
<x-trmnl::layout class="layout--col gap--space-between">
|
||||||
<div class="grid" style="gap: 9px;">
|
<div class="grid" style="gap: 9px;">
|
||||||
<div class="row row--center col--span-3 col--end">
|
<div class="row row--center col--span-3 col--end">
|
||||||
<img class="weather-image" style="max-height: 150px; margin:auto;" src="https://usetrmnl.com/images/plugins/weather/wi-thermometer.svg">
|
<img class="weather-image" style="max-height: 150px; margin:auto;"
|
||||||
|
src="https://usetrmnl.com/images/plugins/weather/wi-thermometer.svg">
|
||||||
</div>
|
</div>
|
||||||
<div class="col col--span-3 col--end">
|
<div class="col col--span-3 col--center">
|
||||||
<div class="item h--full">
|
<div class="item">
|
||||||
<div class="meta"></div>
|
<div class="meta"></div>
|
||||||
<div class="justify-center">
|
<div class="justify-center">
|
||||||
<span class="value value--xxlarge" data-fit-value="true">{{Arr::get($data, 'properties.timeseries.0.data.instant.details.air_temperature', 'N/A')}}</span>
|
<span class="value @if($size == 'full' || $size == 'half_horizontal') value--xxlarge @else value--medium @endif"
|
||||||
|
data-fit-value="true">{{Arr::get($data, 'properties.timeseries.0.data.instant.details.air_temperature', 'N/A')}}</span>
|
||||||
<span class="label">Temperature</span>
|
<span class="label">Temperature</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,7 +24,8 @@
|
||||||
{{-- <img class="weather-icon" src="https://usetrmnl.com/images/weather/wi-thermometer.svg">--}}
|
{{-- <img class="weather-icon" src="https://usetrmnl.com/images/weather/wi-thermometer.svg">--}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<span class="value value--small">{{Arr::get($data, 'properties.timeseries.0.data.instant.details.wind_speed', 'N/A')}}</span>
|
<span
|
||||||
|
class="value value--small">{{Arr::get($data, 'properties.timeseries.0.data.instant.details.wind_speed', 'N/A')}}</span>
|
||||||
<span class="label">Wind Speed (km/h)</span>
|
<span class="label">Wind Speed (km/h)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -43,7 +47,8 @@
|
||||||
{{-- <img class="weather-icon" src="https://usetrmnl.com/images/weather/wi-day-sunny.svg">--}}
|
{{-- <img class="weather-icon" src="https://usetrmnl.com/images/weather/wi-day-sunny.svg">--}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<span class="value value--xsmall">{{Str::title(Arr::get($data, 'properties.timeseries.0.data.next_1_hours.summary.symbol_code', 'N/A'))}}</span>
|
<span
|
||||||
|
class="value value--xsmall">{{Str::title(Arr::get($data, 'properties.timeseries.0.data.next_1_hours.summary.symbol_code', 'N/A'))}}</span>
|
||||||
<span class="label">Right Now</span>
|
<span class="label">Right Now</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
{{--@dump($data)--}}
|
{{--@dump($data)--}}
|
||||||
<x-trmnl::view>
|
@props(['size' => 'full'])
|
||||||
|
<x-trmnl::view size="{{ $size }}">
|
||||||
<x-trmnl::layout>
|
<x-trmnl::layout>
|
||||||
<x-trmnl::layout class="layout--col">
|
<x-trmnl::layout class="layout--col">
|
||||||
<div class="b-h-gray-1">{{$data[0]['a']}}</div>
|
<div class="b-h-gray-1">{{$data[0]['a']}}</div>
|
||||||
@if (strlen($data[0]['q']) < 300)
|
@if (strlen($data[0]['q']) < 300 && $size != 'quadrant')
|
||||||
<p class="value">{{ $data[0]['q'] }}</p>
|
<p class="value">{{ $data[0]['q'] }}</p>
|
||||||
@else
|
@else
|
||||||
<p class="value--small">{{ $data[0]['q'] }}</p>
|
<p class="value--small">{{ $data[0]['q'] }}</p>
|
||||||
|
|
|
||||||
8
resources/views/trmnl-layouts/mashup.blade.php
Normal file
8
resources/views/trmnl-layouts/mashup.blade.php
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
@props(['mashupLayout' => '1Tx1B'])
|
||||||
|
|
||||||
|
<x-trmnl::screen>
|
||||||
|
<x-trmnl::mashup mashup-layout="{{ $mashupLayout }}">
|
||||||
|
{{-- The slot is used to pass the content of the mashup --}}
|
||||||
|
{!! $slot !!}
|
||||||
|
</x-trmnl::mashup>
|
||||||
|
</x-trmnl::screen>
|
||||||
3
resources/views/trmnl-layouts/single.blade.php
Normal file
3
resources/views/trmnl-layouts/single.blade.php
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<x-trmnl::screen>
|
||||||
|
{!! $slot !!}
|
||||||
|
</x-trmnl::screen>
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
use App\Jobs\GenerateScreenJob;
|
use App\Jobs\GenerateScreenJob;
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
use App\Models\DeviceLog;
|
use App\Models\DeviceLog;
|
||||||
|
use App\Models\Plugin;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\ImageGenerationService;
|
use App\Services\ImageGenerationService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Blade;
|
use Illuminate\Support\Facades\Blade;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
Route::get('/display', function (Request $request) {
|
Route::get('/display', function (Request $request) {
|
||||||
|
|
@ -46,13 +48,14 @@ Route::get('/display', function (Request $request) {
|
||||||
'last_refreshed_at' => now(),
|
'last_refreshed_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Get current screen image from mirror device or continue if not available
|
// Get current screen image from a mirror device or continue if not available
|
||||||
if (! $image_uuid = $device->mirrorDevice?->current_screen_image) {
|
if (! $image_uuid = $device->mirrorDevice?->current_screen_image) {
|
||||||
$refreshTimeOverride = null;
|
$refreshTimeOverride = null;
|
||||||
// Skip if cloud proxy is enabled for the device
|
// Skip if cloud proxy is enabled for the device
|
||||||
if (! $device->proxy_cloud || $device->getNextPlaylistItem()) {
|
if (! $device->proxy_cloud || $device->getNextPlaylistItem()) {
|
||||||
$playlistItem = $device->getNextPlaylistItem();
|
$playlistItem = $device->getNextPlaylistItem();
|
||||||
if ($playlistItem) {
|
|
||||||
|
if ($playlistItem && ! $playlistItem->isMashup()) {
|
||||||
$refreshTimeOverride = $playlistItem->playlist()->first()->refresh_time;
|
$refreshTimeOverride = $playlistItem->playlist()->first()->refresh_time;
|
||||||
$plugin = $playlistItem->plugin;
|
$plugin = $playlistItem->plugin;
|
||||||
|
|
||||||
|
|
@ -62,12 +65,7 @@ Route::get('/display', function (Request $request) {
|
||||||
// Check and update stale data if needed
|
// Check and update stale data if needed
|
||||||
if ($plugin->isDataStale() || $plugin->current_image == null) {
|
if ($plugin->isDataStale() || $plugin->current_image == null) {
|
||||||
$plugin->updateDataPayload();
|
$plugin->updateDataPayload();
|
||||||
|
$markup = $plugin->render();
|
||||||
if ($plugin->render_markup) {
|
|
||||||
$markup = Blade::render($plugin->render_markup, ['data' => $plugin->data_payload]);
|
|
||||||
} elseif ($plugin->render_markup_view) {
|
|
||||||
$markup = view($plugin->render_markup_view, ['data' => $plugin->data_payload])->render();
|
|
||||||
}
|
|
||||||
|
|
||||||
GenerateScreenJob::dispatchSync($device->id, $plugin->id, $markup);
|
GenerateScreenJob::dispatchSync($device->id, $plugin->id, $markup);
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +76,28 @@ Route::get('/display', function (Request $request) {
|
||||||
$playlistItem->update(['last_displayed_at' => now()]);
|
$playlistItem->update(['last_displayed_at' => now()]);
|
||||||
$device->update(['current_screen_image' => $plugin->current_image]);
|
$device->update(['current_screen_image' => $plugin->current_image]);
|
||||||
}
|
}
|
||||||
|
} elseif ($playlistItem) {
|
||||||
|
$refreshTimeOverride = $playlistItem->playlist()->first()->refresh_time;
|
||||||
|
|
||||||
|
// Get all plugins for the mashup
|
||||||
|
$plugins = Plugin::whereIn('id', $playlistItem->getMashupPluginIds())->get();
|
||||||
|
|
||||||
|
foreach ($plugins as $plugin) {
|
||||||
|
// Reset cache if Devices with different dimensions exist
|
||||||
|
ImageGenerationService::resetIfNotCacheable($plugin);
|
||||||
|
if ($plugin->isDataStale() || $plugin->current_image == null) {
|
||||||
|
$plugin->updateDataPayload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$markup = $playlistItem->render();
|
||||||
|
GenerateScreenJob::dispatchSync($device->id, null, $markup);
|
||||||
|
|
||||||
|
$device->refresh();
|
||||||
|
|
||||||
|
if ($device->current_screen_image != null) {
|
||||||
|
$playlistItem->update(['last_displayed_at' => now()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue