OTA.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <template>
  2. <transition
  3. name="fade"
  4. mode="out-in"
  5. >
  6. <div
  7. v-if="showForm && update"
  8. class="fixed z-[1000] top-0 left-0 w-screen h-screen bg-black bg-opacity-70 flex justify-center items-end"
  9. >
  10. <div
  11. ref="target"
  12. :class="showForm ? 'show-up' : 'show-down'"
  13. class="w-full bg-background-200 flex flex-col gap-1 rounded-t-xl text-foreground p-5 justify-center items-center"
  14. >
  15. <div @click="showForm = false" class="absolute top-3 right-1">
  16. <IClose
  17. class="h-[48px] w-[48px] fill-red-400 stroke-red-400"
  18. />
  19. </div>
  20. <h1 class="text-2xl font-semibold">
  21. Обновление
  22. </h1>
  23. <div class="flex text-md opacity-50 gap-2">
  24. <p>{{ update[2] || 'Текущая версия' }}</p>
  25. <img :src="`/icons/right-arrow.svg`">
  26. <p>{{ update[1] || 'Новая версия' }}</p>
  27. </div>
  28. <div class="w-full border-b-[1px] border-foreground border-opacity-30 my-1" />
  29. <div class="w-full max-h-[30vh] overflow-y-scroll transition-all">
  30. <template v-if="description && description.features && description.features.length > 0">
  31. <p class="font-bold">
  32. Нововведения
  33. </p>
  34. <ul class="list-disc list-inside text-sm">
  35. <li
  36. v-for="(feat, idx) in description.features"
  37. :key="idx"
  38. >
  39. {{ feat }}
  40. </li>
  41. </ul>
  42. </template>
  43. <template v-if="description && description.bugfixes && description.bugfixes.length > 0">
  44. <p class="font-bold">
  45. Исправления
  46. </p>
  47. <ul class="list-disc list-inside text-sm">
  48. <li
  49. v-for="(fix, idx) in description.bugfixes"
  50. :key="idx"
  51. >
  52. {{ fix }}
  53. </li>
  54. </ul>
  55. </template>
  56. </div>
  57. <div class="w-full border-b-[1px] border-foreground border-opacity-30 my-1" />
  58. <div class="w-full flex justify-center items-center mt-2">
  59. <NuxtLink v-if="update[3]">
  60. <button
  61. class="border-[1px] text-xl px-12 py-1 border-primary hover:bg-primary hover:text-black rounded-xl flex gap-3 justify-center items-center duration-150"
  62. @click="installUpdate"
  63. >
  64. <svg
  65. xmlns="http://www.w3.org/2000/svg"
  66. width="24"
  67. height="24"
  68. viewBox="0 0 24 24"
  69. ><g
  70. fill="none"
  71. stroke="currentColor"
  72. stroke-linecap="round"
  73. stroke-linejoin="round"
  74. stroke-width="2"
  75. ><path
  76. stroke-dasharray="2 4"
  77. stroke-dashoffset="6"
  78. d="M12 3c4.97 0 9 4.03 9 9c0 4.97 -4.03 9 -9 9"
  79. ><animate
  80. attributeName="stroke-dashoffset"
  81. dur="0.6s"
  82. repeatCount="indefinite"
  83. values="6;0"
  84. /></path><path
  85. stroke-dasharray="32"
  86. stroke-dashoffset="32"
  87. d="M12 21c-4.97 0 -9 -4.03 -9 -9c0 -4.97 4.03 -9 9 -9"
  88. ><animate
  89. fill="freeze"
  90. attributeName="stroke-dashoffset"
  91. begin="0.1s"
  92. dur="0.4s"
  93. values="32;0"
  94. /></path><path
  95. stroke-dasharray="10"
  96. stroke-dashoffset="10"
  97. d="M12 8v7.5"
  98. ><animate
  99. fill="freeze"
  100. attributeName="stroke-dashoffset"
  101. begin="0.5s"
  102. dur="0.2s"
  103. values="10;0"
  104. /></path><path
  105. stroke-dasharray="6"
  106. stroke-dashoffset="6"
  107. d="M12 15.5l3.5 -3.5M12 15.5l-3.5 -3.5"
  108. ><animate
  109. fill="freeze"
  110. attributeName="stroke-dashoffset"
  111. begin="0.7s"
  112. dur="0.2s"
  113. values="6;0"
  114. /></path></g></svg>
  115. Скачать обновление
  116. </button>
  117. </NuxtLink>
  118. <button
  119. v-else
  120. class="border-[1px] text-xl px-12 py-1 border-neutral-600 text-neutral-600 rounded-xl flex gap-3 justify-center items-center duration-150"
  121. >
  122. Ссылка временно недоступна
  123. </button>
  124. </div>
  125. </div>
  126. </div>
  127. </transition>
  128. </template>
  129. <script setup lang="ts">
  130. import { onClickOutside } from '@vueuse/core'
  131. import { Browser } from '@capacitor/browser'
  132. import { useOTA } from '~/composables/useOTA'
  133. type UpdateInfo = [boolean, string, string, string] | undefined;
  134. interface Description {
  135. features: string[];
  136. bugfixes: string[];
  137. }
  138. const { needsUpdate, getDescription } = await useOTA()
  139. const log = useLogger('OTAComponent')
  140. const update = ref<UpdateInfo>(needsUpdate() as UpdateInfo)
  141. const description = ref<Description | undefined>()
  142. const target = ref(null)
  143. const showForm = ref(false)
  144. if (update.value) {
  145. showForm.value = true
  146. description.value = getDescription() as Description
  147. }
  148. log.log(update.value);
  149. async function installUpdate() {
  150. if (!update.value?.[3]) {
  151. log.error('Не удалось получить ссылку на обновление')
  152. return
  153. }
  154. try {
  155. await Browser.open({ url: String(update.value[3]) })
  156. } catch (error) {
  157. log.error('Не удалось открыть ссылку на обновление:', error)
  158. }
  159. }
  160. onClickOutside(target, () => {
  161. showForm.value = false
  162. })
  163. </script>
  164. <style scoped>
  165. @keyframes showUp {
  166. 0% { transform: translateY(30vh); }
  167. 100% { transform: translateY(0px) }
  168. }
  169. @keyframes showDown {
  170. 0% { transform: translateY(0px); }
  171. 100% { transform: translateY(30vh) }
  172. }
  173. .show-up {
  174. animation: showUp 300ms ease-in-out;
  175. animation-fill-mode: forwards;
  176. }
  177. .show-down {
  178. animation: showDown 300ms ease-in-out;
  179. animation-fill-mode: forwards;
  180. }
  181. .fade-enter-active,
  182. .fade-leave-active {
  183. transition: opacity 300ms ease-in-out;
  184. }
  185. .fade-enter {
  186. opacity: 0;
  187. }
  188. .fade-leave-to {
  189. opacity: 0;
  190. }
  191. </style>