Updated Map View

This commit is contained in:
2026-06-20 22:21:17 +10:00
parent 6fad966b7e
commit 05ca994253
52 changed files with 2038 additions and 803 deletions
@@ -1,115 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\Achievement;
use App\Models\Aircraft;
use App\Models\Alliance;
use App\Models\Continent;
use App\Models\Country;
use App\Models\User;
use Illuminate\Http\Request;
use Inertia\Inertia;
class AchievementController extends Controller
{
public function index(User $user)
{
$achievements = Achievement::with(['category', 'difficulty'])
->get()
->groupBy(fn(Achievement $a) => $a->category->name)
->map(fn($group) => $group->sortBy('sort_order')->values());
$userAchievements = $user->achievements()
->with('achievement')
->select(['achievement_id', 'progress'])
->orderBy('achievement_id')
->get()
->keyBy('achievement_id');
$unlockedByCategory = $achievements->map(fn($group) =>
$group->filter(fn($a) => $userAchievements->get($a->id)?->unlocked)->count()
);
$unlockedCount = $userAchievements->filter(fn($ua) => $ua->unlocked)->count();
return Inertia::render('UserAchievements', [
'user' => $user,
'canEdit' => auth()->id() === $user->id,
'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
'achievements' => $achievements,
'userAchievements' => $userAchievements,
'loggedInUser' => auth()->user(),
'unlockedCount' => $unlockedCount,
'unlockedByCategory' => $unlockedByCategory,
'totalAchievements' => $achievements->flatten()->count(),
]);
}
function getRegionsByCountryCode(string $countryCode)
{
return Country::whereCode($countryCode)
->first()
->regions()
->orderBy('name')
->get()
->toArray();
}
public function specific(User $user, Achievement $achievement)
{
$regions = match($achievement->internal_name){
'fun_challenges.australian_states' => $this->getRegionsByCountryCode('AU'),
'fun_challenges.chinese_provinces' => $this->getRegionsByCountryCode('CN'),
'fun_challenges.canadian_provinces' => $this->getRegionsByCountryCode('CA'),
'fun_challenges.brazilian_states' => $this->getRegionsByCountryCode('BR'),
'fun_challenges.us_states' => $this->getRegionsByCountryCode('US'),
default => [],
};
$allianceInternalName = match($achievement->internal_name){
'airlines_alliances.all_star_alliance' => 'star_alliance',
'airlines_alliances.all_oneworld' => 'oneworld',
'airlines_alliances.all_skyteam' => 'skyteam',
'airlines_alliances.all_vanilla_alliance' => 'vanilla_alliance',
default => null,
};
$continents = match($achievement->internal_name){
'countries_continents.all_continent_pairs_one_way', 'countries_continents.all_continent_pairs_both_ways' => Continent::all()->toArray(),
default => [],
};
$alliance = null;
$airlines = [];
if ($allianceInternalName) {
$alliance = Alliance::where('internal_name', $allianceInternalName)
->with('airlines')
->firstOrFail();
$airlines = $alliance->airlines()->with('country')->orderBy('name')->get();
}
$aircraftFamilies = match($achievement->internal_name){
'aircraft.all_boeing_7x7' => Aircraft::BOEING_FAMILIES,
'aircraft.all_airbus_a3xx' => Aircraft::AIRBUS_FAMILIES,
default => [],
};
return Inertia::render('Profile/UserAchievement', [
'user' => $user,
'achievement' => $achievement,
'loggedInUser' => auth()->user(),
'userAchievement' => $user->achievements()->where('achievement_id', $achievement->id)->first(),
'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
'flight_api_url' => FlightProfileController::getUserFlightApiURL($user),
'regions' => $regions,
'alliance' => $alliance,
'airlines' => $airlines,
'continents' => $continents,
'aircraft_families' => $aircraftFamilies,
'achievementCount' => $user->unlockedAchievements()->count(),
]);
}
}
@@ -50,14 +50,4 @@ class UserApiController extends ApiController
]);
}
public function flights(string $username, Request $request): JsonResponse
{
$user = User::where('name', 'ilike', $username)->first();
if (!$user) {
return response()->json(['message' => 'User not found'], 404);
}
return response()->json($user->FlightController()->flights($request));
}
}
@@ -1,100 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\UserFlight;
use App\Http\Resources\UserFlightResource;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
class FlightProfileController extends Controller
{
public function index(){
if (auth()->check()) {
$user = auth()->user();
$defaultPage = $user->resolved_settings['default_login_page'];
$route = match ($defaultPage) {
'feed_first' => $user->following()->count() > 0 ? 'feed' : 'profile.view',
'feed' => 'feed',
'profile' => 'profile.view',
'dashboard' => 'dashboard',
};
$args = $route == 'profile.view' ? $user->name : null;
return redirect()->route($route, $args);
}
return redirect()->route('login');
}
public static function getUserFlightApiURL(User $user){
return '/data/user/'.$user->name.'/flights';
}
public function profileData(User $user, string $view, ?int $selectedFlightId = null) : array {
return [
'user' => $user,
'canEdit' => (auth()->check() && auth()->id() === $user->id) || (auth()->check() && auth()->user()->hasRole('admin')),
'initialView' => $view,
'selectedFlightId' => $selectedFlightId,
'flight_api_url' => self::getUserFlightApiURL($user),
'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
'flightCount' => $user->departedFlights()->count(),
];
}
public function departureBoard(User $user, ?UserFlight $flight = null){
$profileData = $this->profileData($user, 'board', $flight?->id);
return Inertia::render('UserProfile', $profileData);
}
public function map(User $user){
$profileData = $this->profileData($user, 'map');
return Inertia::render('UserProfile', $profileData);
}
public function boardingPasses(User $user){
$profileData = $this->profileData($user, 'passes');
return Inertia::render('UserProfile', $profileData);
}
public function view(User $user)
{
$loggedInUser = auth()->user();
$isPrivate = $user->resolved_settings['private_profile'];
if ($isPrivate && $user->id !== $loggedInUser?->id) {
if (!$loggedInUser || !$loggedInUser->isFollowing($user)) {
abort(404);
}
}
$defaultView = $loggedInUser ? $loggedInUser->resolved_settings['default_profile_view'] : 'map';
return match($defaultView) {
'boarding-passes' => $this->boardingPasses($user),
'map' => $this->map($user),
'departure-board' => $this->departureBoard($user),
'achievements' => redirect()->route('profile.achievements', $user->name),
};
}
public function flight(User $user, UserFlight $userFlight)
{
if($userFlight->user_id !== $user->id){
abort(404);
}
return Inertia::render('UserFlight', [
'flightCount' => $user->departedFlights()->count(),
'flight' => $userFlight->snapshot($userFlight->id),
'canEdit' => auth()->check() && auth()->id() === $user->id,
'user' => $user,
'isFollowing' => auth()->check() && auth()->user()->isFollowing($user),
]);
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers;
use App\Models\Followee;
use App\Models\Notification;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FollowerController extends Controller
{
public function index(): JsonResponse
{
$followers = Followee::with('user')
->where('followee_id', auth()->id())
->orderBy('verified') // unverified first
->get()
->map(fn (Followee $f) => [
'user' => $f->user,
'verified' => $f->verified,
]);
return response()->json($followers);
}
public function approve(User $follower): JsonResponse
{
$followee = Followee::where('user_id', $follower->id)
->where('followee_id', auth()->id())
->pending()
->firstOrFail();
$followee->update(['verified' => true]);
Notification::create([
'user_id' => $follower->id,
'title' => 'Follow request accepted',
'body' => auth()->user()->name . ' accepted your follow request.',
'is_achievement' => false,
'url' => '/u/' . auth()->user()->name,
]);
return response()->json(['status' => 'approved']);
}
public function deny(User $follower): JsonResponse
{
Followee::where('user_id', $follower->id)
->where('followee_id', auth()->id())
->pending()
->delete();
return response()->json(['status' => 'denied']);
}
public function remove(User $follower): JsonResponse
{
Followee::where('user_id', $follower->id)
->where('followee_id', auth()->id())
->verified()
->delete();
return response()->json(['status' => 'removed']);
}
}
@@ -26,4 +26,15 @@ class SettingsController extends Controller
$request->user()->updateSettings($validated['settings']);
return response()->json(['message' => 'Settings saved.']);
}
public function updateSingle(Request $request, string $key)
{
$validated = $request->validate([
'value' => ['required'],
]);
$request->user()->updateSetting($key, $validated['value']);
return response()->json(['message' => 'Setting saved.']);
}
}
+47 -7
View File
@@ -9,38 +9,77 @@ use App\Settings\SettingsRegistry;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Inertia\Inertia;
class UserController extends Controller
{
public function follow(User $user): JsonResponse
{
abort_if($user->id === auth()->id(), 403);
$existing = Followee::where('user_id', auth()->id())
->where('followee_id', $user->id)
->first();
if ($existing) {
$existing->delete();
return response()->json(['following' => false]);
return response()->json(['status' => 'none']);
}
$canView = Gate::allows('viewProfileData', $user);
Followee::create([
'user_id' => auth()->id(),
'followee_id' => $user->id,
'verified' => $canView,
]);
Notification::create([
'user_id' => $user->id,
'title' => 'New follower',
'body' => auth()->user()->name . ' is now following you.',
'user_id' => $user->id,
'title' => $canView ? 'New follower' : 'Follow request',
'body' => $canView
? auth()->user()->name . ' is now following you.'
: auth()->user()->name . ' wants to follow you.',
'is_achievement' => false,
'url' => '/u/'. auth()->user()->name,
'url' => $canView ? '/u/' . auth()->user()->name : '/follow-requests',
]);
return response()->json(['following' => true]);
return response()->json(['status' => $canView ? 'following' : 'requested']);
}
public function settings(){
public function approveRequest(User $follower): JsonResponse
{
$followee = Followee::where('user_id', $follower->id)
->where('followee_id', auth()->id())
->pending()
->firstOrFail();
$followee->update(['verified' => true]);
Notification::create([
'user_id' => $follower->id,
'title' => 'Follow request accepted',
'body' => auth()->user()->name . ' accepted your follow request.',
'is_achievement' => false,
'url' => '/u/' . auth()->user()->name,
]);
return response()->json(['approved' => true]);
}
public function denyRequest(User $follower): JsonResponse
{
Followee::where('user_id', $follower->id)
->where('followee_id', auth()->id())
->pending()
->delete();
return response()->json(['denied' => true]);
}
public function settings(?string $category = null){
$allowedTabs = ['general', 'followers'];
$user = auth()->user();
$current = array_merge(SettingsRegistry::defaults(), $user->settings ?? []);
$fields = array_map(fn($field) => array_merge($field, [
@@ -50,6 +89,7 @@ class UserController extends Controller
return Inertia::render('UserSettings', [
'fields' => $fields,
'categories' => SettingsRegistry::categories(),
'defaultTab' => in_array($category, $allowedTabs, true) ? $category : 'general',
]);
}
}
+42 -22
View File
@@ -5,34 +5,54 @@ namespace App\Http\Controllers;
use App\Models\User;
use App\Models\UserFlight;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;
class UserFlightController extends Controller
{
protected User $user;
function __construct(User $user){
$this->user = $user;
public function viewableFlights(User $user, ?Request $request = null)
{
if (Gate::denies('viewProfileData', $user)) {
return response()->json([]);
}
return $this->flights($user, $request);
}
public function flights(?Request $request = null)
public function flights(User $user, ?Request $request = null)
{
return UserFlight::where('user_id', $this->user->id)
->with([
'departureAirport.region.country',
'departureAirport.region.continent',
'arrivalAirport.region.country',
'arrivalAirport.region.continent',
'airline.country',
'airline.alliance',
'aircraft',
'seatType',
'flightReason',
'flightClass',
'crewType'
])
->when($request?->boolean('departed_only'), fn($q) => $q->where('departure_date', '<=', now('UTC')))
->orderBy('departure_date', 'desc')
->get();
$key = "user_flights_{$user->id}";
$json = Cache::remember($key, now()->addDays(30), function () use ($user) {
return UserFlight::where('user_id', $user->id)
->with([
'departureAirport.region.country',
'departureAirport.region.continent',
'arrivalAirport.region.country',
'arrivalAirport.region.continent',
'airline.country',
'airline.alliance',
'aircraft',
'seatType',
'flightReason',
'flightClass',
'crewType'
])
->orderBy('departure_date', 'desc')
->get()
->values()
->toJson();
});
if ($request?->boolean('departed_only')) {
$filtered = collect(json_decode($json))
->filter(fn($f) => $f->departure_date <= now('UTC')->toDateString())
->values()
->toJson();
return response($filtered, 200)->header('Content-Type', 'application/json');
}
return response($json, 200)->header('Content-Type', 'application/json');
}
}
@@ -0,0 +1,194 @@
<?php
namespace App\Http\Controllers;
use App\Models\Achievement;
use App\Models\Aircraft;
use App\Models\Alliance;
use App\Models\Continent;
use App\Models\Country;
use App\Models\User;
use App\Models\UserFlight;
use App\Http\Resources\UserFlightResource;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Inertia\Inertia;
class UserProfileController extends Controller
{
public function index(){
if (auth()->check()) {
$user = auth()->user();
$defaultPage = $user->resolved_settings['default_login_page'];
$route = match ($defaultPage) {
'feed_first' => $user->following()->count() > 0 ? 'feed' : 'profile.view',
'feed' => 'feed',
'profile' => 'profile.view',
'dashboard' => 'dashboard',
};
$args = $route == 'profile.view' ? $user->name : null;
return redirect()->route($route, $args);
}
return redirect()->route('login');
}
public static function getUserFlightApiURL(User $user){
return '/data/user/'.$user->name.'/flights';
}
public function profileData(User $user, string $view, ?int $selectedFlightId = null) : array {
return [
'user' => $user,
'canView' => Gate::allows('viewProfileData', $user),
'canEdit' => auth()->check() && (auth()->id() === $user->id || auth()->user()->hasRole('admin')),
'initialView' => $view,
'selectedFlightId' => $selectedFlightId,
'flight_api_url' => self::getUserFlightApiURL($user),
'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none',
'flightCount' => $user->departedFlights()->count(),
];
}
public function departureBoard(User $user, ?UserFlight $flight = null){
$profileData = $this->profileData($user, 'board', $flight?->id);
return Inertia::render('UserProfile', $profileData);
}
public function map(User $user){
$profileData = $this->profileData($user, 'map');
return Inertia::render('UserProfile', $profileData);
}
public function boardingPasses(User $user){
$profileData = $this->profileData($user, 'passes');
return Inertia::render('UserProfile', $profileData);
}
public function view(User $user, ?string $page = null)
{
$loggedInUser = auth()->user();
$defaultView = $page ?: ($loggedInUser ? $loggedInUser->resolved_settings['default_profile_view'] : 'map');
return match($defaultView) {
'boarding-passes' => $this->boardingPasses($user),
'map' => $this->map($user),
'departure-board' => $this->departureBoard($user),
'achievements' => redirect()->route('profile.achievements', $user->name),
};
}
public function flight(User $user, UserFlight $userFlight)
{
if($userFlight->user_id !== $user->id){
abort(404);
}
return Inertia::render('UserFlight', [
'flightCount' => $user->departedFlights()->count(),
'flight' => $userFlight->snapshot($userFlight->id),
'canEdit' => auth()->check() && auth()->id() === $user->id,
'canView' => Gate::allows('viewProfileData', $user),
'user' => $user,
'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none',
]);
}
public function achievements(User $user)
{
$canView = Gate::allows('viewProfileData', $user);
$achievements = Achievement::with(['category', 'difficulty'])
->get()
->groupBy(fn(Achievement $a) => $a->category->name)
->map(fn($group) => $group->sortBy('sort_order')->values());
$userAchievements = $user->achievements()
->with('achievement')
->select(['achievement_id', 'progress'])
->orderBy('achievement_id')
->get()
->keyBy('achievement_id');
$unlockedByCategory = $achievements->map(fn($group) =>
$group->filter(fn($a) => $userAchievements->get($a->id)?->unlocked)->count()
);
$unlockedCount = $userAchievements->filter(fn($ua) => $ua->unlocked)->count();
return Inertia::render('UserAchievements', [
'canView' => $canView,
'user' => $user,
'canEdit' => auth()->id() === $user->id,
'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none',
'achievements' => $canView ? $achievements : [],
'userAchievements' => $canView ? $userAchievements : [],
'loggedInUser' => auth()->user(),
'unlockedCount' => $unlockedCount,
'unlockedByCategory' => $unlockedByCategory,
'totalAchievements' => $achievements->flatten()->count(),
]);
}
public function achievement(User $user, Achievement $achievement)
{
$regions = match($achievement->internal_name){
'fun_challenges.australian_states' => Country::whereCode('AU')->first()->sortedRegions(),
'fun_challenges.chinese_provinces' => Country::whereCode('CN')->first()->sortedRegions(),
'fun_challenges.canadian_provinces' => Country::whereCode('CA')->first()->sortedRegions(),
'fun_challenges.brazilian_states' => Country::whereCode('BR')->first()->sortedRegions(),
'fun_challenges.us_states' => Country::whereCode('US')->first()->sortedRegions(),
default => [],
};
$allianceInternalName = match($achievement->internal_name){
'airlines_alliances.all_star_alliance' => 'star_alliance',
'airlines_alliances.all_oneworld' => 'oneworld',
'airlines_alliances.all_skyteam' => 'skyteam',
'airlines_alliances.all_vanilla_alliance' => 'vanilla_alliance',
default => null,
};
$continents = match($achievement->internal_name){
'countries_continents.all_continent_pairs_one_way', 'countries_continents.all_continent_pairs_both_ways' => Continent::all()->toArray(),
default => [],
};
$alliance = null;
$airlines = [];
if ($allianceInternalName) {
$alliance = Alliance::where('internal_name', $allianceInternalName)
->with('airlines')
->firstOrFail();
$airlines = $alliance->airlines()->with('country')->orderBy('name')->get();
}
$aircraftFamilies = match($achievement->internal_name){
'aircraft.all_boeing_7x7' => Aircraft::BOEING_FAMILIES,
'aircraft.all_airbus_a3xx' => Aircraft::AIRBUS_FAMILIES,
default => [],
};
$canView = Gate::allows('viewProfileData', $user);
return Inertia::render('Profile/UserAchievement', [
'user' => $user,
'achievement' => $achievement,
'loggedInUser' => auth()->user(),
'userAchievement' => $canView ? $user->achievements()->where('achievement_id', $achievement->id)->first() : null,
'followStatus' => auth()->check() ? auth()->user()->followStatus($user) : 'none',
'flight_api_url' => UserProfileController::getUserFlightApiURL($user),
'regions' => $regions,
'alliance' => $alliance,
'airlines' => $airlines,
'continents' => $continents,
'aircraft_families' => $aircraftFamilies,
'achievementCount' => $user->unlockedAchievements()->count(),
'canView' => $canView,
]);
}
}
+9
View File
@@ -17,4 +17,13 @@ class Country extends Model
{
return $this->hasMany(Region::class);
}
function sortedRegions(): array
{
return $this
->regions()
->orderBy('name')
->get()
->toArray();
}
}
+15
View File
@@ -10,6 +10,11 @@ class Followee extends Model
protected $fillable = [
'user_id',
'followee_id',
'verified',
];
protected $casts = [
'verified' => 'boolean',
];
public function user(): BelongsTo
@@ -21,4 +26,14 @@ class Followee extends Model
{
return $this->belongsTo(User::class, 'followee_id');
}
public function scopeVerified($query)
{
return $query->where('verified', true);
}
public function scopePending($query)
{
return $query->where('verified', false);
}
}
+19 -6
View File
@@ -48,6 +48,10 @@ class User extends Authenticatable
$this->update(['settings' => array_merge($current, $values)]);
}
function updateSetting($settingName, $value) : void{
$this->updateSettings([$settingName => $value]);
}
protected function resolvedSettings(): Attribute
{
return Attribute::make(
@@ -80,11 +84,6 @@ class User extends Authenticatable
return $this->where('name', 'ilike', $value)->firstOrFail();
}
public function FlightController(): UserFlightController
{
return new UserFlightController($this);
}
public function flights(): HasMany {
return $this->hasMany(UserFlight::class);
}
@@ -114,7 +113,21 @@ class User extends Authenticatable
public function isFollowing(User $user): bool
{
return $this->following()->where('followee_id', $user->id)->exists();
return $this->following()
->where('followee_id', $user->id)
->verified()
->exists();
}
public function followStatus(User $user): string
{
$followee = $this->following()->where('followee_id', $user->id)->first();
if (!$followee) {
return 'none';
}
return $followee->verified ? 'following' : 'requested';
}
public function notifications(): HasMany
+23
View File
@@ -48,6 +48,9 @@ class UserFlight extends Model
'duration_display',
'distance',
'livery_url',
'scope',
'range',
'region_range'
];
public function calculateGreatCircleDistance(): float{
@@ -108,6 +111,26 @@ class UserFlight extends Model
);
}
protected function scope(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region->country_id == $this->arrivalAirport->region->country_id ? 'domestic' : 'international'
);
}
protected function range(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region->continent_id == $this->arrivalAirport->region->continent_id ? 'intracontinental' : 'intercontinental'
);
}
protected function regionRange(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region_id == $this->arrivalAirport->region_id ? 'intraregional' : 'interregional'
);
}
protected function arrivalDayDifference(): Attribute
{
return Attribute::make(
+10
View File
@@ -3,15 +3,23 @@
namespace App\Observers;
use App\Models\UserFlight;
use Illuminate\Support\Facades\Cache;
class FlightObserver
{
protected function clearCache(UserFlight $flight): void
{
Cache::forget("user_flights_{$flight->user->id}");
}
/**
* Recalculate after a flight is created.
*/
public function created(UserFlight $flight): void
{
$flight->user->calculateAchievements();
$this->clearCache($flight);
}
/**
@@ -22,6 +30,7 @@ class FlightObserver
public function updated(UserFlight $flight): void
{
$flight->user->calculateAchievements();
$this->clearCache($flight);
}
/**
@@ -31,5 +40,6 @@ class FlightObserver
public function deleted(UserFlight $flight): void
{
$flight->user->calculateAchievements();
$this->clearCache($flight);
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\Response;
class UserPolicy
{
public function viewProfileData(?User $viewer, User $profileUser): bool
{
if ($viewer && ($viewer->id === $profileUser->id || $viewer->hasRole('admin'))) {
return true;
}
$isPrivate = $profileUser->resolved_settings['private_profile'] == 'private';
if (!$isPrivate) {
return true;
}
return $viewer && $viewer->isFollowing($profileUser);
}
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, User $model): bool
{
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, User $model): bool
{
return false;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, User $model): bool
{
return false;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, User $model): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, User $model): bool
{
return false;
}
}
+14
View File
@@ -67,6 +67,20 @@ class SettingsRegistry
['value' => 'achievements', 'label' => 'Achievements'],
],
],
[
'key' => 'show_map_legend',
'type' => 'checkbox',
'label' => 'Expand Map Legend By Default',
'category' => 'FlightsGoneBy Settings',
'default' => true,
],
[
'key' => 'hide_impossible_achievements',
'type' => 'checkbox',
'label' => 'Hide Impossible Achievements By Default',
'category' => 'FlightsGoneBy Settings',
'default' => true,
],
[
'category' => 'AI Generated Content',
'key' => 'ai_liveries',