mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 03:02:22 +01:00
9.0.2
This commit is contained in:
@@ -1,268 +0,0 @@
|
||||
{
|
||||
"find": "ابحث عن الإعدادات",
|
||||
"on": "تشغيل",
|
||||
"off": "تقفيل",
|
||||
"resetDefaultsContent": "إعادة ضبط",
|
||||
"resetDefaultsDialogTitle": "هل تريد إعادة تعيين كافة الإعدادات في علامة التبويب هذه إلى قيمها الافتراضية؟ هذا الإجراء لا رجعة فيه",
|
||||
"resetDefaultsDialogSecondaryAction": "اغلق",
|
||||
"resetDefaultsDialogPrimaryAction": "إعادة ضبط",
|
||||
"authenticatorName": "التوثيق",
|
||||
"authenticatorConfigurationName": "اعدادات التوثيق",
|
||||
"authenticatorConfigurationDescription": "يحتوي هذا القسم على تكوين التوثيق",
|
||||
"authenticatorConfigurationHostName": "استضيف",
|
||||
"authenticatorConfigurationHostDescription": "اسم المضيف للموثق",
|
||||
"authenticatorConfigurationPortName": "Port",
|
||||
"authenticatorConfigurationPortDescription": "منفذ الموثق",
|
||||
"authenticatorConfigurationDetachedName": "منفصل",
|
||||
"authenticatorConfigurationDetachedDescription": "ما إذا كان يجب بدء تشغيل المصادق المضمن كعملية منفصلة، مفيدة لتصحيح الأخطاء",
|
||||
"authenticatorInstallationDirectoryName": "مكان التثبيت",
|
||||
"authenticatorInstallationDirectoryDescription": "يفتح المجلد الذي يوجد به المضمن",
|
||||
"authenticatorInstallationDirectoryContent": "اظهار الملفات",
|
||||
"authenticatorResetDefaultsName": "إعادة تعيين التوثيق",
|
||||
"authenticatorResetDefaultsDescription": "يعيد ضبط إعدادات المصادق على قيمها الافتراضية",
|
||||
"authenticatorResetDefaultsContent": "إعادة ضبط",
|
||||
"hostGameServerName": "خادم اللعبة",
|
||||
"hostGameServerDescription": "قم بتوفير المعلومات الأساسية حول خادم اللعبة الخاص بك لمتصفح الخادم",
|
||||
"hostGameServerNameName": "اسم",
|
||||
"hostGameServerNameDescription": "اسم خادم اللعبة الخاص بك",
|
||||
"hostGameServerDescriptionName": "وصف",
|
||||
"hostGameServerDescriptionDescription": "وصف خادم اللعبة الخاص بك",
|
||||
"hostGameServerPasswordName": "كلمة المرور",
|
||||
"hostGameServerPasswordDescription": "كلمة المرور لخادم اللعبة الخاص بك، إذا كنت في حاجة إليها",
|
||||
"hostGameServerDiscoverableName": "قابل للاكتشاف",
|
||||
"hostGameServerDiscoverableDescription": "اجعل الخادم الخاص بك متاحًا للاعبين الآخرين على متصفح الخادم",
|
||||
"hostShareName": "نشر",
|
||||
"hostShareDescription": "اجعل من السهل على الأشخاص الآخرين الانضمام إلى الخادم الخاص بك من خلال الخيارات الموجودة في هذا القسم",
|
||||
"hostShareLinkName": "الرابط",
|
||||
"hostShareLinkDescription": "نسخ رابط الخادم الخاص بك إلى الحافظة (يتطلب Reboot Launcher)",
|
||||
"hostShareLinkContent": "انسخ الرابط",
|
||||
"hostShareLinkMessageSuccess": "نسخ الرابط الخاص بك إلى الحافظة",
|
||||
"hostShareIpName": "الايبي العام",
|
||||
"hostShareIpDescription": "نسخ عنوان IP العام الحالي الخاص بك إلى الحافظة (لا يتطلب Reboot Launcher)",
|
||||
"hostShareIpContent": "نسخ IP",
|
||||
"hostShareIpMessageLoading": "الحصول على IP العام الخاص بك...",
|
||||
"hostShareIpMessageSuccess": "تم نسخ الرابط الخاص بك إلى الحافظة",
|
||||
"hostShareIpMessageError": "حدث خطأ أثناء الحصول على عنوان IP العام الخاص بك: {error}",
|
||||
"hostResetName": "إعادة تعيين خادم اللعبة",
|
||||
"hostResetDescription": "يعيد ضبط إعدادات خادم اللعبة إلى قيمها الافتراضية",
|
||||
"hostResetContent": "إعادة ضبط",
|
||||
"browserName": "متصفح الخادم",
|
||||
"noServersAvailableTitle": "لا توجد خوادم متاحة الآن",
|
||||
"noServersAvailableSubtitle": "قم باستضافة خادم بنفسك أو قم بالعودة لاحقًا",
|
||||
"joinServer": "انضم للخادم",
|
||||
"noServersAvailableByQueryTitle": "لم يتم العثور على نتائج",
|
||||
"noServersAvailableByQuerySubtitle": "لا يوجد خادم يطابق استعلامك",
|
||||
"findServer": "ابحث عن خادم",
|
||||
"copyIp": "نسخ IP",
|
||||
"hostName": "استضيف",
|
||||
"matchmakerName": "زر ريدي",
|
||||
"matchmakerConfigurationName": "اعدادات زر الريدي",
|
||||
"matchmakerConfigurationDescription": "يحتوي هذا القسم على اعدادات زر الريدي",
|
||||
"matchmakerConfigurationHostName": "استضيف",
|
||||
"matchmakerConfigurationHostDescription": "اسم المضيف لزر الريدي",
|
||||
"matchmakerConfigurationPortName": "بورت",
|
||||
"matchmakerConfigurationPortDescription": "بورت لزر الريدي",
|
||||
"matchmakerConfigurationAddressName": "عنوان خادم اللعبة",
|
||||
"matchmakerConfigurationAddressDescription": "عنوان خادم اللعبة الذي يستخدمه زر الريدي",
|
||||
"matchmakerConfigurationDetachedName": "منفصل",
|
||||
"matchmakerConfigurationDetachedDescription": "ما إذا كان ينبغي بدء أداة التوفيق المضمنة كعملية منفصلة، مفيدة لتصحيح الأخطاء",
|
||||
"matchmakerInstallationDirectoryName": "مكان التحميل",
|
||||
"matchmakerInstallationDirectoryDescription": "يفتح المجلد الذي يوجد به زر ريدي",
|
||||
"matchmakerInstallationDirectoryContent": "اظهار الملفات",
|
||||
"matchmakerResetDefaultsName": "إعادة تعيين زر الريدي",
|
||||
"matchmakerResetDefaultsDescription": "يعيد ضبط إعدادات زر ريدي إلى قيمها الافتراضية",
|
||||
"matchmakerResetDefaultsContent": "إعادة ضبط",
|
||||
"matchmakerResetDefaultsDialogTitle": "هل تريد إعادة تعيين كافة الإعدادات في علامة التبويب هذه إلى قيمها الافتراضية؟ هذا الإجراء لا رجعة فيه",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "يغلق",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "إعادة ضبط",
|
||||
"playName": "العب",
|
||||
"playGameServerName": "خادم اللعبة",
|
||||
"playGameServerDescription": "اختصارات مفيدة للعثور على الخادم الذي تريد اللعب فيه",
|
||||
"playGameServerContentLocal": "الخادم الخاص بك",
|
||||
"playGameServerContentBrowser": "خادم {owner}.",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "استضافة خادم",
|
||||
"playGameServerHostDescription": "هل تريد إنشاء خادم ألعاب لنفسك أو لأصدقائك؟ استضافة واحدة!",
|
||||
"playGameServerHostContent": "استضيف",
|
||||
"playGameServerBrowserName": "تصفح الخوادم",
|
||||
"playGameServerBrowserDescription": "ابحث عن خادم قابل للاكتشاف مستضاف على Reboot Launcher في متصفح الخادم",
|
||||
"playGameServerBrowserContent": "تصفح",
|
||||
"playGameServerCustomName": "انضم إلى خادم مخصص",
|
||||
"playGameServerCustomDescription": "اكتب عنوان أي خادم، سواء كان مستضافًا على Reboot Launcher أم لا",
|
||||
"playGameServerCustomContent": "أدخل IP",
|
||||
"settingsName": "إعدادات",
|
||||
"settingsClientName": "إعدادات العميل",
|
||||
"settingsClientDescription": "يحتوي هذا القسم على ملفات dll المستخدمة لتشغيل عميل Fortnite",
|
||||
"settingsClientConsoleName": "كونسل",
|
||||
"settingsClientConsoleDescription": "يتم إدخال هذا الملف لإلغاء قفل Unreal Engine Console",
|
||||
"settingsClientAuthName": "مصحح التوثيق",
|
||||
"settingsClientAuthDescription": "يتم إدخال هذا الملف لإعادة توجيه جميع طلبات HTTP إلى مُصادق المُشغل",
|
||||
"settingsClientMemoryName": "مصحح الذاكرة",
|
||||
"settingsClientMemoryDescription": "تم إدخال هذا الملف لمنع عميل Fortnite من التعطل بسبب تسرب الذاكرة",
|
||||
"settingsClientArgsName": "وسائط الإطلاق المخصصة",
|
||||
"settingsClientArgsDescription": "وسائط إضافية لاستخدامها عند بدء اللعبة",
|
||||
"settingsClientArgsPlaceholder": "حجة",
|
||||
"settingsServerName": "إعدادات خادم اللعبة",
|
||||
"settingsServerSubtitle": "يحتوي هذا القسم على الإعدادات المتعلقة بتنفيذ خادم اللعبة",
|
||||
"settingsServerFileName": "تطبيق",
|
||||
"settingsServerFileDescription": "يتم حقن هذا الملف لإنشاء خادم اللعبة واستضافة المباريات",
|
||||
"settingsServerPortName": "بورت",
|
||||
"settingsServerPortDescription": "البورت الذي يستخدمه خادم اللعبة dll",
|
||||
"settingsServerMirrorName": "تحديث المرآة",
|
||||
"settingsServerMirrorDescription": "عنوان URL المستخدم لتحديث خادم اللعبة dll",
|
||||
"settingsServerMirrorPlaceholder": "مرآة",
|
||||
"settingsServerTimerName": "تحديث الموقت",
|
||||
"settingsServerTimerSubtitle": "يحدد متى يجب تحديث خادم اللعبة dll",
|
||||
"settingsUtilsName": "المرافق الانشر",
|
||||
"settingsUtilsSubtitle": "يحتوي هذا القسم على إعدادات مفيدة للانشر",
|
||||
"settingsUtilsInstallationDirectoryName": "مكان التثبيت",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "يفتح مكان التثبيت",
|
||||
"settingsUtilsInstallationDirectoryContent": "اظهار الملفات",
|
||||
"settingsUtilsBugReportName": "إنشاء تقرير خطأ",
|
||||
"settingsUtilsBugReportSubtitle": "ساعدني في إصلاح الأخطاء عن طريق الإبلاغ عنها",
|
||||
"settingsUtilsBugReportContent": "الإبلاغ عن خطأ",
|
||||
"settingsUtilsResetDefaultsName": "اعادة الضبط",
|
||||
"settingsUtilsResetDefaultsSubtitle": "يعيد ضبط إعدادات المشغل على قيمها الافتراضية",
|
||||
"settingsUtilsDialogTitle": "هل تريد إعادة تعيين كافة الإعدادات في علامة التبويب هذه إلى قيمها الافتراضية؟ هذا الإجراء لا رجعة فيه",
|
||||
"settingsUtilsResetDefaultsContent": "إعادة ضبط",
|
||||
"settingsUtilsDialogSecondaryAction": "اغلق",
|
||||
"settingsUtilsDialogPrimaryAction": "إعادة ضبط",
|
||||
"addVersionName": "إصدار",
|
||||
"addVersionDescription": "حدد إصدار Fortnite الذي تريد استخدامه",
|
||||
"addLocalBuildName": "قم بإضافة نسخة من وحدة التخزين المحلية لهذا الكمبيوتر",
|
||||
"addLocalBuildDescription": "الإصدارات القادمة من القرص المحلي الخاص بك ليست مضمونة للعمل",
|
||||
"addLocalBuildContent": "أضف تحديث",
|
||||
"downloadBuildName": "قم بتنزيل أي إصدار من السحابة",
|
||||
"downloadBuildDescription": "قم بتنزيل أي إصدار من لعبة Fortnite بسهولة من السحابة",
|
||||
"downloadBuildContent": "تحميل",
|
||||
"cannotUpdateGameServer": "حدث خطأ أثناء تحديث خادم اللعبة: {error}",
|
||||
"launchFortnite": "شغل فورتنايت",
|
||||
"closeFortnite": "إغلاق فورتنايت",
|
||||
"updateGameServerDllNever": "أبداً",
|
||||
"updateGameServerDllEvery": "كل {اسم}",
|
||||
"selectPathPlaceholder": "طريق",
|
||||
"selectPathWindowTitle": "حدد ملف",
|
||||
"defaultDialogSecondaryAction": "اغلق",
|
||||
"stopLoadingDialogAction": "قف",
|
||||
"copyErrorDialogTitle": "نسخ الخطا",
|
||||
"copyErrorDialogSuccess": "خطأ في النسخ إلى الحافظة",
|
||||
"defaultServerName": "Reboot خادم العبه",
|
||||
"defaultServerDescription": "مجرد خادم آخر",
|
||||
"updatingRebootDll": "جارٍ تنزيل ملفReboot.dll..",
|
||||
"updatedRebootDll": "تم تنزيل ملف Reboot dll بنجاح",
|
||||
"updateRebootDllError": "حدث خطأ أثناء تنزيل ملف Reboot dll: {error}",
|
||||
"updateRebootDllErrorAction": "أعد المحاولة",
|
||||
"uncaughtErrorMessage": "تم طرح خطأ لم يتم اكتشافه: {error}",
|
||||
"launchingHeadlessServer": "إطلاق الخادم بدون رأس...",
|
||||
"usernameOrEmail": "اسم المستخدم/البريد الإلكتروني",
|
||||
"usernameOrEmailPlaceholder": "اكتب اسم المستخدم أو البريد الإلكتروني الخاص بك",
|
||||
"password": "كلمة المرور",
|
||||
"passwordPlaceholder": "اكتب كلمة المرور الخاصة بك، إذا كنت تريد استخدام واحدة",
|
||||
"cancelProfileChanges": "الغي",
|
||||
"saveProfileChanges": "احفظ",
|
||||
"startingServer": "بدء {name}...",
|
||||
"startedServer": "تم بدء {name} بنجاح",
|
||||
"startServerError": "حدث خطأ أثناء بدء {name}: {error}",
|
||||
"stoppingServer": "إيقاف {name}...",
|
||||
"stoppedServer": "تم إيقاف {name} بنجاح",
|
||||
"stopServerError": "حدث خطأ أثناء إيقاف {name}: {error}",
|
||||
"missingHostNameError": "اسم المضيف مفقود في تكوين {name}.",
|
||||
"missingPortError": "منفذ مفقود في تكوين {name}.",
|
||||
"illegalPortError": "منفذ غير صالح في تكوين {name}.",
|
||||
"freeingPort": "تحرير بورت {بورت}...",
|
||||
"freedPort": "تم تحرير اليورت {port} بنجاح",
|
||||
"freePortError": "حدث خطأ أثناء تحرير البورت {port}: {error}",
|
||||
"pingingRemoteServer": "جارٍ تنفيذ الأمر ping على جهاز التحكم عن بعد {name}...",
|
||||
"pingingLocalServer": "تنفيذ الأمر ping على {type} {name}...",
|
||||
"pingError": "لا يمكن تنفيذ الأمر ping على {type} {name}",
|
||||
"joinSelfServer": "لا يمكنك الانضمام إلى الخادم الخاص بك",
|
||||
"wrongServerPassword": "كلمة المرور خاطئة: يرجى المحاولة مرة أخرى",
|
||||
"offlineServer": "هذا الخادم غير متصل حاليًا: يرجى المحاولة مرة أخرى لاحقًا",
|
||||
"serverPassword": "كلمة المرور",
|
||||
"serverPasswordPlaceholder": "اكتب كلمة المرور الخاصة بالخادم",
|
||||
"serverPasswordCancel": "الغي",
|
||||
"serverPasswordConfirm": "تأكد",
|
||||
"joinedServer": "لقد انضممت إلى خادم {author} بنجاح!",
|
||||
"copiedIp": "تم نسخ IP إلى الحافظة",
|
||||
"selectVersion": "تحديد إصدار",
|
||||
"noVersions": "يرجى إنشاء أو تنزيل نسخة",
|
||||
"missingVersion": "هذا الإصدار غير موجود على الجهاز المحلي",
|
||||
"deleteVersionDialogTitle": "هل أنت متأكد أنك تريد حذف هذا الإصدار؟",
|
||||
"deleteVersionFromDiskOption": "حذف ملفات الإصدار من القرص",
|
||||
"deleteVersionCancel": "احفظ",
|
||||
"deleteVersionConfirm": "احذف",
|
||||
"versionName": "اسم",
|
||||
"versionNameLabel": "اكتب اسم الإصدار الجديد",
|
||||
"newVersionNameConfirm": "احفظ",
|
||||
"newVersionNameLabel": "اكتب اسم الإصدار الجديد",
|
||||
"gameFolderTitle": "ملف العبة",
|
||||
"gameFolderPlaceholder": "اكتب مجلد اللعبة الجديد",
|
||||
"gameFolderPlaceWindowTitle": "حدد مجلد اللعبة",
|
||||
"gameFolderLabel": "المسار",
|
||||
"openInExplorer": "فتح في المستكشف",
|
||||
"modify": "تعديل",
|
||||
"delete": "احذف",
|
||||
"build": "اصدار",
|
||||
"selectBuild": "حدد اصدار فورت نايت",
|
||||
"fetchingBuilds": "جارٍ جلب الإصدارات والأقراص...",
|
||||
"unknownError": "خطأ غير معروف",
|
||||
"downloadVersionError": "لا يمكن تنزيل الإصدار: {error}",
|
||||
"downloadedVersion": "تم الانتهاء من التحميل بنجاح!",
|
||||
"download": "تحميل",
|
||||
"downloading": "جارى التحميل...",
|
||||
"extracting": "استخراج...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "مكان التثبيت",
|
||||
"buildInstallationDirectoryPlaceholder": "اكتب مكان التثبيت",
|
||||
"buildInstallationDirectoryWindowTitle": "حدد مكان التثبيت",
|
||||
"timeLeft": "الوقت المتبقي: {timeLeft, plural, =0{less than a minute} =1{about {timeLeft} minute} other{about {timeLeft} minutes}}",
|
||||
"localBuildsWarning": "الإنشاءات المحلية ليست مضمونة للعمل",
|
||||
"saveLocalVersion": "احفظ",
|
||||
"embedded": "مغروس",
|
||||
"remote": "من بعد",
|
||||
"local": "محلي",
|
||||
"checkServer": "يفحص{name}",
|
||||
"startServer": "يبدأ {name}",
|
||||
"stopServer": "قف {name}",
|
||||
"startHosting": "ابدأ الاستضافة",
|
||||
"stopHosting": "توقف عن الاستضافة",
|
||||
"startGame": "ابدأ فورت نايت",
|
||||
"stopGame": "إغلاق فورت نايت",
|
||||
"waitingForGameServer": "في انتظار تشغيل خادم اللعبة...",
|
||||
"gameServerStartWarning": "تم بدء تشغيل الخادم بدون رأس بنجاح، ولكن لم يتم تشغيل خادم اللعبة",
|
||||
"gameServerStartLocalWarning": "تم تشغيل خادم اللعبة بنجاح، لكن لا يمكن للاعبين الآخرين الانضمام",
|
||||
"gameServerStarted": "تم تشغيل خادم اللعبة بنجاح",
|
||||
"checkingGameServer": "جارٍ التحقق مما إذا كان بإمكان اللاعبين الآخرين الانضمام إلى خادم اللعبة...",
|
||||
"checkGameServerFixMessage": "لا يمكن للاعبين الآخرين الانضمام إلى خادم اللعبة لأن البورت {port} غير مفتوح",
|
||||
"checkGameServerFixAction": "اصلح",
|
||||
"infoName": "مساعده",
|
||||
"emptyVersionName": "اسم الإصدار فارغ",
|
||||
"versionAlreadyExists": "هذا الإصدار موجود من قبل",
|
||||
"emptyGamePath": "مسار اللعبة فارغ",
|
||||
"directoryDoesNotExist": "المسار غير موجود",
|
||||
"missingShippingExe": "مسار اللعبة غير صالح: مفقودFortniteClient-Win64-Shipping",
|
||||
"invalidDownloadPath": "مسار التنزيل غير صالح",
|
||||
"invalidDllPath": "مسار dll غير صالح",
|
||||
"dllDoesNotExist": "الملف غير موجود",
|
||||
"invalidDllExtension": "هذا الملف ليس DLL",
|
||||
"emptyHostname": "اسم مضيف فارغ",
|
||||
"hostnameFormat": "تنسيق اسم المضيف غير صحيح: IP المتوقع: port",
|
||||
"emptyURL": "عنوان URL للتحديث فارغ",
|
||||
"missingVersionError": "قم بتنزيل الإصدار أو تحديده قبل بدء لعبة Fortnite",
|
||||
"missingExecutableError": "ملف Fortnite القابل للتنفيذ مفقود: يعني هذا عادةً أنه تم نقل التثبيت أو حذفه",
|
||||
"corruptedVersionError": "تثبيت Fortnite تالف: يرجى تنزيله مرة أخرى من المشغل أو تغيير الإصدار",
|
||||
"missingDllError": "ملف dll الموجود في {path} غير موجود",
|
||||
"corruptedDllError": "لا يمكن حقن ملف dll: {error}",
|
||||
"tokenError": "لا يمكن تسجيل الدخول إلى Fortnite: خطأ في المصادقة",
|
||||
"unknownFortniteError": "حدث خطأ غير معروف أثناء تشغيل Fortnite: {error}",
|
||||
"serverNoLongerAvailable": "خادم {owner} لم يعد متاحًا",
|
||||
"serverNoLongerAvailableUnnamed": "الخادم السابق لم يعد متاحا",
|
||||
"noServerFound": "لم يتم العثور على خادم: رابط غير صالح أو منتهي الصلاحية",
|
||||
"settingsUtilsThemeName": "سمة",
|
||||
"settingsUtilsThemeDescription": "حدد السمة التي تريد استخدامها داخل الانشر",
|
||||
"dark": "داكن",
|
||||
"light": "ضوء",
|
||||
"system": "نظام",
|
||||
"settingsUtilsLanguageName": "لغة",
|
||||
"settingsUtilsLanguageDescription": "حدد اللغة التي تريد استخدامها داخل المشغل"
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"find": "Einstellung suchen",
|
||||
"on": "An",
|
||||
"off": "Aus",
|
||||
"resetDefaultsContent": "Zurücksetzen",
|
||||
"resetDefaultsDialogTitle": "Möchten Sie alle Einstellungen in diesem Tab auf ihre Standardwerte zurücksetzen? Diese Aktion ist nicht rückgängig zu machen",
|
||||
"resetDefaultsDialogSecondaryAction": "Schließen",
|
||||
"resetDefaultsDialogPrimaryAction": "Zurücksetzen",
|
||||
"authenticatorName": "Authentifizierer",
|
||||
"authenticatorConfigurationName": "Authentifizierer-Konfiguration",
|
||||
"authenticatorConfigurationDescription": "Dieser Abschnitt enthält die Konfiguration des Authentifizierers",
|
||||
"authenticatorConfigurationHostName": "Host",
|
||||
"authenticatorConfigurationHostDescription": "Der Hostname des Authentifizierers",
|
||||
"authenticatorConfigurationPortName": "Port",
|
||||
"authenticatorConfigurationPortDescription": "Der Port des Authentifizierers",
|
||||
"authenticatorConfigurationDetachedName": "Abgetrennt",
|
||||
"authenticatorConfigurationDetachedDescription": "Ob der eingebettete Authentifizierer als separater Prozess gestartet werden soll, nützlich für die Fehlersuche",
|
||||
"authenticatorInstallationDirectoryName": "Installationsverzeichnis",
|
||||
"authenticatorInstallationDirectoryDescription": "Öffnet den Ordner, in dem der eingebettete Authentifizierer gespeichert ist",
|
||||
"authenticatorInstallationDirectoryContent": "Dateien anzeigen",
|
||||
"authenticatorResetDefaultsName": "Authentifizierer zurücksetzen",
|
||||
"authenticatorResetDefaultsDescription": "Setzt die Einstellungen des Authentifizierers auf ihre Standardwerte zurück",
|
||||
"authenticatorResetDefaultsContent": "Zurücksetzen",
|
||||
"hostGameServerName": "Gameserver",
|
||||
"hostGameServerDescription": "Geben Sie grundlegende Informationen über Ihren Gameserver für den Server-Browser an",
|
||||
"hostGameServerNameName": "Name",
|
||||
"hostGameServerNameDescription": "Der Name Ihres Gameservers",
|
||||
"hostGameServerDescriptionName": "Beschreibung",
|
||||
"hostGameServerDescriptionDescription": "Die Beschreibung Ihres Gameservers",
|
||||
"hostGameServerPasswordName": "Passwort",
|
||||
"hostGameServerPasswordDescription": "Das Passwort Ihres Gameservers, falls benötigt",
|
||||
"hostGameServerDiscoverableName": "Sichtbar",
|
||||
"hostGameServerDiscoverableDescription": "Machen Sie Ihren Server für andere Spieler im Server-Browser verfügbar",
|
||||
"hostShareName": "Teilen",
|
||||
"hostShareDescription": "Erleichtern Sie anderen Personen das Betreten Ihres Servers mit den Optionen in diesem Abschnitt",
|
||||
"hostShareLinkName": "Link",
|
||||
"hostShareLinkDescription": "Kopiert einen Link zu Ihrem Server in die Zwischenablage (erfordert den Reboot Launcher)",
|
||||
"hostShareLinkContent": "Link kopieren",
|
||||
"hostShareLinkMessageSuccess": "Link in die Zwischenablage kopiert",
|
||||
"hostShareIpName": "Öffentliche IP",
|
||||
"hostShareIpDescription": "Kopiert Ihre aktuelle öffentliche IP-Adresse in die Zwischenablage (erfordert nicht den Reboot Launcher)",
|
||||
"hostShareIpContent": "IP kopieren",
|
||||
"hostShareIpMessageLoading": "Ermittlung Ihrer öffentlichen IP...",
|
||||
"hostShareIpMessageSuccess": "Ihre IP-Adresse wurde in die Zwischenablage kopiert",
|
||||
"hostShareIpMessageError": "Beim Ermitteln Ihrer öffentlichen IP ist ein Fehler aufgetreten: {error}",
|
||||
"hostResetName": "Gameserver zurücksetzen",
|
||||
"hostResetDescription": "Setzt die Einstellungen des Gameservers auf ihre Standardwerte zurück",
|
||||
"hostResetContent": "Zurücksetzen",
|
||||
"browserName": "Server-Browser",
|
||||
"noServersAvailableTitle": "Derzeit sind keine Server verfügbar",
|
||||
"noServersAvailableSubtitle": "Hosten Sie selbst einen Server oder kommen Sie später wieder",
|
||||
"joinServer": "Server beitreten",
|
||||
"noServersAvailableByQueryTitle": "Keine Ergebnisse gefunden",
|
||||
"noServersAvailableByQuerySubtitle": "Kein Server entspricht Ihrer Anfrage",
|
||||
"findServer": "Server suchen",
|
||||
"copyIp": "IP kopieren",
|
||||
"hostName": "Host",
|
||||
"matchmakerName": "Vermittler",
|
||||
"matchmakerConfigurationName": "Vermittler-Konfiguration",
|
||||
"matchmakerConfigurationDescription": "Dieser Abschnitt enthält die Konfiguration des Vermittlers",
|
||||
"matchmakerConfigurationHostName": "Host",
|
||||
"matchmakerConfigurationHostDescription": "Der Hostname des Vermittlers",
|
||||
"matchmakerConfigurationPortName": "Port",
|
||||
"matchmakerConfigurationPortDescription": "Der Port des Vermittlers",
|
||||
"matchmakerConfigurationAddressName": "Gameserver-Adresse",
|
||||
"matchmakerConfigurationAddressDescription": "Die Adresse des Gameservers, die vom Vermittler verwendet wird",
|
||||
"matchmakerConfigurationDetachedName": "Abgetrennt",
|
||||
"matchmakerConfigurationDetachedDescription": "Ob der eingebettete Vermittler als separater Prozess gestartet werden soll, nützlich für die Fehlersuche",
|
||||
"matchmakerInstallationDirectoryName": "Installationsverzeichnis",
|
||||
"matchmakerInstallationDirectoryDescription": "Öffnet den Ordner, in dem der eingebettete Vermittler gespeichert ist",
|
||||
"matchmakerInstallationDirectoryContent": "Dateien anzeigen",
|
||||
"matchmakerResetDefaultsName": "Vermittler zurücksetzen",
|
||||
"matchmakerResetDefaultsDescription": "Setzt die Einstellungen des Vermittlers auf ihre Standardwerte zurück",
|
||||
"matchmakerResetDefaultsContent": "Zurücksetzen",
|
||||
"matchmakerResetDefaultsDialogTitle": "Möchten Sie alle Einstellungen in diesem Tab auf ihre Standardwerte zurücksetzen? Diese Aktion ist nicht rückgängig zu machen",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Schließen",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Zurücksetzen",
|
||||
"playName": "Spielen",
|
||||
"playGameServerName": "Gameserver",
|
||||
"playGameServerDescription": "Hilfreiche Verknüpfungen, um den Server zu finden, auf dem Sie spielen möchten",
|
||||
"playGameServerContentLocal": "Ihr Server",
|
||||
"playGameServerContentBrowser": "{owner}'s Server",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Server hosten",
|
||||
"playGameServerHostDescription": "Möchten Sie einen Gameserver für sich selbst oder Ihre Freunde erstellen? Hosten Sie einen!",
|
||||
"playGameServerHostContent": "Hosten",
|
||||
"playGameServerBrowserName": "Server durchsuchen",
|
||||
"playGameServerBrowserDescription": "Finden Sie einen im Server-Browser gehosteten entdeckbaren Server auf dem Reboot Launcher",
|
||||
"playGameServerBrowserContent": "Durchsuchen",
|
||||
"playGameServerCustomName": "Benutzerdefinierten Server beitreten",
|
||||
"playGameServerCustomDescription": "Geben Sie die Adresse eines beliebigen Servers ein, unabhängig davon, ob er auf dem Reboot Launcher gehostet wurde oder nicht",
|
||||
"playGameServerCustomContent": "IP eingeben",
|
||||
"settingsName": "Einstellungen",
|
||||
"settingsClientName": "Client-Einstellungen",
|
||||
"settingsClientDescription": "Dieser Abschnitt enthält die DLLs, die verwendet werden, um den Fortnite-Client zu betreiben",
|
||||
"settingsClientConsoleName": "Unreal Engine-Konsole",
|
||||
"settingsClientConsoleDescription": "Diese Datei wird injiziert, um die Unreal Engine-Konsole freizuschalten",
|
||||
"settingsClientAuthName": "Authentifizierungspatcher",
|
||||
"settingsClientAuthDescription": "Diese Datei wird injiziert, um alle HTTP-Anfragen an den Authenticator des Launchers umzuleiten",
|
||||
"settingsClientMemoryName": "Speicher-Patcher",
|
||||
"settingsClientMemoryDescription": "Diese Datei wird injiziert, um zu verhindern, dass der Fortnite-Client aufgrund eines Speicherlecks abstürzt",
|
||||
"settingsClientArgsName": "Benutzerdefinierte Startargumente",
|
||||
"settingsClientArgsDescription": "Zusätzliche Argumente, die beim Starten des Spiels verwendet werden sollen",
|
||||
"settingsClientArgsPlaceholder": "-Beispiel",
|
||||
"settingsServerName": "Gameserver-Einstellungen",
|
||||
"settingsServerSubtitle": "Dieser Abschnitt enthält Einstellungen, die sich auf die Umsetzung des Gameservers beziehen",
|
||||
"settingsServerFileName": "Implementierung",
|
||||
"settingsServerFileDescription": "Diese Datei wird injiziert, um einen Gameserver zu erstellen und Spiele zu hosten",
|
||||
"settingsServerPortName": "Port",
|
||||
"settingsServerPortDescription": "Der von der Gameserver-DLL verwendete Port",
|
||||
"settingsServerMirrorName": "Update-Spiegel",
|
||||
"settingsServerMirrorDescription": "Die URL, die verwendet wird, um die Gameserver-DLL zu aktualisieren",
|
||||
"settingsServerMirrorPlaceholder": "Spiegel",
|
||||
"settingsServerTimerName": "Update-Timer",
|
||||
"settingsServerTimerSubtitle": "Bestimmt, wann die Gameserver-DLL aktualisiert werden soll",
|
||||
"settingsUtilsName": "Launcher-Dienstprogramme",
|
||||
"settingsUtilsSubtitle": "Dieser Abschnitt enthält nützliche Einstellungen für den Launcher",
|
||||
"settingsUtilsInstallationDirectoryName": "Installationsverzeichnis",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Öffnet das Installationsverzeichnis",
|
||||
"settingsUtilsInstallationDirectoryContent": "Dateien anzeigen",
|
||||
"settingsUtilsBugReportName": "Fehlerbericht erstellen",
|
||||
"settingsUtilsBugReportSubtitle": "Helfen Sie mir, Fehler zu beheben, indem Sie sie melden",
|
||||
"settingsUtilsBugReportContent": "Fehler melden",
|
||||
"settingsUtilsResetDefaultsName": "Einstellungen zurücksetzen",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Setzt die Einstellungen des Launchers auf ihre Standardwerte zurück",
|
||||
"settingsUtilsDialogTitle": "Möchten Sie alle Einstellungen in diesem Tab auf ihre Standardwerte zurücksetzen? Diese Aktion ist nicht rückgängig zu machen",
|
||||
"settingsUtilsResetDefaultsContent": "Zurücksetzen",
|
||||
"settingsUtilsDialogSecondaryAction": "Schließen",
|
||||
"settingsUtilsDialogPrimaryAction": "Zurücksetzen",
|
||||
"addVersionName": "Version",
|
||||
"addVersionDescription": "Wählen Sie die Version von Fortnite aus, die Sie verwenden möchten",
|
||||
"addLocalBuildName": "Eine Version aus dem lokalen Speicher dieses PCs hinzufügen",
|
||||
"addLocalBuildDescription": "Versionen von Ihrer lokalen Festplatte sind nicht garantiert, um zu funktionieren",
|
||||
"addLocalBuildContent": "Version hinzufügen",
|
||||
"downloadBuildName": "Jede Version aus der Cloud herunterladen",
|
||||
"downloadBuildDescription": "Laden Sie jede Fortnite-Version einfach aus der Cloud herunter",
|
||||
"downloadBuildContent": "Herunterladen",
|
||||
"cannotUpdateGameServer": "Beim Aktualisieren des Gameservers ist ein Fehler aufgetreten: {error}",
|
||||
"launchFortnite": "Fortnite starten",
|
||||
"closeFortnite": "Fortnite schließen",
|
||||
"updateGameServerDllNever": "Nie",
|
||||
"updateGameServerDllEvery": "Alle {name}",
|
||||
"selectPathPlaceholder": "Pfad",
|
||||
"selectPathWindowTitle": "Datei auswählen",
|
||||
"defaultDialogSecondaryAction": "Schließen",
|
||||
"stopLoadingDialogAction": "Stopp",
|
||||
"copyErrorDialogTitle": "Fehler kopieren",
|
||||
"copyErrorDialogSuccess": "Fehler in die Zwischenablage kopiert",
|
||||
"defaultServerName": "Reboot Gameserver",
|
||||
"defaultServerDescription": "Nur ein weiterer Server",
|
||||
"updatingRebootDll": "Reboot-DLL herunterladen...",
|
||||
"updatedRebootDll": "Die Reboot-DLL wurde erfolgreich heruntergeladen",
|
||||
"updateRebootDllError": "Beim Herunterladen der Reboot-DLL ist ein Fehler aufgetreten: {error}",
|
||||
"updateRebootDllErrorAction": "Erneut versuchen",
|
||||
"uncaughtErrorMessage": "Ein unbehandelter Fehler ist aufgetreten: {error}",
|
||||
"launchingHeadlessServer": "Starten des Headless-Servers...",
|
||||
"usernameOrEmail": "Benutzername/E-Mail",
|
||||
"usernameOrEmailPlaceholder": "Geben Sie Ihren Benutzernamen oder Ihre E-Mail-Adresse ein",
|
||||
"password": "Passwort",
|
||||
"passwordPlaceholder": "Geben Sie Ihr Passwort ein, wenn Sie eins verwenden möchten",
|
||||
"cancelProfileChanges": "Abbrechen",
|
||||
"saveProfileChanges": "Speichern",
|
||||
"startingServer": "{name} wird gestartet...",
|
||||
"startedServer": "{name} wurde erfolgreich gestartet",
|
||||
"startServerError": "Beim Starten von {name} ist ein Fehler aufgetreten: {error}",
|
||||
"stoppingServer": "{name} wird gestoppt...",
|
||||
"stoppedServer": "{name} wurde erfolgreich gestoppt",
|
||||
"stopServerError": "Beim Stoppen von {name} ist ein Fehler aufgetreten: {error}",
|
||||
"missingHostNameError": "Fehlender Hostname in der Konfiguration von {name}",
|
||||
"missingPortError": "Fehlender Port in der Konfiguration von {name}",
|
||||
"illegalPortError": "Ungültiger Port in der Konfiguration von {name}",
|
||||
"freeingPort": "Port {port} wird freigegeben...",
|
||||
"freedPort": "Port {port} wurde erfolgreich freigegeben",
|
||||
"freePortError": "Beim Freigeben von Port {port} ist ein Fehler aufgetreten: {error}",
|
||||
"pingingRemoteServer": "Pinge den entfernten {name} an...",
|
||||
"pingingLocalServer": "Pinge den {type} {name} an...",
|
||||
"pingError": "Der {type} {name} kann nicht gepingt werden",
|
||||
"joinSelfServer": "Sie können Ihrem eigenen Server nicht beitreten",
|
||||
"wrongServerPassword": "Falsches Passwort: Bitte versuchen Sie es erneut",
|
||||
"offlineServer": "Dieser Server ist derzeit nicht online: Bitte versuchen Sie es später erneut",
|
||||
"serverPassword": "Passwort",
|
||||
"serverPasswordPlaceholder": "Geben Sie das Serverpasswort ein",
|
||||
"serverPasswordCancel": "Abbrechen",
|
||||
"serverPasswordConfirm": "Bestätigen",
|
||||
"joinedServer": "Sie sind erfolgreich {author}'s Server beigetreten!",
|
||||
"copiedIp": "IP in die Zwischenablage kopiert",
|
||||
"selectVersion": "Wählen Sie eine Version aus",
|
||||
"noVersions": "Bitte erstellen oder laden Sie eine Version herunter",
|
||||
"missingVersion": "Diese Version existiert nicht auf dem lokalen Computer",
|
||||
"deleteVersionDialogTitle": "Sind Sie sicher, dass Sie diese Version löschen möchten?",
|
||||
"deleteVersionFromDiskOption": "Version-Dateien von der Festplatte löschen",
|
||||
"deleteVersionCancel": "Behalten",
|
||||
"deleteVersionConfirm": "Löschen",
|
||||
"versionName": "Name",
|
||||
"versionNameLabel": "Geben Sie den neuen Versionnamen ein",
|
||||
"newVersionNameConfirm": "Speichern",
|
||||
"newVersionNameLabel": "Geben Sie den neuen Versionnamen ein",
|
||||
"gameFolderTitle": "Spielverzeichnis",
|
||||
"gameFolderPlaceholder": "Geben Sie das neue Spielverzeichnis ein",
|
||||
"gameFolderPlaceWindowTitle": "Spielverzeichnis auswählen",
|
||||
"gameFolderLabel": "Pfad",
|
||||
"openInExplorer": "Im Explorer öffnen",
|
||||
"modify": "Ändern",
|
||||
"delete": "Löschen",
|
||||
"build": "Bauen",
|
||||
"selectBuild": "Wählen Sie einen Fortnite-Build aus",
|
||||
"fetchingBuilds": "Baut und Laufwerke abrufen...",
|
||||
"unknownError": "Unbekannter Fehler",
|
||||
"downloadVersionError": "Version kann nicht heruntergeladen werden: {error}",
|
||||
"downloadedVersion": "Der Download wurde erfolgreich abgeschlossen!",
|
||||
"download": "Herunterladen",
|
||||
"downloading": "Herunterladen...",
|
||||
"extracting": "Extrahieren...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Installationsverzeichnis",
|
||||
"buildInstallationDirectoryPlaceholder": "Geben Sie das Installationsverzeichnis ein",
|
||||
"buildInstallationDirectoryWindowTitle": "Installationsverzeichnis auswählen",
|
||||
"timeLeft": "Verbleibende Zeit: {timeLeft, plural, =0{weniger als eine Minute} =1{etwa {timeLeft} Minute} other{etwa {timeLeft} Minuten}}",
|
||||
"localBuildsWarning": "Lokale Builds sind nicht garantiert, um zu funktionieren",
|
||||
"saveLocalVersion": "Speichern",
|
||||
"embedded": "Eingebettet",
|
||||
"remote": "Remote",
|
||||
"local": "Lokal",
|
||||
"checkServer": "{name} überprüfen",
|
||||
"startServer": "{name} starten",
|
||||
"stopServer": "{name} stoppen",
|
||||
"startHosting": "Hosting starten",
|
||||
"stopHosting": "Hosting stoppen",
|
||||
"startGame": "Fortnite starten",
|
||||
"stopGame": "Fortnite schließen",
|
||||
"waitingForGameServer": "Warten auf das Hochfahren des Gameservers...",
|
||||
"gameServerStartWarning": "Der Headless-Server wurde erfolgreich gestartet, aber der Gameserver wurde nicht hochgefahren",
|
||||
"gameServerStartLocalWarning": "Der Gameserver wurde erfolgreich gestartet, aber andere Spieler können nicht beitreten",
|
||||
"gameServerStarted": "Der Gameserver wurde erfolgreich gestartet",
|
||||
"checkingGameServer": "Überprüfen, ob andere Spieler dem Gameserver beitreten können...",
|
||||
"checkGameServerFixMessage": "Andere Spieler können dem Gameserver nicht beitreten, da Port {port} nicht geöffnet ist",
|
||||
"checkGameServerFixAction": "Beheben",
|
||||
"infoName": "Info",
|
||||
"emptyVersionName": "Leerer Versionsname",
|
||||
"versionAlreadyExists": "Diese Version existiert bereits",
|
||||
"emptyGamePath": "Leerer Spiel-Pfad",
|
||||
"directoryDoesNotExist": "Verzeichnis existiert nicht",
|
||||
"missingShippingExe": "Ungültiger Spiel-Pfad: FortniteClient-Win64-Shipping fehlt",
|
||||
"invalidDownloadPath": "Ungültiger Download-Pfad",
|
||||
"invalidDllPath": "Ungültiger DLL-Pfad",
|
||||
"dllDoesNotExist": "Die Datei existiert nicht",
|
||||
"invalidDllExtension": "Diese Datei ist keine DLL",
|
||||
"emptyHostname": "Leerer Hostname",
|
||||
"hostnameFormat": "Falsches Hostname-Format: IP:Port erwartet",
|
||||
"emptyURL": "Leere Update-URL"
|
||||
}
|
||||
@@ -7,21 +7,21 @@
|
||||
"resetDefaultsDialogSecondaryAction": "Close",
|
||||
"resetDefaultsDialogPrimaryAction": "Reset",
|
||||
"authenticatorName": "Authenticator",
|
||||
"authenticatorConfigurationName": "Authenticator configuration",
|
||||
"authenticatorConfigurationDescription": "This section contains the authenticator's configuration",
|
||||
"authenticatorTypeName": "Type",
|
||||
"authenticatorTypeDescription": "The type of authenticator to use when logging into Fortnite",
|
||||
"authenticatorConfigurationHostName": "Host",
|
||||
"authenticatorConfigurationHostDescription": "The hostname of the authenticator",
|
||||
"authenticatorConfigurationPortName": "Port",
|
||||
"authenticatorConfigurationPortDescription": "The port of the authenticator",
|
||||
"authenticatorConfigurationDetachedName": "Detached",
|
||||
"authenticatorConfigurationDetachedDescription": "Whether the embedded authenticator should be started as a separate process, useful for debugging",
|
||||
"authenticatorConfigurationDetachedDescription": "Whether a separate process should be spawned, useful for debugging",
|
||||
"authenticatorInstallationDirectoryName": "Installation directory",
|
||||
"authenticatorInstallationDirectoryDescription": "Opens the folder where the embedded authenticator is located",
|
||||
"authenticatorInstallationDirectoryContent": "Show Files",
|
||||
"authenticatorResetDefaultsName": "Reset authenticator",
|
||||
"authenticatorInstallationDirectoryContent": "Show files",
|
||||
"authenticatorResetDefaultsName": "Reset",
|
||||
"authenticatorResetDefaultsDescription": "Resets the authenticator's settings to their default values",
|
||||
"authenticatorResetDefaultsContent": "Reset",
|
||||
"hostGameServerName": "Game server",
|
||||
"hostGameServerName": "Information",
|
||||
"hostGameServerDescription": "Provide basic information about your game server for the Server Browser",
|
||||
"hostGameServerNameName": "Name",
|
||||
"hostGameServerNameDescription": "The name of your game server",
|
||||
@@ -31,19 +31,21 @@
|
||||
"hostGameServerPasswordDescription": "The password of your game server, if you need one",
|
||||
"hostGameServerDiscoverableName": "Discoverable",
|
||||
"hostGameServerDiscoverableDescription": "Make your server available to other players on the server browser",
|
||||
"hostHeadlessName": "Headless",
|
||||
"hostHeadlessDescription": "Runs Fortnite without a graphics to optimize resources usage, may not work for old seasons",
|
||||
"hostShareName": "Share",
|
||||
"hostShareDescription": "Make it easy for other people to join your server with the options in this section",
|
||||
"hostShareLinkName": "Link",
|
||||
"hostShareLinkDescription": "Copies a link for your server to the clipboard (requires the Reboot Launcher)",
|
||||
"hostShareLinkDescription": "Copies a link for your server to the clipboard",
|
||||
"hostShareLinkContent": "Copy Link",
|
||||
"hostShareLinkMessageSuccess": "Copied your link to the clipboard",
|
||||
"hostShareIpName": "Public IP",
|
||||
"hostShareIpDescription": "Copies your current public IP to the clipboard (doesn't require the Reboot Launcher)",
|
||||
"hostShareIpDescription": "Copies your current public IP to the clipboard",
|
||||
"hostShareIpContent": "Copy IP",
|
||||
"hostShareIpMessageLoading": "Obtaining your public IP...",
|
||||
"hostShareIpMessageSuccess": "Copied your link to the clipboard",
|
||||
"hostShareIpMessageError": "An error occurred while obtaining your public IP: {error}",
|
||||
"hostResetName": "Reset game server",
|
||||
"hostResetName": "Reset",
|
||||
"hostResetDescription": "Resets the game server's settings to their default values",
|
||||
"hostResetContent": "Reset",
|
||||
"browserName": "Server Browser",
|
||||
@@ -56,8 +58,8 @@
|
||||
"copyIp": "Copy IP",
|
||||
"hostName": "Host",
|
||||
"matchmakerName": "Matchmaker",
|
||||
"matchmakerConfigurationName": "Matchmaker configuration",
|
||||
"matchmakerConfigurationDescription": "This section contains the matchmaker's configuration",
|
||||
"matchmakerTypeName": "Type",
|
||||
"matchmakerTypeDescription": "The type of matchmaker to use when queueing for a game",
|
||||
"matchmakerConfigurationHostName": "Host",
|
||||
"matchmakerConfigurationHostDescription": "The hostname of the matchmaker",
|
||||
"matchmakerConfigurationPortName": "Port",
|
||||
@@ -65,47 +67,47 @@
|
||||
"matchmakerConfigurationAddressName": "Game server address",
|
||||
"matchmakerConfigurationAddressDescription": "The address of the game server used by the matchmaker",
|
||||
"matchmakerConfigurationDetachedName": "Detached",
|
||||
"matchmakerConfigurationDetachedDescription": "Whether the embedded matchmaker should be started as a separate process, useful for debugging",
|
||||
"matchmakerConfigurationDetachedDescription": "Whether a separate process should be spawned, useful for debugging",
|
||||
"matchmakerInstallationDirectoryName": "Installation directory",
|
||||
"matchmakerInstallationDirectoryDescription": "Opens the folder where the embedded matchmaker is located",
|
||||
"matchmakerInstallationDirectoryContent": "Show Files",
|
||||
"matchmakerResetDefaultsName": "Reset matchmaker",
|
||||
"matchmakerInstallationDirectoryContent": "Show files",
|
||||
"matchmakerResetDefaultsName": "Reset",
|
||||
"matchmakerResetDefaultsDescription": "Resets the matchmaker's settings to their default values",
|
||||
"matchmakerResetDefaultsContent": "Reset",
|
||||
"matchmakerResetDefaultsDialogTitle": "Do you want to reset all the setting in this tab to their default values? This action is irreversible",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Close",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Reset",
|
||||
"playName": "Play",
|
||||
"playGameServerName": "Game Server",
|
||||
"playGameServerDescription": "Helpful shortcuts to find the server where you want to play",
|
||||
"playGameServerName": "Multiplayer",
|
||||
"playGameServerDescription": "See all the available options to start playing",
|
||||
"playGameServerContentLocal": "Your server",
|
||||
"playGameServerContentBrowser": "{owner}'s server",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Host a server",
|
||||
"playGameServerHostDescription": "Do you want to create a game server for yourself or your friends? Host one!",
|
||||
"playGameServerHostDescription": "Configure a game server on your PC",
|
||||
"playGameServerHostContent": "Host",
|
||||
"playGameServerBrowserName": "Browse servers",
|
||||
"playGameServerBrowserDescription": "Find a discoverable server hosted on the Reboot Launcher in the server browser",
|
||||
"playGameServerBrowserDescription": "Discover servers hosted by the community",
|
||||
"playGameServerBrowserContent": "Browse",
|
||||
"playGameServerCustomName": "Join a Custom server",
|
||||
"playGameServerCustomDescription": "Type the address of any server, whether it was hosted on the Reboot Launcher or not",
|
||||
"playGameServerCustomName": "Join a custom server",
|
||||
"playGameServerCustomDescription": "Join a game server using its public IP address",
|
||||
"playGameServerCustomContent": "Enter IP",
|
||||
"settingsName": "Settings",
|
||||
"settingsClientName": "Client settings",
|
||||
"settingsClientName": "Client",
|
||||
"settingsClientDescription": "This section contains the dlls used to make the Fortnite client work",
|
||||
"settingsClientConsoleName": "Unreal engine console",
|
||||
"settingsClientConsoleDescription": "This file is injected to unlock the Unreal Engine Console",
|
||||
"settingsClientConsoleDescription": "Unlocks the Unreal Engine Console",
|
||||
"settingsClientAuthName": "Authentication patcher",
|
||||
"settingsClientAuthDescription": "This file is injected to redirect all HTTP requests to the launcher's authenticator",
|
||||
"settingsClientAuthDescription": "Redirects all HTTP requests to the authenticator",
|
||||
"settingsClientMemoryName": "Memory patcher",
|
||||
"settingsClientMemoryDescription": "This file is injected to prevent the Fortnite client from crashing because of a memory leak",
|
||||
"settingsClientMemoryDescription": "Prevents the client from crashing because of a memory leak",
|
||||
"settingsClientArgsName": "Custom launch arguments",
|
||||
"settingsClientArgsDescription": "Additional arguments to use when launching the game",
|
||||
"settingsClientArgsPlaceholder": "Arguments...",
|
||||
"settingsServerName": "Game server settings",
|
||||
"settingsServerName": "Game server",
|
||||
"settingsServerSubtitle": "This section contains settings related to the game server implementation",
|
||||
"settingsServerFileName": "Implementation",
|
||||
"settingsServerFileDescription": "This file is injected to create a game server & host matches",
|
||||
"settingsServerFileDescription": "Creates a game server to host matches",
|
||||
"settingsServerPortName": "Port",
|
||||
"settingsServerPortDescription": "The port used by the game server dll",
|
||||
"settingsServerMirrorName": "Update mirror",
|
||||
@@ -113,11 +115,11 @@
|
||||
"settingsServerMirrorPlaceholder": "mirror",
|
||||
"settingsServerTimerName": "Update timer",
|
||||
"settingsServerTimerSubtitle": "Determines when the game server dll should be updated",
|
||||
"settingsUtilsName": "Launcher utilities",
|
||||
"settingsUtilsSubtitle": "This section contains handy settings for the launcher",
|
||||
"settingsUtilsName": "Launcher",
|
||||
"settingsUtilsSubtitle": "This section contains settings related to the launcher",
|
||||
"settingsUtilsInstallationDirectoryName": "Installation directory",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Opens the installation directory",
|
||||
"settingsUtilsInstallationDirectoryContent": "Show Files",
|
||||
"settingsUtilsInstallationDirectoryContent": "Show files",
|
||||
"settingsUtilsBugReportName": "Create a bug report",
|
||||
"settingsUtilsBugReportSubtitle": "Help me fix bugs by reporting them",
|
||||
"settingsUtilsBugReportContent": "Report a bug",
|
||||
@@ -127,8 +129,12 @@
|
||||
"settingsUtilsResetDefaultsContent": "Reset",
|
||||
"settingsUtilsDialogSecondaryAction": "Close",
|
||||
"settingsUtilsDialogPrimaryAction": "Reset",
|
||||
"addVersionName": "Version",
|
||||
"addVersionDescription": "Select the version of Fortnite you want to use",
|
||||
"selectFortniteName": "Fortnite version",
|
||||
"selectFortniteDescription": "Select the version of Fortnite you want to use",
|
||||
"manageVersionsName": "Manage versions",
|
||||
"manageVersionsDescription": "Manage your Fortnite installations",
|
||||
"importVersionName": "Import",
|
||||
"importVersionDescription": "Import a new version of Fortnite into the launcher",
|
||||
"addLocalBuildName": "Add a version from this PC's local storage",
|
||||
"addLocalBuildDescription": "Versions coming from your local disk are not guaranteed to work",
|
||||
"addLocalBuildContent": "Add build",
|
||||
@@ -148,12 +154,12 @@
|
||||
"copyErrorDialogSuccess": "Copied error to clipboard",
|
||||
"defaultServerName": "Reboot Game Server",
|
||||
"defaultServerDescription": "Just another server",
|
||||
"updatingRebootDll": "Downloading reboot dll...",
|
||||
"updatedRebootDll": "The reboot dll was downloaded successfully",
|
||||
"updateRebootDllError": "An error occurred while downloading the reboot dll: {error}",
|
||||
"updateRebootDllErrorAction": "Retry",
|
||||
"downloadingDll": "Downloading {name} dll...",
|
||||
"downloadDllSuccess": "The {name} dll was downloaded successfully",
|
||||
"downloadDllError": "An error occurred while downloading the reboot dll: {error}",
|
||||
"downloadDllRetry": "Retry",
|
||||
"uncaughtErrorMessage": "An uncaught error was thrown: {error}",
|
||||
"launchingHeadlessServer": "Launching the headless server...",
|
||||
"launchingHeadlessServer": "Launching the game server...",
|
||||
"usernameOrEmail": "Username/Email",
|
||||
"usernameOrEmailPlaceholder": "Type your username or email",
|
||||
"password": "Password",
|
||||
@@ -162,7 +168,9 @@
|
||||
"saveProfileChanges": "Save",
|
||||
"startingServer": "Starting the {name}...",
|
||||
"startedServer": "The {name} was started successfully",
|
||||
"checkedServer": "The {name} works correctly",
|
||||
"startServerError": "An error occurred while starting the {name}: {error}",
|
||||
"localServerError": "The local {name} doesn't work correctly: {error}",
|
||||
"stoppingServer": "Stopping the {name}...",
|
||||
"stoppedServer": "The {name} was stopped successfully",
|
||||
"stopServerError": "An error occurred while stopping the {name}: {error}",
|
||||
@@ -185,7 +193,6 @@
|
||||
"joinedServer": "You joined {author}'s server successfully!",
|
||||
"copiedIp": "Copied IP to the clipboard",
|
||||
"selectVersion": "Select a version",
|
||||
"noVersions": "Please create or download a version",
|
||||
"missingVersion": "This version doesn't exist on the local machine",
|
||||
"deleteVersionDialogTitle": "Are you sure you want to delete this version?",
|
||||
"deleteVersionFromDiskOption": "Delete version files from disk",
|
||||
@@ -202,8 +209,11 @@
|
||||
"openInExplorer": "Open in explorer",
|
||||
"modify": "Modify",
|
||||
"delete": "Delete",
|
||||
"build": "Build",
|
||||
"selectBuild": "Select a fortnite build",
|
||||
"source": "Source",
|
||||
"manifest": "Manifest",
|
||||
"archive": "Archive",
|
||||
"build": "Version",
|
||||
"selectBuild": "Select a fortnite version",
|
||||
"fetchingBuilds": "Fetching builds and disks...",
|
||||
"unknownError": "Unknown error",
|
||||
"downloadVersionError": "Cannot download version: {error}",
|
||||
@@ -229,7 +239,7 @@
|
||||
"startGame": "Start fortnite",
|
||||
"stopGame": "Close fortnite",
|
||||
"waitingForGameServer": "Waiting for the game server to boot up...",
|
||||
"gameServerStartWarning": "The headless server was started successfully, but the game server didn't boot",
|
||||
"gameServerStartWarning": "The game server was started successfully, but Reboot didn't load",
|
||||
"gameServerStartLocalWarning": "The game server was started successfully, but other players can't join",
|
||||
"gameServerStarted": "The game server was started successfully",
|
||||
"checkingGameServer": "Checking if other players can join the game server...",
|
||||
@@ -251,7 +261,6 @@
|
||||
"missingVersionError": "Download or select a version before starting Fortnite",
|
||||
"missingExecutableError": "Missing Fortnite executable: usually this means that the installation was moved or deleted",
|
||||
"corruptedVersionError": "Corrupted Fortnite installation: please download it again from the launcher or change version",
|
||||
"missingDllError": "The dll at {path} doesn't exist",
|
||||
"corruptedDllError": "Cannot inject dll: {error}",
|
||||
"tokenError": "Cannot log in into Fortnite: authentication error",
|
||||
"unknownFortniteError": "An unknown error occurred while launching Fortnite: {error}",
|
||||
@@ -264,5 +273,19 @@
|
||||
"light": "Light",
|
||||
"system": "System",
|
||||
"settingsUtilsLanguageName": "Language",
|
||||
"settingsUtilsLanguageDescription": "Select the language to use inside the launcher"
|
||||
"settingsUtilsLanguageDescription": "Select the language to use inside the launcher",
|
||||
"playAutomaticServerName": "Embedded game server",
|
||||
"playAutomaticServerDescription": "Whether a game server should be started automatically if none was configured",
|
||||
"infoDocumentationName": "Documentation",
|
||||
"infoDocumentationDescription": "Read some tutorials on how to use Reboot",
|
||||
"infoDocumentationContent": "Open GitHub",
|
||||
"infoDiscordName": "Discord",
|
||||
"infoDiscordDescription": "Join the discord server to receive help",
|
||||
"infoDiscordContent": "Open Discord",
|
||||
"infoVideoName": "Tutorial",
|
||||
"infoVideoDescription": "Watch a tutorial to understand how to use the launcher",
|
||||
"infoVideoContent": "Open YouTube",
|
||||
"dllDeletedTitle": "A critical dll was deleted. If you didn't delete it, your Antivirus probably flagged it. This is a false positive: please disable your Antivirus and try again",
|
||||
"dllDeletedSecondaryAction": "Close",
|
||||
"dllDeletedPrimaryAction": "Try again"
|
||||
}
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"find": "Encontrar una configuración",
|
||||
"on": "Activado",
|
||||
"off": "Desactivado",
|
||||
"resetDefaultsContent": "Restablecer",
|
||||
"resetDefaultsDialogTitle": "¿Deseas restablecer todas las configuraciones de esta pestaña a sus valores predeterminados? Esta acción es irreversible.",
|
||||
"resetDefaultsDialogSecondaryAction": "Cerrar",
|
||||
"resetDefaultsDialogPrimaryAction": "Restablecer",
|
||||
"authenticatorName": "Autenticador",
|
||||
"authenticatorConfigurationName": "Configuración del Autenticador",
|
||||
"authenticatorConfigurationDescription": "Esta sección contiene la configuración del autenticador.",
|
||||
"authenticatorConfigurationHostName": "Host",
|
||||
"authenticatorConfigurationHostDescription": "El nombre del host del autenticador.",
|
||||
"authenticatorConfigurationPortName": "Puerto",
|
||||
"authenticatorConfigurationPortDescription": "El puerto del autenticador.",
|
||||
"authenticatorConfigurationDetachedName": "Separado",
|
||||
"authenticatorConfigurationDetachedDescription": "Si el autenticador incorporado debe iniciarse como un proceso separado, útil para depuración.",
|
||||
"authenticatorInstallationDirectoryName": "Directorio de Instalación",
|
||||
"authenticatorInstallationDirectoryDescription": "Abre la carpeta donde se encuentra el autenticador incorporado.",
|
||||
"authenticatorInstallationDirectoryContent": "Mostrar Archivos",
|
||||
"authenticatorResetDefaultsName": "Restablecer Autenticador",
|
||||
"authenticatorResetDefaultsDescription": "Restablece las configuraciones del autenticador a sus valores predeterminados.",
|
||||
"authenticatorResetDefaultsContent": "Restablecer",
|
||||
"hostGameServerName": "Servidor de Juego",
|
||||
"hostGameServerDescription": "Proporciona información básica sobre tu servidor de juego para el Navegador de Servidores.",
|
||||
"hostGameServerNameName": "Nombre",
|
||||
"hostGameServerNameDescription": "El nombre de tu servidor de juego.",
|
||||
"hostGameServerDescriptionName": "Descripción",
|
||||
"hostGameServerDescriptionDescription": "La descripción de tu servidor de juego.",
|
||||
"hostGameServerPasswordName": "Contraseña",
|
||||
"hostGameServerPasswordDescription": "La contraseña de tu servidor de juego, si la necesitas.",
|
||||
"hostGameServerDiscoverableName": "Visible",
|
||||
"hostGameServerDiscoverableDescription": "Haz que tu servidor esté disponible para otros jugadores en el Navegador de Servidores.",
|
||||
"hostShareName": "Compartir",
|
||||
"hostShareDescription": "Facilita que otras personas se unan a tu servidor con las opciones en esta sección.",
|
||||
"hostShareLinkName": "Enlace",
|
||||
"hostShareLinkDescription": "Copia un enlace a tu servidor al portapapeles (requiere Reboot Launcher).",
|
||||
"hostShareLinkContent": "Copiar Enlace",
|
||||
"hostShareLinkMessageSuccess": "Enlace copiado al portapapeles.",
|
||||
"hostShareIpName": "IP Pública",
|
||||
"hostShareIpDescription": "Copia tu dirección IP pública actual al portapapeles (no requiere Reboot Launcher).",
|
||||
"hostShareIpContent": "Copiar IP",
|
||||
"hostShareIpMessageLoading": "Obteniendo tu IP pública...",
|
||||
"hostShareIpMessageSuccess": "IP copiada al portapapeles.",
|
||||
"hostShareIpMessageError": "Se produjo un error al obtener tu IP pública: {error}.",
|
||||
"hostResetName": "Restablecer Servidor de Juego",
|
||||
"hostResetDescription": "Restablece las configuraciones del servidor de juego a sus valores predeterminados.",
|
||||
"hostResetContent": "Restablecer",
|
||||
"browserName": "Navegador de Servidores",
|
||||
"noServersAvailableTitle": "No hay servidores disponibles en este momento",
|
||||
"noServersAvailableSubtitle": "¡Hospeda un servidor tú mismo o vuelve más tarde!",
|
||||
"joinServer": "Unirse al Servidor",
|
||||
"noServersAvailableByQueryTitle": "No se encontraron resultados",
|
||||
"noServersAvailableByQuerySubtitle": "No hay servidores que coincidan con tu búsqueda.",
|
||||
"findServer": "Encontrar un Servidor",
|
||||
"copyIp": "Copiar IP",
|
||||
"hostName": "Host",
|
||||
"matchmakerName": "Matchmaker",
|
||||
"matchmakerConfigurationName": "Configuración del Matchmaker",
|
||||
"matchmakerConfigurationDescription": "Esta sección contiene la configuración del Matchmaker.",
|
||||
"matchmakerConfigurationHostName": "Host",
|
||||
"matchmakerConfigurationHostDescription": "El nombre del host del Matchmaker.",
|
||||
"matchmakerConfigurationPortName": "Puerto",
|
||||
"matchmakerConfigurationPortDescription": "El puerto del Matchmaker.",
|
||||
"matchmakerConfigurationAddressName": "Dirección del Servidor de Juego",
|
||||
"matchmakerConfigurationAddressDescription": "La dirección del servidor de juego utilizada por el Matchmaker.",
|
||||
"matchmakerConfigurationDetachedName": "Separado",
|
||||
"matchmakerConfigurationDetachedDescription": "Si el Matchmaker incorporado debe iniciarse como un proceso separado, útil para depuración.",
|
||||
"matchmakerInstallationDirectoryName": "Directorio de Instalación",
|
||||
"matchmakerInstallationDirectoryDescription": "Abre la carpeta donde se encuentra el Matchmaker incorporado.",
|
||||
"matchmakerInstallationDirectoryContent": "Mostrar Archivos",
|
||||
"matchmakerResetDefaultsName": "Restablecer Matchmaker",
|
||||
"matchmakerResetDefaultsDescription": "Restablece las configuraciones del Matchmaker a sus valores predeterminados.",
|
||||
"matchmakerResetDefaultsContent": "Restablecer",
|
||||
"matchmakerResetDefaultsDialogTitle": "¿Deseas restablecer todas las configuraciones de esta pestaña a sus valores predeterminados? Esta acción es irreversible.",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Cerrar",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Restablecer",
|
||||
"playName": "Jugar",
|
||||
"playGameServerName": "Servidor de Juego",
|
||||
"playGameServerDescription": "Accesos directos útiles para encontrar el servidor donde quieres jugar.",
|
||||
"playGameServerContentLocal": "Tu servidor",
|
||||
"playGameServerContentBrowser": "Servidor de {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Hospedar un Servidor",
|
||||
"playGameServerHostDescription": "¿Quieres crear un servidor de juego para ti o tus amigos? ¡Hospeda uno!",
|
||||
"playGameServerHostContent": "Hospedar",
|
||||
"playGameServerBrowserName": "Explorar Servidores",
|
||||
"playGameServerBrowserDescription": "Encuentra un servidor visible alojado en Reboot Launcher en el Navegador de Servidores.",
|
||||
"playGameServerBrowserContent": "Explorar",
|
||||
"playGameServerCustomName": "Unirse a un Servidor Personalizado",
|
||||
"playGameServerCustomDescription": "Ingresa la dirección de cualquier servidor, ya sea alojado en Reboot Launcher o no.",
|
||||
"playGameServerCustomContent": "Insertar IP",
|
||||
"settingsName": "Configuraciones",
|
||||
"settingsClientName": "Configuraciones del Cliente",
|
||||
"settingsClientDescription": "Esta sección contiene los archivos DLL utilizados para que el cliente de Fortnite funcione.",
|
||||
"settingsClientConsoleName": "Consola de Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Este archivo se inyecta para desbloquear la Consola de Unreal Engine.",
|
||||
"settingsClientAuthName": "Parche de Autenticación",
|
||||
"settingsClientAuthDescription": "Este archivo se inyecta para redirigir todas las solicitudes HTTP al autenticador del lanzador.",
|
||||
"settingsClientMemoryName": "Parche de Memoria",
|
||||
"settingsClientMemoryDescription": "Este archivo se inyecta para evitar que el cliente de Fortnite falle debido a una fuga de memoria.",
|
||||
"settingsClientArgsName": "Argumentos de Inicio Personalizados",
|
||||
"settingsClientArgsDescription": "Argumentos adicionales a utilizar al iniciar el juego.",
|
||||
"settingsClientArgsPlaceholder": "-ejemplo",
|
||||
"settingsServerName": "Configuraciones del Servidor de Juego",
|
||||
"settingsServerSubtitle": "Esta sección contiene configuraciones relacionadas con la implementación del servidor de juego.",
|
||||
"settingsServerFileName": "Implementación",
|
||||
"settingsServerFileDescription": "Este archivo se inyecta para crear un servidor de juego y alojar partidas.",
|
||||
"settingsServerPortName": "Puerto",
|
||||
"settingsServerPortDescription": "El puerto utilizado por la DLL del servidor de juego.",
|
||||
"settingsServerMirrorName": "Espejo de Actualización",
|
||||
"settingsServerMirrorDescription": "La URL utilizada para actualizar la DLL del servidor de juego.",
|
||||
"settingsServerMirrorPlaceholder": "espejo",
|
||||
"settingsServerTimerName": "Temporizador de Actualización",
|
||||
"settingsServerTimerSubtitle": "Determina cuándo se debe actualizar la DLL del servidor de juego.",
|
||||
"settingsUtilsName": "Utilidades del Lanzador",
|
||||
"settingsUtilsSubtitle": "Esta sección contiene configuraciones útiles para el lanzador.",
|
||||
"settingsUtilsInstallationDirectoryName": "Directorio de Instalación",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Abre el directorio de instalación.",
|
||||
"settingsUtilsInstallationDirectoryContent": "Mostrar Archivos",
|
||||
"settingsUtilsBugReportName": "Crear un Reporte de Error",
|
||||
"settingsUtilsBugReportSubtitle": "Ayúdame a solucionar errores informándolos.",
|
||||
"settingsUtilsBugReportContent": "Informar un Error",
|
||||
"settingsUtilsResetDefaultsName": "Restablecer Configuraciones",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Restablece las configuraciones del lanzador a sus valores predeterminados.",
|
||||
"settingsUtilsDialogTitle": "¿Deseas restablecer todas las configuraciones de esta pestaña a sus valores predeterminados? Esta acción es irreversible.",
|
||||
"settingsUtilsResetDefaultsContent": "Restablecer",
|
||||
"settingsUtilsDialogSecondaryAction": "Cerrar",
|
||||
"settingsUtilsDialogPrimaryAction": "Restablecer",
|
||||
"addVersionName": "Versión",
|
||||
"addVersionDescription": "Selecciona la versión de Fortnite que deseas usar.",
|
||||
"addLocalBuildName": "Agregar una Versión desde el Almacenamiento Local de este PC",
|
||||
"addLocalBuildDescription": "Las versiones provenientes de tu disco local no tienen garantía de funcionamiento.",
|
||||
"addLocalBuildContent": "Agregar Build",
|
||||
"downloadBuildName": "Descargar cualquier Versión desde la Nube",
|
||||
"downloadBuildDescription": "Descarga cualquier versión de Fortnite fácilmente desde la nube.",
|
||||
"downloadBuildContent": "Descargar",
|
||||
"cannotUpdateGameServer": "Se produjo un error al actualizar el servidor de juego: {error}",
|
||||
"launchFortnite": "Iniciar Fortnite",
|
||||
"closeFortnite": "Cerrar Fortnite",
|
||||
"updateGameServerDllNever": "Nunca",
|
||||
"updateGameServerDllEvery": "Cada {name}",
|
||||
"selectPathPlaceholder": "Ruta",
|
||||
"selectPathWindowTitle": "Seleccionar un archivo",
|
||||
"defaultDialogSecondaryAction": "Cerrar",
|
||||
"stopLoadingDialogAction": "Detener",
|
||||
"copyErrorDialogTitle": "Copiar Error",
|
||||
"copyErrorDialogSuccess": "Error copiado al portapapeles",
|
||||
"defaultServerName": "Servidor de Juego Reboot",
|
||||
"defaultServerDescription": "Solo otro servidor",
|
||||
"updatingRebootDll": "Descargando DLL de Reboot...",
|
||||
"updatedRebootDll": "La DLL de Reboot se ha descargado con éxito",
|
||||
"updateRebootDllError": "Se produjo un error al descargar la DLL de Reboot: {error}",
|
||||
"updateRebootDllErrorAction": "Intentar de Nuevo",
|
||||
"uncaughtErrorMessage": "Se produjo un error no controlado: {error}",
|
||||
"launchingHeadlessServer": "Iniciando el servidor sin interfaz gráfica...",
|
||||
"usernameOrEmail": "Nombre de Usuario/Correo Electrónico",
|
||||
"usernameOrEmailPlaceholder": "Ingresa tu nombre de usuario o correo electrónico",
|
||||
"password": "Contraseña",
|
||||
"passwordPlaceholder": "Ingresa tu contraseña, si la deseas usar",
|
||||
"cancelProfileChanges": "Cancelar",
|
||||
"saveProfileChanges": "Guardar",
|
||||
"startingServer": "Iniciando {name}...",
|
||||
"startedServer": "{name} se inició correctamente",
|
||||
"startServerError": "Se produjo un error al iniciar {name}: {error}",
|
||||
"stoppingServer": "Deteniendo {name}...",
|
||||
"stoppedServer": "{name} se detuvo correctamente",
|
||||
"stopServerError": "Se produjo un error al detener {name}: {error}",
|
||||
"missingHostNameError": "Falta el nombre de host en la configuración de {name}",
|
||||
"missingPortError": "Falta el puerto en la configuración de {name}",
|
||||
"illegalPortError": "Puerto no válido en la configuración de {name}",
|
||||
"freeingPort": "Liberando puerto {port}...",
|
||||
"freedPort": "El puerto {port} se liberó correctamente",
|
||||
"freePortError": "Se produjo un error al liberar el puerto {port}: {error}",
|
||||
"pingingRemoteServer": "Haciendo ping al {name} remoto...",
|
||||
"pingingLocalServer": "Haciendo ping al {type} {name}...",
|
||||
"pingError": "No se puede hacer ping a {type} {name}",
|
||||
"joinSelfServer": "No puedes unirte a tu propio servidor",
|
||||
"wrongServerPassword": "Contraseña incorrecta: por favor, inténtalo de nuevo",
|
||||
"offlineServer": "Este servidor no está en línea en este momento: por favor, inténtalo de nuevo más tarde",
|
||||
"serverPassword": "Contraseña",
|
||||
"serverPasswordPlaceholder": "Ingresa la contraseña del servidor",
|
||||
"serverPasswordCancel": "Cancelar",
|
||||
"serverPasswordConfirm": "Confirmar",
|
||||
"joinedServer": "¡Te has unido al servidor de {author} con éxito!",
|
||||
"copiedIp": "IP copiada al portapapeles",
|
||||
"selectVersion": "Seleccionar una Versión",
|
||||
"noVersions": "Por favor, crea o descarga una versión",
|
||||
"missingVersion": "Esta versión no existe en la computadora local",
|
||||
"deleteVersionDialogTitle": "¿Estás seguro de que deseas eliminar esta versión?",
|
||||
"deleteVersionFromDiskOption": "Eliminar archivos de la versión del disco",
|
||||
"deleteVersionCancel": "Mantener",
|
||||
"deleteVersionConfirm": "Eliminar",
|
||||
"versionName": "Nombre",
|
||||
"versionNameLabel": "Ingresa el nuevo nombre de la versión",
|
||||
"newVersionNameConfirm": "Guardar",
|
||||
"newVersionNameLabel": "Ingresa el nuevo nombre de la versión",
|
||||
"gameFolderTitle": "Carpeta del Juego",
|
||||
"gameFolderPlaceholder": "Ingresa la nueva carpeta del juego",
|
||||
"gameFolderPlaceWindowTitle": "Seleccionar carpeta del juego",
|
||||
"gameFolderLabel": "Ruta",
|
||||
"openInExplorer": "Abrir en el Explorador",
|
||||
"modify": "Modificar",
|
||||
"delete": "Eliminar",
|
||||
"build": "Compilar",
|
||||
"selectBuild": "Seleccionar una Compilación de Fortnite",
|
||||
"fetchingBuilds": "Obteniendo compilaciones y discos...",
|
||||
"unknownError": "Error desconocido",
|
||||
"downloadVersionError": "No se pudo descargar la versión: {error}",
|
||||
"downloadedVersion": "¡La descarga se completó correctamente!",
|
||||
"download": "Descargar",
|
||||
"downloading": "Descargando...",
|
||||
"extracting": "Extrayendo...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Directorio de Instalación",
|
||||
"buildInstallationDirectoryPlaceholder": "Ingresa el directorio de instalación",
|
||||
"buildInstallationDirectoryWindowTitle": "Seleccionar directorio de instalación",
|
||||
"timeLeft": "Tiempo restante: {timeLeft, plural, =0{menos de un minuto} =1{alrededor de {timeLeft} minuto} other{alrededor de {timeLeft} minutos}}",
|
||||
"localBuildsWarning": "Las compilaciones locales no tienen garantía de funcionamiento",
|
||||
"saveLocalVersion": "Guardar",
|
||||
"embedded": "Incrustado",
|
||||
"remote": "Remoto",
|
||||
"local": "Local",
|
||||
"checkServer": "Comprobar {name}",
|
||||
"startServer": "Iniciar {name}",
|
||||
"stopServer": "Detener {name}",
|
||||
"startHosting": "Iniciar Alojamiento",
|
||||
"stopHosting": "Detener Alojamiento",
|
||||
"startGame": "Iniciar Fortnite",
|
||||
"stopGame": "Cerrar Fortnite",
|
||||
"waitingForGameServer": "Esperando a que el servidor de juego se inicie...",
|
||||
"gameServerStartWarning": "El servidor sin interfaz gráfica se inició correctamente, pero el servidor de juego no se inició.",
|
||||
"gameServerStartLocalWarning": "El servidor de juego se inició correctamente, pero otros jugadores no pueden unirse.",
|
||||
"gameServerStarted": "El servidor de juego se inició correctamente",
|
||||
"checkingGameServer": "Comprobando si otros jugadores pueden unirse al servidor de juego...",
|
||||
"checkGameServerFixMessage": "Los otros jugadores no pueden unirse al servidor de juego porque el puerto {port} no está abierto",
|
||||
"checkGameServerFixAction": "Arreglar",
|
||||
"infoName": "Información",
|
||||
"emptyVersionName": "Nombre de versión vacío",
|
||||
"versionAlreadyExists": "Esta versión ya existe",
|
||||
"emptyGamePath": "Ruta de juego vacía",
|
||||
"diretoryDoesNotExist": "El directorio no existe",
|
||||
"missingShippingExe": "Ruta de juego no válida: falta FortniteClient-Win64-Shipping.exe",
|
||||
"invalidDownloadPath": "Ruta de descarga no válida",
|
||||
"invalidDllPath": "Ruta de DLL no válida",
|
||||
"dllDoesNotExist": "El archivo no existe",
|
||||
"invalidDllExtension": "Este archivo no es una DLL",
|
||||
"emptyHostname": "Nombre de host vacío",
|
||||
"hostnameFormat": "Formato de nombre de host incorrecto: se espera ip:puerto",
|
||||
"emptyURL": "URL vacía"
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
{
|
||||
"find": "Trouver un paramètre",
|
||||
"on": "Activé",
|
||||
"off": "Désactivé",
|
||||
"resetDefaultsContent": "Réinitialiser",
|
||||
"resetDefaultsDialogTitle": "Voulez-vous réinitialiser l'onglet actif ? Cette action est irréversible",
|
||||
"resetDefaultsDialogSecondaryAction": "Fermer",
|
||||
"resetDefaultsDialogPrimaryAction": "Réinitialiser",
|
||||
"authenticatorName": "Authentificateur",
|
||||
"authenticatorConfigurationName": "Configuration de l'authentificateur",
|
||||
"authenticatorConfigurationDescription": "Cette section contient la configuration de l'authentificateur",
|
||||
"authenticatorConfigurationHostName": "Hôte",
|
||||
"authenticatorConfigurationHostDescription": "Le nom d'hôte de l'authentificateur",
|
||||
"authenticatorConfigurationPortName": "Port",
|
||||
"authenticatorConfigurationPortDescription": "Le port de l'authentificateur",
|
||||
"authenticatorConfigurationDetachedName": "Detaché",
|
||||
"authenticatorConfigurationDetachedDescription": "Lancer l'authentificateur dans un processus à part, utile pour le débug",
|
||||
"authenticatorInstallationDirectoryName": "Dossier d'installation",
|
||||
"authenticatorInstallationDirectoryDescription": "Ouvre le dossier des fichers de l'authentificateur",
|
||||
"authenticatorInstallationDirectoryContent": "Afficher les fichiers",
|
||||
"authenticatorResetDefaultsName": "Réinitialiser l'authentificateur",
|
||||
"authenticatorResetDefaultsDescription": "Réinitialiser les paramètres de l'authentificateur ?",
|
||||
"authenticatorResetDefaultsContent": "Réinitialiser",
|
||||
"hostGameServerName": "Serveur de jeu",
|
||||
"hostGameServerDescription": "Donnez des informations à propos de votre partie",
|
||||
"hostGameServerNameName": "Jeu",
|
||||
"hostGameServerNameDescription": "Le nom de votre serveur de jeu",
|
||||
"hostGameServerDescriptionName": "Description",
|
||||
"hostGameServerDescriptionDescription": "La description de votre serveur de jeu",
|
||||
"hostGameServerPasswordName": "Mot de passe",
|
||||
"hostGameServerPasswordDescription": "Mot de passe de votre serveur de jeu (si besoin)",
|
||||
"hostGameServerDiscoverableName": "Visible",
|
||||
"hostGameServerDiscoverableDescription": "Rendre votre serveur de jeu publique",
|
||||
"hostShareName": "Partager",
|
||||
"hostShareDescription": "Aidez d'autres personnes à rejoindre facilement votre serveur avec les options de cette section",
|
||||
"hostShareLinkName": "Lien",
|
||||
"hostShareLinkDescription": "Copie le lien vers votre serveur dans le presse-papiers (néccessite Reboot)",
|
||||
"hostShareLinkContent": "Copier un lien",
|
||||
"hostShareLinkMessageSuccess": "Le lien a correctement été copier !",
|
||||
"hostShareIpName": "IP publique",
|
||||
"hostShareIpDescription": "Copie votre IP publique dans votre presse-papiers (ne néccessite pas Reboot)",
|
||||
"hostShareIpContent": "Copier l'IP",
|
||||
"hostShareIpMessageLoading": "Récupération de votre IP...",
|
||||
"hostShareIpMessageSuccess": "Le lien a bien été copié",
|
||||
"hostShareIpMessageError": "Impossible de récupérer votre IP: {error}",
|
||||
"hostResetName": "Réinitialiser le serveur de jeu",
|
||||
"hostResetDescription": "Réinitialiser les paramètres du serveur de jeu",
|
||||
"hostResetContent": "Réinitialiser",
|
||||
"browserName": "Navigateur de serveurs",
|
||||
"noServersAvailableTitle": "Aucun serveur n'est disponible pour le moment",
|
||||
"noServersAvailableSubtitle": "Hostez un serveur vous même et revenez plus tard",
|
||||
"joinServer": "Rejoindre le serveur",
|
||||
"noServersAvailableByQueryTitle": "Aucun résultat trouvé",
|
||||
"noServersAvailableByQuerySubtitle": "Aucun serveur ne correspond à vôtre recherche",
|
||||
"findServer": "Trouver un serveur",
|
||||
"copyIp": "Copier l'IP",
|
||||
"hostName": "Hôte",
|
||||
"matchmakerName": "Matchmaker",
|
||||
"matchmakerConfigurationName": "Configuration du Matchmaker",
|
||||
"matchmakerConfigurationDescription": "Cette section contient la configuration du Matchmaker",
|
||||
"matchmakerConfigurationHostName": "Hôte",
|
||||
"matchmakerConfigurationHostDescription": "Le nom d'hôte du Matchmaker",
|
||||
"matchmakerConfigurationPortName": "Port",
|
||||
"matchmakerConfigurationPortDescription": "Le port de votre Matchmaker",
|
||||
"matchmakerConfigurationAddressName": "Adresse du serveur de jeu",
|
||||
"matchmakerConfigurationAddressDescription": "L'adresse de votre serveur de jeu sera utilisé par le Matchmaker",
|
||||
"matchmakerConfigurationDetachedName": "Détaché",
|
||||
"matchmakerConfigurationDetachedDescription": "Lancer le Matchmaker dans un processus à part, utile pour le débug",
|
||||
"matchmakerInstallationDirectoryName": "Dossier d'installation",
|
||||
"matchmakerInstallationDirectoryDescription": "Ouvre le dossier des fichers de l'authentificateur",
|
||||
"matchmakerInstallationDirectoryContent": "Afficher les fichiers",
|
||||
"matchmakerResetDefaultsName": "Réinitialiser le Matchmaker",
|
||||
"matchmakerResetDefaultsDescription": "Réinitialiser le Matchmaker avec ses paramètres par défaut",
|
||||
"matchmakerResetDefaultsContent": "Réinitialiser",
|
||||
"matchmakerResetDefaultsDialogTitle": "Voulez-vous réinitaliser tous les paramètres de cette section ? Ceci est irréversible",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Fermer",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Réinitialiser",
|
||||
"playName": "Jouer",
|
||||
"playGameServerName": "Serveur de jeu",
|
||||
"playGameServerDescription": "Raccourcis pratiques pour trouver le serveur qui vous convient",
|
||||
"playGameServerContentLocal": "Votre serveur",
|
||||
"playGameServerContentBrowser": "Serveur de {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Héberger un serveur",
|
||||
"playGameServerHostDescription": "Vous souhaitez créer un serveur de jeu pour vous ou vos amis ? Hébergez-en un !",
|
||||
"playGameServerHostContent": "Héberger",
|
||||
"playGameServerBrowserName": "Explorer les serveurs",
|
||||
"playGameServerBrowserDescription": "Rechercher un serveur hébergé sur Reboot dans le navigateur de serveurs",
|
||||
"playGameServerBrowserContent": "Explorer",
|
||||
"playGameServerCustomName": "Rejoindre un serveur personnalisé",
|
||||
"playGameServerCustomDescription": "Tapez l'adresse de n'importe quel serveur (qu'il soit hébergé sur Reboot ou non)",
|
||||
"playGameServerCustomContent": "Entrez l'IP",
|
||||
"settingsName": "Paramètres",
|
||||
"settingsClientName": "Options du client",
|
||||
"settingsClientDescription": "Cette section contient les DLLs utilisés par Fortnite pour fonctionner",
|
||||
"settingsClientConsoleName": "Console Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Ce fichier est injecté pour débloquer la console Unreal Engine",
|
||||
"settingsClientAuthName": "Patcheur de l'Autentificateur",
|
||||
"settingsClientAuthDescription": "Ce fichier est injecté pour rediriger les requêtes HTTP vers l'authentificateur",
|
||||
"settingsClientMemoryName": "Patcheur de mémoire",
|
||||
"settingsClientMemoryDescription": "Ce fichier est injecté pour empêcher les crash de Fortnite dû à des fuites de mémoire",
|
||||
"settingsClientArgsName": "Arugments de démarrage",
|
||||
"settingsClientArgsDescription": "Arguments de démarrage à appliquer au lancement",
|
||||
"settingsClientArgsPlaceholder": "-example",
|
||||
"settingsServerName": "Options du serveur de jeu",
|
||||
"settingsServerSubtitle": "Cette section contient les paramètres liés à l'implémentation du serveur de jeu",
|
||||
"settingsServerFileName": "Implémentation",
|
||||
"settingsServerFileDescription": "Ce fichier est injecté pour héberger les matches",
|
||||
"settingsServerPortName": "Port",
|
||||
"settingsServerPortDescription": "Le port utilisé par le DLL du serveur",
|
||||
"settingsServerMirrorName": "Adresse de mises à jours",
|
||||
"settingsServerMirrorDescription": "L'URL permet de mettre à jour les DLLs du serveur",
|
||||
"settingsServerMirrorPlaceholder": "mirroir",
|
||||
"settingsServerTimerName": "Fréquence de mise à jour",
|
||||
"settingsServerTimerSubtitle": "Détermine quand une mise à jour des DLLs doivent être effectuée",
|
||||
"settingsUtilsName": "Utilitaires",
|
||||
"settingsUtilsSubtitle": "Cette section contient des paramètres pratiques pour le lanceur",
|
||||
"settingsUtilsInstallationDirectoryName": "Dossier d'installation",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Ouvre le dossier de l'installation",
|
||||
"settingsUtilsInstallationDirectoryContent": "Affiche les fichiers",
|
||||
"settingsUtilsBugReportName": "Créer un rapport de bug (anglais seulement)",
|
||||
"settingsUtilsBugReportSubtitle": "Aidez moi à fixer les bugs en me les signalants !",
|
||||
"settingsUtilsBugReportContent": "Signaler un bug",
|
||||
"settingsUtilsResetDefaultsName": "Réinitialiser les options",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Réinitialise les paramètres du lanceur à leurs valeurs par défaut",
|
||||
"settingsUtilsDialogTitle": "Voulez-vous réinitialiser tous les paramètres à leurs valeurs par défaut ? Cette action est irréversible",
|
||||
"settingsUtilsResetDefaultsContent": "Réinitialiser",
|
||||
"settingsUtilsDialogSecondaryAction": "Fermer",
|
||||
"settingsUtilsDialogPrimaryAction": "Réinitialiser",
|
||||
"addVersionName": "Version",
|
||||
"addVersionDescription": "Sélectionnez le build de Fortnite que vous souhaitez utiliser",
|
||||
"addLocalBuildName": "Ajouter un build à partir du stockage local de ce PC",
|
||||
"addLocalBuildDescription": "Le fonctionnement des builds locaux n'est pas garanti",
|
||||
"addLocalBuildContent": "Ajouter un build",
|
||||
"downloadBuildName": "Téléchargez n'importe quel build depuis le cloud",
|
||||
"downloadBuildDescription": "Téléchargez facilement n'importe quel build de Fortnite depuis le cloud",
|
||||
"downloadBuildContent": "Télécharger",
|
||||
"cannotUpdateGameServer": "Une erreur s'est produite lors de la mise à jour du serveur de jeu : {error}",
|
||||
"launchFortnite": "Lancer Fortnite",
|
||||
"closeFortnite": "Fermer Fortnite",
|
||||
"updateGameServerDllNever": "Jamais",
|
||||
"updateGameServerDllEvery": "Chaque {name}",
|
||||
"selectPathPlaceholder": "Répertoire",
|
||||
"selectPathWindowTitle": "Sélectionner un fichier",
|
||||
"defaultDialogSecondaryAction": "Fermer",
|
||||
"stopLoadingDialogAction": "Stop",
|
||||
"copyErrorDialogTitle": "Erreur de copie",
|
||||
"copyErrorDialogSuccess": "Erreur copiée dans le presse-papiers",
|
||||
"defaultServerName": "Redémarrer le serveur de jeu",
|
||||
"defaultServerDescription": "Juste un autre serveur",
|
||||
"updatingRebootDll": "Téléchargement du DLL de Reboot...",
|
||||
"updatedRebootDll": "Le DLL de Reboot a été téléchargé avec succès",
|
||||
"updateRebootDllError": "Une erreur s'est produite lors du téléchargement du DLL de Reboot : {error}",
|
||||
"updateRebootDllErrorAction": "Recommencer",
|
||||
"uncaughtErrorMessage": "Erreur : {error}",
|
||||
"launchingHeadlessServer": "Lancement du serveur headless...",
|
||||
"usernameOrEmail": "Nom d'utilisateur/Email",
|
||||
"usernameOrEmailPlaceholder": "Tapez votre nom d'utilisateur ou votre email",
|
||||
"password": "Mot de passe",
|
||||
"passwordPlaceholder": "Tapez votre mot de passe (si vous souhaitez en utiliser un)",
|
||||
"cancelProfileChanges": "Annuler",
|
||||
"saveProfileChanges": "Sauvegarder",
|
||||
"startingServer": "Démarrage de {name}...",
|
||||
"startedServer": "Le {name} a été démarré avec succès",
|
||||
"startServerError": "Une erreur s'est produite lors du démarrage de {name} : {error}",
|
||||
"stoppingServer": "Arrêt de {name}...",
|
||||
"stoppedServer": "Le {name} a été arrêté avec succès",
|
||||
"stopServerError": "Une erreur s'est produite lors de l'arrêt de {name} : {error}",
|
||||
"missingHostNameError": "Nom d'hôte manquant dans la configuration {name}",
|
||||
"missingPortError": "Port manquant dans la configuration {name}",
|
||||
"illegalPortError": "Port invalide dans la configuration {name}",
|
||||
"freeingPort": "Libération du port {port}...",
|
||||
"freedPort": "Le port {port} a été libéré avec succès",
|
||||
"freePortError": "Une erreur s'est produite lors de la libération du port {port} : {error}",
|
||||
"pingingRemoteServer": "Ping du serveur distant {name}...",
|
||||
"pingingLocalServer": "Ping de {type} {name}...",
|
||||
"pingError": "Impossible de ping le {type} {name}",
|
||||
"joinSelfServer": "Vous ne pouvez pas rejoindre votre propre serveur",
|
||||
"wrongServerPassword": "Mot de passe erroné : veuillez réessayer",
|
||||
"offlineServer": "Ce serveur n'est pas en ligne pour le moment : veuillez réessayer plus tard",
|
||||
"serverPassword": "Mot de passe",
|
||||
"serverPasswordPlaceholder": "Tapez le mot de passe du serveur",
|
||||
"serverPasswordCancel": "Annuler",
|
||||
"serverPasswordConfirm": "Confirmer",
|
||||
"joinedServer": "Vous avez rejoint le serveur de {author} avec succès !",
|
||||
"copiedIp": "IP copiée dans le presse-papiers",
|
||||
"selectVersion": "Sélectionnez une version",
|
||||
"noVersions": "Veuillez créer ou télécharger une version",
|
||||
"missingVersion": "Cette version n'existe pas sur cette machine",
|
||||
"deleteVersionDialogTitle": "Êtes-vous sûr de vouloir supprimer cette version ?",
|
||||
"deleteVersionFromDiskOption": "Supprimer les fichiers de la version du disque",
|
||||
"deleteVersionCancel": "Garder",
|
||||
"deleteVersionConfirm": "Supprimer",
|
||||
"versionName": "Nom",
|
||||
"versionNameLabel": "Entrez le nom de la nouvelle version",
|
||||
"newVersionNameConfirm": "Sauvegarder",
|
||||
"newVersionNameLabel": "Entrez le nom de la nouvelle version",
|
||||
"gameFolderTitle": "Dossier du jeu",
|
||||
"gameFolderPlaceholder": "Entrez le dossier du jeu",
|
||||
"gameFolderPlaceWindowTitle": "Sélectionnez le dossier du jeu",
|
||||
"gameFolderLabel": "Répertoire",
|
||||
"openInExplorer": "Ouvrir dans l'explorateur",
|
||||
"modify": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"build": "Build",
|
||||
"selectBuild": "Sélectionnez un build Fortnite",
|
||||
"fetchingBuilds": "Récupération des builds et des disques...",
|
||||
"unknownError": "Erreur inconnue",
|
||||
"downloadVersionError": "Impossible de télécharger la version : {error}",
|
||||
"downloadedVersion": "Le téléchargement s'est terminé avec succès !",
|
||||
"download": "Télécharger",
|
||||
"downloading": "Téléchargement...",
|
||||
"extracting": "Extraction...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Répertoire d'installation",
|
||||
"buildInstallationDirectoryPlaceholder": "Entrez le répertoire d'installation",
|
||||
"buildInstallationDirectoryWindowTitle": "Selectionner le répertoire d'installation",
|
||||
"timeLeft": "Temps restant : {timeLeft, plural, =0{less than a minute} =1{about {timeLeft} minute} other{about {timeLeft} minutes}}",
|
||||
"localBuildsWarning": "Le fonctionnement des builds locaux n'est pas garanties",
|
||||
"saveLocalVersion": "Sauvegarder",
|
||||
"embedded": "Intégré",
|
||||
"remote": "À distance",
|
||||
"local": "Local",
|
||||
"checkServer": "Vérifier {name}",
|
||||
"startServer": "Démarrer {name}",
|
||||
"stopServer": "Arrêter {name}",
|
||||
"startHosting": "Démarrer l'hébergement",
|
||||
"stopHosting": "Arrêter l'hébergement",
|
||||
"startGame": "Démarrer Fortnite",
|
||||
"stopGame": "Fermer Fortnite",
|
||||
"waitingForGameServer": "En attente du démarrage du serveur de jeu...",
|
||||
"gameServerStartWarning": "Fortnite (headless) a été démarré avec succès, mais le serveur n'a pas pu démarrer",
|
||||
"gameServerStartLocalWarning": "Le serveur de jeu a été démarré avec succès, mais les autres joueurs ne peuvent pas le rejoindre",
|
||||
"gameServerStarted": "Le serveur de jeu a été démarré avec succès",
|
||||
"checkingGameServer": "Vérification de si les autres joueurs peuvent rejoindre le serveur de jeu...",
|
||||
"checkGameServerFixMessage": "Les autres joueurs ne peuvent pas rejoindre le serveur de jeu car le port {port} n'est pas ouvert",
|
||||
"checkGameServerFixAction": "Réparer",
|
||||
"infoName": "Info",
|
||||
"emptyVersionName": "Nom de version vide",
|
||||
"versionAlreadyExists": "Cette version existe déjà",
|
||||
"emptyGamePath": "Chemin du jeu vide",
|
||||
"directoryDoesNotExist": "Le répertoire n'existe pas",
|
||||
"missingShippingExe": "Chemin du jeu invalide : FortniteClient-Win64-Shipping manquant",
|
||||
"invalidDownloadPath": "Chemin de téléchargement invalide",
|
||||
"invalidDllPath": "Chemin du DLL invalide",
|
||||
"dllDoesNotExist": "Ce fichier n'existe pas",
|
||||
"invalidDllExtension": "Ce fichier n'est pas un DLL",
|
||||
"emptyHostname": "Nom de domaine vide",
|
||||
"hostnameFormat": "Nom de domaine incorrect (format attendu : IP:Port)",
|
||||
"emptyURL": "URL de mise à jour vide",
|
||||
"missingVersionError": "Téléchargez ou sélectionnez une version avant de lancer Fortnite",
|
||||
"missingExecutableError": "Éxecutable Fortnite manquant: l'installation a-t-elle été supprimée ou déplacée?",
|
||||
"corruptedVersionError": "Cette installation Fortnite est corrompue: S'il vous plaît, retéléchargez-la depuis Reboot ou changez de version",
|
||||
"missingDllError": "Le DLL à {path} n'existe pas",
|
||||
"corruptedDllError": "Impossible d'injecter le DLL: {error}",
|
||||
"tokenError": "Impossible de se connecter à Fortnite: authentication error",
|
||||
"unknownFortniteError": "Une erreur inconnue à empêché Fortnite de se lancer: {error}",
|
||||
"serverNoLongerAvailable": "Le serveur de {owner} n'est plus disponible",
|
||||
"serverNoLongerAvailableUnnamed": "Le serveur précédent n'est plus disponible",
|
||||
"noServerFound": "Aucun serveur trouvé: lien invalide ou expiré",
|
||||
"settingsUtilsThemeName": "Thème",
|
||||
"settingsUtilsThemeDescription": "Sélectionnez un thème à appliquer à Reboot",
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"system": "Système",
|
||||
"settingsUtilsLanguageName": "Langue",
|
||||
"settingsUtilsLanguageDescription": "Sélectionnez la langue de Reboot"
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
{
|
||||
"find": "Znajdź ustawienie",
|
||||
"on": "Wł.",
|
||||
"off": "Wył.",
|
||||
"resetDefaultsContent": "Zresetuj",
|
||||
"resetDefaultsDialogTitle": "Czy chcesz zresetować wszystkie ustawienia na tej karcie do wartości domyślnych? To działanie jest nieodwracalne",
|
||||
"resetDefaultsDialogSecondaryAction": "Zamknij",
|
||||
"resetDefaultsDialogPrimaryAction": "Zresetuj",
|
||||
"authenticatorName": "Uwierzytelniacz",
|
||||
"authenticatorConfigurationName": "Konfiguracja uwierzytelniacza",
|
||||
"authenticatorConfigurationDescription": "Ta sekcja zawiera konfigurację uwierzytelniacza",
|
||||
"authenticatorConfigurationHostName": "Hostuj",
|
||||
"authenticatorConfigurationHostDescription": "Nazwa hosta uwierzytelniacza",
|
||||
"authenticatorConfigurationPortName": "Port",
|
||||
"authenticatorConfigurationPortDescription": "Port uwierzytelniacza",
|
||||
"authenticatorConfigurationDetachedName": "Odłączony",
|
||||
"authenticatorConfigurationDetachedDescription": "Czy wbudowany uwierzytelniacz powinien być uruchamiany jako oddzielny proces, przydatny do debugowania",
|
||||
"authenticatorInstallationDirectoryName": "Folder instalacji",
|
||||
"authenticatorInstallationDirectoryDescription": "Otwiera folder, w którym znajduje się wbudowany uwierzytelniacz",
|
||||
"authenticatorInstallationDirectoryContent": "Pokaż pliki",
|
||||
"authenticatorResetDefaultsName": "Zresetuj uwierzytelniacz",
|
||||
"authenticatorResetDefaultsDescription": "Przywraca domyślne ustawienia uwierzytelniacza",
|
||||
"authenticatorResetDefaultsContent": "Zresetuj",
|
||||
"hostGameServerName": "Serwer gry",
|
||||
"hostGameServerDescription": "Podaj podstawowe informacje o serwerze gry dla przeglądarki serwerów",
|
||||
"hostGameServerNameName": "Nazwa",
|
||||
"hostGameServerNameDescription": "Nazwa twojego serwera gry",
|
||||
"hostGameServerDescriptionName": "Opis",
|
||||
"hostGameServerDescriptionDescription": "Opis twojego serwera gry",
|
||||
"hostGameServerPasswordName": "Hasło",
|
||||
"hostGameServerPasswordDescription": "Hasło do twojego serwera gry, jeśli jest potrzebne",
|
||||
"hostGameServerDiscoverableName": "Wykrywalny",
|
||||
"hostGameServerDiscoverableDescription": "Udostępnij swój serwer innym graczom w przeglądarce serwerów",
|
||||
"hostShareName": "Udostępnij",
|
||||
"hostShareDescription": "Ułatw innym osobom dołączenie do twojego serwera dzięki opcjom dostępnym w tej sekcji",
|
||||
"hostShareLinkName": "Link",
|
||||
"hostShareLinkDescription": "Kopiuje link twojego serwera do schowka (wymaga Reboot Launcher)",
|
||||
"hostShareLinkContent": "Kopiuj link",
|
||||
"hostShareLinkMessageSuccess": "Skopiowano twój link do schowka",
|
||||
"hostShareIpName": "Publiczne IP",
|
||||
"hostShareIpDescription": "Kopiuje bieżące publiczne IP do schowka (nie wymaga Reboot Launcher)",
|
||||
"hostShareIpContent": "Kopiuj IP",
|
||||
"hostShareIpMessageLoading": "Uzyskiwanie publicznego IP...",
|
||||
"hostShareIpMessageSuccess": "Skopiowano twój link do schowka",
|
||||
"hostShareIpMessageError": "Wystąpił błąd podczas uzyskiwania twojego publicznego IP: {error}",
|
||||
"hostResetName": "Zresetuj serwer gry",
|
||||
"hostResetDescription": "Resetuje ustawienia serwera gry do wartości domyślnych",
|
||||
"hostResetContent": "Zresetuj",
|
||||
"browserName": "Przeglądarka serwerów",
|
||||
"noServersAvailableTitle": "W tej chwili żadne serwery nie są dostępne",
|
||||
"noServersAvailableSubtitle": "Hostuj serwer samodzielnie lub wróć później",
|
||||
"joinServer": "Dołącz do serwera",
|
||||
"noServersAvailableByQueryTitle": "Nie znaleziono rezultatów",
|
||||
"noServersAvailableByQuerySubtitle": "Żaden serwer nie pasuje do Twojego zapytania",
|
||||
"findServer": "Znajdź serwer",
|
||||
"copyIp": "Kopiuj IP",
|
||||
"hostName": "Hostuj",
|
||||
"matchmakerName": "System dobierania graczy",
|
||||
"matchmakerConfigurationName": "Konfiguracja systemu dobierania graczy",
|
||||
"matchmakerConfigurationDescription": "Ta sekcja zawiera konfigurację systemu dobierania graczy",
|
||||
"matchmakerConfigurationHostName": "Hostuj",
|
||||
"matchmakerConfigurationHostDescription": "Nazwa hosta systemu dobierania graczy",
|
||||
"matchmakerConfigurationPortName": "Port",
|
||||
"matchmakerConfigurationPortDescription": "Port systemu dobierania graczy",
|
||||
"matchmakerConfigurationAddressName": "Adres serwera gry",
|
||||
"matchmakerConfigurationAddressDescription": "Adres serwera gry używanego przez system dobierania graczy",
|
||||
"matchmakerConfigurationDetachedName": "Odłączony",
|
||||
"matchmakerConfigurationDetachedDescription": "Czy wbudowany system dobierania graczy powinien być uruchamiany jako oddzielny proces, przydatny do debugowania",
|
||||
"matchmakerInstallationDirectoryName": "Folder instalacji",
|
||||
"matchmakerInstallationDirectoryDescription": "Otwiera folder, w którym znajduje się wbudowany system dobierania graczy",
|
||||
"matchmakerInstallationDirectoryContent": "Pokaż pliki",
|
||||
"matchmakerResetDefaultsName": "Zresetuj system dobierania graczy",
|
||||
"matchmakerResetDefaultsDescription": "Resetuje ustawienia systemu dobierania graczy do wartości domyślnych",
|
||||
"matchmakerResetDefaultsContent": "Zresetuj",
|
||||
"matchmakerResetDefaultsDialogTitle": "Czy chcesz zresetować wszystkie ustawienia na tej karcie do wartości domyślnych? To działanie jest nieodwracalne",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Zamknij",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Zresetuj",
|
||||
"playName": "Graj",
|
||||
"playGameServerName": "Serwer gry",
|
||||
"playGameServerDescription": "Pomocne skróty do znalezienia serwera, na którym chcesz grać",
|
||||
"playGameServerContentLocal": "Twój serwer",
|
||||
"playGameServerContentBrowser": "Server {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Hostuj serwer",
|
||||
"playGameServerHostDescription": "Chcesz stworzyć serwer gry dla siebie lub swoich znajomych? Hostuj jeden!",
|
||||
"playGameServerHostContent": "Hostuj",
|
||||
"playGameServerBrowserName": "Przeglądaj serwery",
|
||||
"playGameServerBrowserDescription": "Znajdź wykrywalny serwer hostowany na Reboot Launcher w przeglądarce serwerów",
|
||||
"playGameServerBrowserContent": "Przeglądaj",
|
||||
"playGameServerCustomName": "Dołącz do serwera niestandardowego",
|
||||
"playGameServerCustomDescription": "Wpisz adres dowolnego serwera, niezależnie od tego, czy był on hostowany poprzez Reboot Launcher, czy nie",
|
||||
"playGameServerCustomContent": "Wprowadź IP",
|
||||
"settingsName": "Ustawienia",
|
||||
"settingsClientName": "Ustawienia klienta",
|
||||
"settingsClientDescription": "Ta sekcja zawiera pliki dll używane do działania klienta Fortnite",
|
||||
"settingsClientConsoleName": "Konsola Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Ten plik jest wstrzykiwany w celu odblokowania konsoli Unreal Engine",
|
||||
"settingsClientAuthName": "Łatka uwierzytelniacza",
|
||||
"settingsClientAuthDescription": "Ten plik jest wstrzykiwany w celu przekierowania wszystkich żądań HTTP do uwierzytelniacza programu uruchamiającego",
|
||||
"settingsClientMemoryName": "Łatka pamięci",
|
||||
"settingsClientMemoryDescription": "Ten plik jest wstrzykiwany, aby zapobiec awarii klienta Fortnite z powodu wycieku pamięci",
|
||||
"settingsClientArgsName": "Niestandardowe argumenty uruchamiania",
|
||||
"settingsClientArgsDescription": "Dodatkowe argumenty do użycia podczas uruchamiania gry",
|
||||
"settingsClientArgsPlaceholder": "-przykład",
|
||||
"settingsServerName": "Ustawienia serwera gry",
|
||||
"settingsServerSubtitle": "Ta sekcja zawiera ustawienia związane z implementacją serwera gry",
|
||||
"settingsServerFileName": "Implementacja",
|
||||
"settingsServerFileDescription": "Ten plik jest wstrzykiwany w celu utworzenia serwera gry i hostowania meczów",
|
||||
"settingsServerPortName": "Port",
|
||||
"settingsServerPortDescription": "Port używany przez dll serwera gry",
|
||||
"settingsServerMirrorName": "Aktualizacja linku",
|
||||
"settingsServerMirrorDescription": "Adres URL używany do aktualizacji dll serwera gry",
|
||||
"settingsServerMirrorPlaceholder": "link",
|
||||
"settingsServerTimerName": "Aktualizacja licznika czasu",
|
||||
"settingsServerTimerSubtitle": "Określa, kiedy dll serwera gry powininno zostać zaktualizowane",
|
||||
"settingsUtilsName": "Narzędzia programu do uruchamiania",
|
||||
"settingsUtilsSubtitle": "Ta sekcja zawiera przydatne ustawienia programu uruchamiającego",
|
||||
"settingsUtilsInstallationDirectoryName": "Katalog instalacji",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Otwiera katalog instalacji",
|
||||
"settingsUtilsInstallationDirectoryContent": "Pokaż pliki",
|
||||
"settingsUtilsBugReportName": "Utwórz raport o błędzie",
|
||||
"settingsUtilsBugReportSubtitle": "Pomóż mi naprawić błędy, zgłaszając je",
|
||||
"settingsUtilsBugReportContent": "Zgłoś błąd",
|
||||
"settingsUtilsResetDefaultsName": "Zresetuj ustawienia",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Resetuje ustawienia programu uruchamiającego do wartości domyślnych",
|
||||
"settingsUtilsDialogTitle": "Czy chcesz zresetować wszystkie ustawienia na tej karcie do wartości domyślnych? To działanie jest nieodwracalne",
|
||||
"settingsUtilsResetDefaultsContent": "Zresetuj",
|
||||
"settingsUtilsDialogSecondaryAction": "Zamknij",
|
||||
"settingsUtilsDialogPrimaryAction": "Zresetuj",
|
||||
"addVersionName": "Wersja",
|
||||
"addVersionDescription": "Wybierz wersję Fortnite, której chcesz użyć",
|
||||
"addLocalBuildName": "Dodaj wersję z lokalnej pamięci masowej tego komputera",
|
||||
"addLocalBuildDescription": "Wersje pochodzące z dysku lokalnego nie mają gwarancji działania",
|
||||
"addLocalBuildContent": "Dodaj kompilację",
|
||||
"downloadBuildName": "Pobierz dowolną wersję z chmury",
|
||||
"downloadBuildDescription": "Łatwe pobieranie dowolnej wersji Fortnite z chmury",
|
||||
"downloadBuildContent": "Pobierz",
|
||||
"cannotUpdateGameServer": "Wystąpił błąd podczas aktualizacji serwera gry: {error}",
|
||||
"launchFortnite": "Uruchom Fortnite",
|
||||
"closeFortnite": "Zamknij Fortnite",
|
||||
"updateGameServerDllNever": "Nigdy",
|
||||
"updateGameServerDllEvery": "Każda {name}",
|
||||
"selectPathPlaceholder": "Ścieżka",
|
||||
"selectPathWindowTitle": "Wybierz plik",
|
||||
"defaultDialogSecondaryAction": "Zamknij",
|
||||
"stopLoadingDialogAction": "Stop",
|
||||
"copyErrorDialogTitle": "Kopiuj błąd",
|
||||
"copyErrorDialogSuccess": "Skopiowano błąd do schowka",
|
||||
"defaultServerName": "Serwer gry Reboot",
|
||||
"defaultServerDescription": "Po prostu kolejny serwer",
|
||||
"updatingRebootDll": "Pobieranie dll reboot...",
|
||||
"updatedRebootDll": "Plik dll reboot został pobrany pomyślnie",
|
||||
"updateRebootDllError": "Wystąpił błąd podczas pobierania dll reboot: {error}",
|
||||
"updateRebootDllErrorAction": "Ponów",
|
||||
"uncaughtErrorMessage": "Wystąpił niewyłapany błąd: {error}",
|
||||
"launchingHeadlessServer": "Uruchamianie serwera bezgłowego ...",
|
||||
"usernameOrEmail": "Nazwa użytkownika/Email",
|
||||
"usernameOrEmailPlaceholder": "Wpisz swoją nazwę użytkownika lub adres e-mail",
|
||||
"password": "Hasło",
|
||||
"passwordPlaceholder": "Wpisz hasło, jeśli chcesz je użyć",
|
||||
"cancelProfileChanges": "Anuluj",
|
||||
"saveProfileChanges": "Zapisz",
|
||||
"startingServer": "Uruchamianie {name}...",
|
||||
"startedServer": "{name} został uruchomiony pomyślnie",
|
||||
"startServerError": "Wystąpił błąd podczas uruchamiania {name}: {error}",
|
||||
"stoppingServer": "Zatrzymanie {name}...",
|
||||
"stoppedServer": "{name} został pomyślnie zatrzymany",
|
||||
"stopServerError": "Wystąpił błąd podczas zatrzymywania {name}: {error}",
|
||||
"missingHostNameError": "Brakująca nazwa hosta w konfiguracji {name}",
|
||||
"missingPortError": "Brakujący port w konfiguracji {name}",
|
||||
"illegalPortError": "Niepoprawny port w konfiguracji {name}",
|
||||
"freeingPort": "Zwalnianie portu {port}...",
|
||||
"freedPort": "Port {port} został pomyślnie zwolniony",
|
||||
"freePortError": "Wystąpił błąd podczas zwalniania portu {port}: {error}",
|
||||
"pingingRemoteServer": "Pingowanie zdalnego {name}...",
|
||||
"pingingLocalServer": "Pingowanie {type} {name}...",
|
||||
"pingError": "Nie można pingować {type} {name}",
|
||||
"joinSelfServer": "Nie możesz dołączyć do własnego serwera",
|
||||
"wrongServerPassword": "Błędne hasło: spróbuj ponownie",
|
||||
"offlineServer": "Ten serwer nie jest teraz online: spróbuj ponownie później",
|
||||
"serverPassword": "Hasło",
|
||||
"serverPasswordPlaceholder": "Wpisz hasło serwera",
|
||||
"serverPasswordCancel": "Anuluj",
|
||||
"serverPasswordConfirm": "Potwierdź",
|
||||
"joinedServer": "Udało ci się dołączyć do serwera {author}!",
|
||||
"copiedIp": "Skopiowano IP do schowka",
|
||||
"selectVersion": "Wybierz wersję",
|
||||
"noVersions": "Proszę utwórzyć lub pobrać wersję",
|
||||
"missingVersion": "Ta wersja nie istnieje na lokalnej maszynie.,
|
||||
"deleteVersionDialogTitle": "Czy na pewno chcesz usunąć tę wersję?",
|
||||
"deleteVersionFromDiskOption": "Usuń pliki wersji z dysku",
|
||||
"deleteVersionCancel": "Zachowaj",
|
||||
"deleteVersionConfirm": "Usuń",
|
||||
"versionName": "Nazwa",
|
||||
"versionNameLabel": "Wpisz nazwę nowej wersji",
|
||||
"newVersionNameConfirm": "Zapisz",
|
||||
"newVersionNameLabel": "Wpisz nazwę nowej wersji",
|
||||
"gameFolderTitle": "Folder gry",
|
||||
"gameFolderPlaceholder": "Wpisz nowy folder gry",
|
||||
"gameFolderPlaceWindowTitle": "Wybierz folder gry",
|
||||
"gameFolderLabel": "Ścieżka",
|
||||
"openInExplorer": "Otwórz w eksploratorze",
|
||||
"modify": "Modyfikuj",
|
||||
"delete": "Usuń",
|
||||
"build": "Kompilacja",
|
||||
"selectBuild": "Wybierz kompilację fortnite",
|
||||
"fetchingBuilds": "Pobieranie kompilacji i dysków...",
|
||||
"unknownError": "Nieznany błąd",
|
||||
"downloadVersionError": "Nie można pobrać wersji: {error}",
|
||||
"downloadedVersion": "Pobieranie zostało zakończone pomyślnie!",
|
||||
"download": "Pobierz",
|
||||
"downloading": "Pobieranie...",
|
||||
"extracting": "Wyodrębnianie...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Katalog instalacji",
|
||||
"buildInstallationDirectoryPlaceholder": "Wpisz katalog instalacji,
|
||||
"buildInstallationDirectoryWindowTitle": "Wybierz katalog instalacji",
|
||||
"timeLeft": "Pozostały czas: {timeLeft, plural, =0{mniej niż minuta} =1{około {timeLeft} minuta} other{około {timeLeft} minut}}",
|
||||
"localBuildsWarning": "Nie ma gwarancji, że lokalne kompilacje będą działać",
|
||||
"saveLocalVersion": "Zapisz",
|
||||
"embedded": "Wbudowany",
|
||||
"remote": "Zdalny",
|
||||
"local": "Lokalny",
|
||||
"checkServer": "Sprawdź {name}",
|
||||
"startServer": "Uruchom {name}",
|
||||
"stopServer": "Zatrzymaj {name}",
|
||||
"startHosting": "Rozpocznij hosting",
|
||||
"stopHosting": "Zatrzymaj hosting",
|
||||
"startGame": "Uruchom fortnite",
|
||||
"stopGame": "Zamknij fortnite",
|
||||
"waitingForGameServer": "Oczekiwanie na uruchomienie serwera gry...",
|
||||
"gameServerStartWarning": "Serwer bezgłowy został pomyślnie uruchomiony, ale serwer gry się nie uruchomił",
|
||||
"gameServerStartLocalWarning": "Serwer gry został pomyślnie uruchomiony, ale inni gracze nie mogą do niego dołączyć",
|
||||
"gameServerStarted": "Serwer gry został pomyślnie uruchomiony",
|
||||
"checkingGameServer": "Sprawdzanie, czy inni gracze mogą dołączyć do serwera gry...",
|
||||
"checkGameServerFixMessage": "Inni gracze nie mogą dołączyć do serwera gry, ponieważ port {port} nie jest otwarty",
|
||||
"checkGameServerFixAction": "Napraw",
|
||||
"infoName": "Info",
|
||||
"emptyVersionName": "Pusta nazwa wersji",
|
||||
"versionAlreadyExists": "Ta wersja już istnieje",
|
||||
"emptyGamePath": "Pusta ścieżka gry",
|
||||
"directoryDoesNotExist": "Katalog nie istnieje",
|
||||
"missingShippingExe": "Nieprawidłowa ścieżka do gry: brak FortniteClient-Win64-Shipping",
|
||||
"invalidDownloadPath": "Nieprawidłowa ścieżka pobierania",
|
||||
"invalidDllPath": "Nieprawidłowa ścieżka dll",
|
||||
"dllDoesNotExist": "Plik nie istnieje",
|
||||
"invalidDllExtension": "Ten plik nie jest plikiem dll",
|
||||
"emptyHostname": "Pusta nazwa hosta",
|
||||
"hostnameFormat": "Nieprawidłowy format nazwy hosta: oczekiwano ip:port",
|
||||
"emptyURL": "Pusty adres URL aktualizacji"
|
||||
"missingVersionError": "Pobierz lub wybierz wersję przed uruchomieniem Fortnite",
|
||||
"missingExecutableError": "Brakujący plik wykonywalny Fortnite: zazwyczaj oznacza to, że instalacja została przeniesiona lub usunięta",
|
||||
"corruptedVersionError": "Uszkodzona instalacja Fortnite: pobierz ponownie z programu uruchamiającego lub zmień wersję",
|
||||
"missingDllError": "Plik dll w {patch} nie istnieje",
|
||||
"corruptedDllError": "Nie można wstrzyknąć dll: {error}",
|
||||
"tokenError": "Nie można zalogować się do Fortnite: błąd uwierzytelniania",
|
||||
"unknownFortniteError": "Wystąpił nieznany błąd podczas uruchamiania Fortnite: {error}",
|
||||
"serverNoLongerAvailable": "Serwer {owner} nie jest już dostępny",
|
||||
"serverNoLongerAvailableUnnamed": "Poprzedni serwer nie jest już dostępny",
|
||||
"noServerFound": "Nie znaleziono serwera: nieprawidłowy lub wygasły link",
|
||||
"settingsUtilsThemeName": "Motyw",
|
||||
"settingsUtilsThemeDescription": "Wybierz motyw do użycia w programie uruchamiającym",
|
||||
"dark": "Ciemny",
|
||||
"light": "Jasny",
|
||||
"system": "Systemowy",
|
||||
"settingsUtilsLanguageName": "Język",
|
||||
"settingsUtilsLanguageDescription": "Wybierz język używany w programie uruchamiającym"
|
||||
}
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"find": "Encontrar uma configuração",
|
||||
"on": "Ligado",
|
||||
"off": "Desligado",
|
||||
"resetDefaultsContent": "Redefinir",
|
||||
"resetDefaultsDialogTitle": "Você deseja redefinir todas as configurações desta aba para seus valores padrão? Esta ação é irreversível",
|
||||
"resetDefaultsDialogSecondaryAction": "Fechar",
|
||||
"resetDefaultsDialogPrimaryAction": "Redefinir",
|
||||
"authenticatorName": "Autenticador",
|
||||
"authenticatorConfigurationName": "Configuração do Autenticador",
|
||||
"authenticatorConfigurationDescription": "Esta seção contém a configuração do autenticador",
|
||||
"authenticatorConfigurationHostName": "Host",
|
||||
"authenticatorConfigurationHostDescription": "O nome do host do autenticador",
|
||||
"authenticatorConfigurationPortName": "Porta",
|
||||
"authenticatorConfigurationPortDescription": "A porta do autenticador",
|
||||
"authenticatorConfigurationDetachedName": "Separado",
|
||||
"authenticatorConfigurationDetachedDescription": "Se o autenticador incorporado deve ser iniciado como um processo separado, útil para depuração",
|
||||
"authenticatorInstallationDirectoryName": "Diretório de Instalação",
|
||||
"authenticatorInstallationDirectoryDescription": "Abre a pasta onde o autenticador incorporado está localizado",
|
||||
"authenticatorInstallationDirectoryContent": "Mostrar Arquivos",
|
||||
"authenticatorResetDefaultsName": "Redefinir Autenticador",
|
||||
"authenticatorResetDefaultsDescription": "Redefine as configurações do autenticador para seus valores padrão",
|
||||
"authenticatorResetDefaultsContent": "Redefinir",
|
||||
"hostGameServerName": "Servidor de Jogo",
|
||||
"hostGameServerDescription": "Forneça informações básicas sobre seu servidor de jogo para o Navegador de Servidores",
|
||||
"hostGameServerNameName": "Nome",
|
||||
"hostGameServerNameDescription": "O nome do seu servidor de jogo",
|
||||
"hostGameServerDescriptionName": "Descrição",
|
||||
"hostGameServerDescriptionDescription": "A descrição do seu servidor de jogo",
|
||||
"hostGameServerPasswordName": "Senha",
|
||||
"hostGameServerPasswordDescription": "A senha do seu servidor de jogo, se você precisar de uma",
|
||||
"hostGameServerDiscoverableName": "Visível",
|
||||
"hostGameServerDiscoverableDescription": "Torne o seu servidor disponível para outros jogadores no navegador de servidores",
|
||||
"hostShareName": "Compartilhar",
|
||||
"hostShareDescription": "Facilite para outras pessoas se juntarem ao seu servidor com as opções nesta seção",
|
||||
"hostShareLinkName": "Link",
|
||||
"hostShareLinkDescription": "Copia um link para o seu servidor para a área de transferência (requer o Reboot Launcher)",
|
||||
"hostShareLinkContent": "Copiar Link",
|
||||
"hostShareLinkMessageSuccess": "Link copiado para a área de transferência",
|
||||
"hostShareIpName": "IP Público",
|
||||
"hostShareIpDescription": "Copia o seu IP público atual para a área de transferência (não requer o Reboot Launcher)",
|
||||
"hostShareIpContent": "Copiar IP",
|
||||
"hostShareIpMessageLoading": "Obtendo o seu IP público...",
|
||||
"hostShareIpMessageSuccess": "IP copiado para a área de transferência",
|
||||
"hostShareIpMessageError": "Ocorreu um erro ao obter o seu IP público: {error}",
|
||||
"hostResetName": "Redefinir servidor de jogo",
|
||||
"hostResetDescription": "Redefine as configurações do servidor de jogo para seus valores padrão",
|
||||
"hostResetContent": "Redefinir",
|
||||
"browserName": "Navegador de Servidores",
|
||||
"noServersAvailableTitle": "Nenhum servidor disponível no momento",
|
||||
"noServersAvailableSubtitle": "Hospede um servidor você mesmo ou volte mais tarde",
|
||||
"joinServer": "Entrar no Servidor",
|
||||
"noServersAvailableByQueryTitle": "Nenhum resultado encontrado",
|
||||
"noServersAvailableByQuerySubtitle": "Nenhum servidor corresponde à sua consulta",
|
||||
"findServer": "Encontrar um servidor",
|
||||
"copyIp": "Copiar IP",
|
||||
"hostName": "Host",
|
||||
"matchmakerName": "Matchmaker",
|
||||
"matchmakerConfigurationName": "Configuração do Matchmaker",
|
||||
"matchmakerConfigurationDescription": "Esta seção contém a configuração do Matchmaker",
|
||||
"matchmakerConfigurationHostName": "Host",
|
||||
"matchmakerConfigurationHostDescription": "O nome do host do Matchmaker",
|
||||
"matchmakerConfigurationPortName": "Porta",
|
||||
"matchmakerConfigurationPortDescription": "A porta do Matchmaker",
|
||||
"matchmakerConfigurationAddressName": "Endereço do servidor de jogo",
|
||||
"matchmakerConfigurationAddressDescription": "O endereço do servidor de jogo usado pelo Matchmaker",
|
||||
"matchmakerConfigurationDetachedName": "Separado",
|
||||
"matchmakerConfigurationDetachedDescription": "Se o Matchmaker incorporado deve ser iniciado como um processo separado, útil para depuração",
|
||||
"matchmakerInstallationDirectoryName": "Diretório de Instalação",
|
||||
"matchmakerInstallationDirectoryDescription": "Abre a pasta onde o Matchmaker incorporado está localizado",
|
||||
"matchmakerInstallationDirectoryContent": "Mostrar Arquivos",
|
||||
"matchmakerResetDefaultsName": "Redefinir Matchmaker",
|
||||
"matchmakerResetDefaultsDescription": "Redefine as configurações do Matchmaker para seus valores padrão",
|
||||
"matchmakerResetDefaultsContent": "Redefinir",
|
||||
"matchmakerResetDefaultsDialogTitle": "Você deseja redefinir todas as configurações desta aba para seus valores padrão? Esta ação é irreversível",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Fechar",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Redefinir",
|
||||
"playName": "Jogar",
|
||||
"playGameServerName": "Servidor de Jogo",
|
||||
"playGameServerDescription": "Atalhos úteis para encontrar o servidor onde você quer jogar",
|
||||
"playGameServerContentLocal": "Seu servidor"
|
||||
"playGameServerContentBrowser": "Servidor de {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Hospede um servidor",
|
||||
"playGameServerHostDescription": "Você quer criar um servidor de jogo para você ou seus amigos? Hospede um!",
|
||||
"playGameServerHostContent": "Hospedar",
|
||||
"playGameServerBrowserName": "Navegue pelos servidores",
|
||||
"playGameServerBrowserDescription": "Encontre um servidor visível hospedado no Reboot Launcher no navegador de servidores",
|
||||
"playGameServerBrowserContent": "Navegar",
|
||||
"playGameServerCustomName": "Entrar em um servidor personalizado",
|
||||
"playGameServerCustomDescription": "Digite o endereço de qualquer servidor, seja ele hospedado no Reboot Launcher ou não",
|
||||
"playGameServerCustomContent": "Inserir IP",
|
||||
"settingsName": "Configurações",
|
||||
"settingsClientName": "Configurações do Cliente",
|
||||
"settingsClientDescription": "Esta seção contém os arquivos DLL usados para fazer o cliente do Fortnite funcionar",
|
||||
"settingsClientConsoleName": "Console da Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Este arquivo é injetado para desbloquear o Console da Unreal Engine",
|
||||
"settingsClientAuthName": "Patcher de Autenticação",
|
||||
"settingsClientAuthDescription": "Este arquivo é injetado para redirecionar todas as requisições HTTP para o autenticador do launcher",
|
||||
"settingsClientMemoryName": "Patcher de Memória",
|
||||
"settingsClientMemoryDescription": "Este arquivo é injetado para evitar que o cliente do Fortnite falhe devido a um vazamento de memória",
|
||||
"settingsClientArgsName": "Argumentos de Inicialização Personalizados",
|
||||
"settingsClientArgsDescription": "Argumentos adicionais a serem usados ao iniciar o jogo",
|
||||
"settingsClientArgsPlaceholder": "-exemplo",
|
||||
"settingsServerName": "Configurações do Servidor de Jogo",
|
||||
"settingsServerSubtitle": "Esta seção contém configurações relacionadas à implementação do servidor de jogo",
|
||||
"settingsServerFileName": "Implementação",
|
||||
"settingsServerFileDescription": "Este arquivo é injetado para criar um servidor de jogo e hospedar partidas",
|
||||
"settingsServerPortName": "Porta",
|
||||
"settingsServerPortDescription": "A porta usada pela DLL do servidor de jogo",
|
||||
"settingsServerMirrorName": "Espelho de Atualização",
|
||||
"settingsServerMirrorDescription": "O URL usado para atualizar a DLL do servidor de jogo",
|
||||
"settingsServerMirrorPlaceholder": "espelho",
|
||||
"settingsServerTimerName": "Temporizador de Atualização",
|
||||
"settingsServerTimerSubtitle": "Determina quando a DLL do servidor de jogo deve ser atualizada",
|
||||
"settingsUtilsName": "Utilitários do Launcher",
|
||||
"settingsUtilsSubtitle": "Esta seção contém configurações úteis para o launcher",
|
||||
"settingsUtilsInstallationDirectoryName": "Diretório de Instalação",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Abre o diretório de instalação",
|
||||
"settingsUtilsInstallationDirectoryContent": "Mostrar Arquivos",
|
||||
"settingsUtilsBugReportName": "Criar um Relatório de Bug",
|
||||
"settingsUtilsBugReportSubtitle": "Me ajude a corrigir bugs relatando-os",
|
||||
"settingsUtilsBugReportContent": "Relatar um Bug",
|
||||
"settingsUtilsResetDefaultsName": "Redefinir Configurações",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Redefine as configurações do launcher para seus valores padrão",
|
||||
"settingsUtilsDialogTitle": "Você deseja redefinir todas as configurações desta aba para seus valores padrão? Esta ação é irreversível",
|
||||
"settingsUtilsResetDefaultsContent": "Redefinir",
|
||||
"settingsUtilsDialogSecondaryAction": "Fechar",
|
||||
"settingsUtilsDialogPrimaryAction": "Redefinir",
|
||||
"addVersionName": "Versão",
|
||||
"addVersionDescription": "Selecione a versão do Fortnite que você deseja usar",
|
||||
"addLocalBuildName": "Adicionar uma versão do armazenamento local deste PC",
|
||||
"addLocalBuildDescription": "Versões provenientes do seu disco local não têm garantia de funcionamento",
|
||||
"addLocalBuildContent": "Adicionar build",
|
||||
"downloadBuildName": "Baixar qualquer versão da nuvem",
|
||||
"downloadBuildDescription": "Baixe qualquer versão do Fortnite facilmente da nuvem",
|
||||
"downloadBuildContent": "Baixar",
|
||||
"cannotUpdateGameServer": "Ocorreu um erro ao atualizar o servidor de jogo: {error}",
|
||||
"launchFortnite": "Iniciar Fortnite",
|
||||
"closeFortnite": "Fechar Fortnite",
|
||||
"updateGameServerDllNever": "Nunca"
|
||||
"updateGameServerDllEvery": "A cada {name}",
|
||||
"selectPathPlaceholder": "Caminho",
|
||||
"selectPathWindowTitle": "Selecione um arquivo",
|
||||
"defaultDialogSecondaryAction": "Fechar",
|
||||
"stopLoadingDialogAction": "Parar",
|
||||
"copyErrorDialogTitle": "Copiar erro",
|
||||
"copyErrorDialogSuccess": "Erro copiado para a área de transferência",
|
||||
"defaultServerName": "Servidor de Jogo Reboot",
|
||||
"defaultServerDescription": "Apenas mais um servidor",
|
||||
"updatingRebootDll": "Baixando DLL do Reboot...",
|
||||
"updatedRebootDll": "A DLL do Reboot foi baixada com sucesso",
|
||||
"updateRebootDllError": "Ocorreu um erro ao baixar a DLL do Reboot: {error}",
|
||||
"updateRebootDllErrorAction": "Tentar Novamente",
|
||||
"uncaughtErrorMessage": "Um erro não tratado ocorreu: {error}",
|
||||
"launchingHeadlessServer": "Iniciando o servidor sem interface gráfica...",
|
||||
"usernameOrEmail": "Nome de Usuário/Email",
|
||||
"usernameOrEmailPlaceholder": "Digite seu nome de usuário ou email",
|
||||
"password": "Senha",
|
||||
"passwordPlaceholder": "Digite sua senha, se desejar usar uma",
|
||||
"cancelProfileChanges": "Cancelar",
|
||||
"saveProfileChanges": "Salvar",
|
||||
"startingServer": "Iniciando o {name}...",
|
||||
"startedServer": "O {name} foi iniciado com sucesso",
|
||||
"startServerError": "Ocorreu um erro ao iniciar o {name}: {error}",
|
||||
"stoppingServer": "Parando o {name}...",
|
||||
"stoppedServer": "O {name} foi parado com sucesso",
|
||||
"stopServerError": "Ocorreu um erro ao parar o {name}: {error}",
|
||||
"missingHostNameError": "Hostname ausente na configuração do {name}",
|
||||
"missingPortError": "Porta ausente na configuração do {name}",
|
||||
"illegalPortError": "Porta inválida na configuração do {name}",
|
||||
"freeingPort": "Liberando porta {port}...",
|
||||
"freedPort": "Porta {port} foi liberada com sucesso",
|
||||
"freePortError": "Ocorreu um erro ao liberar a porta {port}: {error}",
|
||||
"pingingRemoteServer": "Pingando o {name} remoto...",
|
||||
"pingingLocalServer": "Pingando o {type} {name}...",
|
||||
"pingError": "Não é possível pingar o {type} {name}",
|
||||
"joinSelfServer": "Você não pode entrar no seu próprio servidor",
|
||||
"wrongServerPassword": "Senha incorreta: por favor, tente novamente",
|
||||
"offlineServer": "Este servidor não está online no momento: por favor, tente novamente mais tarde",
|
||||
"serverPassword": "Senha",
|
||||
"serverPasswordPlaceholder": "Digite a senha do servidor",
|
||||
"serverPasswordCancel": "Cancelar",
|
||||
"serverPasswordConfirm": "Confirmar",
|
||||
"joinedServer": "Você entrou no servidor de {author} com sucesso!",
|
||||
"copiedIp": "IP copiado para a área de transferência",
|
||||
"selectVersion": "Selecionar uma versão",
|
||||
"noVersions": "Por favor, crie ou baixe uma versão",
|
||||
"missingVersion": "Esta versão não existe no computador local",
|
||||
"deleteVersionDialogTitle": "Tem certeza de que deseja excluir esta versão?",
|
||||
"deleteVersionFromDiskOption": "Excluir arquivos da versão do disco",
|
||||
"deleteVersionCancel": "Manter",
|
||||
"deleteVersionConfirm": "Excluir",
|
||||
"versionName": "Nome",
|
||||
"versionNameLabel": "Digite o novo nome da versão",
|
||||
"newVersionNameConfirm": "Salvar",
|
||||
"newVersionNameLabel": "Digite o novo nome da versão",
|
||||
"gameFolderTitle": "Pasta do Jogo",
|
||||
"gameFolderPlaceholder": "Digite a nova pasta do jogo",
|
||||
"gameFolderPlaceWindowTitle": "Selecionar pasta do jogo",
|
||||
"gameFolderLabel": "Caminho",
|
||||
"openInExplorer": "Abrir no explorador",
|
||||
"modify": "Modificar",
|
||||
"delete": "Excluir",
|
||||
"build": "Construir",
|
||||
"selectBuild": "Selecionar uma compilação do Fortnite",
|
||||
"fetchingBuilds": "Obtendo compilações e discos...",
|
||||
"unknownError": "Erro desconhecido",
|
||||
"downloadVersionError": "Não foi possível baixar a versão: {error}",
|
||||
"downloadedVersion": "O download foi concluído com sucesso!",
|
||||
"download": "Baixar",
|
||||
"downloading": "Baixando...",
|
||||
"extracting": "Extraindo...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Diretório de Instalação",
|
||||
"buildInstallationDirectoryPlaceholder": "Digite o diretório de instalação",
|
||||
"buildInstallationDirectoryWindowTitle": "Selecionar diretório de instalação",
|
||||
"timeLeft": "Tempo restante: {timeLeft, plural, =0{menos de um minuto} =1{cerca de {timeLeft} minuto} other{cerca de {timeLeft} minutos}}",
|
||||
"localBuildsWarning": "As compilações locais não têm garantia de funcionamento",
|
||||
"saveLocalVersion": "Salvar",
|
||||
"embedded": "Incorporado",
|
||||
"remote": "Remoto",
|
||||
"local": "Local",
|
||||
"checkServer": "Verificar {name}",
|
||||
"startServer": "Iniciar {name}",
|
||||
"stopServer": "Parar {name}",
|
||||
"startHosting": "Iniciar hospedagem",
|
||||
"stopHosting": "Parar hospedagem",
|
||||
"startGame": "Iniciar Fortnite",
|
||||
"stopGame": "Fechar Fortnite",
|
||||
"waitingForGameServer": "Aguardando o servidor de jogo iniciar...",
|
||||
"gameServerStartWarning": "O servidor sem interface gráfica foi iniciado com sucesso, mas o servidor de jogo não iniciou",
|
||||
"gameServerStartLocalWarning": "O servidor de jogo foi iniciado com sucesso, mas outros jogadores não podem entrar",
|
||||
"gameServerStarted": "O servidor de jogo foi iniciado com sucesso",
|
||||
"checkingGameServer": "Verificando se outros jogadores podem entrar no servidor de jogo...",
|
||||
"checkGameServerFixMessage": "Outros jogadores não podem entrar no servidor de jogo porque a porta {port} não está aberta",
|
||||
"checkGameServerFixAction": "Corrigir",
|
||||
"infoName": "Informações",
|
||||
"emptyVersionName": "Nome da versão vazio",
|
||||
"versionAlreadyExists": "Esta versão já existe",
|
||||
"emptyGamePath": "Caminho do jogo vazio",
|
||||
"diretoryDoesNotExist": "Diretório não existe",
|
||||
"missingShippingExe": "Caminho do jogo inválido: FortniteClient-Win64-Shipping.exe ausente",
|
||||
"invalidDownloadPath": "Caminho de download inválido",
|
||||
"invalidDllPath": "Caminho da DLL inválido",
|
||||
"dllDoesNotExist": "O arquivo não existe",
|
||||
"invalidDllExtension": "Este arquivo não é uma DLL",
|
||||
"emptyHostname": "Hostname vazio",
|
||||
"hostnameFormat": "Formato de hostname incorreto: esperado ip:porta",
|
||||
"emptyURL": "URL vazia"
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"find": "Găsiți o setare",
|
||||
"on": "Pornit",
|
||||
"off": "Oprit",
|
||||
"resetDefaultsContent": "Resetați",
|
||||
"resetDefaultsDialogTitle": "Doriți să resetați toate setările din această filă la valorile implicite? Această acțiune este ireversibilă",
|
||||
"resetDefaultsDialogSecondaryAction": "Închidți",
|
||||
"resetDefaultsDialogPrimaryAction": "Resetați",
|
||||
"authenticatorName": "Authenticator",
|
||||
"authenticatorConfigurationName": "Configurația autentificatorului",
|
||||
"authenticatorConfigurationDescription": "Această secțiune conține configurația autentificatorului",
|
||||
"authenticatorConfigurationHostName": "Gazdă",
|
||||
"authenticatorConfigurationHostDescription": "Numele de gazdă al autentificatorului",
|
||||
"authenticatorConfigurationPortName": "Portul",
|
||||
"authenticatorConfigurationPortDescription": "Portul autentificatorului",
|
||||
"authenticatorConfigurationDetachedName": "Detașat",
|
||||
"authenticatorConfigurationDetachedDescription": "Dacă autentificatorul încorporat ar trebui pornit ca un proces separat, util pentru depanare",
|
||||
"authenticatorInstallationDirectoryName": "Directorul de instalare",
|
||||
"authenticatorInstallationDirectoryDescription": "Deschide folderul în care se află autentificatorul încorporat",
|
||||
"authenticatorInstallationDirectoryContent": "Afișați fișierele",
|
||||
"authenticatorResetDefaultsName": "Resetare autentificator",
|
||||
"authenticatorResetDefaultsDescription": "Resetează setările autentificatorului la valorile implicite",
|
||||
"authenticatorResetDefaultsContent": "Resetați",
|
||||
"hostGameServerName": "Serverul de Joc",
|
||||
"hostGameServerDescription": "Furnizați informații de bază despre serverul dvs. de joc pentru browserul serverului",
|
||||
"hostGameServerNameName": "Numele",
|
||||
"hostGameServerNameDescription": "Numele serverului dvs. de joc",
|
||||
"hostGameServerDescriptionName": "Descriere",
|
||||
"hostGameServerDescriptionDescription": "Descrierea serverului dvs. de joc",
|
||||
"hostGameServerPasswordName": "Parola",
|
||||
"hostGameServerPasswordDescription": "Parola serverului dvs. de joc, dacă aveți nevoie de una",
|
||||
"hostGameServerDiscoverableName": "Descoperibil",
|
||||
"hostGameServerDiscoverableDescription": "Faceți serverul dvs. disponibil și altor jucători pe browserul de server",
|
||||
"hostShareName": "Trimite-ți",
|
||||
"hostShareDescription": "Simplificați accesul altor persoane la serverul dvs. cu ajutorul opțiunilor din această secțiune",
|
||||
"hostShareLinkName": "Link",
|
||||
"hostShareLinkDescription": "Copiază link-ul serverului dvs. în clipboard (necesită Lansatorul Reboot)",
|
||||
"hostShareLinkContent": "Copiați Link-ul",
|
||||
"hostShareLinkMessageSuccess": "S-a copiat link-ul în clipboard",
|
||||
"hostShareIpName": "IP-ul Public",
|
||||
"hostShareIpDescription": "Copiați IP-ul dvs. public în clipboard (nu necesită Lansatorul Reboot)",
|
||||
"hostShareIpContent": "Copiați IP-ul",
|
||||
"hostShareIpMessageLoading": "Se obține IP-ul dvs. public...",
|
||||
"hostShareIpMessageSuccess": "V-am copiat linkul în clipboard",
|
||||
"hostShareIpMessageError": "A apărut o eroare la obținerea IP-ului dvs. public: {error}",
|
||||
"hostResetName": "Resetați serverul de joc",
|
||||
"hostResetDescription": "Resetează setările serverului de joc la valorile implicite",
|
||||
"hostResetContent": "Resetați",
|
||||
"browserName": "Răsfoitor de Servere",
|
||||
"noServersAvailableTitle": "Momentan nu sunt servere disponibile",
|
||||
"noServersAvailableSubtitle": "Găzduiți un server sau reveniți mai târziu",
|
||||
"joinServer": "Conectați-vă la server",
|
||||
"noServersAvailableByQueryTitle": "Niciun rezultat găsit",
|
||||
"noServersAvailableByQuerySubtitle": "Niciun server nu se potrivește cu căutarea dvs.",
|
||||
"findServer": "Găsește un server",
|
||||
"copyIp": "Copiați IP-ul",
|
||||
"hostName": "Gazdă",
|
||||
"matchmakerName": "Matchmaker",
|
||||
"matchmakerConfigurationName": "Configurația Matchmaker-ului",
|
||||
"matchmakerConfigurationDescription": "Această secțiune conține configurația matchmaker-ului",
|
||||
"matchmakerConfigurationHostName": "Gazdă",
|
||||
"matchmakerConfigurationHostDescription": "Numele de gazdă al matchmaker-ului",
|
||||
"matchmakerConfigurationPortName": "Portul",
|
||||
"matchmakerConfigurationPortDescription": "Portul Matchmaker-ului",
|
||||
"matchmakerConfigurationAddressName": "Adresa serverului de joc",
|
||||
"matchmakerConfigurationAddressDescription": "Adresa serverului de joc utilizată de către matchmaker",
|
||||
"matchmakerConfigurationDetachedName": "Detașat",
|
||||
"matchmakerConfigurationDetachedDescription": "Dacă matchmaker-ul încorporat ar trebui să fie pornit ca un proces separat, util pentru depanare",
|
||||
"matchmakerInstallationDirectoryName": "Directorul de Instalare",
|
||||
"matchmakerInstallationDirectoryDescription": "Deschide folderul în care se află matchmaker-ul încorporat",
|
||||
"matchmakerInstallationDirectoryContent": "Vedeți fișierele",
|
||||
"matchmakerResetDefaultsName": "Resetați matchmaker-ul",
|
||||
"matchmakerResetDefaultsDescription": "Resetează setările matchmaker-ului la valorile implicite",
|
||||
"matchmakerResetDefaultsContent": "Resetați",
|
||||
"matchmakerResetDefaultsDialogTitle": "Doriți să resetați toate setările din această filă la valorile lor implicite? Această acțiune este ireversibilă",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Închideți",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Resetați",
|
||||
"playName": "Joacă",
|
||||
"playGameServerName": "Server de joc",
|
||||
"playGameServerDescription": "Scurtături utile pentru a găsi serverul pe care doriți să jucați",
|
||||
"playGameServerContentLocal": "Serverul dvs.",
|
||||
"playGameServerContentBrowser": "Serverul lui {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Găzduiți un server",
|
||||
"playGameServerHostDescription": "Doriți să creați un server de joc pentru dvs. sau pentru prietenii dvs.? Găzduiește unul!",
|
||||
"playGameServerHostContent": "Gazdă",
|
||||
"playGameServerBrowserName": "Răsfoiți serverele",
|
||||
"playGameServerBrowserDescription": "Găsiți un server descoperibil găzduit pe Lansatorul Reboot în browserul de servere",
|
||||
"playGameServerBrowserContent": "Răsfoiți",
|
||||
"playGameServerCustomName": "Conectați-vă la un server personalizat",
|
||||
"playGameServerCustomDescription": "Introduceți adresa oricărui server, indiferent dacă este sau nu găzduit pe Lansatorul Reboot",
|
||||
"playGameServerCustomContent": "Introduceți IP-ul",
|
||||
"settingsName": "Setări",
|
||||
"settingsClientName": "Setările clientului",
|
||||
"settingsClientDescription": "Această secțiune conține dll-urile folosite pentru funcționarea clientului Fortnite",
|
||||
"settingsClientConsoleName": "Consola pentru Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Acest fișier este injectat pentru a debloca Consola pentru Unreal Engine",
|
||||
"settingsClientAuthName": "Reparator de autentificare",
|
||||
"settingsClientAuthDescription": "Acest fișier este injectat pentru a redirecționa toate cererile HTTP către autentificatorul lansatorului",
|
||||
"settingsClientMemoryName": "Reparator de memorie",
|
||||
"settingsClientMemoryDescription": "Acest fișier este injectat pentru a preveni defectarea clientului Fortnite din cauza unei scurgeri de memorie",
|
||||
"settingsClientArgsName": "Argumente de lansare personalizate",
|
||||
"settingsClientArgsDescription": "Argumente suplimentare de utilizat la lansarea jocului",
|
||||
"settingsClientArgsPlaceholder": "-exemplu",
|
||||
"settingsServerName": "Setări ale serverului de joc",
|
||||
"settingsServerSubtitle": "Această secțiune conține setări legate de implementarea serverului de joc",
|
||||
"settingsServerFileName": "Implementarea",
|
||||
"settingsServerFileDescription": "Acest fișier este injectat pentru a crea un server de joc și pentru a găzdui meciuri.",
|
||||
"settingsServerPortName": "Portul",
|
||||
"settingsServerPortDescription": "Portul utilizat de dll-ul serverului de joc",
|
||||
"settingsServerMirrorName": "Oglindă de actualizare",
|
||||
"settingsServerMirrorDescription": "Adresa URL utilizată pentru actualizarea dll-ului serverului de joc",
|
||||
"settingsServerMirrorPlaceholder": "oglindă",
|
||||
"settingsServerTimerName": "Temporizatorul actualizării serverului",
|
||||
"settingsServerTimerSubtitle": "Determină când ar trebui să fie actualizat dll-ul serverului de joc",
|
||||
"settingsUtilsName": "Utilitățile lansatorului",
|
||||
"settingsUtilsSubtitle": "Această secțiune conține setări la îndemână pentru lansator",
|
||||
"settingsUtilsInstallationDirectoryName": "Directorul de Instalare",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Deschide directorul de instalare",
|
||||
"settingsUtilsInstallationDirectoryContent": "Afișați fișierele",
|
||||
"settingsUtilsBugReportName": "Creați un raport de erori",
|
||||
"settingsUtilsBugReportSubtitle": "Ajutați-mă să repar problemele prin raportarea lor",
|
||||
"settingsUtilsBugReportContent": "Raportați o problemă",
|
||||
"settingsUtilsResetDefaultsName": "Resetați setările",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Resetați setările lansatorului la valorile implicite",
|
||||
"settingsUtilsDialogTitle": "Doriți să resetați toate setările din această filă la valorile lor implicite? Această acțiune este ireversibilă",
|
||||
"settingsUtilsResetDefaultsContent": "Resetați",
|
||||
"settingsUtilsDialogSecondaryAction": "Închideți",
|
||||
"settingsUtilsDialogPrimaryAction": "Resetați",
|
||||
"addVersionName": "Versiunea",
|
||||
"addVersionDescription": "Selectați versiunea de Fortnite pe care doriți să jucați",
|
||||
"addLocalBuildName": "Adăugați o versiune din stocarea locală a PC-ului",
|
||||
"addLocalBuildDescription": "Versiunile provenite din stocarea locală nu sunt garantate să funcționeze",
|
||||
"addLocalBuildContent": "Adăugați versiunea de joc",
|
||||
"downloadBuildName": "Descărcați orice versiune din cloud",
|
||||
"downloadBuildDescription": "Descărcați orice versiune de Fortnite cu ușurință din cloud",
|
||||
"downloadBuildContent": "Descărcați",
|
||||
"cannotUpdateGameServer": "S-a produs o eroare în timpul actualizării serverului de joc: {error}",
|
||||
"launchFortnite": "Lansați Fortnite",
|
||||
"closeFortnite": "Închideți Fortnite",
|
||||
"updateGameServerDllNever": "Niciodată",
|
||||
"updateGameServerDllEvery": "La fiecare {name}",
|
||||
"selectPathPlaceholder": "Locație",
|
||||
"selectPathWindowTitle": "Selectați un fișier",
|
||||
"defaultDialogSecondaryAction": "Închideți",
|
||||
"stopLoadingDialogAction": "Opriți",
|
||||
"copyErrorDialogTitle": "Copiați Eroarea",
|
||||
"copyErrorDialogSuccess": "Eroare copiată în clipboard",
|
||||
"defaultServerName": "Serverul de Joc Reboot",
|
||||
"defaultServerDescription": "Doar un alt server",
|
||||
"updatingRebootDll": "Se descarcă dll-ul reboot ...",
|
||||
"updatedRebootDll": "DLL-ul reboot a fost descărcat cu succes",
|
||||
"updateRebootDllError": "S-a produs o eroare în timpul descărcării dll-ului rebot: {error}",
|
||||
"updateRebootDllErrorAction": "Reîncercați",
|
||||
"uncaughtErrorMessage": "S-a produs o eroare nepreluată: {error}",
|
||||
"launchingHeadlessServer": "Se lansează serverul fără interfața jocului...",
|
||||
"usernameOrEmail": "Nume de utilizator/Email",
|
||||
"usernameOrEmailPlaceholder": "Introduceți numele dvs. de utilizator sau adresa de e-mail",
|
||||
"password": "Parola",
|
||||
"passwordPlaceholder": "Introduceți parola, dacă doriți să folosiți una",
|
||||
"cancelProfileChanges": "Anulați",
|
||||
"saveProfileChanges": "Salvați",
|
||||
"startingServer": "Se pornește {name}...",
|
||||
"startedServer": "{name} a fost pornit cu succes",
|
||||
"startServerError": "A apărut o eroare la pornirea {name}: {error}",
|
||||
"stoppingServer": "Se oprește {name}...",
|
||||
"stoppedServer": "{name} a fost oprit cu succes",
|
||||
"stopServerError": "A apărut o eroare în timpul opririi {name}: {error}",
|
||||
"missingHostNameError": "Lipsește numele de gazdă în configurația {name}",
|
||||
"missingPortError": "Port lipsă în configurația {name}",
|
||||
"illegalPortError": "Port invalid în configurația {name}",
|
||||
"freeingPort": "Se eliberează portul {port}...",
|
||||
"freedPort": "Portul {port} a fost eliberat cu succes",
|
||||
"freePortError": "A apărut o eroare în timpul eliberării portului {port}: {error}",
|
||||
"pingingRemoteServer": "Ping la telecomanda {name}...",
|
||||
"pingingLocalServer": "Se dă ping la {type} {name}...",
|
||||
"pingError": "Nu se poate face ping la {tip} {name}",
|
||||
"joinSelfServer": "Nu vă puteți alătura propriului server",
|
||||
"wrongServerPassword": "Parolă greșită: vă rugăm să încercați din nou",
|
||||
"offlineServer": "Acest server nu este online momentan: vă rugăm să încercați din nou mai târziu",
|
||||
"serverPassword": "Parolă",
|
||||
"serverPasswordPlaceholder": "Introduceți parola serverului",
|
||||
"serverPasswordCancel": "Anulați",
|
||||
"serverPasswordConfirm": "Confirmați",
|
||||
"joinedServer": "Ați intrat cu succes pe serverul lui {author}!",
|
||||
"copiedIp": "IP copiat în clipboard",
|
||||
"selectVersion": "Selectați o versiune",
|
||||
"noVersions": "Vă rugăm să creați sau să descărcați o versiune",
|
||||
"missingVersion": "Această versiune nu există pe stocarea locală",
|
||||
"deleteVersionDialogTitle": "Sunteți sigur că doriți să ștergeți această versiune?",
|
||||
"deleteVersionFromDiskOption": "Ștergeți versiunea jocului de pe disc",
|
||||
"deleteVersionCancel": "Păstrați",
|
||||
"deleteVersionConfirm": "Ștergeți",
|
||||
"versionName": "Nume",
|
||||
"versionNameLabel": "Introduceți noul nume al versiunii",
|
||||
"newVersionNameConfirm": "Salvați",
|
||||
"newVersionNameLabel": "Introduceți noul nume al versiunii",
|
||||
"gameFolderTitle": "Folderul Jocului",
|
||||
"gameFolderPlaceholder": "Introduceți folderul noului joc",
|
||||
"gameFolderPlaceWindowTitle": "Selectați folderul jocului",
|
||||
"gameFolderLabel": "Locația",
|
||||
"openInExplorer": "Deschideți în Explorer",
|
||||
"modify": "Modificați",
|
||||
"delete": "Ștergeți",
|
||||
"build": "Versiunea",
|
||||
"selectBuild": "Selectați o versiune de Fortnite",
|
||||
"fetchingBuilds": "Recuperarea versiunilor și a discurilor...",
|
||||
"unknownError": "Eroare necunoscută",
|
||||
"downloadVersionError": "Nu se poate descărca versiunea: {error}",
|
||||
"downloadedVersion": "Descărcarea a fost finalizată cu succes!",
|
||||
"download": "Descărcați",
|
||||
"downloading": "Se descărcă...",
|
||||
"extracting": "Se extrage...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Director de instalare",
|
||||
"buildInstallationDirectoryPlaceholder": "Introduceți directorul de instalare",
|
||||
"buildInstallationDirectoryWindowTitle": "Selectați directorul de instalare",
|
||||
"timeLeft": "Timp rămas: {timeLeft, plural, =0{mai puțin de un minut} =1{aproximativ {timeLeft} minut} other{aproximativ {timeLeft} minute}}",
|
||||
"localBuildsWarning": "Versiunile locale nu sunt garantate să funcționeze",
|
||||
"saveLocalVersion": "Salvați",
|
||||
"embedded": "Încorporat",
|
||||
"remote": "Telecomandă",
|
||||
"local": "Local",
|
||||
"checkServer": "Verificați {name}",
|
||||
"startServer": "Porniți {name}",
|
||||
"stopServer": "Opriți {name}",
|
||||
"startHosting": "Începeți să găzduiți",
|
||||
"stopHosting": "Opriți găzduirea",
|
||||
"startGame": "Porniți Fortnite",
|
||||
"stopGame": "Opriți fortnite",
|
||||
"waitingForGameServer": "Se așteaptă pornirea serverului de joc...",
|
||||
"gameServerStartWarning": "Serverul fără interfața de joc a fost pornit cu succes, dar serverul de joc(meci) nu a pornit",
|
||||
"gameServerStartLocalWarning": "Serverul de joc a fost pornit cu succes, dar alți jucători nu se pot conecta",
|
||||
"gameServerStarted": "Serverul de joc a fost pornit cu succes",
|
||||
"checkingGameServer": "Se verifică dacă alți jucători se pot conecta la serverul de joc...",
|
||||
"checkGameServerFixMessage": "Alți jucători nu se pot conecta la serverul de joc deoarece portul {port} nu este deschis",
|
||||
"checkGameServerFixAction": "Reparați",
|
||||
"infoName": "Informații",
|
||||
"emptyVersionName": "Numele versiunii este gol",
|
||||
"versionAlreadyExists": "Deja există această versiune",
|
||||
"emptyGamePath": "Locația jocului este goală",
|
||||
"directoryDoesNotExist": "Directorul nu există",
|
||||
"missingShippingExe": "Locația jocului invalidă: lipsește FortniteClient-Win64-Shipping",
|
||||
"invalidDownloadPath": "Locația de descărcare este invalidă",
|
||||
"invalidDllPath": "Locația dll-ului este invalidă",
|
||||
"dllDoesNotExist": "Fișierul nu există",
|
||||
"invalidDllExtension": "Acest fișier nu este un dll",
|
||||
"emptyHostname": "Nume de gazdă gol",
|
||||
"hostnameFormat": "Format greșit al numelui de gazdă: era de așteptat ip:port",
|
||||
"emptyURL": "URL de actualizare gol"
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
{
|
||||
"find": "Поиск",
|
||||
"on": "Вкл.",
|
||||
"off": "Выкл.",
|
||||
"resetDefaultsContent": "Сбросить",
|
||||
"resetDefaultsDialogTitle": "Вы хотите сбросить все настройки в этой вкладке к значениям по умолчанию? Это действие нельзя отменить",
|
||||
"resetDefaultsDialogSecondaryAction": "Закрыть",
|
||||
"resetDefaultsDialogPrimaryAction": "Сбросить",
|
||||
"authenticatorName": "Аутентификатор",
|
||||
"authenticatorConfigurationName": "Конфигурация аутентификатора",
|
||||
"authenticatorConfigurationDescription": "В этом разделе содержится конфигурация аутентификатора",
|
||||
"authenticatorConfigurationHostName": "Хост",
|
||||
"authenticatorConfigurationHostDescription": "Имя хоста аутентификатора",
|
||||
"authenticatorConfigurationPortName": "Порт",
|
||||
"authenticatorConfigurationPortDescription": "Порт аутентификатора",
|
||||
"authenticatorConfigurationDetachedName": "Отделенный",
|
||||
"authenticatorConfigurationDetachedDescription": "Запуск встроенного аутентификатора в качестве отдельного процесса, полезно для отладки",
|
||||
"authenticatorInstallationDirectoryName": "Папка установки аутентификатора",
|
||||
"authenticatorInstallationDirectoryDescription": "Открывает папку, в которой находится встроенный аутентификатор",
|
||||
"authenticatorInstallationDirectoryContent": "Показать файлы",
|
||||
"authenticatorResetDefaultsName": "Сбросить аутентификатор",
|
||||
"authenticatorResetDefaultsDescription": "Сбрасывает настройки аутентификатора к значениям по умолчанию",
|
||||
"authenticatorResetDefaultsContent": "Сбросить",
|
||||
"hostGameServerName": "Игровой сервер",
|
||||
"hostGameServerDescription": "Предоставьте основную информацию о вашем игровом сервере для браузера серверов",
|
||||
"hostGameServerNameName": "Название",
|
||||
"hostGameServerNameDescription": "Название вашего игрового сервера",
|
||||
"hostGameServerDescriptionName": "Описание",
|
||||
"hostGameServerDescriptionDescription": "Описание вашего игрового сервера",
|
||||
"hostGameServerPasswordName": "Пароль",
|
||||
"hostGameServerPasswordDescription": "Пароль для вашего игрового сервера, если требуется",
|
||||
"hostGameServerDiscoverableName": "Доступность",
|
||||
"hostGameServerDiscoverableDescription": "Сделайте ваш сервер доступным для других игроков в браузере серверов",
|
||||
"hostShareName": "Поделиться",
|
||||
"hostShareDescription": "Сделайте процесс присоединения других людей к вашему серверу проще с помощью настроек в этом разделе",
|
||||
"hostShareLinkName": "Ссылка",
|
||||
"hostShareLinkDescription": "Копирует ссылку на ваш сервер в буфер обмена (требуется Reboot Launcher)",
|
||||
"hostShareLinkContent": "Скопировать ссылку",
|
||||
"hostShareLinkMessageSuccess": "Ссылка скопирована в буфер обмена",
|
||||
"hostShareIpName": "Публичный IP",
|
||||
"hostShareIpDescription": "Копирует ваш текущий публичный IP в буфер обмена (не требует Reboot Launcher)",
|
||||
"hostShareIpContent": "Скопировать IP",
|
||||
"hostShareIpMessageLoading": "Получение вашего публичного IP...",
|
||||
"hostShareIpMessageSuccess": "IP скопирован в буфер обмена",
|
||||
"hostShareIpMessageError": "Произошла ошибка при получении вашего публичного IP: {error}",
|
||||
"hostResetName": "Сбросить настройки игрового сервера",
|
||||
"hostResetDescription": "Сбрасывает настройки игрового сервера к значениям по умолчанию",
|
||||
"hostResetContent": "Сбросить",
|
||||
"browserName": "Браузер серверов",
|
||||
"noServersAvailableTitle": "В данный момент серверов нет в наличии"
|
||||
"noServersAvailableSubtitle": "Создайте сервер сами или вернитесь позже",
|
||||
"joinServer": "Присоединиться к серверу",
|
||||
"noServersAvailableByQueryTitle": "Результаты не найдены",
|
||||
"noServersAvailableByQuerySubtitle": "Нет серверов, соответствующих вашему запросу",
|
||||
"findServer": "Найти сервер",
|
||||
"copyIp": "Копировать IP",
|
||||
"hostName": "Хост",
|
||||
"matchmakerName": "Матчмейкер",
|
||||
"matchmakerConfigurationName": "Настройки матчмейкера",
|
||||
"matchmakerConfigurationDescription": "Этот раздел содержит настройки матчмейкера",
|
||||
"matchmakerConfigurationHostName": "Хост",
|
||||
"matchmakerConfigurationHostDescription": "Имя хоста матчмейкера",
|
||||
"matchmakerConfigurationPortName": "Порт",
|
||||
"matchmakerConfigurationPortDescription": "Порт матчмейкера",
|
||||
"matchmakerConfigurationAddressName": "Адрес игрового сервера",
|
||||
"matchmakerConfigurationAddressDescription": "Адрес игрового сервера, используемый матчмейкером",
|
||||
"matchmakerConfigurationDetachedName": "Отделенный",
|
||||
"matchmakerConfigurationDetachedDescription": "Запускать встроенный матчмейкер как отдельный процесс, полезно для отладки",
|
||||
"matchmakerInstallationDirectoryName": "Папка установки матчмейкера",
|
||||
"matchmakerInstallationDirectoryDescription": "Открывает папку, в которой находится встроенный матчмейкер",
|
||||
"matchmakerInstallationDirectoryContent": "Показать файлы",
|
||||
"matchmakerResetDefaultsName": "Сбросить настройки матчмейкера",
|
||||
"matchmakerResetDefaultsDescription": "Сбрасывает настройки матчмейкера до значений по умолчанию",
|
||||
"matchmakerResetDefaultsContent": "Сбросить",
|
||||
"matchmakerResetDefaultsDialogTitle": "Вы хотите сбросить все настройки на этой вкладке до значений по умолчанию? Данное действие нельзя будет отменить",
|
||||
"matchmakerResetDefaultsDialogSecondaryAction": "Закрыть",
|
||||
"matchmakerResetDefaultsDialogPrimaryAction": "Сбросить",
|
||||
"playName": "Играть",
|
||||
"playGameServerName": "Игровой сервер",
|
||||
"playGameServerDescription": "Полезные ярлыки для поиска сервера, на котором вы хотите играть",
|
||||
"playGameServerContentLocal": "Ваш сервер",
|
||||
"playGameServerContentBrowser": "Сервер {owner}",
|
||||
"playGameServerContentCustom": "{address}",
|
||||
"playGameServerHostName": "Создать собственный сервер",
|
||||
"playGameServerHostDescription": "Хотите создать игровой сервер для себя или своих друзей? Создайте один!",
|
||||
"playGameServerHostContent": "Создать",
|
||||
"playGameServerBrowserName": "Просмотр серверов",
|
||||
"playGameServerBrowserDescription": "Найти обнаруженный сервер, размещенный в Reboot Launcher, в браузере серверов",
|
||||
"playGameServerBrowserContent": "Просмотр",
|
||||
"playGameServerCustomName": "Присоединиться к пользовательскому серверу",
|
||||
"playGameServerCustomDescription": "Введите адрес любого сервера, будь то сервер, размещенный в Reboot Launcher или нет",
|
||||
"playGameServerCustomContent": "Введите IP",
|
||||
"settingsName": "Настройки",
|
||||
"settingsClientName": "Настройки клиента",
|
||||
"settingsClientDescription": "Этот раздел содержит DLL-файлы, необходимые для работы клиента Fortnite",
|
||||
"settingsClientConsoleName": "Консоль Unreal Engine",
|
||||
"settingsClientConsoleDescription": "Этот файл внедряется для разблокировки консоли Unreal Engine",
|
||||
"settingsClientAuthName": "Патчер аутентификации",
|
||||
"settingsClientAuthDescription": "Этот файл внедряется для перенаправления всех HTTP-запросов к аутентификатору лаунчера",
|
||||
"settingsClientMemoryName": "Патчер памяти",
|
||||
"settingsClientMemoryDescription": "Этот файл внедрен для предотвращения сбоев клиента Fortnite из-за утечки памяти",
|
||||
"settingsClientArgsName": "Пользовательские аргументы запуска",
|
||||
"settingsClientArgsDescription": "Дополнительные аргументы для использования при запуске игры",
|
||||
"settingsClientArgsPlaceholder": "-пример",
|
||||
"settingsServerName": "Настройки игрового сервера",
|
||||
"settingsServerSubtitle": "Этот раздел содержит настройки, связанные с реализацией игрового сервера",
|
||||
"settingsServerFileName": "Реализация",
|
||||
"settingsServerFileDescription": "Этот файл внедрен для создания игрового сервера и проведения матчей",
|
||||
"settingsServerPortName": "Порт",
|
||||
"settingsServerPortDescription": "Порт, используемый сервером игры",
|
||||
"settingsServerMirrorName": "Зеркало обновлений",
|
||||
"settingsServerMirrorDescription": "URL-адрес, используемый для обновления файла сервера игры",
|
||||
"settingsServerMirrorPlaceholder": "зеркало",
|
||||
"settingsServerTimerName": "Таймер обновления",
|
||||
"settingsServerTimerSubtitle": "Определяет, когда следует обновлять файл сервера игры",
|
||||
"settingsUtilsName": "Утилиты лаунчера",
|
||||
"settingsUtilsSubtitle": "Этот раздел содержит удобные настройки для лаунчера",
|
||||
"settingsUtilsInstallationDirectoryName": "Директория установки",
|
||||
"settingsUtilsInstallationDirectorySubtitle": "Открывает директорию установки",
|
||||
"settingsUtilsInstallationDirectoryContent": "Показать файлы",
|
||||
"settingsUtilsBugReportName": "Создать отчет об ошибке",
|
||||
"settingsUtilsBugReportSubtitle": "Помогите мне исправить ошибки, сообщив о них",
|
||||
"settingsUtilsBugReportContent": "Сообщить об ошибке",
|
||||
"settingsUtilsResetDefaultsName": "Сбросить настройки",
|
||||
"settingsUtilsResetDefaultsSubtitle": "Сбрасывает настройки лаунчера к значениям по умолчанию",
|
||||
"settingsUtilsDialogTitle": "Вы хотите сбросить все настройки в этой вкладке до значений по умолчанию? Это действие необратимо",
|
||||
"settingsUtilsResetDefaultsContent": "Сбросить",
|
||||
"settingsUtilsDialogSecondaryAction": "Закрыть",
|
||||
"settingsUtilsDialogPrimaryAction": "Сбросить",
|
||||
"addVersionName": "Версия",
|
||||
"addVersionDescription": "Выберите версию Fortnite, которую хотите использовать",
|
||||
"addLocalBuildName": "Добавить версию из локального хранилища на этом ПК",
|
||||
"addLocalBuildDescription": "Версии из локального диска не гарантируют работоспособность",
|
||||
"addLocalBuildContent": "Добавить сборку",
|
||||
"downloadBuildName": "Скачать любую версию из облака",
|
||||
"downloadBuildDescription": "Легко скачать любую версию Fortnite из облака",
|
||||
"downloadBuildContent": "Скачать",
|
||||
"cannotUpdateGameServer": "Произошла ошибка при обновлении игрового сервера: {error}",
|
||||
"launchFortnite": "Запустить Fortnite",
|
||||
"closeFortnite": "Закрыть Fortnite",
|
||||
"updateGameServerDllNever": "Никогда",
|
||||
"updateGameServerDllEvery": "Каждые {name}",
|
||||
"selectPathPlaceholder": "Путь",
|
||||
"selectPathWindowTitle": "Выберите файл",
|
||||
"defaultDialogSecondaryAction": "Закрыть",
|
||||
"stopLoadingDialogAction": "Остановить",
|
||||
"copyErrorDialogTitle": "Копировать ошибку",
|
||||
"copyErrorDialogSuccess": "Скопировано в буфер обмена",
|
||||
"defaultServerName": "Перезагрузить игровой сервер",
|
||||
"defaultServerDescription": "Просто еще один сервер",
|
||||
"updatingRebootDll": "Загрузка файла перезагрузки...",
|
||||
"updatedRebootDll": "Файл перезагрузки успешно загружен",
|
||||
"updateRebootDllError": "Произошла ошибка при загрузке файла перезагрузки: {error}",
|
||||
"updateRebootDllErrorAction": "Повторить",
|
||||
"uncaughtErrorMessage": "Произошла необработанная ошибка: {error}",
|
||||
"launchingHeadlessServer": "Запуск сервера без графического интерфейса...",
|
||||
"usernameOrEmail": "Имя пользователя/Электронная почта",
|
||||
"usernameOrEmailPlaceholder": "Введите имя пользователя или адрес электронной почты",
|
||||
"password": "Пароль",
|
||||
"passwordPlaceholder": "Введите пароль, если вы хотите использовать его",
|
||||
"cancelProfileChanges": "Отменить",
|
||||
"saveProfileChanges": "Сохранить",
|
||||
"startingServer": "Запуск {name}...",
|
||||
"startedServer": "{name} успешно запущен",
|
||||
"startServerError": "Произошла ошибка при запуске {name}: {error}",
|
||||
"stoppingServer": "Остановка {name}...",
|
||||
"stoppedServer": "{name} успешно остановлен",
|
||||
"stopServerError": "Произошла ошибка при остановке {name}: {error}",
|
||||
"missingHostNameError": "Отсутствует имя хоста в конфигурации {name}",
|
||||
"missingPortError": "Отсутствует порт в конфигурации {name}",
|
||||
"illegalPortError": "Недопустимый порт в конфигурации {name}",
|
||||
"freeingPort": "Освобождение порта {port}...",
|
||||
"freedPort": "Порт {port} успешно освобожден",
|
||||
"freePortError": "Произошла ошибка при освобождении порта {port}: {error}",
|
||||
"pingingRemoteServer": "Проверка доступности удаленного сервера {name}...",
|
||||
"pingingLocalServer": "Проверка доступности {type} {name}...",
|
||||
"pingError": "Не удалось проверить доступность {type} {name}",
|
||||
"joinSelfServer": "Вы не можете присоединиться к собственному серверу",
|
||||
"wrongServerPassword": "Неверный пароль: пожалуйста, попробуйте снова",
|
||||
"offlineServer": "Этот сервер сейчас недоступен: пожалуйста, попробуйте позже",
|
||||
"serverPassword": "Пароль сервера",
|
||||
"serverPasswordPlaceholder": "Введите пароль сервера",
|
||||
"serverPasswordCancel": "Отменить",
|
||||
"serverPasswordConfirm": "Подтвердить",
|
||||
"joinedServer": "Вы успешно присоединились к серверу {author}!",
|
||||
"copiedIp": "Скопирован IP в буфер обмена",
|
||||
"selectVersion": "Выберите версию",
|
||||
"noVersions": "Пожалуйста, создайте или загрузите версию",
|
||||
"missingVersion": "Этой версии не существует на локальной машине",
|
||||
"deleteVersionDialogTitle": "Вы уверены, что хотите удалить эту версию?",
|
||||
"deleteVersionFromDiskOption": "Удалить файлы версии с диска",
|
||||
"deleteVersionCancel": "Отменить",
|
||||
"deleteVersionConfirm": "Удалить",
|
||||
"versionName": "Название",
|
||||
"versionNameLabel": "Введите новое название версии",
|
||||
"newVersionNameConfirm": "Сохранить",
|
||||
"newVersionNameLabel": "Введите новое название версии",
|
||||
"gameFolderTitle": "Папка с игрой",
|
||||
"gameFolderPlaceholder": "Введите новую папку с игрой",
|
||||
"gameFolderPlaceWindowTitle": "Выберите папку с игрой",
|
||||
"gameFolderLabel": "Путь",
|
||||
"openInExplorer": "Открыть в проводнике",
|
||||
"modify": "Изменить",
|
||||
"delete": "Удалить",
|
||||
"build": "Версия",
|
||||
"selectBuild": "Выберите версий Fortnite",
|
||||
"fetchingBuilds": "Получение версий и дисков...",
|
||||
"unknownError": "Неизвестная ошибка",
|
||||
"downloadVersionError": "Не удается загрузить версию: {error}",
|
||||
"downloadedVersion": "Загрузка успешно завершена!",
|
||||
"download": "Загрузить",
|
||||
"downloading": "Загрузка...",
|
||||
"extracting": "Извлечение...",
|
||||
"buildProgress": "{progress}%",
|
||||
"buildInstallationDirectory": "Директория установки",
|
||||
"buildInstallationDirectoryPlaceholder": "Введите директорию установки",
|
||||
"buildInstallationDirectoryWindowTitle": "Выберите директорию установки",
|
||||
"timeLeft": "Осталось времени: {timeLeft, plural, =0{менее минуты} =1{примерно {timeLeft} минута} other{примерно {timeLeft} минут}}",
|
||||
"localBuildsWarning": "Локальные версии не гарантируют работоспособность",
|
||||
"saveLocalVersion": "Сохранить",
|
||||
"embedded": "Встроенная",
|
||||
"remote": "Удаленная",
|
||||
"local": "Локальная",
|
||||
"checkServer": "Проверить {name}",
|
||||
"startServer": "Запустить {name}",
|
||||
"stopServer": "Остановить {name}",
|
||||
"startHosting": "Начать хостинг",
|
||||
"stopHosting": "Завершить хостинг",
|
||||
"startGame": "Запустить Fortnite",
|
||||
"stopGame": "Закрыть Fortnite",
|
||||
"waitingForGameServer": "Ожидание запуска игрового сервера...",
|
||||
"gameServerStartWarning": "Headless-сервер успешно запущен, но игровой сервер не запустился",
|
||||
"gameServerStartLocalWarning": "Игровой сервер успешно запущен, но другие игроки не могут присоединиться",
|
||||
"gameServerStarted": "Игровой сервер успешно запущен",
|
||||
"checkingGameServer": "Проверка возможности присоединения других игроков к игровому серверу...",
|
||||
"checkGameServerFixMessage": "Другие игроки не могут присоединиться к игровому серверу, так как порт {port} закрыт",
|
||||
"checkGameServerFixAction": "Исправить",
|
||||
"infoName": "Информация",
|
||||
"emptyVersionName": "Пустое имя версии",
|
||||
"versionAlreadyExists": "Эта версия уже существует",
|
||||
"emptyGamePath": "Пустой путь к игре",
|
||||
"directoryDoesNotExist": "Папка не существует",
|
||||
"missingShippingExe": "Недействительный путь к игре: отсутствует FortniteClient-Win64-Shipping",
|
||||
"invalidDownloadPath": "Недействительный путь загрузки",
|
||||
"invalidDllPath": "Недействительный путь к DLL",
|
||||
"dllDoesNotExist": "Файл не существует",
|
||||
"invalidDllExtension": "Этот файл не является DLL",
|
||||
"emptyHostname": "Пустое имя хоста",
|
||||
"hostnameFormat": "Неверный формат имени хоста: ожидается IP:порт",
|
||||
"emptyURL": "Пустой URL обновления"
|
||||
"missingVersionError": "Скачайте или выберите версию перед запуском Fortnite",
|
||||
"missingExecutableError": "Отсутствует исполняемый файл Fortnite: обычно это означает, что установка была перемещена или удалена",
|
||||
"corruptedVersionError": "Повреждена установка Fortnite: пожалуйста, скачайте ее заново из лаунчера или измените версию",
|
||||
"missingDllError": "DLL-файл по пути {path} не существует",
|
||||
"corruptedDllError": "Невозможно внедрить DLL: {error}",
|
||||
"tokenError": "Не удается войти в Fortnite: ошибка аутентификации",
|
||||
"unknownFortniteError": "Произошла неизвестная ошибка при запуске Fortnite: {error}",
|
||||
"serverNoLongerAvailable": "Сервер {owner} больше не доступен",
|
||||
"serverNoLongerAvailableUnnamed": "Предыдущий сервер больше не доступен",
|
||||
"noServerFound": "Сервер не найден: недействительная или устаревшая ссылка",
|
||||
"settingsUtilsThemeName": "Тема",
|
||||
"settingsUtilsThemeDescription": "Выберите тему для использования в лаунчере",
|
||||
"dark": "Темная",
|
||||
"light": "Светлая",
|
||||
"system": "Системная",
|
||||
"settingsUtilsLanguageName": "Язык",
|
||||
"settingsUtilsLanguageDescription": "Выберите язык для использования в лаунчере"
|
||||
}
|
||||
@@ -5,56 +5,76 @@ import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_acrylic/flutter_acrylic.dart';
|
||||
import 'package:flutter_gen/gen_l10n/reboot_localizations.dart';
|
||||
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/info_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/update_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/error.dart';
|
||||
import 'package:reboot_launcher/src/controller/authenticator_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/authenticator_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/info_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/update_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/error.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
|
||||
import 'package:reboot_launcher/src/page/implementation/home_page.dart';
|
||||
import 'package:reboot_launcher/src/util/daemon.dart';
|
||||
import 'package:reboot_launcher/src/util/matchmaker.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/util/watch.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
import 'package:url_protocol/url_protocol.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:flutter_gen/gen_l10n/reboot_localizations.dart';
|
||||
|
||||
const double kDefaultWindowWidth = 1536;
|
||||
const double kDefaultWindowHeight = 1024;
|
||||
const String kCustomUrlSchema = "reboot";
|
||||
const String kCustomUrlSchema = "Reboot";
|
||||
|
||||
void main() => runZonedGuarded(() async {
|
||||
await installationDirectory.create(recursive: true);
|
||||
await Supabase.initialize(
|
||||
url: supabaseUrl,
|
||||
anonKey: supabaseAnonKey
|
||||
);
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await SystemTheme.accentColor.load();
|
||||
_initWindow();
|
||||
var storageError = await _initStorage();
|
||||
var urlError = await _initUrlHandler();
|
||||
var observerError = _initObservers();
|
||||
_checkGameServer();
|
||||
runApp(const RebootApplication());
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) => _handleErrors([urlError, storageError, observerError]));
|
||||
},
|
||||
(error, stack) => onError(error, stack, false),
|
||||
void main() => runZonedGuarded(
|
||||
() async {
|
||||
final errors = <Object>[];
|
||||
try {
|
||||
await installationDirectory.create(recursive: true);
|
||||
await Supabase.initialize(
|
||||
url: supabaseUrl,
|
||||
anonKey: supabaseAnonKey
|
||||
);
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await SystemTheme.accentColor.load();
|
||||
_initWindow();
|
||||
final storageError = await _initStorage();
|
||||
if(storageError != null) {
|
||||
errors.add(storageError);
|
||||
}
|
||||
|
||||
final urlError = await _initUrlHandler();
|
||||
if(urlError != null) {
|
||||
errors.add(urlError);
|
||||
}
|
||||
|
||||
final observerError = _initObservers();
|
||||
if(observerError != null) {
|
||||
errors.add(observerError);
|
||||
}
|
||||
|
||||
_checkGameServer();
|
||||
}catch(uncaughtError) {
|
||||
errors.add(uncaughtError);
|
||||
} finally{
|
||||
runApp(const RebootApplication());
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) => _handleErrors(errors));
|
||||
}
|
||||
},
|
||||
(error, stack) => onError(error, stack, false),
|
||||
zoneSpecification: ZoneSpecification(
|
||||
handleUncaughtError: (self, parent, zone, error, stacktrace) => onError(error, stacktrace, false)
|
||||
));
|
||||
handleUncaughtError: (self, parent, zone, error, stacktrace) => onError(error, stacktrace, false)
|
||||
)
|
||||
);
|
||||
|
||||
void _handleErrors(List<Object?> errors) {
|
||||
errors.where((element) => element != null).forEach((element) => onError(element!, null, false));
|
||||
@@ -78,7 +98,7 @@ Future<void> _checkGameServer() async {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => showInfoBar(
|
||||
oldOwner == null ? translations.serverNoLongerAvailableUnnamed : translations.serverNoLongerAvailable(oldOwner),
|
||||
severity: InfoBarSeverity.warning,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
));
|
||||
}catch(_) {
|
||||
// Intended behaviour
|
||||
@@ -90,7 +110,7 @@ Future<Object?> _initUrlHandler() async {
|
||||
try {
|
||||
registerProtocolHandler(kCustomUrlSchema, arguments: ['%s']);
|
||||
var appLinks = AppLinks();
|
||||
var initialUrl = await appLinks.getInitialAppLink();
|
||||
var initialUrl = await appLinks.getInitialLink();
|
||||
if(initialUrl != null) {
|
||||
_joinServer(initialUrl);
|
||||
}
|
||||
@@ -112,7 +132,7 @@ void _joinServer(Uri uri) {
|
||||
}else {
|
||||
showInfoBar(
|
||||
translations.noServerFound,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
}
|
||||
@@ -153,11 +173,9 @@ Object? _initObservers() {
|
||||
var gameController = Get.find<GameController>();
|
||||
var gameInstance = gameController.instance.value;
|
||||
gameInstance?.startObserver();
|
||||
gameController.saveInstance();
|
||||
var hostingController = Get.find<HostingController>();
|
||||
var hostingInstance = hostingController.instance.value;
|
||||
hostingInstance?.startObserver();
|
||||
hostingController.saveInstance();
|
||||
return null;
|
||||
}catch(error) {
|
||||
return error;
|
||||
@@ -179,9 +197,7 @@ Future<Object?> _initStorage() async {
|
||||
Get.put(SettingsController());
|
||||
Get.put(HostingController());
|
||||
Get.put(InfoController());
|
||||
var updateController = UpdateController();
|
||||
Get.put(updateController);
|
||||
updateController.update();
|
||||
Get.put(UpdateController());
|
||||
return null;
|
||||
}catch(error) {
|
||||
return error;
|
||||
|
||||
@@ -16,7 +16,7 @@ class AuthenticatorController extends ServerController {
|
||||
String get defaultHost => kDefaultAuthenticatorHost;
|
||||
|
||||
@override
|
||||
String get defaultPort => kDefaultAuthenticatorPort;
|
||||
String get defaultPort => kDefaultAuthenticatorPort.toString();
|
||||
|
||||
@override
|
||||
Future<bool> get isPortFree => isAuthenticatorPortFree();
|
||||
|
||||
@@ -3,17 +3,38 @@ import 'package:reboot_common/common.dart';
|
||||
|
||||
class BuildController extends GetxController {
|
||||
List<FortniteBuild>? _builds;
|
||||
Rxn<FortniteBuild> selectedBuild;
|
||||
Rxn<FortniteBuild> _selectedBuild;
|
||||
Rx<FortniteBuildSource> _selectedBuildSource;
|
||||
|
||||
BuildController() : selectedBuild = Rxn();
|
||||
BuildController() : _selectedBuild = Rxn(),
|
||||
_selectedBuildSource = Rx(FortniteBuildSource.manifest);
|
||||
|
||||
List<FortniteBuild>? get builds => _builds;
|
||||
|
||||
FortniteBuild? get selectedBuild => _selectedBuild.value;
|
||||
|
||||
set selectedBuild(FortniteBuild? value) {
|
||||
_selectedBuild.value = value;
|
||||
if(value != null && value.source != value.source) {
|
||||
_selectedBuildSource.value = value.source;
|
||||
}
|
||||
}
|
||||
|
||||
FortniteBuildSource get selectedBuildSource => _selectedBuildSource.value;
|
||||
|
||||
set selectedBuildSource(FortniteBuildSource value) {
|
||||
_selectedBuildSource.value = value;
|
||||
final selected = selectedBuild;
|
||||
if(selected == null || selected.source != value) {
|
||||
final selectable = builds?.firstWhereOrNull((element) => element.source == value);
|
||||
_selectedBuild.value = selectable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set builds(List<FortniteBuild>? builds) {
|
||||
_builds = builds;
|
||||
if(builds == null || builds.isEmpty){
|
||||
return;
|
||||
}
|
||||
selectedBuild.value = builds[0];
|
||||
final selectable = builds?.firstWhereOrNull((element) => element.source == selectedBuildSource);
|
||||
_selectedBuild.value = selectable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,14 +39,9 @@ class GameController extends GetxController {
|
||||
customLaunchArgs.addListener(() =>
|
||||
_storage.write("custom_launch_args", customLaunchArgs.text));
|
||||
started = RxBool(false);
|
||||
var serializedInstance = _storage.read("instance");
|
||||
instance = Rxn(serializedInstance != null ? GameInstance.fromJson(jsonDecode(serializedInstance)) : null);
|
||||
instance.listen((_) => saveInstance());
|
||||
instance = Rxn();
|
||||
}
|
||||
|
||||
Future<void> saveInstance() =>
|
||||
_storage.write("instance", jsonEncode(instance.value?.toJson()));
|
||||
|
||||
void reset() {
|
||||
username.text = kDefaultPlayerName;
|
||||
password.text = "";
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
@@ -16,8 +13,10 @@ class HostingController extends GetxController {
|
||||
late final TextEditingController password;
|
||||
late final RxBool showPassword;
|
||||
late final RxBool discoverable;
|
||||
late final RxBool headless;
|
||||
late final RxBool started;
|
||||
late final RxBool published;
|
||||
late final RxBool automaticServer;
|
||||
late final Rxn<GameInstance> instance;
|
||||
late final Rxn<Set<Map<String, dynamic>>> servers;
|
||||
|
||||
@@ -33,24 +32,27 @@ class HostingController extends GetxController {
|
||||
password.addListener(() => _storage.write("password", password.text));
|
||||
discoverable = RxBool(_storage.read("discoverable") ?? true);
|
||||
discoverable.listen((value) => _storage.write("discoverable", value));
|
||||
headless = RxBool(_storage.read("headless") ?? true);
|
||||
headless.listen((value) => _storage.write("headless", value));
|
||||
started = RxBool(false);
|
||||
published = RxBool(false);
|
||||
showPassword = RxBool(false);
|
||||
var serializedInstance = _storage.read("instance");
|
||||
instance = Rxn(serializedInstance != null ? GameInstance.fromJson(jsonDecode(serializedInstance)) : null);
|
||||
instance.listen((_) => saveInstance());
|
||||
var supabase = Supabase.instance.client;
|
||||
instance = Rxn();
|
||||
automaticServer = RxBool(_storage.read("auto") ?? true);
|
||||
automaticServer.listen((value) => _storage.write("auto", value));
|
||||
final supabase = Supabase.instance.client;
|
||||
servers = Rxn();
|
||||
supabase.from('hosts')
|
||||
supabase.from("hosting")
|
||||
.stream(primaryKey: ['id'])
|
||||
.map((event) => _parseValidServers(event))
|
||||
.listen((event) => servers.value = event);
|
||||
.listen((event) {
|
||||
servers.value = event;
|
||||
published.value = event.any((element) => element["id"] == uuid);
|
||||
});
|
||||
}
|
||||
|
||||
Set<Map<String, dynamic>> _parseValidServers(event) => event.where((element) => element["ip"] != null).toSet();
|
||||
|
||||
Future<void> saveInstance() => _storage.write("instance", jsonEncode(instance.value?.toJson()));
|
||||
|
||||
void reset() {
|
||||
name.text = "";
|
||||
description.text = "";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
|
||||
class InfoController extends GetxController {
|
||||
List<String>? links;
|
||||
|
||||
@@ -45,7 +45,7 @@ class MatchmakerController extends ServerController {
|
||||
String get defaultHost => kDefaultMatchmakerHost;
|
||||
|
||||
@override
|
||||
String get defaultPort => kDefaultMatchmakerPort;
|
||||
String get defaultPort => kDefaultMatchmakerPort.toString();
|
||||
|
||||
@override
|
||||
Future<bool> get isPortFree => isMatchmakerPortFree();
|
||||
|
||||
@@ -17,7 +17,6 @@ abstract class ServerController extends GetxController {
|
||||
late RxBool started;
|
||||
late RxBool detached;
|
||||
StreamSubscription? worker;
|
||||
int? embeddedServerPid;
|
||||
HttpServer? localServer;
|
||||
HttpServer? remoteServer;
|
||||
|
||||
@@ -93,8 +92,16 @@ abstract class ServerController extends GetxController {
|
||||
return;
|
||||
}
|
||||
|
||||
yield ServerResult(ServerResultType.starting);
|
||||
started.value = true;
|
||||
if(type() != ServerType.local) {
|
||||
started.value = true;
|
||||
yield ServerResult(ServerResultType.starting);
|
||||
}else {
|
||||
started.value = false;
|
||||
if(port != defaultPort) {
|
||||
yield ServerResult(ServerResultType.starting);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var host = this.host.text.trim();
|
||||
if (host.isEmpty) {
|
||||
@@ -117,7 +124,7 @@ abstract class ServerController extends GetxController {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type() != ServerType.local && await isPortTaken) {
|
||||
if ((type() != ServerType.local || port != defaultPort) && await isPortTaken) {
|
||||
yield ServerResult(ServerResultType.freeingPort);
|
||||
var result = await freePort();
|
||||
yield ServerResult(result ? ServerResultType.freePortSuccess : ServerResultType.freePortError);
|
||||
@@ -126,9 +133,15 @@ abstract class ServerController extends GetxController {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(type()){
|
||||
case ServerType.embedded:
|
||||
embeddedServerPid = await startEmbeddedInternal();
|
||||
final pid = await startEmbeddedInternal();
|
||||
watchProcess(pid).then((value) {
|
||||
if(started()) {
|
||||
started.value = false;
|
||||
}
|
||||
});
|
||||
break;
|
||||
case ServerType.remote:
|
||||
yield ServerResult(ServerResultType.pingingRemote);
|
||||
@@ -143,7 +156,7 @@ abstract class ServerController extends GetxController {
|
||||
break;
|
||||
case ServerType.local:
|
||||
if(port != defaultPort) {
|
||||
localServer = await startRemoteAuthenticatorProxy(Uri.parse("http://$defaultHost:$defaultPort"));
|
||||
localServer = await startRemoteAuthenticatorProxy(Uri.parse("http://$defaultHost:$port"));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -153,6 +166,8 @@ abstract class ServerController extends GetxController {
|
||||
var uriResult = await pingServer(defaultHost, defaultPort);
|
||||
if(uriResult == null) {
|
||||
yield ServerResult(ServerResultType.pingError);
|
||||
remoteServer?.close(force: true);
|
||||
localServer?.close(force: true);
|
||||
started.value = false;
|
||||
return;
|
||||
}
|
||||
@@ -164,6 +179,8 @@ abstract class ServerController extends GetxController {
|
||||
error: error,
|
||||
stackTrace: stackTrace
|
||||
);
|
||||
remoteServer?.close(force: true);
|
||||
localServer?.close(force: true);
|
||||
started.value = false;
|
||||
}
|
||||
}
|
||||
@@ -178,7 +195,7 @@ abstract class ServerController extends GetxController {
|
||||
try{
|
||||
switch(type()){
|
||||
case ServerType.embedded:
|
||||
Process.killPid(embeddedServerPid!, ProcessSignal.sigabrt);
|
||||
killProcessByPort(int.parse(defaultPort));
|
||||
break;
|
||||
case ServerType.remote:
|
||||
await remoteServer?.close(force: true);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
@@ -17,36 +17,36 @@ class UpdateController {
|
||||
timestamp = RxnInt(_storage.read("ts"));
|
||||
timestamp.listen((value) => _storage.write("ts", value));
|
||||
var timerIndex = _storage.read("timer");
|
||||
timer = Rx(timerIndex == null ? UpdateTimer.never : UpdateTimer.values.elementAt(timerIndex));
|
||||
timer = Rx(timerIndex == null ? UpdateTimer.hour : UpdateTimer.values.elementAt(timerIndex));
|
||||
timer.listen((value) => _storage.write("timer", value.index));
|
||||
url = TextEditingController(text: _storage.read("update_url") ?? rebootDownloadUrl);
|
||||
url = TextEditingController(text: _storage.read("update_url") ?? kRebootDownloadUrl);
|
||||
url.addListener(() => _storage.write("update_url", url.text));
|
||||
status = Rx(UpdateStatus.waiting);
|
||||
}
|
||||
|
||||
Future<void> update([bool force = false]) async {
|
||||
if(timer.value == UpdateTimer.never) {
|
||||
status.value = UpdateStatus.success;
|
||||
return;
|
||||
}
|
||||
|
||||
showInfoBar(
|
||||
translations.updatingRebootDll,
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
try {
|
||||
timestamp.value = await downloadRebootDll(
|
||||
url.text,
|
||||
final needsUpdate = await hasRebootDllUpdate(
|
||||
timestamp.value,
|
||||
hours: timer.value.hours,
|
||||
force: force
|
||||
);
|
||||
if(!needsUpdate) {
|
||||
status.value = UpdateStatus.success;
|
||||
return;
|
||||
}
|
||||
|
||||
showInfoBar(
|
||||
translations.downloadingDll("reboot"),
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
timestamp.value = await downloadRebootDll(url.text);
|
||||
status.value = UpdateStatus.success;
|
||||
showInfoBar(
|
||||
translations.updatedRebootDll,
|
||||
translations.downloadDllSuccess("reboot"),
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: snackbarShortDuration
|
||||
duration: infoBarShortDuration
|
||||
);
|
||||
}catch(message) {
|
||||
var error = message.toString();
|
||||
@@ -54,12 +54,12 @@ class UpdateController {
|
||||
error = error.toLowerCase();
|
||||
status.value = UpdateStatus.error;
|
||||
showInfoBar(
|
||||
translations.updateRebootDllError(error.toString()),
|
||||
duration: snackbarLongDuration,
|
||||
translations.downloadDllError(error.toString()),
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error,
|
||||
action: Button(
|
||||
onPressed: () => update(true),
|
||||
child: Text(translations.updateRebootDllErrorAction),
|
||||
child: Text(translations.downloadDllRetry),
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ class UpdateController {
|
||||
void reset() {
|
||||
timestamp.value = null;
|
||||
timer.value = UpdateTimer.never;
|
||||
url.text = rebootDownloadUrl;
|
||||
url.text = kRebootDownloadUrl;
|
||||
status.value = UpdateStatus.waiting;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as fluent show showDialog;
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
import 'dialog_button.dart';
|
||||
|
||||
Future<T?> showAppDialog<T extends Object?>({required WidgetBuilder builder}) => fluent.showDialog(
|
||||
context: appKey.currentContext!,
|
||||
useRootNavigator: false,
|
||||
builder: builder
|
||||
);
|
||||
bool inDialog = false;
|
||||
|
||||
Future<T?> showAppDialog<T extends Object?>({required WidgetBuilder builder}) async {
|
||||
inDialog = true;
|
||||
pagesController.add(null);
|
||||
try {
|
||||
return await fluent.showDialog(
|
||||
context: appKey.currentContext!,
|
||||
useRootNavigator: false,
|
||||
builder: builder
|
||||
);
|
||||
}finally {
|
||||
inDialog = false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractDialog extends StatelessWidget {
|
||||
const AbstractDialog({Key? key}) : super(key: key);
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:sync/semaphore.dart';
|
||||
|
||||
const infoBarLongDuration = Duration(seconds: 4);
|
||||
const infoBarShortDuration = Duration(seconds: 2);
|
||||
|
||||
Semaphore _semaphore = Semaphore();
|
||||
HashMap<int, OverlayEntry?> _overlays = HashMap();
|
||||
HashMap<int, _OverlayEntry> _overlays = HashMap();
|
||||
|
||||
void restoreMessage(int pageIndex, int lastIndex) {
|
||||
removeMessageByPage(lastIndex);
|
||||
var overlay = _overlays[pageIndex];
|
||||
if(overlay == null) {
|
||||
final entry = _overlays[pageIndex];
|
||||
if(entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Overlay.of(pageKey.currentContext!).insert(overlay);
|
||||
Overlay.of(pageKey.currentContext!).insert(entry.overlay);
|
||||
}
|
||||
|
||||
OverlayEntry showInfoBar(dynamic text,
|
||||
{RebootPageType? pageType,
|
||||
InfoBarSeverity severity = InfoBarSeverity.info,
|
||||
{InfoBarSeverity severity = InfoBarSeverity.info,
|
||||
bool loading = false,
|
||||
Duration? duration = snackbarShortDuration,
|
||||
Duration? duration = infoBarShortDuration,
|
||||
void Function()? onDismissed,
|
||||
Widget? action}) {
|
||||
try {
|
||||
_semaphore.acquire();
|
||||
var index = pageType?.index ?? pageIndex.value;
|
||||
removeMessageByPage(index);
|
||||
var overlay = OverlayEntry(
|
||||
removeMessageByPage(pageIndex.value);
|
||||
final overlay = OverlayEntry(
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: 12.0,
|
||||
left: 12.0,
|
||||
bottom: pagesWithButtonIndexes.contains(index) ? 72.0 : 16.0
|
||||
bottom: hasPageButton ? 72.0 : 16.0
|
||||
),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
@@ -71,19 +70,22 @@ OverlayEntry showInfoBar(dynamic text,
|
||||
),
|
||||
)
|
||||
);
|
||||
if(index == pageIndex.value) {
|
||||
Overlay.of(pageKey.currentContext!).insert(overlay);
|
||||
}
|
||||
_overlays[index] = overlay;
|
||||
Overlay.of(pageKey.currentContext!).insert(overlay);
|
||||
_overlays[pageIndex.value] = _OverlayEntry(
|
||||
overlay: overlay,
|
||||
onDismissed: onDismissed
|
||||
);
|
||||
if(duration != null) {
|
||||
Future.delayed(duration).then((_) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
if(_overlays[index] == overlay) {
|
||||
final currentOverlay = _overlays[pageIndex.value];
|
||||
if(currentOverlay == overlay) {
|
||||
if(overlay.mounted) {
|
||||
overlay.remove();
|
||||
}
|
||||
|
||||
_overlays[index] = null;
|
||||
_overlays.remove(pageIndex.value);
|
||||
currentOverlay?.onDismissed?.call();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -95,20 +97,23 @@ OverlayEntry showInfoBar(dynamic text,
|
||||
}
|
||||
|
||||
void removeMessageByPage(int index) {
|
||||
var lastOverlay = _overlays[index];
|
||||
final lastOverlay = _overlays[index];
|
||||
if(lastOverlay != null) {
|
||||
removeMessageByOverlay(lastOverlay);
|
||||
_overlays[index] = null;
|
||||
try {
|
||||
lastOverlay.overlay.remove();
|
||||
}catch(_) {
|
||||
// Do not use .isMounted
|
||||
// This is intended behaviour
|
||||
}finally {
|
||||
_overlays.remove(index);
|
||||
lastOverlay.onDismissed?.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeMessageByOverlay(OverlayEntry? overlay) {
|
||||
try {
|
||||
if(overlay != null) {
|
||||
overlay.remove();
|
||||
}
|
||||
}catch(_) {
|
||||
// Do not use .isMounted
|
||||
// This is intended behaviour
|
||||
}
|
||||
class _OverlayEntry {
|
||||
final OverlayEntry overlay;
|
||||
final void Function()? onDismissed;
|
||||
|
||||
_OverlayEntry({required this.overlay, required this.onDismissed});
|
||||
}
|
||||
24
gui/lib/src/dialog/implementation/dll.dart
Normal file
24
gui/lib/src/dialog/implementation/dll.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
Future<void> showDllDeletedDialog(Function() onConfirm) => showAppDialog(
|
||||
builder: (context) => InfoDialog(
|
||||
text: translations.dllDeletedTitle,
|
||||
buttons: [
|
||||
DialogButton(
|
||||
type: ButtonType.secondary,
|
||||
text: translations.dllDeletedSecondaryAction,
|
||||
),
|
||||
DialogButton(
|
||||
type: ButtonType.secondary,
|
||||
text: translations.dllDeletedPrimaryAction,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
onConfirm();
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
@@ -2,8 +2,8 @@ import 'dart:async';
|
||||
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
import 'package:dart_ipify/dart_ipify.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/material.dart' show Icons;
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
@@ -12,27 +12,22 @@ import 'package:reboot_launcher/src/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:reboot_launcher/src/util/cryptography.dart';
|
||||
import 'package:reboot_launcher/src/util/matchmaker.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:sync/semaphore.dart';
|
||||
|
||||
extension ServerControllerDialog on ServerController {
|
||||
Future<bool> toggleInteractive(RebootPageType caller, [bool showSuccessMessage = true]) async {
|
||||
Future<bool> toggleInteractive([bool showSuccessMessage = true]) async {
|
||||
var stream = toggle();
|
||||
return await _handleStream(caller, stream, showSuccessMessage);
|
||||
}
|
||||
|
||||
Future<bool> _handleStream(RebootPageType caller, Stream<ServerResult> stream, bool showSuccessMessage) async {
|
||||
var completer = Completer<bool>();
|
||||
worker = stream.listen((event) {
|
||||
switch (event.type) {
|
||||
case ServerResultType.starting:
|
||||
showInfoBar(
|
||||
translations.startingServer(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.info,
|
||||
loading: true,
|
||||
duration: null
|
||||
@@ -41,8 +36,7 @@ extension ServerControllerDialog on ServerController {
|
||||
case ServerResultType.startSuccess:
|
||||
if(showSuccessMessage) {
|
||||
showInfoBar(
|
||||
translations.startedServer(controllerName),
|
||||
pageType: caller,
|
||||
type.value == ServerType.local ? translations.checkedServer(controllerName) : translations.startedServer(controllerName),
|
||||
severity: InfoBarSeverity.success
|
||||
);
|
||||
}
|
||||
@@ -50,17 +44,14 @@ extension ServerControllerDialog on ServerController {
|
||||
break;
|
||||
case ServerResultType.startError:
|
||||
showInfoBar(
|
||||
translations.startServerError(
|
||||
event.error ?? translations.unknownError, controllerName),
|
||||
pageType: caller,
|
||||
type.value == ServerType.local ? translations.localServerError(event.error ?? translations.unknownError, controllerName) : translations.startServerError(event.error ?? translations.unknownError, controllerName),
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
break;
|
||||
case ServerResultType.stopping:
|
||||
showInfoBar(
|
||||
translations.stoppingServer,
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.info,
|
||||
loading: true,
|
||||
duration: null
|
||||
@@ -70,7 +61,6 @@ extension ServerControllerDialog on ServerController {
|
||||
if(showSuccessMessage) {
|
||||
showInfoBar(
|
||||
translations.stoppedServer(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.success
|
||||
);
|
||||
}
|
||||
@@ -80,36 +70,31 @@ extension ServerControllerDialog on ServerController {
|
||||
showInfoBar(
|
||||
translations.stopServerError(
|
||||
event.error ?? translations.unknownError, controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
break;
|
||||
case ServerResultType.missingHostError:
|
||||
showInfoBar(
|
||||
translations.missingHostNameError(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
break;
|
||||
case ServerResultType.missingPortError:
|
||||
showInfoBar(
|
||||
translations.missingPortError(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
break;
|
||||
case ServerResultType.illegalPortError:
|
||||
showInfoBar(
|
||||
translations.illegalPortError(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
break;
|
||||
case ServerResultType.freeingPort:
|
||||
showInfoBar(
|
||||
translations.freeingPort(defaultPort),
|
||||
pageType: caller,
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
@@ -117,24 +102,21 @@ extension ServerControllerDialog on ServerController {
|
||||
case ServerResultType.freePortSuccess:
|
||||
showInfoBar(
|
||||
translations.freedPort(defaultPort),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: snackbarShortDuration
|
||||
duration: infoBarShortDuration
|
||||
);
|
||||
break;
|
||||
case ServerResultType.freePortError:
|
||||
showInfoBar(
|
||||
translations.freePortError(event.error ?? translations.unknownError, controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
break;
|
||||
case ServerResultType.pingingRemote:
|
||||
if(started.value) {
|
||||
showInfoBar(
|
||||
translations.pingingRemoteServer(controllerName),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.info,
|
||||
loading: true,
|
||||
duration: null
|
||||
@@ -142,20 +124,16 @@ extension ServerControllerDialog on ServerController {
|
||||
}
|
||||
break;
|
||||
case ServerResultType.pingingLocal:
|
||||
if(started.value) {
|
||||
showInfoBar(
|
||||
translations.pingingLocalServer(controllerName, type().name),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.info,
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
}
|
||||
showInfoBar(
|
||||
translations.pingingLocalServer(controllerName, type().name),
|
||||
severity: InfoBarSeverity.info,
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
break;
|
||||
case ServerResultType.pingError:
|
||||
showInfoBar(
|
||||
translations.pingError(controllerName, type().name),
|
||||
pageType: caller,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
break;
|
||||
@@ -166,19 +144,12 @@ extension ServerControllerDialog on ServerController {
|
||||
}
|
||||
});
|
||||
|
||||
var result = await completer.future;
|
||||
if(result && type() == ServerType.embedded) {
|
||||
watchProcess(embeddedServerPid!).then((value) {
|
||||
if(started()) {
|
||||
started.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
return await completer.future;
|
||||
}
|
||||
}
|
||||
|
||||
final Semaphore _publishingSemaphore = Semaphore();
|
||||
|
||||
extension MatchmakerControllerExtension on MatchmakerController {
|
||||
void joinLocalHost() {
|
||||
gameServerAddress.text = kDefaultGameServerHost;
|
||||
@@ -190,7 +161,7 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
if(uuid == id) {
|
||||
showInfoBar(
|
||||
translations.joinSelfServer,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
return;
|
||||
@@ -219,7 +190,7 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
if(!checkPassword(confirmPassword, hashedPassword)) {
|
||||
showInfoBar(
|
||||
translations.wrongServerPassword,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
return;
|
||||
@@ -242,16 +213,16 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
|
||||
showInfoBar(
|
||||
translations.offlineServer,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<String?> _askForPassword() async {
|
||||
var confirmPasswordController = TextEditingController();
|
||||
var showPassword = RxBool(false);
|
||||
var showPasswordTrailing = RxBool(false);
|
||||
final confirmPasswordController = TextEditingController();
|
||||
final showPassword = RxBool(false);
|
||||
final showPasswordTrailing = RxBool(false);
|
||||
return await showAppDialog<String?>(
|
||||
builder: (context) => FormDialog(
|
||||
content: Column(
|
||||
@@ -270,15 +241,14 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
autofocus: true,
|
||||
autocorrect: false,
|
||||
onChanged: (text) => showPasswordTrailing.value = text.isNotEmpty,
|
||||
suffix: Button(
|
||||
onPressed: () => showPasswordTrailing.value = !showPasswordTrailing.value,
|
||||
suffix: !showPasswordTrailing.value ? null : Button(
|
||||
onPressed: () => showPassword.value = !showPassword.value,
|
||||
style: ButtonStyle(
|
||||
shape: ButtonState.all(const CircleBorder()),
|
||||
backgroundColor: ButtonState.all(Colors.transparent)
|
||||
),
|
||||
child: Icon(
|
||||
showPassword.value ? Icons.visibility_off : Icons.visibility,
|
||||
color: showPassword.value ? null : Colors.transparent
|
||||
showPassword.value ? FluentIcons.eye_off_24_regular : FluentIcons.eye_24_regular
|
||||
),
|
||||
)
|
||||
))
|
||||
@@ -312,7 +282,7 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => showInfoBar(
|
||||
embedded ? translations.joinedServer(author) : translations.copiedIp,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.success
|
||||
));
|
||||
}
|
||||
@@ -320,40 +290,62 @@ extension MatchmakerControllerExtension on MatchmakerController {
|
||||
|
||||
extension HostingControllerExtension on HostingController {
|
||||
Future<void> publishServer(String author, String version) async {
|
||||
var passwordText = password.text;
|
||||
var hasPassword = passwordText.isNotEmpty;
|
||||
var ip = await Ipify.ipv4();
|
||||
if(hasPassword) {
|
||||
ip = aes256Encrypt(ip, passwordText);
|
||||
}
|
||||
try {
|
||||
_publishingSemaphore.acquire();
|
||||
if(published.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
var supabase = Supabase.instance.client;
|
||||
var hosts = supabase.from('hosts');
|
||||
var payload = {
|
||||
'name': name.text,
|
||||
'description': description.text,
|
||||
'author': author,
|
||||
'ip': ip,
|
||||
'version': version,
|
||||
'password': hasPassword ? hashPassword(passwordText) : null,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
'discoverable': discoverable.value
|
||||
};
|
||||
if(published()) {
|
||||
await hosts.update(payload).eq("id", uuid);
|
||||
}else {
|
||||
payload["id"] = uuid;
|
||||
await hosts.insert(payload);
|
||||
}
|
||||
final passwordText = password.text;
|
||||
final hasPassword = passwordText.isNotEmpty;
|
||||
var ip = await Ipify.ipv4();
|
||||
if(hasPassword) {
|
||||
ip = aes256Encrypt(ip, passwordText);
|
||||
}
|
||||
|
||||
published.value = true;
|
||||
var supabase = Supabase.instance.client;
|
||||
var hosts = supabase.from("hosting");
|
||||
var payload = {
|
||||
'name': name.text,
|
||||
'description': description.text,
|
||||
'author': author,
|
||||
'ip': ip,
|
||||
'version': version,
|
||||
'password': hasPassword ? hashPassword(passwordText) : null,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
'discoverable': discoverable.value
|
||||
};
|
||||
if(published()) {
|
||||
await hosts.update(payload).eq("id", uuid);
|
||||
}else {
|
||||
payload["id"] = uuid;
|
||||
await hosts.insert(payload);
|
||||
}
|
||||
|
||||
published.value = true;
|
||||
}catch(error) {
|
||||
published.value = false;
|
||||
}finally {
|
||||
_publishingSemaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> discardServer() async {
|
||||
var supabase = Supabase.instance.client;
|
||||
await supabase.from('hosts')
|
||||
.delete()
|
||||
.match({'id': uuid});
|
||||
published.value = false;
|
||||
try {
|
||||
_publishingSemaphore.acquire();
|
||||
if(!published.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
final supabase = Supabase.instance.client;
|
||||
await supabase.from("hosting")
|
||||
.delete()
|
||||
.match({'id': uuid});
|
||||
published.value = false;
|
||||
}catch(_) {
|
||||
published.value = true;
|
||||
}finally {
|
||||
_publishingSemaphore.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart' as messenger;
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
|
||||
abstract class RebootPage extends StatefulWidget {
|
||||
@@ -14,9 +12,7 @@ abstract class RebootPage extends StatefulWidget {
|
||||
|
||||
int get index => type.index;
|
||||
|
||||
List<PageSetting> get settings;
|
||||
|
||||
bool get hasButton;
|
||||
bool hasButton(String? pageName);
|
||||
|
||||
@override
|
||||
RebootPageState createState();
|
||||
@@ -49,21 +45,9 @@ abstract class RebootPageState<T extends RebootPage> extends State<T> with Autom
|
||||
);
|
||||
}
|
||||
|
||||
OverlayEntry showInfoBar(dynamic text, {InfoBarSeverity severity = InfoBarSeverity.info, bool loading = false, Duration? duration = snackbarShortDuration, Widget? action}) => messenger.showInfoBar(
|
||||
text,
|
||||
pageType: widget.type,
|
||||
severity: severity,
|
||||
loading: loading,
|
||||
duration: duration,
|
||||
action: action
|
||||
);
|
||||
|
||||
ListView get _listView => ListView.builder(
|
||||
itemCount: settings.length * 2,
|
||||
itemBuilder: (context, index) => index.isEven ? Align(
|
||||
alignment: Alignment.center,
|
||||
child: settings[index ~/ 2],
|
||||
) : const SizedBox(height: 8.0),
|
||||
itemCount: settings.length,
|
||||
itemBuilder: (context, index) => settings[index],
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
class PageSetting {
|
||||
final String name;
|
||||
final String description;
|
||||
final String? content;
|
||||
final List<PageSetting>? children;
|
||||
final int pageIndex;
|
||||
|
||||
PageSetting(
|
||||
{required this.name,
|
||||
required this.description,
|
||||
this.content,
|
||||
this.children,
|
||||
this.pageIndex = -1});
|
||||
|
||||
PageSetting withPageIndex(int pageIndex) => this.pageIndex != -1
|
||||
? this
|
||||
: PageSetting(
|
||||
name: name,
|
||||
description: description,
|
||||
content: content,
|
||||
children: children,
|
||||
pageIndex: pageIndex);
|
||||
|
||||
@override
|
||||
String toString() => "$name: $description";
|
||||
}
|
||||
13
gui/lib/src/page/abstract/page_suggestion.dart
Normal file
13
gui/lib/src/page/abstract/page_suggestion.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
class PageSuggestion {
|
||||
final String name;
|
||||
final String description;
|
||||
final String? content;
|
||||
final int pageIndex;
|
||||
final String? routeName;
|
||||
|
||||
PageSuggestion({required this.name,
|
||||
required this.description,
|
||||
this.content,
|
||||
required this.pageIndex,
|
||||
this.routeName});
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as fluentUi show FluentIcons;
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/authenticator_controller.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/server/start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/server/type_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/server_start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/server_type_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../dialog/implementation/data.dart';
|
||||
@@ -27,39 +28,7 @@ class AuthenticatorPage extends RebootPage {
|
||||
RebootPageType get type => RebootPageType.authenticator;
|
||||
|
||||
@override
|
||||
bool get hasButton => true;
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [
|
||||
PageSetting(
|
||||
name: translations.authenticatorConfigurationName,
|
||||
description: translations.authenticatorConfigurationDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.authenticatorConfigurationHostName,
|
||||
description: translations.authenticatorConfigurationHostDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.authenticatorConfigurationPortName,
|
||||
description: translations.authenticatorConfigurationPortDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.authenticatorConfigurationDetachedName,
|
||||
description: translations.authenticatorConfigurationDetachedDescription
|
||||
)
|
||||
]
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.authenticatorInstallationDirectoryName,
|
||||
description: translations.authenticatorInstallationDirectoryDescription,
|
||||
content: translations.authenticatorInstallationDirectoryContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.authenticatorResetDefaultsName,
|
||||
description: translations.authenticatorResetDefaultsDescription,
|
||||
content: translations.authenticatorResetDefaultsContent
|
||||
)
|
||||
];
|
||||
bool hasButton(String? pageName) => pageName == null;
|
||||
|
||||
@override
|
||||
RebootPageState<AuthenticatorPage> createState() => _AuthenticatorPageState();
|
||||
@@ -70,86 +39,126 @@ class _AuthenticatorPageState extends RebootPageState<AuthenticatorPage> {
|
||||
|
||||
@override
|
||||
List<Widget> get settings => [
|
||||
_configuration,
|
||||
_type,
|
||||
_hostName,
|
||||
_port,
|
||||
_detached,
|
||||
_installationDirectory,
|
||||
_resetDefaults
|
||||
];
|
||||
|
||||
@override
|
||||
Widget get button => const ServerButton(
|
||||
authenticator: true
|
||||
);
|
||||
Widget get _hostName => Obx(() {
|
||||
if(_authenticatorController.type.value != ServerType.remote) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.globe_24_regular
|
||||
),
|
||||
title: Text(translations.authenticatorConfigurationHostName),
|
||||
subtitle: Text(translations.authenticatorConfigurationHostDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.authenticatorConfigurationHostName,
|
||||
controller: _authenticatorController.host
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _port => Obx(() {
|
||||
if(_authenticatorController.type.value == ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
fluentUi.FluentIcons.number_field
|
||||
),
|
||||
title: Text(translations.authenticatorConfigurationPortName),
|
||||
subtitle: Text(translations.authenticatorConfigurationPortDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.authenticatorConfigurationPortName,
|
||||
controller: _authenticatorController.port,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _detached => Obx(() {
|
||||
if(_authenticatorController.type.value != ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.developer_board_24_regular
|
||||
),
|
||||
title: Text(translations.authenticatorConfigurationDetachedName),
|
||||
subtitle: Text(translations.authenticatorConfigurationDetachedDescription),
|
||||
contentWidth: null,
|
||||
content: Row(
|
||||
children: [
|
||||
Text(
|
||||
_authenticatorController.detached.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _authenticatorController.detached(),
|
||||
onChanged: (value) => _authenticatorController.detached.value = value
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
SettingTile get _resetDefaults => SettingTile(
|
||||
title: translations.authenticatorResetDefaultsName,
|
||||
subtitle: translations.authenticatorResetDefaultsDescription,
|
||||
icon: Icon(
|
||||
FluentIcons.arrow_reset_24_regular
|
||||
),
|
||||
title: Text(translations.authenticatorResetDefaultsName),
|
||||
subtitle: Text(translations.authenticatorResetDefaultsDescription),
|
||||
content: Button(
|
||||
onPressed: () => showResetDialog(_authenticatorController.reset),
|
||||
child: Text(translations.authenticatorResetDefaultsContent),
|
||||
)
|
||||
);
|
||||
|
||||
SettingTile get _installationDirectory => SettingTile(
|
||||
title: translations.authenticatorInstallationDirectoryName,
|
||||
subtitle: translations.authenticatorInstallationDirectoryDescription,
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(authenticatorDirectory.uri),
|
||||
child: Text(translations.authenticatorInstallationDirectoryContent)
|
||||
Widget get _installationDirectory => Obx(() {
|
||||
if(_authenticatorController.type.value != ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.folder_24_regular
|
||||
),
|
||||
title: Text(translations.authenticatorInstallationDirectoryName),
|
||||
subtitle: Text(translations.authenticatorInstallationDirectoryDescription),
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(authenticatorDirectory.uri),
|
||||
child: Text(translations.authenticatorInstallationDirectoryContent)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _type => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.password_24_regular
|
||||
),
|
||||
title: Text(translations.authenticatorTypeName),
|
||||
subtitle: Text(translations.authenticatorTypeDescription),
|
||||
content: const ServerTypeSelector(
|
||||
authenticator: true
|
||||
)
|
||||
);
|
||||
|
||||
Widget get _configuration => Obx(() => SettingTile(
|
||||
title: translations.authenticatorConfigurationName,
|
||||
subtitle: translations.authenticatorConfigurationDescription,
|
||||
content: const ServerTypeSelector(
|
||||
authenticator: true
|
||||
),
|
||||
expandedContent: [
|
||||
if(_authenticatorController.type.value == ServerType.remote)
|
||||
SettingTile(
|
||||
title: translations.authenticatorConfigurationHostName,
|
||||
subtitle: translations.authenticatorConfigurationHostDescription,
|
||||
isChild: true,
|
||||
content: TextFormBox(
|
||||
placeholder: translations.authenticatorConfigurationHostName,
|
||||
controller: _authenticatorController.host
|
||||
)
|
||||
),
|
||||
if(_authenticatorController.type.value != ServerType.embedded)
|
||||
SettingTile(
|
||||
title: translations.authenticatorConfigurationPortName,
|
||||
subtitle: translations.authenticatorConfigurationPortDescription,
|
||||
isChild: true,
|
||||
content: TextFormBox(
|
||||
placeholder: translations.authenticatorConfigurationPortName,
|
||||
controller: _authenticatorController.port,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
]
|
||||
)
|
||||
),
|
||||
if(_authenticatorController.type.value == ServerType.embedded)
|
||||
SettingTile(
|
||||
title: translations.authenticatorConfigurationDetachedName,
|
||||
subtitle: translations.authenticatorConfigurationDetachedDescription,
|
||||
contentWidth: null,
|
||||
isChild: true,
|
||||
content: Obx(() => Row(
|
||||
children: [
|
||||
Text(
|
||||
_authenticatorController.detached.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _authenticatorController.detached(),
|
||||
onChanged: (value) => _authenticatorController.detached.value = value
|
||||
),
|
||||
],
|
||||
))
|
||||
)
|
||||
],
|
||||
));
|
||||
@override
|
||||
Widget get button => const ServerButton(
|
||||
authenticator: true
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart' show MaterialPage;
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/update_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/dll.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_suggestion.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:reboot_launcher/src/util/dll.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/home/profile.dart';
|
||||
import 'package:reboot_launcher/src/widget/os/title_bar.dart';
|
||||
import 'package:reboot_launcher/src/widget/profile_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/title_bar.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@@ -27,12 +33,11 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
static const double _kDefaultPadding = 12.0;
|
||||
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
final UpdateController _updateController = Get.find<UpdateController>();
|
||||
final GlobalKey _searchKey = GlobalKey();
|
||||
final FocusNode _searchFocusNode = FocusNode();
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
final RxBool _focused = RxBool(true);
|
||||
final Queue<int> _pagesStack = Queue();
|
||||
bool _hitBack = false;
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
@@ -42,21 +47,17 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
windowManager.addListener(this);
|
||||
var lastValue = pageIndex.value;
|
||||
pageIndex.listen((value) {
|
||||
if(_hitBack) {
|
||||
_hitBack = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(value == lastValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pagesStack.add(lastValue);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
restoreMessage(value, lastValue);
|
||||
lastValue = value;
|
||||
});
|
||||
});
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_updateController.update();
|
||||
watchDlls().listen((filePath) => showDllDeletedDialog(() {
|
||||
downloadCriticalDllInteractive(filePath);
|
||||
}));
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -64,6 +65,7 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
void dispose() {
|
||||
_searchFocusNode.dispose();
|
||||
_searchController.dispose();
|
||||
pagesController.close();
|
||||
windowManager.removeListener(this);
|
||||
super.dispose();
|
||||
}
|
||||
@@ -103,27 +105,17 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Obx(() {
|
||||
_settingsController.language.value;
|
||||
loadTranslations(context);
|
||||
return NavigationPaneTheme(
|
||||
_settingsController.language.value;
|
||||
loadTranslations(context);
|
||||
return Obx(() => NavigationPaneTheme(
|
||||
data: NavigationPaneThemeData(
|
||||
backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.93),
|
||||
),
|
||||
child: NavigationView(
|
||||
paneBodyBuilder: (pane, body) => Navigator(
|
||||
onPopPage: (page, data) => false,
|
||||
pages: [
|
||||
MaterialPage(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(_kDefaultPadding),
|
||||
child: SizedBox(
|
||||
key: pageKey,
|
||||
child: body
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
paneBodyBuilder: (pane, body) => _PaneBody(
|
||||
padding: _kDefaultPadding,
|
||||
controller: pagesController,
|
||||
body: body
|
||||
),
|
||||
appBar: NavigationAppBar(
|
||||
height: 32,
|
||||
@@ -133,43 +125,64 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
automaticallyImplyLeading: false,
|
||||
),
|
||||
pane: NavigationPane(
|
||||
key: appKey,
|
||||
selected: pageIndex.value,
|
||||
onChanged: (index) => pageIndex.value = index,
|
||||
menuButton: const SizedBox(),
|
||||
displayMode: PaneDisplayMode.open,
|
||||
items: _items,
|
||||
header: const ProfileWidget(),
|
||||
autoSuggestBox: _autoSuggestBox,
|
||||
indicator: const StickyNavigationIndicator(
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.easeOut,
|
||||
indicatorSize: 3.25
|
||||
)
|
||||
selected: pageIndex.value,
|
||||
onChanged: (index) {
|
||||
final lastPageIndex = pageIndex.value;
|
||||
if(lastPageIndex != index) {
|
||||
pageIndex.value = index;
|
||||
}else if(pageStack.isNotEmpty) {
|
||||
Navigator.of(pageKey.currentContext!).pop();
|
||||
final element = pageStack.removeLast();
|
||||
appStack.remove(element);
|
||||
pagesController.add(null);
|
||||
}
|
||||
},
|
||||
menuButton: const SizedBox(),
|
||||
displayMode: PaneDisplayMode.open,
|
||||
items: _items,
|
||||
customPane: _CustomPane(),
|
||||
header: const ProfileWidget(),
|
||||
autoSuggestBox: _autoSuggestBox,
|
||||
indicator: const StickyNavigationIndicator(
|
||||
duration: Duration(milliseconds: 500),
|
||||
curve: Curves.easeOut,
|
||||
indicatorSize: 3.25
|
||||
)
|
||||
),
|
||||
contentShape: const RoundedRectangleBorder(),
|
||||
onOpenSearch: () => _searchFocusNode.requestFocus(),
|
||||
transitionBuilder: (child, animation) => child
|
||||
)
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget get _backButton => Obx(() {
|
||||
pageIndex.value;
|
||||
return Button(
|
||||
style: ButtonStyle(
|
||||
padding: ButtonState.all(const EdgeInsets.only(top: 6.0)),
|
||||
backgroundColor: ButtonState.all(Colors.transparent),
|
||||
border: ButtonState.all(const BorderSide(color: Colors.transparent))
|
||||
),
|
||||
onPressed: _pagesStack.isEmpty ? null : () {
|
||||
_hitBack = true;
|
||||
pageIndex.value = _pagesStack.removeLast();
|
||||
},
|
||||
child: const Icon(FluentIcons.back, size: 12.0),
|
||||
);
|
||||
});
|
||||
Widget get _backButton => StreamBuilder(
|
||||
stream: pagesController.stream,
|
||||
builder: (context, _) => Button(
|
||||
style: ButtonStyle(
|
||||
padding: ButtonState.all(const EdgeInsets.only(top: 6.0)),
|
||||
backgroundColor: ButtonState.all(Colors.transparent),
|
||||
shape: ButtonState.all(Border())
|
||||
),
|
||||
onPressed: appStack.isEmpty && !inDialog ? null : () {
|
||||
if(inDialog) {
|
||||
Navigator.of(appKey.currentContext!).pop();
|
||||
}else {
|
||||
final lastPage = appStack.removeLast();
|
||||
pageStack.remove(lastPage);
|
||||
if (lastPage is int) {
|
||||
hitBack = true;
|
||||
pageIndex.value = lastPage;
|
||||
} else {
|
||||
Navigator.of(pageKey.currentContext!).pop();
|
||||
}
|
||||
}
|
||||
pagesController.add(null);
|
||||
},
|
||||
child: const Icon(FluentIcons.back, size: 12.0),
|
||||
)
|
||||
);
|
||||
|
||||
GestureDetector get _draggableArea => GestureDetector(
|
||||
onDoubleTap: appWindow.maximizeOrRestore,
|
||||
@@ -178,34 +191,28 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
);
|
||||
|
||||
Widget get _autoSuggestBox => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: AutoSuggestBox<PageSetting>(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0
|
||||
),
|
||||
child: AutoSuggestBox<PageSuggestion>(
|
||||
key: _searchKey,
|
||||
controller: _searchController,
|
||||
placeholder: translations.find,
|
||||
focusNode: _searchFocusNode,
|
||||
selectionHeightStyle: BoxHeightStyle.max,
|
||||
itemBuilder: (context, item) => Wrap(
|
||||
children: [
|
||||
ListTile(
|
||||
onPressed: () {
|
||||
pageIndex.value = item.value.pageIndex;
|
||||
_searchController.clear();
|
||||
_searchFocusNode.unfocus();
|
||||
},
|
||||
leading: item.child,
|
||||
title: Text(
|
||||
item.value.name,
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1
|
||||
),
|
||||
subtitle: item.value.description.isNotEmpty ? Text(
|
||||
item.value.description,
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1
|
||||
) : null
|
||||
),
|
||||
],
|
||||
itemBuilder: (context, item) => ListTile(
|
||||
onPressed: () {
|
||||
pageIndex.value = item.value.pageIndex;
|
||||
_searchController.clear();
|
||||
_searchFocusNode.unfocus();
|
||||
},
|
||||
leading: item.child,
|
||||
title: Text(
|
||||
item.value.name,
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1
|
||||
)
|
||||
),
|
||||
items: _suggestedItems,
|
||||
autofocus: true,
|
||||
@@ -221,36 +228,22 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
)
|
||||
);
|
||||
|
||||
List<AutoSuggestBoxItem<PageSetting>> get _suggestedItems => pages.mapMany((page) {
|
||||
var icon = SizedBox.square(
|
||||
List<AutoSuggestBoxItem<PageSuggestion>> get _suggestedItems => pages.mapMany((page) {
|
||||
final pageIcon = SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset(page.iconAsset)
|
||||
);
|
||||
var outerResults = <AutoSuggestBoxItem<PageSetting>>[];
|
||||
outerResults.add(AutoSuggestBoxItem(
|
||||
value: PageSetting(
|
||||
final results = <AutoSuggestBoxItem<PageSuggestion>>[];
|
||||
results.add(AutoSuggestBoxItem(
|
||||
value: PageSuggestion(
|
||||
name: page.name,
|
||||
description: "",
|
||||
pageIndex: page.index
|
||||
),
|
||||
label: page.name,
|
||||
child: icon
|
||||
child: pageIcon
|
||||
));
|
||||
outerResults.addAll(page.settings.mapMany((setting) {
|
||||
var results = <AutoSuggestBoxItem<PageSetting>>[];
|
||||
results.add(AutoSuggestBoxItem(
|
||||
value: setting.withPageIndex(page.index),
|
||||
label: setting.toString(),
|
||||
child: icon
|
||||
));
|
||||
setting.children?.forEach((childSetting) => results.add(AutoSuggestBoxItem(
|
||||
value: childSetting.withPageIndex(page.index),
|
||||
label: childSetting.toString(),
|
||||
child: icon
|
||||
)));
|
||||
return results;
|
||||
}).toList());
|
||||
return outerResults;
|
||||
return results;
|
||||
}).toList();
|
||||
|
||||
List<NavigationPaneItem> get _items => pages.map((page) => _createItem(page)).toList();
|
||||
@@ -263,4 +256,252 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
),
|
||||
body: page
|
||||
);
|
||||
}
|
||||
|
||||
class _PaneBody extends StatefulWidget {
|
||||
const _PaneBody({
|
||||
required this.padding,
|
||||
required this.controller,
|
||||
required this.body
|
||||
});
|
||||
|
||||
final double padding;
|
||||
final StreamController<void> controller;
|
||||
final Widget? body;
|
||||
|
||||
@override
|
||||
State<_PaneBody> createState() => _PaneBodyState();
|
||||
}
|
||||
|
||||
class _PaneBodyState extends State<_PaneBody> with AutomaticKeepAliveClientMixin {
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
final PageController _pageController = PageController(keepPage: true);
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
pageIndex.listen((index) => _pageController.jumpToPage(index));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final themeMode = _settingsController.themeMode.value;
|
||||
final inactiveColor = themeMode == ThemeMode.dark
|
||||
|| (themeMode == ThemeMode.system && isDarkMode) ? Colors.grey[60] : Colors.grey[100];
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: widget.padding,
|
||||
right: widget.padding * 2,
|
||||
top: widget.padding,
|
||||
bottom: widget.padding * 2
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 1000
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: StreamBuilder(
|
||||
stream: widget.controller.stream,
|
||||
builder: (context, _) {
|
||||
final elements = <TextSpan>[];
|
||||
elements.add(TextSpan(
|
||||
text: pages[pageIndex.value].name,
|
||||
recognizer: pageStack.isNotEmpty ? (TapGestureRecognizer()..onTap = () {
|
||||
for(var i = 0; i < pageStack.length; i++) {
|
||||
Navigator.of(pageKey.currentContext!).pop();
|
||||
final element = pageStack.removeLast();
|
||||
appStack.remove(element);
|
||||
}
|
||||
|
||||
widget.controller.add(null);
|
||||
}) : null,
|
||||
style: TextStyle(
|
||||
color: pageStack.isNotEmpty ? inactiveColor : null
|
||||
)
|
||||
));
|
||||
for(var i = pageStack.length - 1; i >= 0; i--) {
|
||||
var innerPage = pageStack.elementAt(i);
|
||||
innerPage = innerPage.substring(innerPage.indexOf("_") + 1);
|
||||
elements.add(TextSpan(
|
||||
text: " > ",
|
||||
style: TextStyle(
|
||||
color: inactiveColor
|
||||
)
|
||||
));
|
||||
elements.add(TextSpan(
|
||||
text: innerPage,
|
||||
recognizer: i == pageStack.length - 1 ? null : (TapGestureRecognizer()..onTap = () {
|
||||
for(var j = 0; j < i - 1; j++) {
|
||||
Navigator.of(pageKey.currentContext!).pop();
|
||||
final element = pageStack.removeLast();
|
||||
appStack.remove(element);
|
||||
}
|
||||
widget.controller.add(null);
|
||||
}),
|
||||
style: TextStyle(
|
||||
color: i == pageStack.length - 1 ? null : inactiveColor
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return Text.rich(
|
||||
TextSpan(
|
||||
children: elements
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24.0),
|
||||
Expanded(
|
||||
child: PageView.builder(
|
||||
controller: _pageController,
|
||||
itemBuilder: (context, index) => Navigator(
|
||||
onPopPage: (page, data) => true,
|
||||
observers: [
|
||||
_NestedPageObserver(
|
||||
onChanged: (routeName) {
|
||||
if(routeName != null) {
|
||||
pageIndex.refresh();
|
||||
addSubPageToStack(routeName);
|
||||
widget.controller.add(null);
|
||||
}
|
||||
}
|
||||
)
|
||||
],
|
||||
pages: [
|
||||
MaterialPage(
|
||||
child: KeyedSubtree(
|
||||
key: getPageKeyByIndex(index),
|
||||
child: widget.body ?? const SizedBox.shrink()
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
itemCount: pages.length
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CustomPane extends NavigationPaneWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, NavigationPaneWidgetData data) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
data.appBar,
|
||||
Expanded(
|
||||
child: Navigator(
|
||||
key: appKey,
|
||||
onPopPage: (page, data) => false,
|
||||
pages: [
|
||||
MaterialPage(
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 310,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
data.pane.header ?? const SizedBox.shrink(),
|
||||
data.pane.autoSuggestBox ?? const SizedBox.shrink(),
|
||||
const SizedBox(height: 12.0),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0
|
||||
),
|
||||
child: Scrollbar(
|
||||
controller: data.scrollController,
|
||||
child: ListView.separated(
|
||||
controller: data.scrollController,
|
||||
itemCount: data.pane.items.length,
|
||||
separatorBuilder: (context, index) => const SizedBox(
|
||||
height: 4.0
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final item = data.pane.items[index] as PaneItem;
|
||||
return HoverButton(
|
||||
onPressed: () => data.pane.onChanged?.call(index),
|
||||
builder: (context, states) => Container(
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: ButtonThemeData.uncheckedInputColor(
|
||||
FluentTheme.of(context),
|
||||
item == data.pane.selectedItem ? {ButtonStates.hovering} : states,
|
||||
transparentWhenNone: true,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(6.0))
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
data.pane.indicator ?? const SizedBox.shrink(),
|
||||
item.icon,
|
||||
const SizedBox(width: 12.0),
|
||||
item.title ?? const SizedBox.shrink()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: data.content
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class _NestedPageObserver extends NavigatorObserver {
|
||||
final void Function(String?) onChanged;
|
||||
|
||||
_NestedPageObserver({required this.onChanged});
|
||||
|
||||
@override
|
||||
void didPush(Route route, Route? previousRoute) {
|
||||
if(previousRoute != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => onChanged(route.settings.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:markdown_widget/config/markdown_generator.dart';
|
||||
import 'package:reboot_launcher/src/controller/info_controller.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:reboot_launcher/src/util/tutorial.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
|
||||
class InfoPage extends RebootPage {
|
||||
const InfoPage({Key? key}) : super(key: key);
|
||||
@@ -24,105 +20,68 @@ class InfoPage extends RebootPage {
|
||||
String get iconAsset => "assets/images/info.png";
|
||||
|
||||
@override
|
||||
bool get hasButton => false;
|
||||
bool hasButton(String? routeName) => false;
|
||||
|
||||
@override
|
||||
RebootPageType get type => RebootPageType.info;
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [];
|
||||
}
|
||||
|
||||
class _InfoPageState extends RebootPageState<InfoPage> {
|
||||
final InfoController _infoController = Get.find<InfoController>();
|
||||
late Future<List<String>> _fetchFuture;
|
||||
late double _height;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_fetchFuture = _infoController.links != null
|
||||
? Future.value(_infoController.links)
|
||||
: _initQuery();
|
||||
super.initState();
|
||||
}
|
||||
List<SettingTile> get settings => [
|
||||
_documentation,
|
||||
_discord,
|
||||
_youtubeTutorial,
|
||||
_reportBug
|
||||
];
|
||||
|
||||
Future<List<String>> _initQuery() async {
|
||||
var response = await http.get(Uri.parse("https://api.github.com/repos/Auties00/reboot_launcher/contents/documentation/$currentLocale"));
|
||||
List results = jsonDecode(response.body);
|
||||
results.sort((first, second) {
|
||||
var firstIndex = int.parse(first["name"][0]);
|
||||
var secondIndex = int.parse(second["name"][0]);
|
||||
return firstIndex > secondIndex ? 1 : firstIndex == secondIndex ? 0 : -1;
|
||||
});
|
||||
List<String> parsed = results.map<String>((entry) => entry["download_url"] as String).toList();
|
||||
return _infoController.links = parsed;
|
||||
}
|
||||
|
||||
Future<String> _readLink(String url) async {
|
||||
var known = _infoController.linksData[url];
|
||||
if(known != null) {
|
||||
return known;
|
||||
}
|
||||
|
||||
var response = await http.get(Uri.parse(url));
|
||||
return _infoController.linksData[url] = response.body;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
_height = MediaQuery.of(context).size.height / 3;
|
||||
return FutureBuilder(
|
||||
future: _fetchFuture,
|
||||
builder: (context, linksSnapshot) {
|
||||
var linksData = linksSnapshot.data;
|
||||
if(linksData == null) {
|
||||
return const Center(
|
||||
child: ProgressRing()
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 1000
|
||||
),
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (context, index) => const SizedBox(
|
||||
height: 16.0
|
||||
),
|
||||
itemBuilder: (context, index) => Card(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
child: _buildBody(linksData, index)
|
||||
),
|
||||
itemCount: linksData.length
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(List<String> linksData, int index) => FutureBuilder(
|
||||
future: _readLink(linksData[index]),
|
||||
builder: (context, linkDataSnapshot) {
|
||||
var markdownGenerator = MarkdownGenerator();
|
||||
var result = markdownGenerator.buildWidgets(linkDataSnapshot.data ?? "");
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: result
|
||||
);
|
||||
}
|
||||
SettingTile get _reportBug => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.bug_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsBugReportName),
|
||||
subtitle: Text(translations.settingsUtilsBugReportSubtitle) ,
|
||||
content: Button(
|
||||
onPressed: openBugReport,
|
||||
child: Text(translations.settingsUtilsBugReportContent),
|
||||
)
|
||||
);
|
||||
|
||||
@override
|
||||
List<SettingTile> get settings => [];
|
||||
SettingTile get _youtubeTutorial => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.video_24_regular
|
||||
),
|
||||
title: Text(translations.infoVideoName),
|
||||
subtitle: Text(translations.infoVideoDescription),
|
||||
content: Button(
|
||||
onPressed: openYoutubeTutorial,
|
||||
child: Text(translations.infoVideoContent)
|
||||
)
|
||||
);
|
||||
|
||||
SettingTile get _discord => SettingTile(
|
||||
icon: Icon(
|
||||
Icons.discord_outlined
|
||||
),
|
||||
title: Text(translations.infoDiscordName),
|
||||
subtitle: Text(translations.infoDiscordDescription),
|
||||
content: Button(
|
||||
onPressed: openDiscordServer,
|
||||
child: Text(translations.infoDiscordContent)
|
||||
)
|
||||
);
|
||||
|
||||
SettingTile get _documentation => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.document_24_regular
|
||||
),
|
||||
title: Text(translations.infoDocumentationName),
|
||||
subtitle: Text(translations.infoDocumentationDescription),
|
||||
content: Button(
|
||||
onPressed: openTutorials,
|
||||
child: Text(translations.infoDocumentationContent)
|
||||
)
|
||||
);
|
||||
|
||||
@override
|
||||
Widget? get button => null;
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as fluentUi show FluentIcons;
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/data.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/server/start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/server/type_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/server_start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/server_type_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MatchmakerPage extends RebootPage {
|
||||
@@ -26,42 +27,10 @@ class MatchmakerPage extends RebootPage {
|
||||
String get iconAsset => "assets/images/matchmaker.png";
|
||||
|
||||
@override
|
||||
bool get hasButton => true;
|
||||
bool hasButton(String? pageName) => pageName == null;
|
||||
|
||||
@override
|
||||
RebootPageType get type => RebootPageType.matchmaker;
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [
|
||||
PageSetting(
|
||||
name: translations.matchmakerConfigurationName,
|
||||
description: translations.matchmakerConfigurationDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.matchmakerConfigurationHostName,
|
||||
description: translations.matchmakerConfigurationHostDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.matchmakerConfigurationPortName,
|
||||
description: translations.matchmakerConfigurationPortDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.matchmakerConfigurationDetachedName,
|
||||
description: translations.matchmakerConfigurationDetachedDescription
|
||||
)
|
||||
]
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.matchmakerInstallationDirectoryName,
|
||||
description: translations.matchmakerInstallationDirectoryDescription,
|
||||
content: translations.matchmakerInstallationDirectoryContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.matchmakerResetDefaultsName,
|
||||
description: translations.matchmakerResetDefaultsDescription,
|
||||
content: translations.matchmakerResetDefaultsContent
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
class _MatchmakerPageState extends RebootPageState<MatchmakerPage> {
|
||||
@@ -74,89 +43,138 @@ class _MatchmakerPageState extends RebootPageState<MatchmakerPage> {
|
||||
|
||||
@override
|
||||
List<Widget> get settings => [
|
||||
_configuration,
|
||||
_type,
|
||||
_hostName,
|
||||
_port,
|
||||
_gameServerAddress,
|
||||
_detached,
|
||||
_installationDirectory,
|
||||
_resetDefaults
|
||||
];
|
||||
|
||||
Widget get _configuration => Obx(() => SettingTile(
|
||||
title: translations.matchmakerConfigurationName,
|
||||
subtitle: translations.matchmakerConfigurationDescription,
|
||||
Widget get _detached => Obx(() {
|
||||
if(_matchmakerController.type.value != ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.developer_board_24_regular
|
||||
),
|
||||
title: Text(translations.matchmakerConfigurationDetachedName),
|
||||
subtitle: Text(translations.matchmakerConfigurationDetachedDescription),
|
||||
contentWidth: null,
|
||||
content: Row(
|
||||
children: [
|
||||
Text(
|
||||
_matchmakerController.detached.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _matchmakerController.detached.value,
|
||||
onChanged: (value) => _matchmakerController.detached.value = value
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _gameServerAddress => Obx(() {
|
||||
if(_matchmakerController.type.value != ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.stream_input_20_regular
|
||||
),
|
||||
title: Text(translations.matchmakerConfigurationAddressName),
|
||||
subtitle: Text(translations.matchmakerConfigurationAddressDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationAddressName,
|
||||
controller: _matchmakerController.gameServerAddress,
|
||||
focusNode: _matchmakerController.gameServerAddressFocusNode
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _port => Obx(() {
|
||||
if(_matchmakerController.type.value == ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
fluentUi.FluentIcons.number_field
|
||||
),
|
||||
title: Text(translations.matchmakerConfigurationPortName),
|
||||
subtitle: Text(translations.matchmakerConfigurationPortDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationPortName,
|
||||
controller: _matchmakerController.port,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _hostName => Obx(() {
|
||||
if(_matchmakerController.type.value == ServerType.remote) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.globe_24_regular
|
||||
),
|
||||
title: Text(translations.matchmakerConfigurationHostName),
|
||||
subtitle: Text(translations.matchmakerConfigurationHostDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationHostName,
|
||||
controller: _matchmakerController.host
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Widget get _type => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.people_24_regular
|
||||
),
|
||||
title: Text(translations.matchmakerTypeName),
|
||||
subtitle: Text(translations.matchmakerTypeDescription),
|
||||
content: const ServerTypeSelector(
|
||||
authenticator: false
|
||||
),
|
||||
expandedContent: [
|
||||
if(_matchmakerController.type.value == ServerType.remote)
|
||||
SettingTile(
|
||||
title: translations.matchmakerConfigurationHostName,
|
||||
subtitle: translations.matchmakerConfigurationHostDescription,
|
||||
isChild: true,
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationHostName,
|
||||
controller: _matchmakerController.host
|
||||
)
|
||||
),
|
||||
if(_matchmakerController.type.value != ServerType.embedded)
|
||||
SettingTile(
|
||||
title: translations.matchmakerConfigurationPortName,
|
||||
subtitle: translations.matchmakerConfigurationPortDescription,
|
||||
isChild: true,
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationPortName,
|
||||
controller: _matchmakerController.port,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
]
|
||||
)
|
||||
),
|
||||
if(_matchmakerController.type.value == ServerType.embedded)
|
||||
SettingTile(
|
||||
title: translations.matchmakerConfigurationAddressName,
|
||||
subtitle: translations.matchmakerConfigurationAddressDescription,
|
||||
isChild: true,
|
||||
content: TextFormBox(
|
||||
placeholder: translations.matchmakerConfigurationAddressName,
|
||||
controller: _matchmakerController.gameServerAddress,
|
||||
focusNode: _matchmakerController.gameServerAddressFocusNode
|
||||
)
|
||||
),
|
||||
if(_matchmakerController.type.value == ServerType.embedded)
|
||||
SettingTile(
|
||||
title: translations.matchmakerConfigurationDetachedName,
|
||||
subtitle: translations.matchmakerConfigurationDetachedDescription,
|
||||
contentWidth: null,
|
||||
isChild: true,
|
||||
content: Obx(() => Row(
|
||||
children: [
|
||||
Text(
|
||||
_matchmakerController.detached.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _matchmakerController.detached.value,
|
||||
onChanged: (value) => _matchmakerController.detached.value = value
|
||||
),
|
||||
],
|
||||
)),
|
||||
)
|
||||
]
|
||||
));
|
||||
|
||||
SettingTile get _installationDirectory => SettingTile(
|
||||
title: translations.matchmakerInstallationDirectoryName,
|
||||
subtitle: translations.matchmakerInstallationDirectoryDescription,
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(matchmakerDirectory.uri),
|
||||
child: Text(translations.matchmakerInstallationDirectoryContent)
|
||||
)
|
||||
);
|
||||
|
||||
Widget get _installationDirectory => Obx(() {
|
||||
if(_matchmakerController.type.value != ServerType.embedded) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.folder_24_regular
|
||||
),
|
||||
title: Text(translations.matchmakerInstallationDirectoryName),
|
||||
subtitle: Text(translations.matchmakerInstallationDirectoryDescription),
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(matchmakerDirectory.uri),
|
||||
child: Text(translations.matchmakerInstallationDirectoryContent)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
SettingTile get _resetDefaults => SettingTile(
|
||||
title: translations.matchmakerResetDefaultsName,
|
||||
subtitle: translations.matchmakerResetDefaultsDescription,
|
||||
icon: Icon(
|
||||
FluentIcons.arrow_reset_24_regular
|
||||
),
|
||||
title: Text(translations.matchmakerResetDefaultsName),
|
||||
subtitle: Text(translations.matchmakerResetDefaultsDescription),
|
||||
content: Button(
|
||||
onPressed: () => showResetDialog(_matchmakerController.reset),
|
||||
child: Text(translations.matchmakerResetDefaultsContent),
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/game/start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_selector_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/game_start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_selector_tile.dart';
|
||||
|
||||
|
||||
class PlayPage extends RebootPage {
|
||||
@@ -20,7 +20,7 @@ class PlayPage extends RebootPage {
|
||||
RebootPageState<PlayPage> createState() => _PlayPageState();
|
||||
|
||||
@override
|
||||
bool get hasButton => true;
|
||||
bool hasButton(String? pageName) => pageName == null;
|
||||
|
||||
@override
|
||||
String get name => translations.playName;
|
||||
@@ -30,33 +30,6 @@ class PlayPage extends RebootPage {
|
||||
|
||||
@override
|
||||
RebootPageType get type => RebootPageType.play;
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [
|
||||
versionSelectorRebootSetting,
|
||||
PageSetting(
|
||||
name: translations.playGameServerName,
|
||||
description: translations.playGameServerDescription,
|
||||
content: translations.playGameServerContentLocal,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.playGameServerHostName,
|
||||
description: translations.playGameServerHostDescription,
|
||||
content: translations.playGameServerHostName
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.playGameServerBrowserName,
|
||||
description: translations.playGameServerBrowserDescription,
|
||||
content: translations.playGameServerBrowserName
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.playGameServerCustomName,
|
||||
description: translations.playGameServerCustomDescription,
|
||||
content: translations.playGameServerCustomContent
|
||||
)
|
||||
]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
class _PlayPageState extends RebootPageState<PlayPage> {
|
||||
@@ -84,60 +57,39 @@ class _PlayPageState extends RebootPageState<PlayPage> {
|
||||
|
||||
@override
|
||||
List<SettingTile> get settings => [
|
||||
versionSelectorSettingTile,
|
||||
_gameServerSelector
|
||||
versionSelectSettingTile,
|
||||
_hostSettingTile,
|
||||
_browseServerTile,
|
||||
_matchmakerTile
|
||||
];
|
||||
|
||||
SettingTile get _gameServerSelector => SettingTile(
|
||||
title: translations.playGameServerName,
|
||||
subtitle: translations.playGameServerDescription,
|
||||
content: IgnorePointer(
|
||||
child: Button(
|
||||
style: ButtonStyle(
|
||||
backgroundColor: ButtonState.all(FluentTheme.of(context).resources.controlFillColorDefault)
|
||||
),
|
||||
onPressed: () {},
|
||||
child: Obx(() {
|
||||
var address = _matchmakerController.gameServerAddress.text;
|
||||
var owner = _matchmakerController.gameServerOwner.value;
|
||||
return Text(
|
||||
isLocalHost(address) ? translations.playGameServerContentLocal : owner != null ? translations.playGameServerContentBrowser(owner) : address,
|
||||
textAlign: TextAlign.start
|
||||
);
|
||||
})
|
||||
),
|
||||
),
|
||||
expandedContent: [
|
||||
SettingTile(
|
||||
title: translations.playGameServerHostName,
|
||||
subtitle: translations.playGameServerHostDescription,
|
||||
content: Button(
|
||||
onPressed: () => pageIndex.value = RebootPageType.host.index,
|
||||
child: Text(translations.playGameServerHostName)
|
||||
),
|
||||
isChild: true
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.playGameServerBrowserName,
|
||||
subtitle: translations.playGameServerBrowserDescription,
|
||||
content: Button(
|
||||
onPressed: () => pageIndex.value = RebootPageType.browser.index,
|
||||
child: Text(translations.playGameServerBrowserName)
|
||||
),
|
||||
isChild: true
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.playGameServerCustomName,
|
||||
subtitle: translations.playGameServerCustomDescription,
|
||||
content: Button(
|
||||
onPressed: () {
|
||||
pageIndex.value = RebootPageType.matchmaker.index;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _matchmakerController.gameServerAddressFocusNode.requestFocus());
|
||||
},
|
||||
child: Text(translations.playGameServerCustomContent)
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
]
|
||||
SettingTile get _matchmakerTile => SettingTile(
|
||||
onPressed: () {
|
||||
pageIndex.value = RebootPageType.matchmaker.index;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _matchmakerController.gameServerAddressFocusNode.requestFocus());
|
||||
},
|
||||
icon: Icon(
|
||||
FluentIcons.globe_24_regular
|
||||
),
|
||||
title: Text(translations.playGameServerCustomName),
|
||||
subtitle: Text(translations.playGameServerCustomDescription),
|
||||
);
|
||||
|
||||
SettingTile get _browseServerTile => SettingTile(
|
||||
onPressed: () => pageIndex.value = RebootPageType.browser.index,
|
||||
icon: Icon(
|
||||
FluentIcons.search_24_regular
|
||||
),
|
||||
title: Text(translations.playGameServerBrowserName),
|
||||
subtitle: Text(translations.playGameServerBrowserDescription)
|
||||
);
|
||||
|
||||
SettingTile get _hostSettingTile => SettingTile(
|
||||
onPressed: () => pageIndex.value = RebootPageType.host.index,
|
||||
icon: Icon(
|
||||
FluentIcons.desktop_24_regular
|
||||
),
|
||||
title: Text(translations.playGameServerHostName),
|
||||
subtitle: Text(translations.playGameServerHostDescription),
|
||||
);
|
||||
}
|
||||
@@ -9,11 +9,9 @@ import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:skeletons/skeletons.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
|
||||
class BrowsePage extends RebootPage {
|
||||
const BrowsePage({Key? key}) : super(key: key);
|
||||
@@ -28,13 +26,10 @@ class BrowsePage extends RebootPage {
|
||||
String get iconAsset => "assets/images/server_browser.png";
|
||||
|
||||
@override
|
||||
bool get hasButton => false;
|
||||
bool hasButton(String? pageName) => false;
|
||||
|
||||
@override
|
||||
RebootPageState<BrowsePage> createState() => _BrowsePageState();
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [];
|
||||
}
|
||||
|
||||
class _BrowsePageState extends RebootPageState<BrowsePage> {
|
||||
@@ -73,28 +68,22 @@ class _BrowsePageState extends RebootPageState<BrowsePage> {
|
||||
],
|
||||
);
|
||||
|
||||
Widget _buildPageBody(Set<Map<String, dynamic>> data) => Column(
|
||||
children: [
|
||||
_searchBar,
|
||||
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: StreamBuilder<String?>(
|
||||
stream: _filterControllerStream.stream,
|
||||
builder: (context, filterSnapshot) {
|
||||
var items = data.where((entry) => _isValidItem(entry, filterSnapshot.data)).toSet();
|
||||
if(items.isEmpty) {
|
||||
return _noServersByQuery;
|
||||
}
|
||||
|
||||
return _buildPopulatedListBody(items);
|
||||
}
|
||||
),
|
||||
)
|
||||
],
|
||||
Widget _buildPageBody(Set<Map<String, dynamic>> data) => StreamBuilder(
|
||||
stream: _filterControllerStream.stream,
|
||||
builder: (context, filterSnapshot) {
|
||||
final items = data.where((entry) => _isValidItem(entry, filterSnapshot.data)).toSet();
|
||||
return Column(
|
||||
children: [
|
||||
_searchBar,
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: items.isEmpty ? _noServersByQuery : _buildPopulatedListBody(items)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Widget _buildPopulatedListBody(Set<Map<String, dynamic>> items) => ListView.builder(
|
||||
@@ -109,17 +98,16 @@ class _BrowsePageState extends RebootPageState<BrowsePage> {
|
||||
var entry = items.elementAt(index ~/ 2);
|
||||
var hasPassword = entry["password"] != null;
|
||||
return SettingTile(
|
||||
title: "${_formatName(entry)} • ${entry["author"]}",
|
||||
subtitle: "${_formatDescription(entry)} • ${_formatVersion(entry)}",
|
||||
icon: Icon(
|
||||
hasPassword ? FluentIcons.lock : FluentIcons.globe
|
||||
),
|
||||
title: Text("${_formatName(entry)} • ${entry["author"]}"),
|
||||
subtitle: Text("${_formatDescription(entry)} • ${_formatVersion(entry)}"),
|
||||
content: Button(
|
||||
onPressed: () => _matchmakerController.joinServer(_hostingController.uuid, entry),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if(hasPassword)
|
||||
const Icon(FluentIcons.lock),
|
||||
if(hasPassword)
|
||||
const SizedBox(width: 8.0),
|
||||
Text(_matchmakerController.type.value == ServerType.embedded ? translations.joinServer : translations.copyIp),
|
||||
],
|
||||
),
|
||||
@@ -177,12 +165,20 @@ class _BrowsePageState extends RebootPageState<BrowsePage> {
|
||||
return false;
|
||||
}
|
||||
|
||||
Widget get _searchBar => TextBox(
|
||||
placeholder: translations.findServer,
|
||||
controller: _filterController,
|
||||
autofocus: true,
|
||||
onChanged: (value) => _filterControllerStream.add(value),
|
||||
suffix: _searchBarIcon,
|
||||
Widget get _searchBar => Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 350
|
||||
),
|
||||
child: TextBox(
|
||||
placeholder: translations.findServer,
|
||||
controller: _filterController,
|
||||
autofocus: true,
|
||||
onChanged: (value) => _filterControllerStream.add(value),
|
||||
suffix: _searchBarIcon,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _searchBarIcon => Button(
|
||||
@@ -191,8 +187,8 @@ class _BrowsePageState extends RebootPageState<BrowsePage> {
|
||||
_filterControllerStream.add("");
|
||||
},
|
||||
style: ButtonStyle(
|
||||
backgroundColor: _filterController.text.isNotEmpty ? null : ButtonState.all(Colors.transparent),
|
||||
border: _filterController.text.isNotEmpty ? null : ButtonState.all(const BorderSide(color: Colors.transparent))
|
||||
backgroundColor: ButtonState.all(Colors.transparent),
|
||||
shape: ButtonState.all(Border())
|
||||
),
|
||||
child: _searchBarIconData
|
||||
);
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
import 'package:dart_ipify/dart_ipify.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/material.dart' show Icons;
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/data.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/game/start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_selector_tile.dart';
|
||||
import 'package:sync/semaphore.dart';
|
||||
import 'package:reboot_launcher/src/widget/game_start_button.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_selector_tile.dart';
|
||||
|
||||
class HostPage extends RebootPage {
|
||||
const HostPage({Key? key}) : super(key: key);
|
||||
@@ -30,64 +29,15 @@ class HostPage extends RebootPage {
|
||||
RebootPageType get type => RebootPageType.host;
|
||||
|
||||
@override
|
||||
bool get hasButton => true;
|
||||
bool hasButton(String? pageName) => pageName == null;
|
||||
|
||||
@override
|
||||
RebootPageState<HostPage> createState() => _HostingPageState();
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [
|
||||
PageSetting(
|
||||
name: translations.hostGameServerName,
|
||||
description: translations.hostGameServerDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.hostGameServerNameName,
|
||||
description: translations.hostGameServerNameDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.hostGameServerDescriptionName,
|
||||
description: translations.hostGameServerDescriptionDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.hostGameServerPasswordName,
|
||||
description: translations.hostGameServerDescriptionDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.hostGameServerDiscoverableName,
|
||||
description: translations.hostGameServerDiscoverableDescription
|
||||
)
|
||||
],
|
||||
),
|
||||
versionSelectorRebootSetting,
|
||||
PageSetting(
|
||||
name: translations.hostShareName,
|
||||
description: translations.hostShareDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.hostShareLinkName,
|
||||
description: translations.hostShareLinkDescription,
|
||||
content: translations.hostShareLinkContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.hostShareIpName,
|
||||
description: translations.hostShareIpDescription,
|
||||
content: translations.hostShareIpContent
|
||||
)
|
||||
],
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.hostResetName,
|
||||
description: translations.hostResetDescription,
|
||||
content: translations.hostResetContent
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
class _HostingPageState extends RebootPageState<HostPage> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final HostingController _hostingController = Get.find<HostingController>();
|
||||
final Semaphore _semaphore = Semaphore();
|
||||
|
||||
late final RxBool _showPasswordTrailing = RxBool(_hostingController.password.text.isNotEmpty);
|
||||
|
||||
@@ -110,16 +60,20 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
);
|
||||
|
||||
@override
|
||||
List<SettingTile> get settings => [
|
||||
List<Widget> get settings => [
|
||||
_gameServer,
|
||||
versionSelectorSettingTile,
|
||||
versionSelectSettingTile,
|
||||
_headless,
|
||||
_share,
|
||||
_resetDefaults
|
||||
];
|
||||
|
||||
SettingTile get _resetDefaults => SettingTile(
|
||||
title: translations.hostResetName,
|
||||
subtitle: translations.hostResetDescription,
|
||||
icon: Icon(
|
||||
FluentIcons.arrow_reset_24_regular
|
||||
),
|
||||
title: Text(translations.hostResetName),
|
||||
subtitle: Text(translations.hostResetDescription),
|
||||
content: Button(
|
||||
onPressed: () => showResetDialog(_hostingController.reset),
|
||||
child: Text(translations.hostResetContent),
|
||||
@@ -127,13 +81,18 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
);
|
||||
|
||||
SettingTile get _gameServer => SettingTile(
|
||||
title: translations.hostGameServerName,
|
||||
subtitle: translations.hostGameServerDescription,
|
||||
expandedContent: [
|
||||
icon: Icon(
|
||||
FluentIcons.info_24_regular
|
||||
),
|
||||
title: Text(translations.hostGameServerName),
|
||||
subtitle: Text(translations.hostGameServerDescription),
|
||||
children: [
|
||||
SettingTile(
|
||||
title: translations.hostGameServerNameName,
|
||||
subtitle: translations.hostGameServerNameDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.textbox_24_regular
|
||||
),
|
||||
title: Text(translations.hostGameServerNameName),
|
||||
subtitle: Text(translations.hostGameServerNameDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.hostGameServerNameName,
|
||||
controller: _hostingController.name,
|
||||
@@ -141,9 +100,11 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.hostGameServerDescriptionName,
|
||||
subtitle: translations.hostGameServerDescriptionDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.text_description_24_regular
|
||||
),
|
||||
title: Text(translations.hostGameServerDescriptionName),
|
||||
subtitle: Text(translations.hostGameServerDescriptionDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.hostGameServerDescriptionName,
|
||||
controller: _hostingController.description,
|
||||
@@ -151,9 +112,11 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.hostGameServerPasswordName,
|
||||
subtitle: translations.hostGameServerDescriptionDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.password_24_regular
|
||||
),
|
||||
title: Text(translations.hostGameServerPasswordName),
|
||||
subtitle: Text(translations.hostGameServerDescriptionDescription),
|
||||
content: Obx(() => TextFormBox(
|
||||
placeholder: translations.hostGameServerPasswordName,
|
||||
controller: _hostingController.password,
|
||||
@@ -172,16 +135,18 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
backgroundColor: ButtonState.all(Colors.transparent)
|
||||
),
|
||||
child: Icon(
|
||||
_hostingController.showPassword.value ? Icons.visibility_off : Icons.visibility,
|
||||
_hostingController.showPassword.value ? FluentIcons.eye_off_24_filled : FluentIcons.eye_24_filled,
|
||||
color: _showPasswordTrailing.value ? null : Colors.transparent
|
||||
),
|
||||
)
|
||||
))
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.hostGameServerDiscoverableName,
|
||||
subtitle: translations.hostGameServerDiscoverableDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.eye_24_regular
|
||||
),
|
||||
title: Text(translations.hostGameServerDiscoverableName),
|
||||
subtitle: Text(translations.hostGameServerDiscoverableDescription),
|
||||
contentWidth: null,
|
||||
content: Obx(() => Row(
|
||||
children: [
|
||||
@@ -204,14 +169,43 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
]
|
||||
);
|
||||
|
||||
Widget get _headless => Obx(() => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.window_console_20_regular
|
||||
),
|
||||
title: Text(translations.hostHeadlessName),
|
||||
subtitle: Text(translations.hostHeadlessDescription),
|
||||
contentWidth: null,
|
||||
content: Row(
|
||||
children: [
|
||||
Text(
|
||||
_hostingController.headless.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _hostingController.headless.value,
|
||||
onChanged: (value) => _hostingController.headless.value = value
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
SettingTile get _share => SettingTile(
|
||||
title: translations.hostShareName,
|
||||
subtitle: translations.hostShareDescription,
|
||||
expandedContent: [
|
||||
icon: Icon(
|
||||
FluentIcons.link_24_regular
|
||||
),
|
||||
title: Text(translations.hostShareName),
|
||||
subtitle: Text(translations.hostShareDescription),
|
||||
children: [
|
||||
SettingTile(
|
||||
title: translations.hostShareLinkName,
|
||||
subtitle: translations.hostShareLinkDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.link_24_regular
|
||||
),
|
||||
title: Text(translations.hostShareLinkName),
|
||||
subtitle: Text(translations.hostShareLinkDescription),
|
||||
content: Button(
|
||||
onPressed: () async {
|
||||
FlutterClipboard.controlC("$kCustomUrlSchema://${_hostingController.uuid}");
|
||||
@@ -221,9 +215,11 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.hostShareIpName,
|
||||
subtitle: translations.hostShareIpDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.globe_24_regular
|
||||
),
|
||||
title: Text(translations.hostShareIpName),
|
||||
subtitle: Text(translations.hostShareIpDescription),
|
||||
content: Button(
|
||||
onPressed: () async {
|
||||
try {
|
||||
@@ -247,15 +243,12 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
}
|
||||
|
||||
try {
|
||||
_semaphore.acquire();
|
||||
_hostingController.publishServer(
|
||||
_gameController.username.text,
|
||||
_hostingController.instance.value!.versionName
|
||||
);
|
||||
} catch(error) {
|
||||
_showCannotUpdateGameServer(error);
|
||||
} finally {
|
||||
_semaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,12 +271,12 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
||||
void _showCannotCopyIp(Object error) => showInfoBar(
|
||||
translations.hostShareIpMessageError(error.toString()),
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
|
||||
void _showCannotUpdateGameServer(Object error) => showInfoBar(
|
||||
translations.cannotUpdateGameServer(error.toString()),
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as fluentUi show FluentIcons;
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_gen/gen_l10n/reboot_localizations.dart';
|
||||
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/update_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/data.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:flutter_gen/gen_l10n/reboot_localizations.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SettingsPage extends RebootPage {
|
||||
@@ -31,91 +33,15 @@ class SettingsPage extends RebootPage {
|
||||
RebootPageType get type => RebootPageType.settings;
|
||||
|
||||
@override
|
||||
bool get hasButton => false;
|
||||
bool hasButton(String? pageName) => false;
|
||||
|
||||
@override
|
||||
RebootPageState<SettingsPage> createState() => _SettingsPageState();
|
||||
|
||||
@override
|
||||
List<PageSetting> get settings => [
|
||||
PageSetting(
|
||||
name: translations.settingsClientName,
|
||||
description: translations.settingsClientDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.settingsClientConsoleName,
|
||||
description: translations.settingsClientConsoleDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsClientAuthName,
|
||||
description: translations.settingsClientAuthDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsClientMemoryName,
|
||||
description: translations.settingsClientMemoryDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsClientArgsName,
|
||||
description: translations.settingsClientArgsDescription
|
||||
),
|
||||
],
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsServerName,
|
||||
description: translations.settingsServerSubtitle,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.settingsServerFileName,
|
||||
description: translations.settingsServerFileDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsServerPortName,
|
||||
description: translations.settingsServerPortDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsServerMirrorName,
|
||||
description: translations.settingsServerMirrorDescription
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsServerTimerName,
|
||||
description: translations.settingsServerTimerSubtitle
|
||||
),
|
||||
],
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsName,
|
||||
description: translations.settingsUtilsSubtitle,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsThemeName,
|
||||
description: translations.settingsUtilsThemeDescription,
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsLanguageName,
|
||||
description: translations.settingsUtilsLanguageDescription,
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsInstallationDirectoryName,
|
||||
description: translations.settingsUtilsInstallationDirectorySubtitle,
|
||||
content: translations.settingsUtilsInstallationDirectoryContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsBugReportName,
|
||||
description: translations.settingsUtilsBugReportSubtitle,
|
||||
content: translations.settingsUtilsBugReportContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.settingsUtilsResetDefaultsName,
|
||||
description: translations.settingsUtilsResetDefaultsSubtitle,
|
||||
content: translations.settingsUtilsResetDefaultsContent
|
||||
)
|
||||
],
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final HostingController _hostingController = Get.find<HostingController>();
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
final UpdateController _updateController = Get.find<UpdateController>();
|
||||
|
||||
@@ -126,13 +52,29 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
List<Widget> get settings => [
|
||||
_clientSettings,
|
||||
_gameServerSettings,
|
||||
_launcherUtilities
|
||||
_launcherSettings,
|
||||
_installationDirectory
|
||||
];
|
||||
|
||||
SettingTile get _installationDirectory => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.folder_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsInstallationDirectoryName),
|
||||
subtitle: Text(translations.settingsUtilsInstallationDirectorySubtitle),
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(installationDirectory.uri),
|
||||
child: Text(translations.settingsUtilsInstallationDirectoryContent),
|
||||
)
|
||||
);
|
||||
|
||||
SettingTile get _clientSettings => SettingTile(
|
||||
title: translations.settingsClientName,
|
||||
subtitle: translations.settingsClientDescription,
|
||||
expandedContent: [
|
||||
icon: Icon(
|
||||
FluentIcons.desktop_24_regular
|
||||
),
|
||||
title: Text(translations.settingsClientName),
|
||||
subtitle: Text(translations.settingsClientDescription),
|
||||
children: [
|
||||
_createFileSetting(
|
||||
title: translations.settingsClientConsoleName,
|
||||
description: translations.settingsClientConsoleDescription,
|
||||
@@ -149,9 +91,11 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
controller: _settingsController.memoryLeakDll
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsClientArgsName,
|
||||
subtitle: translations.settingsClientArgsDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.text_box_settings_24_regular
|
||||
),
|
||||
title: Text(translations.settingsClientArgsName),
|
||||
subtitle: Text(translations.settingsClientArgsDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.settingsClientArgsPlaceholder,
|
||||
controller: _gameController.customLaunchArgs,
|
||||
@@ -161,17 +105,23 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
);
|
||||
|
||||
SettingTile get _gameServerSettings => SettingTile(
|
||||
title: translations.settingsServerName,
|
||||
subtitle: translations.settingsServerSubtitle,
|
||||
expandedContent: [
|
||||
icon: Icon(
|
||||
FluentIcons.server_24_regular
|
||||
),
|
||||
title: Text(translations.settingsServerName),
|
||||
subtitle: Text(translations.settingsServerSubtitle),
|
||||
children: [
|
||||
_createFileSetting(
|
||||
title: translations.settingsServerFileName,
|
||||
description: translations.settingsServerFileDescription,
|
||||
controller: _settingsController.gameServerDll
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsServerPortName,
|
||||
subtitle: translations.settingsServerPortDescription,
|
||||
icon: Icon(
|
||||
fluentUi.FluentIcons.number_field
|
||||
),
|
||||
title: Text(translations.settingsServerPortName),
|
||||
subtitle: Text(translations.settingsServerPortDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.settingsServerPortName,
|
||||
controller: _settingsController.gameServerPort,
|
||||
@@ -179,22 +129,26 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly
|
||||
]
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsServerMirrorName,
|
||||
subtitle: translations.settingsServerMirrorDescription,
|
||||
icon: Icon(
|
||||
FluentIcons.globe_24_regular
|
||||
),
|
||||
title: Text(translations.settingsServerMirrorName),
|
||||
subtitle: Text(translations.settingsServerMirrorDescription),
|
||||
content: TextFormBox(
|
||||
placeholder: translations.settingsServerMirrorPlaceholder,
|
||||
controller: _updateController.url,
|
||||
validator: checkUpdateUrl
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsServerTimerName,
|
||||
subtitle: translations.settingsServerTimerSubtitle,
|
||||
icon: Icon(
|
||||
FluentIcons.timer_24_regular
|
||||
),
|
||||
title: Text(translations.settingsServerTimerName),
|
||||
subtitle: Text(translations.settingsServerTimerSubtitle),
|
||||
content: Obx(() => DropDownButton(
|
||||
leading: Text(_updateController.timer.value.text),
|
||||
items: UpdateTimer.values.map((entry) => MenuFlyoutItem(
|
||||
@@ -205,20 +159,46 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
_updateController.update(true);
|
||||
}
|
||||
)).toList()
|
||||
)),
|
||||
isChild: true
|
||||
))
|
||||
),
|
||||
SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.developer_board_24_regular
|
||||
),
|
||||
title: Text(translations.playAutomaticServerName),
|
||||
subtitle: Text(translations.playAutomaticServerDescription),
|
||||
contentWidth: null,
|
||||
content: Obx(() => Row(
|
||||
children: [
|
||||
Text(
|
||||
_hostingController.automaticServer.value ? translations.on : translations.off
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16.0
|
||||
),
|
||||
ToggleSwitch(
|
||||
checked: _hostingController.automaticServer.value,
|
||||
onChanged: (value) => _hostingController.automaticServer.value = value
|
||||
),
|
||||
],
|
||||
)),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
SettingTile get _launcherUtilities => SettingTile(
|
||||
title: translations.settingsUtilsName,
|
||||
subtitle: translations.settingsUtilsSubtitle,
|
||||
expandedContent: [
|
||||
SettingTile get _launcherSettings => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.play_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsName),
|
||||
subtitle: Text(translations.settingsUtilsSubtitle),
|
||||
children: [
|
||||
SettingTile(
|
||||
title: translations.settingsUtilsLanguageName,
|
||||
subtitle: translations.settingsUtilsLanguageDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.local_language_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsLanguageName),
|
||||
subtitle: Text(translations.settingsUtilsLanguageDescription),
|
||||
content: Obx(() => DropDownButton(
|
||||
leading: Text(_getLocaleName(_settingsController.language.value)),
|
||||
items: AppLocalizations.supportedLocales.map((locale) => MenuFlyoutItem(
|
||||
@@ -228,9 +208,11 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
))
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsUtilsThemeName,
|
||||
subtitle: translations.settingsUtilsThemeDescription,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.dark_theme_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsThemeName),
|
||||
subtitle: Text(translations.settingsUtilsThemeDescription),
|
||||
content: Obx(() => DropDownButton(
|
||||
leading: Text(_settingsController.themeMode.value.title),
|
||||
items: ThemeMode.values.map((themeMode) => MenuFlyoutItem(
|
||||
@@ -240,27 +222,11 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
))
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsUtilsInstallationDirectoryName,
|
||||
subtitle: translations.settingsUtilsInstallationDirectorySubtitle,
|
||||
isChild: true,
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(installationDirectory.uri),
|
||||
child: Text(translations.settingsUtilsInstallationDirectoryContent),
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsUtilsBugReportName,
|
||||
subtitle: translations.settingsUtilsBugReportSubtitle,
|
||||
isChild: true,
|
||||
content: Button(
|
||||
onPressed: () => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/issues")),
|
||||
child: Text(translations.settingsUtilsBugReportContent),
|
||||
)
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.settingsUtilsResetDefaultsName,
|
||||
subtitle: translations.settingsUtilsResetDefaultsSubtitle,
|
||||
isChild: true,
|
||||
icon: Icon(
|
||||
FluentIcons.arrow_reset_24_regular
|
||||
),
|
||||
title: Text(translations.settingsUtilsResetDefaultsName),
|
||||
subtitle: Text(translations.settingsUtilsResetDefaultsSubtitle),
|
||||
content: Button(
|
||||
onPressed: () => showResetDialog(_settingsController.reset),
|
||||
child: Text(translations.settingsUtilsResetDefaultsContent),
|
||||
@@ -278,9 +244,12 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
return locale;
|
||||
}
|
||||
|
||||
Widget _createFileSetting({required String title, required String description, required TextEditingController controller}) => SettingTile(
|
||||
title: title,
|
||||
subtitle: description,
|
||||
SettingTile _createFileSetting({required String title, required String description, required TextEditingController controller}) => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.document_24_regular
|
||||
),
|
||||
title: Text(title),
|
||||
subtitle: Text(description),
|
||||
content: FileSelector(
|
||||
placeholder: translations.selectPathPlaceholder,
|
||||
windowTitle: translations.selectPathWindowTitle,
|
||||
@@ -288,8 +257,7 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
||||
validator: checkDll,
|
||||
extension: "dll",
|
||||
folder: false
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
@@ -11,6 +12,9 @@ import 'package:reboot_launcher/src/page/implementation/server_browser_page.dart
|
||||
import 'package:reboot_launcher/src/page/implementation/server_host_page.dart';
|
||||
import 'package:reboot_launcher/src/page/implementation/settings_page.dart';
|
||||
|
||||
final StreamController<void> pagesController = StreamController.broadcast();
|
||||
bool hitBack = false;
|
||||
|
||||
final List<RebootPage> pages = [
|
||||
const PlayPage(),
|
||||
const HostPage(),
|
||||
@@ -25,19 +29,47 @@ final RxInt pageIndex = RxInt(0);
|
||||
|
||||
final HashMap<int, GlobalKey> _pageKeys = HashMap();
|
||||
|
||||
GlobalKey appKey = GlobalKey();
|
||||
GlobalKey get pageKey {
|
||||
var index = pageIndex.value;
|
||||
var key = _pageKeys[index];
|
||||
final GlobalKey appKey = GlobalKey();
|
||||
|
||||
GlobalKey get pageKey => getPageKeyByIndex(pageIndex.value);
|
||||
|
||||
GlobalKey getPageKeyByIndex(int index) {
|
||||
final key = _pageKeys[index];
|
||||
if(key != null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
var result = GlobalKey();
|
||||
final result = GlobalKey();
|
||||
_pageKeys[index] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
List<int> get pagesWithButtonIndexes => pages.where((page) => page.hasButton)
|
||||
.map((page) => page.index)
|
||||
.toList();
|
||||
bool get hasPageButton => pages[pageIndex.value].hasButton(pageStack.lastOrNull);
|
||||
|
||||
final Queue<Object?> appStack = _createAppStack();
|
||||
Queue _createAppStack() {
|
||||
final queue = Queue();
|
||||
var lastValue = pageIndex.value;
|
||||
pageIndex.listen((index) {
|
||||
if(!hitBack && lastValue != index) {
|
||||
queue.add(lastValue);
|
||||
pagesController.add(null);
|
||||
}
|
||||
|
||||
hitBack = false;
|
||||
lastValue = index;
|
||||
});
|
||||
return queue;
|
||||
}
|
||||
|
||||
final Map<int, Queue<String>> _pagesStack = Map.fromEntries(List.generate(pages.length, (index) => MapEntry(index, Queue<String>())));
|
||||
|
||||
Queue<String> get pageStack => _pagesStack[pageIndex.value]!;
|
||||
|
||||
void addSubPageToStack(String pageName) {
|
||||
final index = pageIndex.value;
|
||||
final identifier = "${index}_$pageName";
|
||||
appStack.add(identifier);
|
||||
_pagesStack[index]!.add(identifier);
|
||||
pagesController.add(null);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,13 @@ const int _keyLength = 32;
|
||||
|
||||
String hashPassword(String plaintext) => BCrypt.hashpw(plaintext, BCrypt.gensalt());
|
||||
|
||||
bool checkPassword(String password, String hashedText) => BCrypt.checkpw(password, hashedText);
|
||||
bool checkPassword(String password, String hashedText) {
|
||||
try {
|
||||
return BCrypt.checkpw(password, hashedText);
|
||||
}catch(error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String aes256Encrypt(String plainText, String password) {
|
||||
final random = Random.secure();
|
||||
|
||||
@@ -6,9 +6,6 @@ import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
final SupabaseClient _supabase = Supabase.instance.client;
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final HostingController _hostingController = Get.find<HostingController>();
|
||||
final File _executable = File("${assetsDirectory.path}\\misc\\watch.exe");
|
||||
|
||||
extension GameInstanceWatcher on GameInstance {
|
||||
@@ -17,18 +14,24 @@ extension GameInstanceWatcher on GameInstance {
|
||||
Process.killPid(observerPid!, ProcessSignal.sigabrt);
|
||||
}
|
||||
|
||||
final hostingController = Get.find<HostingController>();
|
||||
final gameController = Get.find<GameController>();
|
||||
watchProcess(gamePid).then((value) async {
|
||||
if(hosting) {
|
||||
_onHostingStopped();
|
||||
gameController.started.value = false;
|
||||
gameController.instance.value?.kill();
|
||||
if(_nestedHosting) {
|
||||
hostingController.started.value = false;
|
||||
hostingController.instance.value?.kill();
|
||||
await Supabase.instance.client.from("hosting")
|
||||
.delete()
|
||||
.match({'id': hostingController.uuid});
|
||||
}
|
||||
|
||||
_onGameStopped();
|
||||
});
|
||||
|
||||
observerPid = await startBackgroundProcess(
|
||||
executable: _executable,
|
||||
args: [
|
||||
_hostingController.uuid,
|
||||
hostingController.uuid,
|
||||
gamePid.toString(),
|
||||
launcherPid?.toString() ?? "-1",
|
||||
eacPid?.toString() ?? "-1",
|
||||
@@ -37,19 +40,16 @@ extension GameInstanceWatcher on GameInstance {
|
||||
);
|
||||
}
|
||||
|
||||
void _onGameStopped() {
|
||||
_gameController.started.value = false;
|
||||
_gameController.instance.value?.kill();
|
||||
if(linkedHosting) {
|
||||
_onHostingStopped();
|
||||
}
|
||||
}
|
||||
bool get _nestedHosting {
|
||||
GameInstance? child = this;
|
||||
while(child != null) {
|
||||
if(child.hosting) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> _onHostingStopped() async {
|
||||
_hostingController.started.value = false;
|
||||
_hostingController.instance.value?.kill();
|
||||
await _supabase.from('hosts')
|
||||
.delete()
|
||||
.match({'id': _hostingController.uuid});
|
||||
child = child.child;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
52
gui/lib/src/util/dll.dart
Normal file
52
gui/lib/src/util/dll.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/update_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
final UpdateController _updateController = Get.find<UpdateController>();
|
||||
Future<void> downloadCriticalDllInteractive(String filePath) async {
|
||||
try {
|
||||
final fileName = path.basename(filePath);
|
||||
if (fileName == "reboot.dll") {
|
||||
_updateController.update(true);
|
||||
return;
|
||||
}
|
||||
|
||||
final fileNameWithoutExtension = path.basenameWithoutExtension(filePath);
|
||||
await showInfoBar(
|
||||
translations.downloadingDll(fileNameWithoutExtension),
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
await downloadCriticalDll(fileName, filePath);
|
||||
await showInfoBar(
|
||||
translations.downloadDllSuccess(fileNameWithoutExtension),
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: infoBarShortDuration
|
||||
);
|
||||
}catch(message) {
|
||||
var error = message.toString();
|
||||
error = error.contains(": ") ? error.substring(error.indexOf(": ") + 2) : error;
|
||||
error = error.toLowerCase();
|
||||
final completer = Completer();
|
||||
await showInfoBar(
|
||||
translations.downloadDllError(error.toString()),
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error,
|
||||
onDismissed: () => completer.complete(null),
|
||||
action: Button(
|
||||
onPressed: () async {
|
||||
await downloadCriticalDllInteractive(filePath);
|
||||
completer.complete(null);
|
||||
},
|
||||
child: Text(translations.downloadDllRetry),
|
||||
)
|
||||
);
|
||||
await completer.future;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
final RegExp _winBuildRegex = RegExp(r'(?<=\(Build )(.*)(?=\))');
|
||||
|
||||
bool get isWin11 {
|
||||
@@ -10,4 +13,7 @@ bool get isWin11 {
|
||||
|
||||
var intBuild = int.tryParse(result);
|
||||
return intBuild != null && intBuild > 22000;
|
||||
}
|
||||
}
|
||||
|
||||
bool get isDarkMode
|
||||
=> SchedulerBinding.instance.platformDispatcher.platformBrightness.isDark;
|
||||
@@ -1,3 +1,12 @@
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
Future<void> openPortTutorial() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/blob/master/documentation/en/PortForwarding.md"));
|
||||
Future<void> openYoutubeTutorial() => launchUrl(Uri.parse("https://www.youtube.com/watch?v=nrVE2RB0qa4"));
|
||||
|
||||
Future<void> openDiscordServer() => launchUrl(Uri.parse("https://discord.gg/reboot"));
|
||||
|
||||
Future<void> openTutorials() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/blob/master/documentation/$currentLocale"));
|
||||
|
||||
Future<void> openPortTutorial() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/blob/master/documentation/$currentLocale/PortForwarding.md"));
|
||||
|
||||
Future<void> openBugReport() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/issues"));
|
||||
8
gui/lib/src/util/types.dart
Normal file
8
gui/lib/src/util/types.dart
Normal file
@@ -0,0 +1,8 @@
|
||||
extension IterableExtension<E> on Iterable<E> {
|
||||
E? firstWhereOrNull(bool test(E element)) {
|
||||
for (E element in this) {
|
||||
if (test(element)) return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_name_input.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_name_input.dart';
|
||||
|
||||
class AddLocalVersion extends StatefulWidget {
|
||||
const AddLocalVersion({Key? key})
|
||||
@@ -12,9 +12,8 @@ import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_build_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_name_input.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_name_input.dart';
|
||||
import 'package:universal_disk_space/universal_disk_space.dart';
|
||||
import 'package:windows_taskbar/windows_taskbar.dart';
|
||||
|
||||
@@ -65,7 +64,7 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
|
||||
void _cancelDownload() {
|
||||
Process.run('${assetsDirectory.path}\\build\\stop.bat', []);
|
||||
_downloadPort?.send("kill");
|
||||
_downloadPort?.send(kStopBuildDownloadSignal);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -125,15 +124,15 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
|
||||
void _startDownload(BuildContext context) async {
|
||||
try {
|
||||
var build = _buildController.selectedBuild.value;
|
||||
final build = _buildController.selectedBuild;
|
||||
if(build == null){
|
||||
return;
|
||||
}
|
||||
|
||||
_status.value = DownloadStatus.downloading;
|
||||
var communicationPort = ReceivePort();
|
||||
final communicationPort = ReceivePort();
|
||||
communicationPort.listen((message) {
|
||||
if(message is ArchiveDownloadProgress) {
|
||||
if(message is FortniteBuildDownloadProgress) {
|
||||
_onProgress(message.progress, message.minutesLeft, message.extracting);
|
||||
}else if(message is SendPort) {
|
||||
_downloadPort = message;
|
||||
@@ -141,12 +140,12 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
_onDownloadError(message, null);
|
||||
}
|
||||
});
|
||||
var options = ArchiveDownloadOptions(
|
||||
build.link,
|
||||
final options = FortniteBuildDownloadOptions(
|
||||
build,
|
||||
Directory(_pathController.text),
|
||||
communicationPort.sendPort
|
||||
);
|
||||
var errorPort = ReceivePort();
|
||||
final errorPort = ReceivePort();
|
||||
errorPort.listen((message) => _onDownloadError(message, null));
|
||||
await Isolate.spawn(
|
||||
downloadArchiveBuild,
|
||||
@@ -173,6 +172,7 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
}
|
||||
|
||||
void _onDownloadError(Object? error, StackTrace? stackTrace) {
|
||||
_cancelDownload();
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
}
|
||||
|
||||
Widget get _progressBody {
|
||||
var timeLeft = _timeLeft.value;
|
||||
final timeLeft = _timeLeft.value;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -256,10 +256,14 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
BuildSelector(
|
||||
onSelected: _updateFormDefaults
|
||||
_buildSelectorType(),
|
||||
|
||||
const SizedBox(
|
||||
height: 16.0
|
||||
),
|
||||
|
||||
_buildSelector(),
|
||||
|
||||
const SizedBox(
|
||||
height: 16.0
|
||||
),
|
||||
@@ -287,6 +291,70 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
],
|
||||
);
|
||||
|
||||
Widget _buildSelectorType() => InfoLabel(
|
||||
label: translations.source,
|
||||
child: Obx(() => ComboBox<FortniteBuildSource>(
|
||||
placeholder: Text(translations.selectBuild),
|
||||
isExpanded: true,
|
||||
items: _buildSources,
|
||||
value: _buildController.selectedBuildSource,
|
||||
onChanged: (value) {
|
||||
if(value == null){
|
||||
return;
|
||||
}
|
||||
|
||||
_buildController.selectedBuildSource = value;
|
||||
_updateFormDefaults();
|
||||
}
|
||||
))
|
||||
);
|
||||
|
||||
Widget _buildSelector() => InfoLabel(
|
||||
label: translations.build,
|
||||
child: Obx(() => ComboBox<FortniteBuild>(
|
||||
placeholder: Text(translations.selectBuild),
|
||||
isExpanded: true,
|
||||
items: _builds,
|
||||
value: _buildController.selectedBuild,
|
||||
onChanged: (value) {
|
||||
if(value == null){
|
||||
return;
|
||||
}
|
||||
|
||||
_buildController.selectedBuild = value;
|
||||
_updateFormDefaults();
|
||||
}
|
||||
))
|
||||
);
|
||||
|
||||
List<ComboBoxItem<FortniteBuild>> get _builds => _buildController.builds!
|
||||
.where((element) => element.source == _buildController.selectedBuild?.source)
|
||||
.map((element) => _buildItem(element))
|
||||
.toList();
|
||||
|
||||
ComboBoxItem<FortniteBuild> _buildItem(FortniteBuild element) => ComboBoxItem<FortniteBuild>(
|
||||
value: element,
|
||||
child: Text(element.version.toString())
|
||||
);
|
||||
|
||||
List<ComboBoxItem<FortniteBuildSource>> get _buildSources => FortniteBuildSource.values
|
||||
.map((element) => _buildSourceItem(element))
|
||||
.toList();
|
||||
|
||||
ComboBoxItem<FortniteBuildSource> _buildSourceItem(FortniteBuildSource element) => ComboBoxItem<FortniteBuildSource>(
|
||||
value: element,
|
||||
child: Text(_getBuildSourceName(element))
|
||||
);
|
||||
|
||||
String _getBuildSourceName(FortniteBuildSource element) {
|
||||
switch(element) {
|
||||
case FortniteBuildSource.archive:
|
||||
return translations.archive;
|
||||
case FortniteBuildSource.manifest:
|
||||
return translations.manifest;
|
||||
}
|
||||
}
|
||||
|
||||
List<DialogButton> get _stopButton => [
|
||||
DialogButton(
|
||||
text: "Stop",
|
||||
@@ -300,17 +368,17 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
}
|
||||
|
||||
await _fetchFuture;
|
||||
var bestDisk = _diskSpace.disks
|
||||
final bestDisk = _diskSpace.disks
|
||||
.reduce((first, second) => first.availableSpace > second.availableSpace ? first : second);
|
||||
var build = _buildController.selectedBuild.value;
|
||||
if(build== null){
|
||||
final build = _buildController.selectedBuild;
|
||||
if(build == null){
|
||||
return;
|
||||
}
|
||||
|
||||
var pathText = "${bestDisk.devicePath}\\FortniteBuilds\\${build.version}";
|
||||
final pathText = "${bestDisk.devicePath}\\FortniteBuilds\\${build.version}";
|
||||
_pathController.text = pathText;
|
||||
_pathController.selection = TextSelection.collapsed(offset: pathText.length);
|
||||
var buildName = build.version.toString();
|
||||
final buildName = build.version.toString();
|
||||
_nameController.text = buildName;
|
||||
_nameController.selection = TextSelection.collapsed(offset: buildName.length);
|
||||
_formKey.currentState?.validate();
|
||||
@@ -1,136 +0,0 @@
|
||||
import 'package:auto_animated_list/auto_animated_list.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:skeletons/skeletons.dart';
|
||||
|
||||
class SettingTile extends StatefulWidget {
|
||||
static const double kDefaultContentWidth = 200.0;
|
||||
static const double kDefaultHeaderHeight = 72;
|
||||
|
||||
final String? title;
|
||||
final TextStyle? titleStyle;
|
||||
final dynamic subtitle;
|
||||
final TextStyle? subtitleStyle;
|
||||
final Widget? content;
|
||||
final double? contentWidth;
|
||||
final List<Widget>? expandedContent;
|
||||
final double expandedContentHeaderHeight;
|
||||
final bool isChild;
|
||||
|
||||
const SettingTile(
|
||||
{Key? key,
|
||||
this.title,
|
||||
this.titleStyle,
|
||||
this.subtitle,
|
||||
this.subtitleStyle,
|
||||
this.content,
|
||||
this.contentWidth = kDefaultContentWidth,
|
||||
this.expandedContentHeaderHeight = kDefaultHeaderHeight,
|
||||
this.expandedContent,
|
||||
this.isChild = false})
|
||||
: assert((title == null && subtitle == null) || (title != null && subtitle != null), "title and subtitle can only be null together"),
|
||||
assert(subtitle == null || subtitle is String || subtitle is Widget, "subtitle can only be null, String or Widget"),
|
||||
assert(subtitle is! Widget || subtitleStyle == null, "subtitleStyle must be null if subtitle is a widget"),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<SettingTile> createState() => _SettingTileState();
|
||||
}
|
||||
|
||||
class _SettingTileState extends State<SettingTile> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 1000
|
||||
),
|
||||
child: () {
|
||||
if (widget.expandedContent == null || widget.expandedContent?.isEmpty == true) {
|
||||
return _contentCard;
|
||||
}
|
||||
|
||||
return Expander(
|
||||
initiallyExpanded: true,
|
||||
headerShape: (open) => const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
),
|
||||
header: SizedBox(
|
||||
height: widget.expandedContentHeaderHeight,
|
||||
child: _buildTile(false)
|
||||
),
|
||||
trailing: _trailing,
|
||||
content: _expandedContent
|
||||
);
|
||||
}()
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _expandedContent {
|
||||
var expandedContents = widget.expandedContent!;
|
||||
var separatedContents = List.generate(expandedContents.length, (index) => expandedContents[index]);
|
||||
return AutoAnimatedList<Widget>(
|
||||
scrollDirection: Axis.vertical,
|
||||
shrinkWrap: true,
|
||||
items: separatedContents,
|
||||
itemBuilder: (context, child, index, animation) => FadeTransition(
|
||||
opacity: animation,
|
||||
child: child
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _trailing =>
|
||||
SizedBox(width: widget.contentWidth, child: widget.content);
|
||||
|
||||
Widget get _contentCard {
|
||||
if (widget.isChild) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: _buildTile(true)
|
||||
);
|
||||
}
|
||||
|
||||
return Card(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
child: _buildTile(true)
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTile(bool trailing) {
|
||||
return ListTile(
|
||||
title: widget.title == null ? _skeletonTitle : _title,
|
||||
subtitle: widget.title == null ? _skeletonSubtitle : _subtitle,
|
||||
trailing: trailing ? _trailing : null
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _title => Text(
|
||||
widget.title!,
|
||||
style:
|
||||
widget.titleStyle ?? FluentTheme.of(context).typography.subtitle
|
||||
);
|
||||
|
||||
Widget get _skeletonTitle => const SkeletonLine(
|
||||
style: SkeletonLineStyle(
|
||||
padding: EdgeInsets.only(
|
||||
right: 24.0
|
||||
),
|
||||
height: 18
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _subtitle => widget.subtitle is Widget ? widget.subtitle : Text(
|
||||
widget.subtitle!,
|
||||
style: widget.subtitleStyle ?? FluentTheme.of(context).typography.body
|
||||
);
|
||||
|
||||
Widget get _skeletonSubtitle => const SkeletonLine(
|
||||
style: SkeletonLineStyle(
|
||||
padding: EdgeInsets.only(
|
||||
top: 8.0,
|
||||
bottom: 8.0,
|
||||
right: 24.0
|
||||
),
|
||||
height: 13
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'dart:io';
|
||||
import 'package:async/async.dart';
|
||||
import 'package:dart_ipify/dart_ipify.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:process_run/shell.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
@@ -13,13 +14,15 @@ import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart' as messenger;
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:reboot_launcher/src/util/daemon.dart';
|
||||
import 'package:reboot_launcher/src/util/dll.dart';
|
||||
import 'package:reboot_launcher/src/util/matchmaker.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/util/tutorial.dart';
|
||||
import 'package:reboot_launcher/src/util/watch.dart';
|
||||
|
||||
class LaunchButton extends StatefulWidget {
|
||||
final bool host;
|
||||
@@ -86,15 +89,15 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
|
||||
_setStarted(widget.host, true);
|
||||
for (var injectable in _Injectable.values) {
|
||||
for (final injectable in _Injectable.values) {
|
||||
if(await _getDllFileOrStop(injectable, widget.host) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var version = _gameController.selectedVersion!;
|
||||
var executable = await version.executable;
|
||||
final version = _gameController.selectedVersion!;
|
||||
final executable = await version.executable;
|
||||
if(executable == null){
|
||||
_onStop(
|
||||
reason: _StopReason.missingExecutableError,
|
||||
@@ -103,7 +106,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
return;
|
||||
}
|
||||
|
||||
var authenticatorResult = _authenticatorController.started() || await _authenticatorController.toggleInteractive(_pageType, false);
|
||||
final authenticatorResult = _authenticatorController.started() || await _authenticatorController.toggleInteractive(false);
|
||||
if(!authenticatorResult){
|
||||
_onStop(
|
||||
reason: _StopReason.authenticatorError
|
||||
@@ -111,7 +114,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
return;
|
||||
}
|
||||
|
||||
var matchmakerResult = _matchmakerController.started() || await _matchmakerController.toggleInteractive(_pageType, false);
|
||||
final matchmakerResult = _matchmakerController.started() || await _matchmakerController.toggleInteractive(false);
|
||||
if(!matchmakerResult){
|
||||
_onStop(
|
||||
reason: _StopReason.matchmakerError
|
||||
@@ -119,9 +122,9 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
return;
|
||||
}
|
||||
|
||||
var automaticallyStartedServer = await _startMatchMakingServer(version);
|
||||
await _startGameProcesses(version, widget.host, automaticallyStartedServer);
|
||||
if(automaticallyStartedServer || widget.host){
|
||||
final linkedHostingInstance = await _startMatchMakingServer(version);
|
||||
await _startGameProcesses(version, widget.host, linkedHostingInstance);
|
||||
if(linkedHostingInstance != null || widget.host){
|
||||
_showLaunchingGameServerWidget();
|
||||
}
|
||||
} catch (exception, stackTrace) {
|
||||
@@ -133,45 +136,55 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _startMatchMakingServer(FortniteVersion version) async {
|
||||
Future<GameInstance?> _startMatchMakingServer(FortniteVersion version) async {
|
||||
if(widget.host){
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
var matchmakingIp = _matchmakerController.gameServerAddress.text;
|
||||
final matchmakingIp = _matchmakerController.gameServerAddress.text;
|
||||
if(!isLocalHost(matchmakingIp)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if(_hostingController.started()){
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!_hostingController.automaticServer()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_startGameProcesses(version, true, false); // Do not await
|
||||
final instance = await _startGameProcesses(version, true, null);
|
||||
_setStarted(true, true);
|
||||
return true;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Future<void> _startGameProcesses(FortniteVersion version, bool host, bool linkedHosting) async {
|
||||
var launcherProcess = await _createLauncherProcess(version);
|
||||
var eacProcess = await _createEacProcess(version);
|
||||
var executable = await version.executable;
|
||||
var gameProcess = await _createGameProcess(executable!.path, host);
|
||||
Future<GameInstance?> _startGameProcesses(FortniteVersion version, bool host, GameInstance? linkedHosting) async {
|
||||
final launcherProcess = await _createLauncherProcess(version);
|
||||
final eacProcess = await _createEacProcess(version);
|
||||
final executable = await version.executable;
|
||||
final gameProcess = await _createGameProcess(executable!.path, host);
|
||||
if(gameProcess == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
var instance = GameInstance(version.name, gameProcess, launcherProcess, eacProcess, host, linkedHosting);
|
||||
final instance = GameInstance(
|
||||
versionName: version.name,
|
||||
gamePid: gameProcess,
|
||||
launcherPid: launcherProcess,
|
||||
eacPid: eacProcess,
|
||||
hosting: host,
|
||||
child: linkedHosting
|
||||
);
|
||||
instance.startObserver();
|
||||
if(host){
|
||||
_hostingController.discardServer();
|
||||
_hostingController.instance.value = instance;
|
||||
_hostingController.saveInstance();
|
||||
}else{
|
||||
_gameController.instance.value = instance;
|
||||
_gameController.saveInstance();
|
||||
}
|
||||
_injectOrShowError(_Injectable.sslBypass, host);
|
||||
return instance;
|
||||
}
|
||||
|
||||
Future<int?> _createGameProcess(String gamePath, bool host) async {
|
||||
@@ -179,63 +192,68 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
return null;
|
||||
}
|
||||
|
||||
var gameArgs = createRebootArgs(
|
||||
final gameArgs = createRebootArgs(
|
||||
_gameController.username.text,
|
||||
_gameController.password.text,
|
||||
host,
|
||||
_hostingController.headless.value,
|
||||
_gameController.customLaunchArgs.text
|
||||
);
|
||||
var gameProcess = await Process.start(
|
||||
final gameProcess = await Process.start(
|
||||
gamePath,
|
||||
gameArgs
|
||||
);
|
||||
gameProcess
|
||||
..exitCode.then((_) => _onStop(reason: _StopReason.normal))
|
||||
..outLines.forEach((line) => _onGameOutput(line, host))
|
||||
..errLines.forEach((line) => _onGameOutput(line, host));
|
||||
..exitCode.then((_) => _onStop(reason: _StopReason.exitCode))
|
||||
..outLines.forEach((line) => _onGameOutput(line, host, false))
|
||||
..errLines.forEach((line) => _onGameOutput(line, host, true));
|
||||
return gameProcess.pid;
|
||||
}
|
||||
|
||||
Future<int?> _createLauncherProcess(FortniteVersion version) async {
|
||||
var launcherFile = version.launcher;
|
||||
final launcherFile = version.launcher;
|
||||
if (launcherFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var launcherProcess = await Process.start(launcherFile.path, []);
|
||||
var pid = launcherProcess.pid;
|
||||
final launcherProcess = await Process.start(launcherFile.path, []);
|
||||
final pid = launcherProcess.pid;
|
||||
suspend(pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
Future<int?> _createEacProcess(FortniteVersion version) async {
|
||||
var eacFile = version.eacExecutable;
|
||||
final eacFile = version.eacExecutable;
|
||||
if (eacFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var eacProcess = await Process.start(eacFile.path, []);
|
||||
var pid = eacProcess.pid;
|
||||
final eacProcess = await Process.start(eacFile.path, []);
|
||||
final pid = eacProcess.pid;
|
||||
suspend(pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
void _onGameOutput(String line, bool host) {
|
||||
if (line.contains(shutdownLine)) {
|
||||
void _onGameOutput(String line, bool host, bool error) {
|
||||
if(kDebugMode) {
|
||||
print("${error ? '[ERROR]' : '[MESSAGE]'} $line");
|
||||
}
|
||||
|
||||
if (line.contains(kShutdownLine)) {
|
||||
_onStop(
|
||||
reason: _StopReason.normal
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if(corruptedBuildErrors.any((element) => line.contains(element))){
|
||||
if(kCorruptedBuildErrors.any((element) => line.contains(element))){
|
||||
_onStop(
|
||||
reason: _StopReason.corruptedVersionError
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if(cannotConnectErrors.any((element) => line.contains(element))){
|
||||
if(kCannotConnectErrors.any((element) => line.contains(element))){
|
||||
_onStop(
|
||||
reason: _StopReason.tokenError
|
||||
);
|
||||
@@ -251,39 +269,40 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
|
||||
_injectOrShowError(_Injectable.memoryFix, host);
|
||||
var instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||
final instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||
instance?.launched = true;
|
||||
instance?.tokenError = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onGameServerInjected() async {
|
||||
var theme = FluentTheme.of(appKey.currentContext!);
|
||||
final theme = FluentTheme.of(appKey.currentContext!);
|
||||
showInfoBar(
|
||||
translations.waitingForGameServer,
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
var gameServerPort = _settingsController.gameServerPort.text;
|
||||
var localPingResult = await pingGameServer(
|
||||
final gameServerPort = _settingsController.gameServerPort.text;
|
||||
final localPingResult = await pingGameServer(
|
||||
"127.0.0.1:$gameServerPort",
|
||||
timeout: const Duration(minutes: 1)
|
||||
timeout: const Duration(minutes: 2)
|
||||
);
|
||||
if(!localPingResult) {
|
||||
showInfoBar(
|
||||
translations.gameServerStartWarning,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_matchmakerController.joinLocalHost();
|
||||
var accessible = await _checkGameServer(theme, gameServerPort);
|
||||
final accessible = await _checkGameServer(theme, gameServerPort);
|
||||
if(!accessible) {
|
||||
showInfoBar(
|
||||
translations.gameServerStartLocalWarning,
|
||||
severity: InfoBarSeverity.warning,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -295,7 +314,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
showInfoBar(
|
||||
translations.gameServerStarted,
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: snackbarLongDuration
|
||||
duration: infoBarLongDuration
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,13 +324,13 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
var publicIp = await Ipify.ipv4();
|
||||
var externalResult = await pingGameServer("$publicIp:$gameServerPort");
|
||||
final publicIp = await Ipify.ipv4();
|
||||
final externalResult = await pingGameServer("$publicIp:$gameServerPort");
|
||||
if(externalResult) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var future = pingGameServer(
|
||||
final future = pingGameServer(
|
||||
"$publicIp:$gameServerPort",
|
||||
timeout: const Duration(days: 365)
|
||||
);
|
||||
@@ -333,15 +352,12 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
await _operation?.cancel();
|
||||
await _authenticatorController.worker?.cancel();
|
||||
await _matchmakerController.worker?.cancel();
|
||||
var instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||
final instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||
if(instance != null){
|
||||
if(instance.linkedHosting){
|
||||
_onStop(
|
||||
_onStop(
|
||||
reason: _StopReason.normal,
|
||||
host: true
|
||||
);
|
||||
}
|
||||
|
||||
);
|
||||
instance.kill();
|
||||
if(host){
|
||||
_hostingController.instance.value = null;
|
||||
@@ -355,7 +371,10 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
_hostingController.discardServer();
|
||||
}
|
||||
|
||||
messenger.removeMessageByPage(_pageType.index);
|
||||
if(reason == _StopReason.normal) {
|
||||
messenger.removeMessageByPage(_pageType.index);
|
||||
}
|
||||
|
||||
switch(reason) {
|
||||
case _StopReason.authenticatorError:
|
||||
case _StopReason.matchmakerError:
|
||||
@@ -365,49 +384,53 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
showInfoBar(
|
||||
translations.missingVersionError,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.missingExecutableError:
|
||||
showInfoBar(
|
||||
translations.missingExecutableError,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.exitCode:
|
||||
final instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||
if(instance != null && !instance.launched) {
|
||||
showInfoBar(
|
||||
translations.corruptedVersionError,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
case _StopReason.corruptedVersionError:
|
||||
showInfoBar(
|
||||
translations.corruptedVersionError,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.missingDllError:
|
||||
showInfoBar(
|
||||
translations.missingDllError(error!),
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.corruptedDllError:
|
||||
showInfoBar(
|
||||
translations.corruptedDllError(error!),
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.tokenError:
|
||||
showInfoBar(
|
||||
translations.tokenError,
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
case _StopReason.unknownError:
|
||||
showInfoBar(
|
||||
translations.unknownFortniteError(error ?? translations.unknownError),
|
||||
severity: InfoBarSeverity.error,
|
||||
duration: snackbarLongDuration,
|
||||
duration: infoBarLongDuration,
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -415,14 +438,14 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
|
||||
Future<void> _injectOrShowError(_Injectable injectable, bool hosting) async {
|
||||
var instance = hosting ? _hostingController.instance.value : _gameController.instance.value;
|
||||
final instance = hosting ? _hostingController.instance.value : _gameController.instance.value;
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var gameProcess = instance.gamePid;
|
||||
var dllPath = await _getDllFileOrStop(injectable, hosting);
|
||||
final gameProcess = instance.gamePid;
|
||||
final dllPath = await _getDllFileOrStop(injectable, hosting);
|
||||
if(dllPath == null) {
|
||||
return;
|
||||
}
|
||||
@@ -452,17 +475,13 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
|
||||
Future<File?> _getDllFileOrStop(_Injectable injectable, bool host) async {
|
||||
var path = _getDllPath(injectable);
|
||||
var file = File(path);
|
||||
final path = _getDllPath(injectable);
|
||||
final file = File(path);
|
||||
if(await file.exists()) {
|
||||
return file;
|
||||
}
|
||||
|
||||
_onStop(
|
||||
reason: _StopReason.missingDllError,
|
||||
host: host,
|
||||
error: path
|
||||
);
|
||||
await downloadCriticalDllInteractive(path);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -472,15 +491,6 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
duration: null
|
||||
);
|
||||
|
||||
OverlayEntry showInfoBar(dynamic text, {InfoBarSeverity severity = InfoBarSeverity.info, bool loading = false, Duration? duration = snackbarShortDuration, Widget? action}) => messenger.showInfoBar(
|
||||
text,
|
||||
pageType: _pageType,
|
||||
severity: severity,
|
||||
loading: loading,
|
||||
duration: duration,
|
||||
action: action
|
||||
);
|
||||
|
||||
RebootPageType get _pageType => widget.host ? RebootPageType.host : RebootPageType.play;
|
||||
}
|
||||
|
||||
@@ -489,12 +499,11 @@ enum _StopReason {
|
||||
missingVersionError,
|
||||
missingExecutableError,
|
||||
corruptedVersionError,
|
||||
missingDllError,
|
||||
corruptedDllError,
|
||||
authenticatorError,
|
||||
matchmakerError,
|
||||
tokenError,
|
||||
unknownError
|
||||
unknownError, exitCode
|
||||
}
|
||||
|
||||
enum _Injectable {
|
||||
@@ -1,100 +0,0 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/profile.dart';
|
||||
|
||||
class ProfileWidget extends StatefulWidget {
|
||||
const ProfileWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ProfileWidget> createState() => _ProfileWidgetState();
|
||||
}
|
||||
|
||||
class _ProfileWidgetState extends State<ProfileWidget> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12.0,
|
||||
horizontal: 12.0
|
||||
),
|
||||
child: Button(
|
||||
style: ButtonStyle(
|
||||
padding: ButtonState.all(EdgeInsets.zero),
|
||||
backgroundColor: ButtonState.all(Colors.transparent),
|
||||
border: ButtonState.all(const BorderSide(color: Colors.transparent))
|
||||
),
|
||||
onPressed: () async {
|
||||
if(await showProfileForm(context)) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
child: Image.asset("assets/images/user.png")
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12.0,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_username,
|
||||
textAlign: TextAlign.start,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
maxLines: 1
|
||||
),
|
||||
Text(
|
||||
_email,
|
||||
textAlign: TextAlign.start,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w100
|
||||
),
|
||||
maxLines: 1
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
String get _username {
|
||||
var username = _gameController.username.text;
|
||||
if(username.isEmpty) {
|
||||
return kDefaultPlayerName;
|
||||
}
|
||||
|
||||
var atIndex = username.indexOf("@");
|
||||
if(atIndex == -1) {
|
||||
return username.substring(0, 1).toUpperCase() + username.substring(1);
|
||||
}
|
||||
|
||||
var result = username.substring(0, atIndex);
|
||||
return result.substring(0, 1).toUpperCase() + result.substring(1);
|
||||
}
|
||||
|
||||
String get _email {
|
||||
var username = _gameController.username.text;
|
||||
if(username.isEmpty) {
|
||||
return "$kDefaultPlayerName@projectreboot.dev";
|
||||
}
|
||||
|
||||
if(username.contains("@")) {
|
||||
return username.toLowerCase();
|
||||
}
|
||||
|
||||
return "$username@projectreboot.dev".toLowerCase();
|
||||
}
|
||||
}
|
||||
106
gui/lib/src/widget/profile_tile.dart
Normal file
106
gui/lib/src/widget/profile_tile.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/profile.dart';
|
||||
|
||||
class ProfileWidget extends StatefulWidget {
|
||||
const ProfileWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ProfileWidget> createState() => _ProfileWidgetState();
|
||||
}
|
||||
|
||||
class _ProfileWidgetState extends State<ProfileWidget> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => HoverButton(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
onPressed: () async {
|
||||
if(await showProfileForm(context)) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
builder: (context, states) => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ButtonThemeData.uncheckedInputColor(
|
||||
FluentTheme.of(context),
|
||||
states,
|
||||
transparentWhenNone: true,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(6.0))
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
horizontal: 8.0
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
child: Image.asset("assets/images/user.png")
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12.0,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_username,
|
||||
textAlign: TextAlign.start,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
maxLines: 1
|
||||
),
|
||||
Text(
|
||||
_email,
|
||||
textAlign: TextAlign.start,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w100
|
||||
),
|
||||
maxLines: 1
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
String get _username {
|
||||
var username = _gameController.username.text;
|
||||
if(username.isEmpty) {
|
||||
return kDefaultPlayerName;
|
||||
}
|
||||
|
||||
var atIndex = username.indexOf("@");
|
||||
if(atIndex == -1) {
|
||||
return username.substring(0, 1).toUpperCase() + username.substring(1);
|
||||
}
|
||||
|
||||
var result = username.substring(0, atIndex);
|
||||
return result.substring(0, 1).toUpperCase() + result.substring(1);
|
||||
}
|
||||
|
||||
String get _email {
|
||||
var username = _gameController.username.text;
|
||||
if(username.isEmpty) {
|
||||
return "$kDefaultPlayerName@projectreboot.dev";
|
||||
}
|
||||
|
||||
if(username.contains("@")) {
|
||||
return username.toLowerCase();
|
||||
}
|
||||
|
||||
return "$username@projectreboot.dev".toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
@@ -5,7 +7,6 @@ import 'package:reboot_launcher/src/controller/authenticator_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/matchmaker_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
class ServerButton extends StatefulWidget {
|
||||
@@ -18,27 +19,43 @@ class ServerButton extends StatefulWidget {
|
||||
|
||||
class _ServerButtonState extends State<ServerButton> {
|
||||
late final ServerController _controller = widget.authenticator ? Get.find<AuthenticatorController>() : Get.find<MatchmakerController>();
|
||||
late final StreamController<void> _textController = StreamController.broadcast();
|
||||
late final void Function() _listener = () => _textController.add(null);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_controller.port.addListener(_listener);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.port.removeListener(_listener);
|
||||
_textController.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Obx(() => SizedBox(
|
||||
height: 48,
|
||||
child: Button(
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(_buttonText),
|
||||
),
|
||||
onPressed: () => _controller.toggleInteractive(widget.authenticator ? RebootPageType.authenticator : RebootPageType.matchmaker)
|
||||
),
|
||||
)),
|
||||
),
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
width: double.infinity,
|
||||
child: Button(
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: StreamBuilder(
|
||||
stream: _textController.stream,
|
||||
builder: (context, snapshot) => Obx(() => Text(_buttonText))
|
||||
),
|
||||
),
|
||||
onPressed: () => _controller.toggleInteractive()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
String get _buttonText {
|
||||
if(_controller.type.value == ServerType.local){
|
||||
if(_controller.type.value == ServerType.local && _controller.port.text.trim() == _controller.defaultPort){
|
||||
return translations.checkServer(_controller.controllerName);
|
||||
}
|
||||
|
||||
164
gui/lib/src/widget/setting_tile.dart
Normal file
164
gui/lib/src/widget/setting_tile.dart
Normal file
@@ -0,0 +1,164 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:reboot_launcher/src/page/pages.dart';
|
||||
import 'package:skeletons/skeletons.dart';
|
||||
|
||||
class SettingTile extends StatefulWidget {
|
||||
static const double kDefaultContentWidth = 200.0;
|
||||
static const double kDefaultHeaderHeight = 72;
|
||||
|
||||
final void Function()? onPressed;
|
||||
final Icon icon;
|
||||
final Text? title;
|
||||
final Text? subtitle;
|
||||
final Widget? content;
|
||||
final double? contentWidth;
|
||||
final List<Widget>? children;
|
||||
|
||||
const SettingTile({
|
||||
this.onPressed,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
this.content,
|
||||
this.contentWidth = kDefaultContentWidth,
|
||||
this.children
|
||||
});
|
||||
|
||||
@override
|
||||
State<SettingTile> createState() => _SettingTileState();
|
||||
}
|
||||
|
||||
class _SettingTileState extends State<SettingTile> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 4.0
|
||||
),
|
||||
child: HoverButton(
|
||||
onPressed: _buildOnPressed(),
|
||||
builder: (context, states) => Container(
|
||||
height: 80,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: ButtonThemeData.uncheckedInputColor(
|
||||
FluentTheme.of(context),
|
||||
states,
|
||||
transparentWhenNone: true,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(4.0))
|
||||
),
|
||||
child: Card(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(4.0)
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 12.0,
|
||||
vertical: 6.0
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
widget.icon,
|
||||
const SizedBox(width: 16.0),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
widget.title == null ? _skeletonTitle : widget.title!,
|
||||
widget.subtitle == null ? _skeletonSubtitle : widget.subtitle!,
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
_trailing
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void Function()? _buildOnPressed() {
|
||||
if(widget.onPressed != null) {
|
||||
return widget.onPressed;
|
||||
}
|
||||
|
||||
final children = widget.children;
|
||||
if (children == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return () async {
|
||||
await Navigator.of(context).push(PageRouteBuilder(
|
||||
transitionDuration: Duration.zero,
|
||||
reverseTransitionDuration: Duration.zero,
|
||||
settings: RouteSettings(
|
||||
name: widget.title?.data
|
||||
),
|
||||
pageBuilder: (context, incoming, outgoing) => ListView.builder(
|
||||
itemCount: children.length,
|
||||
itemBuilder: (context, index) => children[index]
|
||||
)
|
||||
));
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) => pageIndex.value = pageIndex.value);
|
||||
};
|
||||
}
|
||||
|
||||
Widget get _trailing {
|
||||
final hasContent = widget.content != null;
|
||||
final hasChildren = widget.children?.isNotEmpty == true;
|
||||
final hasListener = widget.onPressed != null;
|
||||
if(hasContent && hasChildren) {
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: widget.contentWidth,
|
||||
child: widget.content
|
||||
),
|
||||
const SizedBox(width: 16.0),
|
||||
Icon(
|
||||
FluentIcons.chevron_right_24_regular
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (hasContent) {
|
||||
return SizedBox(
|
||||
width: widget.contentWidth,
|
||||
child: widget.content
|
||||
);
|
||||
}
|
||||
|
||||
if (hasChildren || hasListener) {
|
||||
return Icon(
|
||||
FluentIcons.chevron_right_24_regular
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
Widget get _skeletonTitle => const SkeletonLine(
|
||||
style: SkeletonLineStyle(
|
||||
padding: EdgeInsets.only(
|
||||
right: 24.0
|
||||
),
|
||||
height: 18
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _skeletonSubtitle => const SkeletonLine(
|
||||
style: SkeletonLineStyle(
|
||||
padding: EdgeInsets.only(
|
||||
top: 8.0,
|
||||
bottom: 8.0,
|
||||
right: 24.0
|
||||
),
|
||||
height: 13
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/widget/os/buttons.dart';
|
||||
import 'package:reboot_launcher/src/widget/title_bar_buttons.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
|
||||
class WindowTitleBar extends StatelessWidget {
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart' show appWindow;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'icons.dart';
|
||||
import 'mouse.dart';
|
||||
import 'title_bar_icons.dart';
|
||||
import 'title_bar_mouse.dart';
|
||||
|
||||
typedef WindowButtonIconBuilder = Widget Function(
|
||||
WindowButtonContext buttonContext);
|
||||
@@ -1,50 +0,0 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
class BuildSelector extends StatefulWidget {
|
||||
final Function() onSelected;
|
||||
|
||||
const BuildSelector({Key? key, required this.onSelected}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<BuildSelector> createState() => _BuildSelectorState();
|
||||
}
|
||||
|
||||
class _BuildSelectorState extends State<BuildSelector> {
|
||||
final BuildController _buildController = Get.find<BuildController>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InfoLabel(
|
||||
label: translations.build,
|
||||
child: Obx(() => ComboBox<FortniteBuild>(
|
||||
placeholder: Text(translations.selectBuild),
|
||||
isExpanded: true,
|
||||
items: _items,
|
||||
value: _buildController.selectedBuild.value,
|
||||
onChanged: (value) {
|
||||
if(value == null){
|
||||
return;
|
||||
}
|
||||
|
||||
_buildController.selectedBuild.value = value;
|
||||
widget.onSelected();
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
List<ComboBoxItem<FortniteBuild>> get _items =>_buildController.builds!
|
||||
.map((element) => _buildItem(element))
|
||||
.toList();
|
||||
|
||||
ComboBoxItem<FortniteBuild> _buildItem(FortniteBuild element) {
|
||||
return ComboBoxItem<FortniteBuild>(
|
||||
value: element,
|
||||
child: Text(element.version.toString())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/page/abstract/page_setting.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/version_selector.dart';
|
||||
|
||||
SettingTile get versionSelectorSettingTile => SettingTile(
|
||||
title: translations.addVersionName,
|
||||
subtitle: translations.addVersionDescription,
|
||||
content: const VersionSelector(),
|
||||
expandedContent: [
|
||||
SettingTile(
|
||||
title: translations.addLocalBuildName,
|
||||
subtitle: translations.addLocalBuildDescription,
|
||||
content: Button(
|
||||
onPressed: VersionSelector.openAddDialog,
|
||||
child: Text(translations.addLocalBuildContent)
|
||||
),
|
||||
isChild: true
|
||||
),
|
||||
SettingTile(
|
||||
title: translations.downloadBuildName,
|
||||
subtitle: translations.downloadBuildDescription,
|
||||
content: Button(
|
||||
onPressed: VersionSelector.openDownloadDialog,
|
||||
child: Text(translations.downloadBuildContent)
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
PageSetting get versionSelectorRebootSetting => PageSetting(
|
||||
name: translations.addVersionName,
|
||||
description: translations.addVersionDescription,
|
||||
children: [
|
||||
PageSetting(
|
||||
name: translations.addLocalBuildName,
|
||||
description: translations.addLocalBuildDescription,
|
||||
content: translations.addLocalBuildContent
|
||||
),
|
||||
PageSetting(
|
||||
name: translations.downloadBuildName,
|
||||
description: translations.downloadBuildDescription,
|
||||
content: translations.downloadBuildContent
|
||||
)
|
||||
]
|
||||
);
|
||||
@@ -11,9 +11,9 @@ import 'package:reboot_launcher/src/dialog/abstract/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/common/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/add_local_version.dart';
|
||||
import 'package:reboot_launcher/src/widget/version/add_server_version.dart';
|
||||
import 'package:reboot_launcher/src/widget/add_local_version.dart';
|
||||
import 'package:reboot_launcher/src/widget/add_server_version.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class VersionSelector extends StatefulWidget {
|
||||
@@ -37,7 +37,12 @@ class _VersionSelectorState extends State<VersionSelector> {
|
||||
final FlyoutController _flyoutController = FlyoutController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Obx(() => _createOptionsMenu(
|
||||
Widget build(BuildContext context) => Obx(() {
|
||||
if(_gameController.hasNoVersions) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return _createOptionsMenu(
|
||||
version: _gameController.selectedVersion,
|
||||
close: false,
|
||||
child: FlyoutTarget(
|
||||
@@ -47,18 +52,13 @@ class _VersionSelectorState extends State<VersionSelector> {
|
||||
items: _createSelectorItems(context)
|
||||
),
|
||||
)
|
||||
));
|
||||
);
|
||||
});
|
||||
|
||||
List<MenuFlyoutItem> _createSelectorItems(BuildContext context) => _gameController.hasNoVersions ? [_createDefaultVersionItem()]
|
||||
: _gameController.versions.value
|
||||
List<MenuFlyoutItem> _createSelectorItems(BuildContext context) => _gameController.versions.value
|
||||
.map((version) => _createVersionItem(context, version))
|
||||
.toList();
|
||||
|
||||
MenuFlyoutItem _createDefaultVersionItem() => MenuFlyoutItem(
|
||||
text: Text(translations.noVersions),
|
||||
onPressed: () {}
|
||||
);
|
||||
|
||||
MenuFlyoutItem _createVersionItem(BuildContext context, FortniteVersion version) => MenuFlyoutItem(
|
||||
text: _createOptionsMenu(
|
||||
version: version,
|
||||
61
gui/lib/src/widget/version_selector_tile.dart
Normal file
61
gui/lib/src/widget/version_selector_tile.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_selector.dart';
|
||||
|
||||
SettingTile get versionSelectSettingTile => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.play_24_regular
|
||||
),
|
||||
title: Text(translations.manageVersionsName),
|
||||
subtitle: Text(translations.manageVersionsDescription),
|
||||
content: const VersionSelector(),
|
||||
children: [
|
||||
_selectVersionTile,
|
||||
_addLocalTile,
|
||||
_downloadTile
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _selectVersionTile => Obx(() {
|
||||
final gameController = Get.find<GameController>();
|
||||
if(gameController.hasNoVersions) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.play_24_regular
|
||||
),
|
||||
title: Text(translations.selectFortniteName),
|
||||
subtitle: Text(translations.selectFortniteDescription),
|
||||
content: const VersionSelector()
|
||||
);
|
||||
});
|
||||
|
||||
SettingTile get _downloadTile => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.arrow_download_24_regular
|
||||
),
|
||||
title: Text(translations.downloadBuildName),
|
||||
subtitle: Text(translations.downloadBuildDescription),
|
||||
content: Button(
|
||||
onPressed: VersionSelector.openDownloadDialog,
|
||||
child: Text(translations.downloadBuildContent)
|
||||
)
|
||||
);
|
||||
|
||||
SettingTile get _addLocalTile => SettingTile(
|
||||
icon: Icon(
|
||||
FluentIcons.folder_add_24_regular
|
||||
),
|
||||
title: Text(translations.addLocalBuildName),
|
||||
subtitle: Text(translations.addLocalBuildDescription),
|
||||
content: Button(
|
||||
onPressed: VersionSelector.openAddDialog,
|
||||
child: Text(translations.addLocalBuildContent)
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user