mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 08:43:48 +03:00
Merge branch 'main' into feat/remove-synchronize-typeorm
This commit is contained in:
commit
6b3d3c8f5b
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -27,7 +27,7 @@ body:
|
|||||||
label: Expected behavior
|
label: Expected behavior
|
||||||
description: A clear and concise description of what you expected to happen.
|
description: A clear and concise description of what you expected to happen.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: screenshots
|
id: screenshots
|
||||||
attributes:
|
attributes:
|
||||||
@ -56,3 +56,12 @@ body:
|
|||||||
description: Please provide any additional information and context about your problem.
|
description: Please provide any additional information and context about your problem.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
- type: checkboxes
|
||||||
|
id: terms
|
||||||
|
attributes:
|
||||||
|
label: Before opening this Issue
|
||||||
|
options:
|
||||||
|
- label: I have searched the issues of this repository and believe that this is not a duplicate.
|
||||||
|
required: true
|
||||||
|
- label: I am aware that Hydra team does not offer any support or help regarding the downloaded games.
|
||||||
|
required: true
|
||||||
|
@ -270,6 +270,7 @@
|
|||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"no_pending_invites": "You have no pending invites",
|
"no_pending_invites": "You have no pending invites",
|
||||||
"no_blocked_users": "You have no blocked users",
|
"no_blocked_users": "You have no blocked users",
|
||||||
"friend_code_copied": "Friend code copied"
|
"friend_code_copied": "Friend code copied",
|
||||||
|
"undo_friendship_modal_text": "This will undo your friendship with {{displayName}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,9 +177,6 @@
|
|||||||
"download_count_zero": "No hay descargas en la lista",
|
"download_count_zero": "No hay descargas en la lista",
|
||||||
"download_count_one": "{{countFormatted}} descarga en la lista",
|
"download_count_one": "{{countFormatted}} descarga en la lista",
|
||||||
"download_count_other": "{{countFormatted}} descargas en la lista",
|
"download_count_other": "{{countFormatted}} descargas en la lista",
|
||||||
"download_options_zero": "No hay descargas disponibles",
|
|
||||||
"download_options_one": "{{countFormatted}} descarga disponible",
|
|
||||||
"download_options_other": "{{countFormatted}} descargas disponibles",
|
|
||||||
"download_source_url": "Descargar URL de origen",
|
"download_source_url": "Descargar URL de origen",
|
||||||
"add_download_source_description": "Introduce la URL con el archivo .json",
|
"add_download_source_description": "Introduce la URL con el archivo .json",
|
||||||
"download_source_up_to_date": "Al día",
|
"download_source_up_to_date": "Al día",
|
||||||
@ -261,6 +258,18 @@
|
|||||||
"undo_friendship": "Eliminar amistad",
|
"undo_friendship": "Eliminar amistad",
|
||||||
"request_accepted": "Solicitud aceptada",
|
"request_accepted": "Solicitud aceptada",
|
||||||
"user_blocked_successfully": "Usuario bloqueado exitosamente",
|
"user_blocked_successfully": "Usuario bloqueado exitosamente",
|
||||||
"user_block_modal_text": "Esto va a bloquear a {{displayName}}"
|
"user_block_modal_text": "Esto va a bloquear a {{displayName}}",
|
||||||
|
"settings": "Ajustes",
|
||||||
|
"public": "Público",
|
||||||
|
"private": "Privado",
|
||||||
|
"friends_only": "Solo Amigos",
|
||||||
|
"privacy": "Privacidad",
|
||||||
|
"blocked_users": "Usuarios bloqueados",
|
||||||
|
"unblock": "Desbloquear",
|
||||||
|
"no_friends_added": "Todavía no tienes amigos añadidos",
|
||||||
|
"pending": "Pendiente",
|
||||||
|
"no_pending_invites": "No tienes invitaciones pendientes",
|
||||||
|
"no_blocked_users": "No has bloqueado a ningún usuario",
|
||||||
|
"friend_code_copied": "Código de amigo copiado"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,6 +273,7 @@
|
|||||||
"pending": "Pendentes",
|
"pending": "Pendentes",
|
||||||
"no_pending_invites": "Você não possui convites de amizade pendentes",
|
"no_pending_invites": "Você não possui convites de amizade pendentes",
|
||||||
"no_blocked_users": "Você não tem nenhum usuário bloqueado",
|
"no_blocked_users": "Você não tem nenhum usuário bloqueado",
|
||||||
"friend_code_copied": "Código de amigo copiado"
|
"friend_code_copied": "Código de amigo copiado",
|
||||||
|
"undo_friendship_modal_text": "Isso irá remover sua amizade com {{displayName}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,9 +177,6 @@
|
|||||||
"download_count_zero": "В списке нет загрузок",
|
"download_count_zero": "В списке нет загрузок",
|
||||||
"download_count_one": "{{countFormatted}} загрузка в списке",
|
"download_count_one": "{{countFormatted}} загрузка в списке",
|
||||||
"download_count_other": "{{countFormatted}} загрузок в списке",
|
"download_count_other": "{{countFormatted}} загрузок в списке",
|
||||||
"download_options_zero": "Нет доступных загрузок",
|
|
||||||
"download_options_one": "{{countFormatted}} вариант загрузки доступен",
|
|
||||||
"download_options_other": "{{countFormatted}} вариантов загрузки доступно",
|
|
||||||
"download_source_url": "Ссылка на источник",
|
"download_source_url": "Ссылка на источник",
|
||||||
"add_download_source_description": "Вставьте ссылку на .json-файл",
|
"add_download_source_description": "Вставьте ссылку на .json-файл",
|
||||||
"download_source_up_to_date": "Обновлён",
|
"download_source_up_to_date": "Обновлён",
|
||||||
@ -241,6 +238,38 @@
|
|||||||
"successfully_signed_out": "Успешный выход из аккаунта",
|
"successfully_signed_out": "Успешный выход из аккаунта",
|
||||||
"sign_out": "Выйти",
|
"sign_out": "Выйти",
|
||||||
"playing_for": "Сыграно {{amount}}",
|
"playing_for": "Сыграно {{amount}}",
|
||||||
"sign_out_modal_text": "Ваша библиотека связана с текущей учетной записью. При выходе из системы ваша библиотека станет недоступна, и прогресс не будет сохранен. Выйти?"
|
"sign_out_modal_text": "Ваша библиотека связана с текущей учетной записью. При выходе из системы ваша библиотека станет недоступна, и прогресс не будет сохранен. Выйти?",
|
||||||
|
"add_friends": "Добавить друзей",
|
||||||
|
"add": "Добавить",
|
||||||
|
"friend_code": "Код друга",
|
||||||
|
"see_profile": "Просмотреть профиль",
|
||||||
|
"sending": "Отправка",
|
||||||
|
"friend_request_sent": "Запрос в друзья отправлен",
|
||||||
|
"friends": "Друзья",
|
||||||
|
"friends_list": "Список друзей",
|
||||||
|
"user_not_found": "Пользователь не найден",
|
||||||
|
"block_user": "Заблокировать пользователя",
|
||||||
|
"add_friend": "Добавить друга",
|
||||||
|
"request_sent": "Запрос отправлен",
|
||||||
|
"request_received": "Запрос получен",
|
||||||
|
"accept_request": "Принять запрос",
|
||||||
|
"ignore_request": "Игнорировать запрос",
|
||||||
|
"cancel_request": "Отменить запрос",
|
||||||
|
"undo_friendship": "Удалить друга",
|
||||||
|
"request_accepted": "Запрос принят",
|
||||||
|
"user_blocked_successfully": "Пользователь успешно заблокирован",
|
||||||
|
"user_block_modal_text": "{{displayName}} будет заблокирован",
|
||||||
|
"settings": "Настройки",
|
||||||
|
"public": "Публичный",
|
||||||
|
"private": "Приватный",
|
||||||
|
"friends_only": "Только друзья",
|
||||||
|
"privacy": "Приватность",
|
||||||
|
"blocked_users": "Заблокированные пользователи",
|
||||||
|
"unblock": "Разблокировать",
|
||||||
|
"no_friends_added": "Вы ещё не добавили ни одного друга",
|
||||||
|
"pending": "Ожидание",
|
||||||
|
"no_pending_invites": "У вас нет запросов ожидающих ответа",
|
||||||
|
"no_blocked_users": "Вы не заблокировали ни одного пользователя",
|
||||||
|
"friend_code_copied": "Код друга скопирован"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,10 +106,15 @@ app.on("browser-window-created", (_, window) => {
|
|||||||
|
|
||||||
const handleDeepLinkPath = (uri?: string) => {
|
const handleDeepLinkPath = (uri?: string) => {
|
||||||
if (!uri) return;
|
if (!uri) return;
|
||||||
const url = new URL(uri);
|
|
||||||
|
|
||||||
if (url.host === "install-source") {
|
try {
|
||||||
WindowManager.redirect(`settings${url.search}`);
|
const url = new URL(uri);
|
||||||
|
|
||||||
|
if (url.host === "install-source") {
|
||||||
|
WindowManager.redirect(`settings${url.search}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Error handling deep link", uri, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -104,6 +104,7 @@ export const section = style({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: `${SPACING_UNIT * 2}px`,
|
gap: `${SPACING_UNIT * 2}px`,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const backButton = recipe({
|
export const backButton = recipe({
|
||||||
@ -136,11 +137,15 @@ export const backButton = recipe({
|
|||||||
export const title = recipe({
|
export const title = recipe({
|
||||||
base: {
|
base: {
|
||||||
transition: "all ease 0.2s",
|
transition: "all ease 0.2s",
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
width: "100%",
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
hasBackButton: {
|
hasBackButton: {
|
||||||
true: {
|
true: {
|
||||||
transform: "translateX(28px)",
|
transform: "translateX(28px)",
|
||||||
|
width: "calc(100% - 28px)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -72,7 +72,7 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
|
|||||||
isWindows: window.electron.platform === "win32",
|
isWindows: window.electron.platform === "win32",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<section className={styles.section}>
|
<section className={styles.section} style={{ flex: 1 }}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.backButton({
|
className={styles.backButton({
|
||||||
|
@ -7,22 +7,24 @@ export const profileContainerBackground = createVar();
|
|||||||
export const profileContainer = style({
|
export const profileContainer = style({
|
||||||
background: profileContainerBackground,
|
background: profileContainerBackground,
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
gap: `${SPACING_UNIT}px`,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
":hover": {
|
":hover": {
|
||||||
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
||||||
},
|
},
|
||||||
|
borderBottom: `solid 1px ${vars.color.border}`,
|
||||||
|
boxShadow: "0px 0px 15px 0px rgb(0 0 0 / 70%)",
|
||||||
|
padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const profileButton = style({
|
export const profileButton = style({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
transition: "all ease 0.1s",
|
transition: "all ease 0.1s",
|
||||||
padding: `${SPACING_UNIT * 2}px ${SPACING_UNIT * 2}px`,
|
|
||||||
color: vars.color.muted,
|
color: vars.color.muted,
|
||||||
borderBottom: `solid 1px ${vars.color.border}`,
|
|
||||||
boxShadow: "0px 0px 15px 0px rgb(0 0 0 / 70%)",
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
zIndex: "10",
|
overflow: "hidden",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const profileButtonContent = style({
|
export const profileButtonContent = style({
|
||||||
@ -75,16 +77,6 @@ export const profileButtonTitle = style({
|
|||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const friendRequestContainer = style({
|
|
||||||
position: "absolute",
|
|
||||||
padding: "8px",
|
|
||||||
right: `${SPACING_UNIT}px`,
|
|
||||||
display: "flex",
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
alignItems: "center",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const friendRequestButton = style({
|
export const friendRequestButton = style({
|
||||||
color: vars.color.success,
|
color: vars.color.success,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
|
@ -41,6 +41,9 @@ export function SidebarProfile() {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}, [profileBackground]);
|
}, [profileBackground]);
|
||||||
|
|
||||||
|
const showPendingRequests =
|
||||||
|
userDetails && receivedRequests.length > 0 && !gameRunning;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.profileContainer}
|
className={styles.profileContainer}
|
||||||
@ -88,19 +91,17 @@ export function SidebarProfile() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{userDetails && receivedRequests.length > 0 && !gameRunning && (
|
{showPendingRequests && (
|
||||||
<div className={styles.friendRequestContainer}>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className={styles.friendRequestButton}
|
||||||
className={styles.friendRequestButton}
|
onClick={() =>
|
||||||
onClick={() =>
|
showFriendsModal(UserFriendModalTab.AddFriend, userDetails.id)
|
||||||
showFriendsModal(UserFriendModalTab.AddFriend, userDetails.id)
|
}
|
||||||
}
|
>
|
||||||
>
|
<PersonAddIcon size={24} />
|
||||||
<PersonAddIcon size={24} />
|
{receivedRequests.length}
|
||||||
{receivedRequests.length}
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Button, Modal } from "@renderer/components";
|
||||||
|
import * as styles from "./user.css";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
export interface UserConfirmUndoFriendshipModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
displayName: string;
|
||||||
|
onConfirm: () => void;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserConfirmUndoFriendshipModal({
|
||||||
|
visible,
|
||||||
|
displayName,
|
||||||
|
onConfirm,
|
||||||
|
onClose,
|
||||||
|
}: UserConfirmUndoFriendshipModalProps) {
|
||||||
|
const { t } = useTranslation("user_profile");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
title={t("sign_out_modal_title")}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<div className={styles.signOutModalContent}>
|
||||||
|
<p>{t("undo_friendship_modal_text", { displayName })}</p>
|
||||||
|
<div className={styles.signOutModalButtonsContainer}>
|
||||||
|
<Button onClick={onConfirm} theme="danger">
|
||||||
|
{t("undo_friendship")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button onClick={onClose} theme="primary">
|
||||||
|
{t("cancel")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
@ -34,6 +34,7 @@ import { UserProfileSettingsModal } from "./user-profile-settings-modal";
|
|||||||
import { UserSignOutModal } from "./user-sign-out-modal";
|
import { UserSignOutModal } from "./user-sign-out-modal";
|
||||||
import { UserFriendModalTab } from "../shared-modals/user-friend-modal";
|
import { UserFriendModalTab } from "../shared-modals/user-friend-modal";
|
||||||
import { UserBlockModal } from "./user-block-modal";
|
import { UserBlockModal } from "./user-block-modal";
|
||||||
|
import { UserConfirmUndoFriendshipModal } from "./user-confirm-undo-friendship-modal";
|
||||||
|
|
||||||
const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120;
|
const MAX_MINUTES_TO_SHOW_IN_PLAYTIME = 120;
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ export function UserContent({
|
|||||||
useState(false);
|
useState(false);
|
||||||
const [showSignOutModal, setShowSignOutModal] = useState(false);
|
const [showSignOutModal, setShowSignOutModal] = useState(false);
|
||||||
const [showUserBlockModal, setShowUserBlockModal] = useState(false);
|
const [showUserBlockModal, setShowUserBlockModal] = useState(false);
|
||||||
|
const [showUndoFriendshipModal, setShowUndoFriendshipModal] = useState(false);
|
||||||
const [currentGame, setCurrentGame] = useState<GameRunning | null>(null);
|
const [currentGame, setCurrentGame] = useState<GameRunning | null>(null);
|
||||||
|
|
||||||
const { gameRunning } = useAppSelector((state) => state.gameRunning);
|
const { gameRunning } = useAppSelector((state) => state.gameRunning);
|
||||||
@ -213,17 +215,12 @@ export function UserContent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (userProfile.relation.status === "ACCEPTED") {
|
if (userProfile.relation.status === "ACCEPTED") {
|
||||||
const userId =
|
|
||||||
userProfile.relation.AId === userDetails?.id
|
|
||||||
? userProfile.relation.BId
|
|
||||||
: userProfile.relation.AId;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
theme="outline"
|
theme="outline"
|
||||||
className={styles.cancelRequestButton}
|
className={styles.cancelRequestButton}
|
||||||
onClick={() => handleFriendAction(userId, "UNDO")}
|
onClick={() => setShowUndoFriendshipModal(true)}
|
||||||
>
|
>
|
||||||
<XCircleIcon size={28} /> {t("undo_friendship")}
|
<XCircleIcon size={28} /> {t("undo_friendship")}
|
||||||
</Button>
|
</Button>
|
||||||
@ -291,6 +288,13 @@ export function UserContent({
|
|||||||
displayName={userProfile.displayName}
|
displayName={userProfile.displayName}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<UserConfirmUndoFriendshipModal
|
||||||
|
visible={showUndoFriendshipModal}
|
||||||
|
onClose={() => setShowUndoFriendshipModal(false)}
|
||||||
|
onConfirm={() => handleFriendAction(userProfile.id, "UNDO")}
|
||||||
|
displayName={userProfile.displayName}
|
||||||
|
/>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
className={styles.profileContentBox}
|
className={styles.profileContentBox}
|
||||||
style={{
|
style={{
|
||||||
@ -328,7 +332,9 @@ export function UserContent({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.profileInformation}>
|
<div className={styles.profileInformation}>
|
||||||
<h2 style={{ fontWeight: "bold" }}>{userProfile.displayName}</h2>
|
<h2 className={styles.profileDisplayName}>
|
||||||
|
{userProfile.displayName}
|
||||||
|
</h2>
|
||||||
{currentGame && (
|
{currentGame && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -126,6 +126,7 @@ export const UserEditProfile = ({
|
|||||||
value={form.displayName}
|
value={form.displayName}
|
||||||
required
|
required
|
||||||
minLength={3}
|
minLength={3}
|
||||||
|
maxLength={50}
|
||||||
containerProps={{ style: { width: "100%" } }}
|
containerProps={{ style: { width: "100%" } }}
|
||||||
onChange={(e) => setForm({ ...form, displayName: e.target.value })}
|
onChange={(e) => setForm({ ...form, displayName: e.target.value })}
|
||||||
/>
|
/>
|
||||||
|
@ -23,6 +23,7 @@ export const profileContentBox = style({
|
|||||||
|
|
||||||
export const profileAvatarContainer = style({
|
export const profileAvatarContainer = style({
|
||||||
width: "96px",
|
width: "96px",
|
||||||
|
minWidth: "96px",
|
||||||
height: "96px",
|
height: "96px",
|
||||||
borderRadius: "50%",
|
borderRadius: "50%",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@ -100,6 +101,14 @@ export const profileInformation = style({
|
|||||||
alignItems: "flex-start",
|
alignItems: "flex-start",
|
||||||
color: "#c0c1c7",
|
color: "#c0c1c7",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
|
overflow: "hidden",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const profileDisplayName = style({
|
||||||
|
fontWeight: "bold",
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
width: "100%",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const profileContent = style({
|
export const profileContent = style({
|
||||||
|
Loading…
Reference in New Issue
Block a user