feat: add haptic feedback toggle setting
- Add haptic_enabled field to AppDTO with default value true - Update SettingsSerializerService to deserialize haptic_enabled - Add haptic_enabled setting in admin panel (GeneralView) with toggle - Update admin settings store to include haptic_enabled default value - Update SPA SettingsStore to load haptic_enabled from API - Refactor useHapticFeedback composable to return safe wrapper object - Replace all direct window.Telegram.WebApp.HapticFeedback usage with composable - Update useHapticScroll to use useHapticFeedback composable - Add getHapticFeedback helper function in CheckoutStore for store usage - Add haptic_enabled default value to app.php configuration - All haptic feedback methods now check settings internally - Remove redundant if checks from components (handled in composable)
This commit is contained in:
@@ -20,6 +20,7 @@ export const useSettingsStore = defineStore('settings', {
|
||||
privacy_policy_link: null,
|
||||
image_aspect_ratio: '1:1',
|
||||
image_crop_algorithm: 'cover',
|
||||
haptic_enabled: true,
|
||||
},
|
||||
|
||||
telegram: {
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
<li><strong>Resize</strong> - изменяет размер изображения с сохранением пропорций (без обрезки)</li>
|
||||
</ul>
|
||||
</ItemSelect>
|
||||
|
||||
<ItemBool label="Тактильная обратная связь (Haptic Feedback)" v-model="settings.items.app.haptic_enabled">
|
||||
Включить виброотклик при взаимодействии с элементами интерфейса. Если выключено, тактильная обратная связь не будет использоваться.
|
||||
</ItemBool>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
@@ -62,6 +62,7 @@ import AppDebugMessage from "@/components/AppDebugMessage.vue";
|
||||
import PrivacyPolicy from "@/components/PrivacyPolicy.vue";
|
||||
import BrowserNotSupported from "@/BrowserNotSupported.vue";
|
||||
import {useSwipeBack} from "@/composables/useSwipeBack.js";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@@ -69,7 +70,7 @@ const settings = useSettingsStore();
|
||||
const filtersStore = useProductFiltersStore();
|
||||
const keyboardStore = useKeyboardStore();
|
||||
const backButton = window.Telegram.WebApp.BackButton;
|
||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||
const haptic = useHapticFeedback();
|
||||
const swiperBack = useSwipeBack();
|
||||
|
||||
const routesToHideAppDock = [
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
import {computed, onMounted} from "vue";
|
||||
import {useCartStore} from "@/stores/CartStore.js";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const cart = useCartStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const isCartBtnShow = computed(() => {
|
||||
return route.name === 'product.show';
|
||||
@@ -29,7 +31,7 @@ const isCartBtnShow = computed(() => {
|
||||
|
||||
|
||||
function openCart() {
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
router.push({name: 'cart'});
|
||||
}
|
||||
|
||||
|
||||
@@ -84,12 +84,13 @@ import {useRoute} from "vue-router";
|
||||
import {useCartStore} from "@/stores/CartStore.js";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import {useTgData} from "@/composables/useTgData.js";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const route = useRoute();
|
||||
const cart = useCartStore();
|
||||
const settings = useSettingsStore();
|
||||
const tgData = useTgData();
|
||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
function onDockItemClick(event) {
|
||||
haptic.selectionChanged();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
import {Navigation, Pagination, Zoom} from "swiper/modules";
|
||||
import {Swiper, SwiperSlide} from "swiper/vue";
|
||||
import {onMounted} from "vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const props = defineProps({
|
||||
images: {
|
||||
@@ -49,11 +50,12 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
const emits = defineEmits(['close']);
|
||||
const haptic = useHapticFeedback();
|
||||
let canVibrate = true;
|
||||
|
||||
function vibrate() {
|
||||
if (!canVibrate) return;
|
||||
window.Telegram.WebApp.HapticFeedback.impactOccurred('soft');
|
||||
haptic.impactOccurred('soft');
|
||||
canVibrate = false;
|
||||
setTimeout(() => {
|
||||
canVibrate = true;
|
||||
@@ -61,7 +63,7 @@ function vibrate() {
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
window.Telegram.WebApp.HapticFeedback.impactOccurred('medium');
|
||||
haptic.impactOccurred('medium');
|
||||
emits('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const isLoading = ref(false);
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const props = defineProps({
|
||||
block: {
|
||||
@@ -41,6 +43,6 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
function onCategoryClick() {
|
||||
window.Telegram.WebApp.HapticFeedback.impactOccurred('soft');
|
||||
haptic.impactOccurred('soft');
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -66,9 +66,10 @@ import IconFunnel from "@/components/Icons/IconFunnel.vue";
|
||||
import {useProductFiltersStore} from "@/stores/ProductFiltersStore.js";
|
||||
import {useRouter} from "vue-router";
|
||||
import PriceTitle from "@/components/ProductItem/PriceTitle.vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const router = useRouter();
|
||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||
const haptic = useHapticFeedback();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const settings = useSettingsStore();
|
||||
const filtersStore = useProductFiltersStore();
|
||||
@@ -104,7 +105,7 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
function productClick(product, index) {
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
yaMetrika.dataLayerPush({
|
||||
"ecommerce": {
|
||||
"currencyCode": settings.currency_code,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const model = defineModel();
|
||||
const props = defineProps({
|
||||
@@ -22,6 +23,8 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const btnClassList = computed(() => {
|
||||
let classList = ['btn'];
|
||||
if (props.size) {
|
||||
@@ -33,7 +36,7 @@ const btnClassList = computed(() => {
|
||||
function inc() {
|
||||
if (props.disabled) return;
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
|
||||
if (props.max && model.value + 1 > props.max) {
|
||||
model.value = props.max;
|
||||
@@ -46,7 +49,7 @@ function inc() {
|
||||
function dec() {
|
||||
if (props.disabled) return;
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
|
||||
if (model.value - 1 >= 1) {
|
||||
model.value--;
|
||||
|
||||
@@ -26,13 +26,15 @@
|
||||
<script setup>
|
||||
import {useRouter} from "vue-router";
|
||||
import {useSearchStore} from "@/stores/SearchStore.js";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const router = useRouter();
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
function showSearchPage() {
|
||||
router.push({name: 'search'});
|
||||
useSearchStore().reset();
|
||||
window.Telegram.WebApp.HapticFeedback.impactOccurred('medium');
|
||||
haptic.impactOccurred('medium');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,3 +1,39 @@
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
|
||||
/**
|
||||
* Composable для безопасной работы с HapticFeedback
|
||||
* Проверяет настройку haptic_enabled перед использованием
|
||||
* @returns {object} Объект с методами haptic feedback, которые безопасно вызываются
|
||||
*/
|
||||
export function useHapticFeedback() {
|
||||
return window.Telegram?.WebApp?.HapticFeedback;
|
||||
const settings = useSettingsStore();
|
||||
const haptic = window.Telegram?.WebApp?.HapticFeedback;
|
||||
|
||||
// Возвращаем обёртку с методами, которые проверяют настройку при каждом вызове
|
||||
return {
|
||||
impactOccurred: (style) => {
|
||||
// Проверяем настройку при каждом вызове (реактивно)
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.impactOccurred) {
|
||||
return;
|
||||
}
|
||||
haptic.impactOccurred(style);
|
||||
},
|
||||
selectionChanged: () => {
|
||||
// Проверяем настройку при каждом вызове (реактивно)
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.selectionChanged) {
|
||||
return;
|
||||
}
|
||||
haptic.selectionChanged();
|
||||
},
|
||||
notificationOccurred: (type) => {
|
||||
// Проверяем настройку при каждом вызове (реактивно)
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.notificationOccurred) {
|
||||
return;
|
||||
}
|
||||
haptic.notificationOccurred(type);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {ref} from 'vue';
|
||||
import {useHapticFeedback} from './useHapticFeedback.js';
|
||||
|
||||
/**
|
||||
* Composable для Haptic Feedback по свайпу
|
||||
@@ -13,6 +14,7 @@ export function useHapticScroll(
|
||||
feedback = 'soft'
|
||||
) {
|
||||
const lastTranslate = ref(0);
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
return function (
|
||||
swiper
|
||||
@@ -20,14 +22,11 @@ export function useHapticScroll(
|
||||
const current = Math.abs(swiper.translate);
|
||||
const delta = Math.abs(current - lastTranslate.value);
|
||||
|
||||
if (delta > threshold) {
|
||||
const haptic = window.Telegram?.WebApp?.HapticFeedback;
|
||||
if (haptic) {
|
||||
if (type === 'impactOccurred' && haptic.impactOccurred) {
|
||||
haptic.impactOccurred(feedback);
|
||||
} else if (type === 'selectionChanged' && haptic.selectionChanged) {
|
||||
haptic.selectionChanged();
|
||||
}
|
||||
if (delta > threshold && haptic) {
|
||||
if (type === 'impactOccurred' && haptic.impactOccurred) {
|
||||
haptic.impactOccurred(feedback);
|
||||
} else if (type === 'selectionChanged' && haptic.selectionChanged) {
|
||||
haptic.selectionChanged();
|
||||
}
|
||||
lastTranslate.value = current;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,40 @@ import {usePulseStore} from "@/stores/Pulse.js";
|
||||
import {TC_PULSE_EVENTS} from "@/constants/tPulseEvents.js";
|
||||
import {nextTick} from "vue";
|
||||
|
||||
/**
|
||||
* Helper функция для получения haptic feedback (можно использовать в store)
|
||||
* @returns {object} Объект с методами haptic feedback
|
||||
*/
|
||||
function getHapticFeedback() {
|
||||
const settings = useSettingsStore();
|
||||
const haptic = window.Telegram?.WebApp?.HapticFeedback;
|
||||
|
||||
// Возвращаем обёртку с методами, которые проверяют настройку при каждом вызове
|
||||
return {
|
||||
impactOccurred: (style) => {
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.impactOccurred) {
|
||||
return;
|
||||
}
|
||||
haptic.impactOccurred(style);
|
||||
},
|
||||
selectionChanged: () => {
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.selectionChanged) {
|
||||
return;
|
||||
}
|
||||
haptic.selectionChanged();
|
||||
},
|
||||
notificationOccurred: (type) => {
|
||||
const isHapticEnabled = settings.haptic_enabled !== false;
|
||||
if (!haptic || !isHapticEnabled || !haptic.notificationOccurred) {
|
||||
return;
|
||||
}
|
||||
haptic.notificationOccurred(type);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const useCheckoutStore = defineStore('checkout', {
|
||||
state: () => ({
|
||||
form: {},
|
||||
@@ -95,7 +129,8 @@ export const useCheckoutStore = defineStore('checkout', {
|
||||
});
|
||||
});
|
||||
|
||||
await window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||
const haptic = getHapticFeedback();
|
||||
await haptic.notificationOccurred('success');
|
||||
await useCartStore().getProducts();
|
||||
} catch (error) {
|
||||
if (error.response?.status === 422) {
|
||||
@@ -104,7 +139,8 @@ export const useCheckoutStore = defineStore('checkout', {
|
||||
console.error('Server error', error);
|
||||
}
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('error');
|
||||
const haptic = getHapticFeedback();
|
||||
haptic.notificationOccurred('error');
|
||||
|
||||
this.errorMessage = 'Возникла ошибка при создании заказа.';
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export const useSettingsStore = defineStore('settings', {
|
||||
feature_vouchers: false,
|
||||
show_category_products_button: true,
|
||||
currency_code: null,
|
||||
haptic_enabled: true,
|
||||
theme: {
|
||||
light: 'light', dark: 'dark', variables: {
|
||||
'--product_list_title_max_lines': 2,
|
||||
@@ -53,6 +54,7 @@ export const useSettingsStore = defineStore('settings', {
|
||||
this.mainpage_blocks = settings.mainpage_blocks;
|
||||
this.privacy_policy_link = settings.privacy_policy_link;
|
||||
this.image_aspect_ratio = settings.image_aspect_ratio;
|
||||
this.haptic_enabled = settings.haptic_enabled ?? true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -82,6 +82,7 @@ import {onMounted, onUnmounted} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {usePulseStore} from "@/stores/Pulse.js";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Account'
|
||||
@@ -92,6 +93,7 @@ const settings = useSettingsStore();
|
||||
const route = useRoute();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const pulse = usePulseStore();
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const username = computed(() => {
|
||||
if (tgData?.user?.first_name || tgData?.user?.last_name) {
|
||||
@@ -136,7 +138,7 @@ function openManagerChat() {
|
||||
return;
|
||||
}
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
|
||||
// Формируем ссылку для открытия чата с менеджером
|
||||
const managerUsername = String(settings.manager_username).trim();
|
||||
@@ -149,7 +151,7 @@ function openManagerChat() {
|
||||
}
|
||||
|
||||
function handleHomeScreenAdded() {
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||
haptic.notificationOccurred('success');
|
||||
window.Telegram.WebApp.showAlert('Приложение успешно добавлено на главный экран!');
|
||||
isHomeScreenAdded.value = true;
|
||||
}
|
||||
@@ -169,7 +171,7 @@ function checkHomeScreenSupport() {
|
||||
}
|
||||
|
||||
function addToHomeScreen() {
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
|
||||
// Используем Telegram Web App API для добавления на главный экран
|
||||
if (window.Telegram?.WebApp?.addToHomeScreen) {
|
||||
|
||||
@@ -153,12 +153,14 @@ import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import BaseViewWrapper from "@/views/BaseViewWrapper.vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const route = useRoute();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const cart = useCartStore();
|
||||
const router = useRouter();
|
||||
const settings = useSettingsStore();
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
// const componentMap = {
|
||||
// radio: OptionRadio,
|
||||
@@ -174,7 +176,7 @@ const lastTotal = computed(() => {
|
||||
|
||||
function removeItem(cartItem, cartId, index) {
|
||||
cart.removeItem(cartItem, cartId, index);
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('error');
|
||||
haptic.notificationOccurred('error');
|
||||
}
|
||||
|
||||
function goToCheckout() {
|
||||
|
||||
@@ -53,6 +53,7 @@ import {useRoute, useRouter} from "vue-router";
|
||||
import ProductCategory from "@/components/ProductFilters/Components/ProductCategory/ProductCategory.vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Filters'
|
||||
@@ -70,7 +71,7 @@ const route = useRoute();
|
||||
const emit = defineEmits(['close', 'apply']);
|
||||
|
||||
const filtersStore = useProductFiltersStore();
|
||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const applyFilters = async () => {
|
||||
filtersStore.applied = JSON.parse(JSON.stringify(filtersStore.draft));
|
||||
|
||||
@@ -17,6 +17,7 @@ import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import MainPage from "@/components/MainPage/MainPage.vue";
|
||||
import {useBlocksStore} from "@/stores/BlocksStore.js";
|
||||
import Navbar from "@/components/Navbar.vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Home'
|
||||
@@ -25,7 +26,7 @@ defineOptions({
|
||||
const router = useRouter();
|
||||
const filtersStore = useProductFiltersStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||
const haptic = useHapticFeedback();
|
||||
const settings = useSettingsStore();
|
||||
const blocks = useBlocksStore();
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import Loader from "@/components/Loader.vue";
|
||||
import SingleProductImageSwiper from "@/components/SingleProductImageSwiper.vue";
|
||||
import {useHapticFeedback} from "@/composables/useHapticFeedback.js";
|
||||
|
||||
const route = useRoute();
|
||||
const productId = computed(() => route.params.id);
|
||||
@@ -247,6 +248,7 @@ const settings = useSettingsStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const imagesLoaded = ref(false);
|
||||
const images = ref([]);
|
||||
const haptic = useHapticFeedback();
|
||||
|
||||
const canAddToCart = computed(() => {
|
||||
if (!product.value || product.value.options === undefined || product.value.options?.length === 0) {
|
||||
@@ -269,7 +271,7 @@ async function onCartBtnClick() {
|
||||
if (isInCart.value === false) {
|
||||
await cart.addProduct(productId.value, product.value.name, product.value.price, quantity.value, product.value.options);
|
||||
isInCart.value = true;
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||
haptic.notificationOccurred('success');
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.ADD_TO_CART, {
|
||||
price: product.value.final_price_numeric,
|
||||
currency: product.value.currency,
|
||||
@@ -294,12 +296,12 @@ async function onCartBtnClick() {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
await router.push({'name': 'cart'});
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
await window.Telegram.WebApp.HapticFeedback.notificationOccurred('error');
|
||||
await haptic.notificationOccurred('error');
|
||||
error.value = e.message;
|
||||
}
|
||||
}
|
||||
@@ -322,7 +324,7 @@ function openManagerChat() {
|
||||
return;
|
||||
}
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
|
||||
// Формируем ссылку для открытия чата с менеджером
|
||||
// manager_username должен быть username (например, @username)
|
||||
@@ -340,7 +342,7 @@ function openManagerChat() {
|
||||
|
||||
function setQuantity(newQuantity) {
|
||||
quantity.value = newQuantity;
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
haptic.selectionChanged();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
@@ -10,6 +10,7 @@ return [
|
||||
"app_debug" => false,
|
||||
'image_aspect_ratio' => '1:1',
|
||||
'image_crop_algorithm' => 'cover',
|
||||
'haptic_enabled' => true,
|
||||
],
|
||||
|
||||
'telegram' => [
|
||||
|
||||
@@ -12,6 +12,7 @@ final class AppDTO
|
||||
private bool $appDebug;
|
||||
private int $languageId;
|
||||
private string $shopBaseUrl;
|
||||
private bool $hapticEnabled;
|
||||
|
||||
public function __construct(
|
||||
bool $appEnabled,
|
||||
@@ -21,7 +22,8 @@ final class AppDTO
|
||||
string $themeDark,
|
||||
bool $appDebug,
|
||||
int $languageId,
|
||||
string $shopBaseUrl
|
||||
string $shopBaseUrl,
|
||||
bool $hapticEnabled = true
|
||||
) {
|
||||
$this->appEnabled = $appEnabled;
|
||||
$this->appName = $appName;
|
||||
@@ -31,6 +33,7 @@ final class AppDTO
|
||||
$this->appDebug = $appDebug;
|
||||
$this->languageId = $languageId;
|
||||
$this->shopBaseUrl = $shopBaseUrl;
|
||||
$this->hapticEnabled = $hapticEnabled;
|
||||
}
|
||||
|
||||
public function isAppEnabled(): bool
|
||||
@@ -73,6 +76,11 @@ final class AppDTO
|
||||
return $this->shopBaseUrl;
|
||||
}
|
||||
|
||||
public function isHapticEnabled(): bool
|
||||
{
|
||||
return $this->hapticEnabled;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
@@ -84,6 +92,7 @@ final class AppDTO
|
||||
'app_debug' => $this->isAppDebug(),
|
||||
'language_id' => $this->getLanguageId(),
|
||||
'shop_base_url' => $this->getShopBaseUrl(),
|
||||
'haptic_enabled' => $this->isHapticEnabled(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class SettingsHandler
|
||||
'mainpage_blocks' => $this->settings->get('mainpage_blocks', []),
|
||||
'privacy_policy_link' => $this->settings->get('app.privacy_policy_link'),
|
||||
'image_aspect_ratio' => $this->settings->get('app.image_aspect_ratio', '1:1'),
|
||||
'haptic_enabled' => $appConfig->isHapticEnabled(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,8 @@ class SettingsSerializerService
|
||||
$data['theme_dark'] ?? 'dark',
|
||||
$data['app_debug'] ?? false,
|
||||
$data['language_id'],
|
||||
$data['shop_base_url']
|
||||
$data['shop_base_url'],
|
||||
$data['haptic_enabled'] ?? true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user