Compare commits
No commits in common. "0359616c8f9fb1437590a8c224f5e8459738c331" and "d63391fadf9c51a38bbfceeb1d47ca6687d4e9c8" have entirely different histories.
0359616c8f
...
d63391fadf
@ -395,7 +395,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
|
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 6;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEVELOPMENT_TEAM = V22H44W47J;
|
DEVELOPMENT_TEAM = V22H44W47J;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@ -435,7 +435,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
|
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 6;
|
CURRENT_PROJECT_VERSION = 5;
|
||||||
DEVELOPMENT_TEAM = V22H44W47J;
|
DEVELOPMENT_TEAM = V22H44W47J;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "ru",
|
"sourceLanguage" : "ru",
|
||||||
"strings" : {
|
"strings" : {
|
||||||
|
"(не работает) Отправить предложение" : {
|
||||||
|
|
||||||
|
},
|
||||||
"@%@" : {
|
"@%@" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -31,17 +34,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"%d символов" : {
|
|
||||||
"comment" : "feedback: character count",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "%d characters"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"%lld" : {
|
"%lld" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -211,16 +203,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Ваш e-mail" : {
|
"Ваше предложение" : {
|
||||||
"comment" : "feedback: email placeholder",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Your email"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Версия:" : {
|
"Версия:" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -305,16 +289,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Выберите оценку — это поможет нам понять настроение." : {
|
"Вы предложили: %@" : {
|
||||||
"comment" : "feedback: rating hint",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Select a rating — this helps us understand the vibe."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Выйти из аккаунта" : {
|
"Выйти из аккаунта" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -484,17 +460,6 @@
|
|||||||
"Здесь появится информация о собеседнике и существующих чатах." : {
|
"Здесь появится информация о собеседнике и существующих чатах." : {
|
||||||
"comment" : "Search placeholder description"
|
"comment" : "Search placeholder description"
|
||||||
},
|
},
|
||||||
"Идея" : {
|
|
||||||
"comment" : "feedback category: idea",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Idea"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Избранные сообщения" : {
|
"Избранные сообщения" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -538,6 +503,9 @@
|
|||||||
},
|
},
|
||||||
"Как связаться с поддержкой?" : {
|
"Как связаться с поддержкой?" : {
|
||||||
"comment" : "FAQ question: support"
|
"comment" : "FAQ question: support"
|
||||||
|
},
|
||||||
|
"Какая вкладка вам нужна?" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Кастомная" : {
|
"Кастомная" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -562,17 +530,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Контент" : {
|
|
||||||
"comment" : "feedback category: content",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Content"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Конфиденциальность" : {
|
"Конфиденциальность" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -736,107 +693,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Мы используем адрес только для ответа на ваш запрос." : {
|
"Мы планируем заменить вкладку. Поделитесь, что бы вы хотели видеть здесь чаще всего." : {
|
||||||
"comment" : "feedback: email hint",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "We’ll only use your email to respond to your request."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Мы постараемся всё исправить. Напишите, что смутило." : {
|
|
||||||
"comment" : "feedback: rating description 2",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "We’ll do our best to fix it. Tell us what felt off."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Мы свяжемся с вами по адресу %@, как только ответим." : {
|
|
||||||
"comment" : "feedback: success email",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "We’ll contact you at %@ once we reply."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Мы читаем каждый отзыв и используем его, чтобы сделать Yobble полезнее для вас." : {
|
|
||||||
"comment" : "feedback: header subtitle",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "We read every piece of feedback and use it to make Yobble better for you."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Напишите нам через форму обратной связи в разделе \"Поддержка\"." : {
|
"Напишите нам через форму обратной связи в разделе \"Поддержка\"." : {
|
||||||
"comment" : "FAQ answer: support"
|
"comment" : "FAQ answer: support"
|
||||||
},
|
},
|
||||||
"Например: заметил неточную информацию в статье..." : {
|
"Например: закладки, друзья, активность..." : {
|
||||||
"comment" : "feedback placeholder: content",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "For example: I noticed inaccurate information in an article…"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Например: понравилась новая лента, потому что..." : {
|
|
||||||
"comment" : "feedback placeholder: praise",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "For example: I liked the new feed because…"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Например: приложение вылетает, когда я открываю профиль..." : {
|
|
||||||
"comment" : "feedback placeholder: bug",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "For example: the app crashes when I open a profile…"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Например: хотелось бы видеть подборку по интересам..." : {
|
|
||||||
"comment" : "feedback placeholder: idea",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "For example: I’d love to see personalized recommendations…"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Насколько вам нравится Yobble?" : {
|
|
||||||
"comment" : "feedback: rating title",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "How much do you like Yobble?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Настройки" : {
|
"Настройки" : {
|
||||||
"comment" : "Settings",
|
"comment" : "Settings",
|
||||||
@ -1060,17 +924,6 @@
|
|||||||
},
|
},
|
||||||
"Необходимо авторизоваться заново." : {
|
"Необходимо авторизоваться заново." : {
|
||||||
|
|
||||||
},
|
|
||||||
"Неплохо, но можно лучше — что добавить?" : {
|
|
||||||
"comment" : "feedback: rating description 3",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Not bad, but it could be better — what would you add?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Нет аккаунта? Регистрация" : {
|
"Нет аккаунта? Регистрация" : {
|
||||||
"comment" : "Регистрация",
|
"comment" : "Регистрация",
|
||||||
@ -1117,28 +970,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Нужно ли вам ответить?" : {
|
|
||||||
"comment" : "feedback: contact title",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Do you need a response?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"О каком контенте идёт речь?" : {
|
|
||||||
"comment" : "feedback prompt: content",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "What content are you referring to?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"О приложении" : {
|
"О приложении" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -1160,7 +991,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Обратная связь" : {
|
"Обратная связь" : {
|
||||||
"comment" : "feedback: navigation title",
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -1170,9 +1000,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Обратная связь (не работает)" : {
|
|
||||||
"comment" : "feedback: navigation title"
|
|
||||||
},
|
|
||||||
"Ограничить таймер автоудаления (максимум)" : {
|
"Ограничить таймер автоудаления (максимум)" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -1185,64 +1012,12 @@
|
|||||||
},
|
},
|
||||||
"Описание" : {
|
"Описание" : {
|
||||||
|
|
||||||
},
|
|
||||||
"Опишите идею" : {
|
|
||||||
"comment" : "feedback prompt: idea",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Describe your idea"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Отображаемое имя" : {
|
"Отображаемое имя" : {
|
||||||
|
|
||||||
},
|
|
||||||
"Отправить отзыв" : {
|
|
||||||
"comment" : "feedback: submit button",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Submit Feedback"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Отправляем..." : {
|
"Отправляем..." : {
|
||||||
"comment" : "feedback: sending state",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Sending..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Оценка %d" : {
|
|
||||||
"comment" : "feedback: rating accessibility",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Rating %d"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Оценка: %d из 5" : {
|
|
||||||
"comment" : "feedback: success rating",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Rating: %d out of 5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Ошибка" : {
|
"Ошибка" : {
|
||||||
"comment" : "Profile update error title",
|
"comment" : "Profile update error title",
|
||||||
@ -1425,28 +1200,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Поделитесь идеями, сообщите об ошибке или расскажите, что работает отлично." : {
|
|
||||||
"comment" : "feedback: info detail",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Share ideas, report a bug, or tell us what works well."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Поделитесь, что понравилось" : {
|
|
||||||
"comment" : "feedback category subtitle: praise",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Share what you liked"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Подтверждение пароля" : {
|
"Подтверждение пароля" : {
|
||||||
"comment" : "Подтверждение пароля",
|
"comment" : "Подтверждение пароля",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1458,17 +1211,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Пожалуйста, введите корректный e-mail." : {
|
|
||||||
"comment" : "feedback: email error",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Please enter a valid email."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Поиск" : {
|
"Поиск" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1515,17 +1257,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Получить ответ от команды" : {
|
|
||||||
"comment" : "feedback: contact toggle",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Get a reply from the team"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Пользователь Системы 1" : {
|
"Пользователь Системы 1" : {
|
||||||
"comment" : "Тестовая подмена офф аккаунта",
|
"comment" : "Тестовая подмена офф аккаунта",
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
@ -1551,39 +1282,6 @@
|
|||||||
},
|
},
|
||||||
"Попробуйте изменить запрос поиска." : {
|
"Попробуйте изменить запрос поиска." : {
|
||||||
|
|
||||||
},
|
|
||||||
"Похвала" : {
|
|
||||||
"comment" : "feedback category: praise",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Praise"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Предложите, что добавить" : {
|
|
||||||
"comment" : "feedback category subtitle: idea",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Suggest what to add"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Прекрасно! Расскажите, что понравилось больше всего." : {
|
|
||||||
"comment" : "feedback: rating description 5",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Amazing! Tell us what you liked the most."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Приватные чаты" : {
|
"Приватные чаты" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1675,17 +1373,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Проблема" : {
|
|
||||||
"comment" : "feedback category: bug",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Bug"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Проверьте данные и повторите попытку." : {
|
"Проверьте данные и повторите попытку." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -1765,28 +1452,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Расскажите о своём опыте" : {
|
|
||||||
"comment" : "feedback: header title",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Tell us about your experience"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Расскажите, что не работает" : {
|
|
||||||
"comment" : "feedback category subtitle: bug",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Tell us what isn’t working"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Регистрация" : {
|
"Регистрация" : {
|
||||||
"comment" : "Регистрация",
|
"comment" : "Регистрация",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1970,17 +1635,6 @@
|
|||||||
},
|
},
|
||||||
"Сообщение" : {
|
"Сообщение" : {
|
||||||
|
|
||||||
},
|
|
||||||
"Сообщите о материалах" : {
|
|
||||||
"comment" : "feedback category subtitle: content",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Report content issues"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Сохранить изменения" : {
|
"Сохранить изменения" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -1992,27 +1646,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Спасибо! Мы получили ваш отзыв" : {
|
"Спасибо!" : {
|
||||||
"comment" : "feedback: success title",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Thank you! We’ve received your feedback"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Спасибо! Что поможет нам добраться до пятёрки?" : {
|
|
||||||
"comment" : "feedback: rating description 4",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Thanks! What would get us to a five?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Старый пароль" : {
|
"Старый пароль" : {
|
||||||
"comment" : "Старый пароль",
|
"comment" : "Старый пароль",
|
||||||
@ -2035,17 +1670,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Тема: %@" : {
|
|
||||||
"comment" : "feedback: success category",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Category: %@"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Тёмная" : {
|
"Тёмная" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -2182,50 +1806,6 @@
|
|||||||
"Черновики доступны в боковом меню в разделе Drafts." : {
|
"Черновики доступны в боковом меню в разделе Drafts." : {
|
||||||
"comment" : "FAQ answer: drafts"
|
"comment" : "FAQ answer: drafts"
|
||||||
},
|
},
|
||||||
"Что вам понравилось?" : {
|
|
||||||
"comment" : "feedback prompt: praise",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "What did you like?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Что вы хотите обсудить?" : {
|
|
||||||
"comment" : "feedback: category title",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "What would you like to talk about?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Что случилось?" : {
|
|
||||||
"comment" : "feedback prompt: bug",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "What happened?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Что-то пошло не так. Расскажите подробности ниже." : {
|
|
||||||
"comment" : "feedback: rating description 1",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Something went wrong. Tell us more below."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Экран чата в разработке" : {
|
"Экран чата в разработке" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,364 +5,127 @@ import UIKit
|
|||||||
|
|
||||||
struct FeedbackView: View {
|
struct FeedbackView: View {
|
||||||
@State private var suggestion: String = ""
|
@State private var suggestion: String = ""
|
||||||
@State private var submittedFeedback: SubmittedFeedback? = nil
|
@State private var submittedSuggestion: String? = nil
|
||||||
@State private var isSubmitting: Bool = false
|
@State private var isSubmitting: Bool = false
|
||||||
@State private var showSubmissionMessage: Bool = false
|
@State private var showSubmissionMessage: Bool = false
|
||||||
@State private var feedbackCategory: FeedbackCategory = .idea
|
@FocusState private var isSuggestionFocused: Bool
|
||||||
@State private var rating: Int = 0
|
|
||||||
@State private var wantsResponse: Bool = false
|
|
||||||
@State private var contactEmail: String = ""
|
|
||||||
@FocusState private var focusedField: Field?
|
|
||||||
|
|
||||||
private let gridColumns = [GridItem(.adaptive(minimum: 120), spacing: 12)]
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(alignment: .leading, spacing: 24) {
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
headerSection
|
Text(NSLocalizedString("Какая вкладка вам нужна?", comment: ""))
|
||||||
infoSection
|
.font(.title2)
|
||||||
categorySection
|
.fontWeight(.semibold)
|
||||||
ratingSection
|
|
||||||
suggestionSection
|
Text(NSLocalizedString(
|
||||||
contactSection
|
"Мы планируем заменить вкладку. Поделитесь, что бы вы хотели видеть здесь чаще всего.",
|
||||||
|
comment: ""
|
||||||
|
))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
|
Text(NSLocalizedString("Ваше предложение", comment: ""))
|
||||||
|
.font(.headline)
|
||||||
|
|
||||||
|
TextEditor(text: $suggestion)
|
||||||
|
.frame(minHeight: 120)
|
||||||
|
.padding(12)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(Color(.systemGray6))
|
||||||
|
)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.stroke(Color(.systemGray4))
|
||||||
|
)
|
||||||
|
.overlay(
|
||||||
|
Group {
|
||||||
|
if suggestion.isEmpty {
|
||||||
|
Text(NSLocalizedString("Например: закладки, друзья, активность...", comment: ""))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.padding(18)
|
||||||
|
.allowsHitTesting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.disableAutocorrection(true)
|
||||||
|
.focused($isSuggestionFocused)
|
||||||
|
}
|
||||||
|
|
||||||
Button(action: submitSuggestion) {
|
Button(action: submitSuggestion) {
|
||||||
HStack(spacing: 10) {
|
HStack {
|
||||||
if isSubmitting {
|
if isSubmitting {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.progressViewStyle(CircularProgressViewStyle())
|
.progressViewStyle(CircularProgressViewStyle())
|
||||||
}
|
}
|
||||||
Text(isSubmitting
|
Text(isSubmitting
|
||||||
? NSLocalizedString("Отправляем...", comment: "feedback: sending state")
|
? NSLocalizedString("Отправляем...", comment: "")
|
||||||
: NSLocalizedString("Отправить отзыв", comment: "feedback: submit button"))
|
: NSLocalizedString("(не работает) Отправить предложение", comment: ""))
|
||||||
.fontWeight(.semibold)
|
.fontWeight(.semibold)
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding()
|
.padding()
|
||||||
.background(buttonBackgroundColor)
|
.background(suggestionIsValid ? Color.accentColor : Color(.systemGray4))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.cornerRadius(16)
|
.cornerRadius(14)
|
||||||
}
|
}
|
||||||
.disabled(!canSubmit)
|
.disabled(!suggestionIsValid || isSubmitting)
|
||||||
|
|
||||||
if let submission = submittedFeedback, showSubmissionMessage {
|
if let submittedSuggestion, showSubmissionMessage {
|
||||||
successSection(for: submission)
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
.transition(.move(edge: .top).combined(with: .opacity))
|
Text(NSLocalizedString("Спасибо!", comment: ""))
|
||||||
|
.font(.headline)
|
||||||
|
Text(String(format: NSLocalizedString("Вы предложили: %@", comment: ""), submittedSuggestion))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
.transition(.opacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(minLength: 16)
|
Spacer(minLength: 24)
|
||||||
|
|
||||||
|
// Text(NSLocalizedString(
|
||||||
|
// "Позже мы добавим отправку на сервер, чтобы собрать статистику, и расскажем о результатах в обновлениях.",
|
||||||
|
// comment: ""
|
||||||
|
// ))
|
||||||
|
// .font(.footnote)
|
||||||
|
// .foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
.padding(.vertical, 32)
|
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
|
.padding(.vertical, 32)
|
||||||
}
|
}
|
||||||
.background(Color(.systemGroupedBackground).ignoresSafeArea())
|
|
||||||
.navigationTitle(NSLocalizedString("Обратная связь (не работает)", comment: "feedback: navigation title"))
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.simultaneousGesture(
|
.simultaneousGesture(
|
||||||
TapGesture().onEnded {
|
TapGesture().onEnded {
|
||||||
dismissKeyboardIfNeeded()
|
dismissKeyboardIfNeeded()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onChange(of: wantsResponse) { wants in
|
|
||||||
if !wants {
|
|
||||||
contactEmail = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var headerSection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
|
||||||
Text(NSLocalizedString("Расскажите о своём опыте", comment: "feedback: header title"))
|
|
||||||
.font(.title2)
|
|
||||||
.fontWeight(.bold)
|
|
||||||
Text(NSLocalizedString("Мы читаем каждый отзыв и используем его, чтобы сделать Yobble полезнее для вас.", comment: "feedback: header subtitle"))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var infoSection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
|
||||||
Label {
|
|
||||||
Text(NSLocalizedString("Поделитесь идеями, сообщите об ошибке или расскажите, что работает отлично.", comment: "feedback: info detail"))
|
|
||||||
} icon: {
|
|
||||||
Image(systemName: "bubble.left.and.bubble.right.fill")
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
}
|
|
||||||
.font(.callout)
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.fill(Color.accentColor.opacity(0.08))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var categorySection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
|
||||||
sectionTitle(NSLocalizedString("Что вы хотите обсудить?", comment: "feedback: category title"))
|
|
||||||
LazyVGrid(columns: gridColumns, alignment: .leading, spacing: 12) {
|
|
||||||
ForEach(FeedbackCategory.allCases) { category in
|
|
||||||
categoryButton(for: category)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var ratingSection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
|
||||||
sectionTitle(NSLocalizedString("Насколько вам нравится Yobble?", comment: "feedback: rating title"))
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
ForEach(1...5, id: \.self) { value in
|
|
||||||
Button {
|
|
||||||
rating = value
|
|
||||||
} label: {
|
|
||||||
Image(systemName: rating >= value ? "star.fill" : "star")
|
|
||||||
.foregroundColor(rating >= value ? Color.yellow : Color(.systemGray3))
|
|
||||||
.font(.title3)
|
|
||||||
.padding(.vertical, 4)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.accessibilityLabel(Text(String(format: NSLocalizedString("Оценка %d", comment: "feedback: rating accessibility"), value)))
|
|
||||||
.accessibilityAddTraits(rating == value ? .isSelected : [])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rating > 0 {
|
|
||||||
Text(ratingDescription(for: rating))
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
} else {
|
|
||||||
Text(NSLocalizedString("Выберите оценку — это поможет нам понять настроение.", comment: "feedback: rating hint"))
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var suggestionSection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
|
||||||
sectionTitle(feedbackCategory.promptTitle)
|
|
||||||
|
|
||||||
TextEditor(text: $suggestion)
|
|
||||||
.frame(minHeight: 140)
|
|
||||||
.padding(12)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
|
||||||
.fill(Color(.systemBackground))
|
|
||||||
)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
|
||||||
.stroke(Color(.systemGray4), lineWidth: 1)
|
|
||||||
)
|
|
||||||
.overlay(
|
|
||||||
Group {
|
|
||||||
if suggestion.isEmpty {
|
|
||||||
Text(feedbackCategory.placeholder)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
.padding(.horizontal, 18)
|
|
||||||
.padding(.vertical, 16)
|
|
||||||
.allowsHitTesting(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.focused($focusedField, equals: .suggestion)
|
|
||||||
.autocorrectionDisabled(false)
|
|
||||||
|
|
||||||
Text(String(format: NSLocalizedString("%d символов", comment: "feedback: character count"), suggestion.count))
|
|
||||||
.font(.caption2)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var contactSection: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
|
||||||
sectionTitle(NSLocalizedString("Нужно ли вам ответить?", comment: "feedback: contact title"))
|
|
||||||
|
|
||||||
Toggle(NSLocalizedString("Получить ответ от команды", comment: "feedback: contact toggle"), isOn: $wantsResponse)
|
|
||||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
|
||||||
|
|
||||||
if wantsResponse {
|
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
|
||||||
TextField(NSLocalizedString("Ваш e-mail", comment: "feedback: email placeholder"), text: $contactEmail)
|
|
||||||
.textContentType(.emailAddress)
|
|
||||||
.textInputAutocapitalization(.never)
|
|
||||||
.keyboardType(.emailAddress)
|
|
||||||
.autocorrectionDisabled(true)
|
|
||||||
.padding(12)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
|
||||||
.fill(Color(.systemBackground))
|
|
||||||
)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
|
||||||
.stroke(emailBorderColor, lineWidth: 1)
|
|
||||||
)
|
|
||||||
.focused($focusedField, equals: .email)
|
|
||||||
|
|
||||||
if !contactEmail.isEmpty && !emailIsValid {
|
|
||||||
Text(NSLocalizedString("Пожалуйста, введите корректный e-mail.", comment: "feedback: email error"))
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.red)
|
|
||||||
} else {
|
|
||||||
Text(NSLocalizedString("Мы используем адрес только для ответа на ваш запрос.", comment: "feedback: email hint"))
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var canSubmit: Bool {
|
|
||||||
suggestionIsValid && emailIsValid && !isSubmitting
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var suggestionIsValid: Bool {
|
private var suggestionIsValid: Bool {
|
||||||
!suggestion.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
!suggestion.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
private var emailIsValid: Bool {
|
|
||||||
guard wantsResponse else { return true }
|
|
||||||
let trimmed = contactEmail.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
guard !trimmed.isEmpty else { return false }
|
|
||||||
return trimmed.contains("@") && trimmed.contains(".")
|
|
||||||
}
|
|
||||||
|
|
||||||
private var buttonBackgroundColor: Color {
|
|
||||||
suggestionIsValid && emailIsValid ? Color.accentColor : Color(.systemGray4)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var emailBorderColor: Color {
|
|
||||||
if contactEmail.isEmpty { return Color(.systemGray4) }
|
|
||||||
return emailIsValid ? Color.accentColor : .red
|
|
||||||
}
|
|
||||||
|
|
||||||
private func sectionTitle(_ text: String) -> some View {
|
|
||||||
Text(text)
|
|
||||||
.font(.headline)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func categoryButton(for category: FeedbackCategory) -> some View {
|
|
||||||
let isSelected = feedbackCategory == category
|
|
||||||
|
|
||||||
return Button {
|
|
||||||
feedbackCategory = category
|
|
||||||
} label: {
|
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
|
||||||
Image(systemName: category.iconName)
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundColor(isSelected ? .accentColor : .secondary)
|
|
||||||
Text(category.title)
|
|
||||||
.fontWeight(.semibold)
|
|
||||||
.foregroundColor(.primary)
|
|
||||||
Text(category.subtitle)
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.padding(.vertical, 14)
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.fill(isSelected ? Color.accentColor.opacity(0.12) : Color(.systemBackground))
|
|
||||||
)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.stroke(isSelected ? Color.accentColor : Color(.systemGray4), lineWidth: isSelected ? 2 : 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func ratingDescription(for rating: Int) -> String {
|
|
||||||
switch rating {
|
|
||||||
case 1:
|
|
||||||
return NSLocalizedString("Что-то пошло не так. Расскажите подробности ниже.", comment: "feedback: rating description 1")
|
|
||||||
case 2:
|
|
||||||
return NSLocalizedString("Мы постараемся всё исправить. Напишите, что смутило.", comment: "feedback: rating description 2")
|
|
||||||
case 3:
|
|
||||||
return NSLocalizedString("Неплохо, но можно лучше — что добавить?", comment: "feedback: rating description 3")
|
|
||||||
case 4:
|
|
||||||
return NSLocalizedString("Спасибо! Что поможет нам добраться до пятёрки?", comment: "feedback: rating description 4")
|
|
||||||
case 5:
|
|
||||||
return NSLocalizedString("Прекрасно! Расскажите, что понравилось больше всего.", comment: "feedback: rating description 5")
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func submitSuggestion() {
|
private func submitSuggestion() {
|
||||||
guard canSubmit else { return }
|
guard suggestionIsValid else { return }
|
||||||
|
let trimmed = suggestion.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
let trimmedSuggestion = suggestion.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
let trimmedEmail = contactEmail.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
||||||
|
|
||||||
dismissKeyboardIfNeeded()
|
dismissKeyboardIfNeeded()
|
||||||
|
|
||||||
isSubmitting = true
|
isSubmitting = true
|
||||||
showSubmissionMessage = false
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) { // имитируем сетевой вызов
|
||||||
|
submittedSuggestion = trimmed
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
|
|
||||||
submittedFeedback = SubmittedFeedback(
|
|
||||||
suggestion: trimmedSuggestion,
|
|
||||||
category: feedbackCategory,
|
|
||||||
rating: rating,
|
|
||||||
email: wantsResponse ? trimmedEmail : nil
|
|
||||||
)
|
|
||||||
suggestion = ""
|
suggestion = ""
|
||||||
rating = 0
|
|
||||||
if !wantsResponse {
|
|
||||||
contactEmail = ""
|
|
||||||
}
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
showSubmissionMessage = true
|
showSubmissionMessage = true
|
||||||
}
|
}
|
||||||
isSubmitting = false
|
isSubmitting = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func successSection(for submission: SubmittedFeedback) -> some View {
|
private extension FeedbackView {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
func dismissKeyboardIfNeeded() {
|
||||||
Label {
|
guard isSuggestionFocused else { return }
|
||||||
Text(NSLocalizedString("Спасибо! Мы получили ваш отзыв", comment: "feedback: success title"))
|
isSuggestionFocused = false
|
||||||
} icon: {
|
|
||||||
Image(systemName: "checkmark.seal.fill")
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
}
|
|
||||||
.font(.headline)
|
|
||||||
|
|
||||||
Text(String(format: NSLocalizedString("Тема: %@", comment: "feedback: success category"), submission.category.title))
|
|
||||||
.font(.subheadline)
|
|
||||||
|
|
||||||
if submission.rating > 0 {
|
|
||||||
Text(String(format: NSLocalizedString("Оценка: %d из 5", comment: "feedback: success rating"), submission.rating))
|
|
||||||
.font(.subheadline)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !submission.suggestion.isEmpty {
|
|
||||||
Text(submission.suggestion)
|
|
||||||
.font(.callout)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let email = submission.email, !email.isEmpty {
|
|
||||||
Text(String(format: NSLocalizedString("Мы свяжемся с вами по адресу %@, как только ответим.", comment: "feedback: success email"), email))
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 16, style: .continuous)
|
|
||||||
.fill(Color.accentColor.opacity(0.12))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func dismissKeyboardIfNeeded() {
|
|
||||||
guard focusedField != nil else { return }
|
|
||||||
focusedField = nil
|
|
||||||
|
|
||||||
#if canImport(UIKit)
|
#if canImport(UIKit)
|
||||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||||
@ -370,99 +133,9 @@ struct FeedbackView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension FeedbackView {
|
|
||||||
enum Field: Hashable {
|
|
||||||
case suggestion
|
|
||||||
case email
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SubmittedFeedback {
|
|
||||||
let suggestion: String
|
|
||||||
let category: FeedbackCategory
|
|
||||||
let rating: Int
|
|
||||||
let email: String?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FeedbackCategory: String, CaseIterable, Identifiable {
|
|
||||||
case idea
|
|
||||||
case bug
|
|
||||||
case praise
|
|
||||||
case content
|
|
||||||
|
|
||||||
var id: String { rawValue }
|
|
||||||
|
|
||||||
var title: String {
|
|
||||||
switch self {
|
|
||||||
case .idea:
|
|
||||||
return NSLocalizedString("Идея", comment: "feedback category: idea")
|
|
||||||
case .bug:
|
|
||||||
return NSLocalizedString("Проблема", comment: "feedback category: bug")
|
|
||||||
case .praise:
|
|
||||||
return NSLocalizedString("Похвала", comment: "feedback category: praise")
|
|
||||||
case .content:
|
|
||||||
return NSLocalizedString("Контент", comment: "feedback category: content")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var subtitle: String {
|
|
||||||
switch self {
|
|
||||||
case .idea:
|
|
||||||
return NSLocalizedString("Предложите, что добавить", comment: "feedback category subtitle: idea")
|
|
||||||
case .bug:
|
|
||||||
return NSLocalizedString("Расскажите, что не работает", comment: "feedback category subtitle: bug")
|
|
||||||
case .praise:
|
|
||||||
return NSLocalizedString("Поделитесь, что понравилось", comment: "feedback category subtitle: praise")
|
|
||||||
case .content:
|
|
||||||
return NSLocalizedString("Сообщите о материалах", comment: "feedback category subtitle: content")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var iconName: String {
|
|
||||||
switch self {
|
|
||||||
case .idea:
|
|
||||||
return "lightbulb"
|
|
||||||
case .bug:
|
|
||||||
return "ant"
|
|
||||||
case .praise:
|
|
||||||
return "heart.fill"
|
|
||||||
case .content:
|
|
||||||
return "doc.richtext"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var promptTitle: String {
|
|
||||||
switch self {
|
|
||||||
case .idea:
|
|
||||||
return NSLocalizedString("Опишите идею", comment: "feedback prompt: idea")
|
|
||||||
case .bug:
|
|
||||||
return NSLocalizedString("Что случилось?", comment: "feedback prompt: bug")
|
|
||||||
case .praise:
|
|
||||||
return NSLocalizedString("Что вам понравилось?", comment: "feedback prompt: praise")
|
|
||||||
case .content:
|
|
||||||
return NSLocalizedString("О каком контенте идёт речь?", comment: "feedback prompt: content")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var placeholder: String {
|
|
||||||
switch self {
|
|
||||||
case .idea:
|
|
||||||
return NSLocalizedString("Например: хотелось бы видеть подборку по интересам...", comment: "feedback placeholder: idea")
|
|
||||||
case .bug:
|
|
||||||
return NSLocalizedString("Например: приложение вылетает, когда я открываю профиль...", comment: "feedback placeholder: bug")
|
|
||||||
case .praise:
|
|
||||||
return NSLocalizedString("Например: понравилась новая лента, потому что...", comment: "feedback placeholder: praise")
|
|
||||||
case .content:
|
|
||||||
return NSLocalizedString("Например: заметил неточную информацию в статье...", comment: "feedback placeholder: content")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FeedbackView_Previews: PreviewProvider {
|
struct FeedbackView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationView {
|
|
||||||
FeedbackView()
|
FeedbackView()
|
||||||
.environmentObject(ThemeManager())
|
.environmentObject(ThemeManager())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user