Add guaranteed icon on wish counter page

This commit is contained in:
Made Baruna 2022-02-16 02:34:57 +07:00
parent affe44be7c
commit f6e884a177
7 changed files with 195 additions and 20 deletions

View file

@ -28,6 +28,7 @@
<style>
.tooltip {
@apply text-background rounded-xl bg-gray-400 border border-gray-800 p-2 absolute text-sm;
@apply p-2 absolute rounded-xl bg-gray-400 border border-gray-800;
@apply text-sm text-background z-10;
}
</style>

View file

@ -314,6 +314,17 @@ export const banners = {
// featured: ['zhongli', 'ganyu'],
// featuredRare: ['xingqiu', 'beidou', 'yanfei'],
// },
{
name: 'Everbloom Violet',
image: 1,
shortName: 'Yae',
start: '2022-02-16 06:00:00',
end: '2022-03-08 17:59:59',
color: '#ffd1f9',
featured: ['yae_miko'],
featuredRare: ['thoma', 'diona', 'fischl'],
timezoneDependent: true,
},
],
weapons: [
{
@ -581,5 +592,16 @@ export const banners = {
featured: ['amos_bow', 'vortex_vanquisher'],
featuredRare: ['lithic_blade', 'favonius_sword', 'dragons_bane', 'favonius_codex', 'sacrificial_bow'],
},
{
name: 'Epitome Invocation',
image: 25,
start: '2022-02-16 06:00:00',
end: '2022-03-08 17:59:59',
shortName: 'Verity',
color: '#b042f5',
featured: ['kaguras_verity', 'primordial_jade_cutter'],
featuredRare: ['wavebreakers_fin', 'sacrificial_sword', 'rainslasher', 'eye_of_perception', 'the_stringless'],
timezoneDependent: true,
},
],
};

View file

@ -448,6 +448,10 @@
"won": "Won 50:50",
"lost": "Lost 50:50",
"guaranteed": "Guaranteed"
},
"backupReminder": {
"title": "All data are saved on your browser!",
"desc": "So if by any chance the browser cache got deleted, your wish history will be gone! You can enable Google Drive sync on setting to backup your data, or download the data manually there."
}
},
"calculator": {

View file

@ -47,6 +47,7 @@
let errorProcessingPull = null;
const bannerType = bannerTypes[id];
const withRateIcon = bannerType === 'characters' || bannerType === 'weapons';
let bannerChart;
let pieChart;
@ -208,16 +209,20 @@
};
if (item.rarity === 5) {
newPull.guaranteed = rateUp;
rateUp = !currentBanner.featured.includes(newPull.id);
newPull.loseRateOff = rateUp;
if (withRateIcon) {
newPull.guaranteed = rateUp;
rateUp = !currentBanner.featured.includes(newPull.id);
newPull.loseRateOff = rateUp;
}
selectedBanners[currentBannerIndex].legendary.push(newPull);
allLegendary.push(newPull);
} else if (item.rarity === 4) {
newPull.guaranteed = rateUpRare;
rateUpRare = !currentBanner.featuredRare.includes(newPull.id);
newPull.loseRateOff = rateUpRare;
if (withRateIcon) {
newPull.guaranteed = rateUpRare;
rateUpRare = !currentBanner.featuredRare.includes(newPull.id);
newPull.loseRateOff = rateUpRare;
}
allRare.push(newPull);
if (pull.type === 'character') {
@ -612,7 +617,7 @@
<Icon marginBottom={2} size={0.7} path={mdiStar} />
</Tooltip>
{/if}
{:else if pull.rarity > 3}
{:else if pull.guaranteed === true && withRateIcon}
<Tooltip title={$t('wish.rateon.guaranteed')}>
<Icon marginBottom={2} size={0.7} path={mdiStarOutline} className="opacity-50" />
</Tooltip>

View file

@ -0,0 +1,12 @@
<script>
import { t } from 'svelte-i18n';
import Button from '../../components/Button.svelte';
export let close;
</script>
<p class="text-white font-bold text-lg mb-2">{$t('wish.backupReminder.title')}</p>
<p class="text-gray-200 mb-4">{$t('wish.backupReminder.desc')}</p>
<div class="flex justify-end">
<Button on:click={close}>{$t('wish.import.close')}</Button>
</div>

View file

@ -3,7 +3,7 @@
import { onMount, getContext } from 'svelte';
import { slide } from 'svelte/transition';
import { mdiPencil, mdiStar, mdiChevronDown, mdiTableOfContents } from '@mdi/js';
import { mdiPencil, mdiStar, mdiChevronDown, mdiTableOfContents, mdiArrowUpCircle } from '@mdi/js';
import debounce from 'lodash/debounce';
const { open: openModal, close: closeModal } = getContext('simple-modal');
@ -18,6 +18,7 @@
import dayjs from 'dayjs';
import { weaponList } from '../../data/weaponList';
import { getAccountPrefix } from '../../stores/account';
import Tooltip from '../../components/Tooltip.svelte';
let numberFormat = Intl.NumberFormat();
@ -41,6 +42,11 @@
let showRarity = [true, true, false];
let sortedPull = [];
let guaranteed = {
legendary: false,
rare: false,
};
$: path = `wish-counter-${id}`;
$: if ($fromRemote) {
readLocalData();
@ -199,6 +205,11 @@
legendary = counterData.legendary;
rare = counterData.rare;
pulls = counterData.pulls || [];
if (counterData.guaranteed) {
guaranteed.legendary = counterData.guaranteed.legendary;
guaranteed.rare = counterData.guaranteed.rare;
}
}
}
@ -278,7 +289,6 @@
rare = 0;
saveData();
}
</script>
<div class="bg-item rounded-xl p-4 inline-flex flex-col w-full" style="height: min-content;">
@ -310,7 +320,9 @@
</span>
{#if isEdit}
<Input type="number" min={1} bind:value={totalEdit} />
{:else}<span class="font-black text-3xl text-white ml-4">{total}</span>{/if}
{:else}
<span class="font-black text-3xl text-white ml-4">{total}</span>
{/if}
</div>
<div
class={`${
@ -326,14 +338,20 @@
</div>
{/if}
<span class="text-gray-200 whitespace-no-wrap flex-1">
5
<Icon path={mdiStar} size={0.75} className="mb-1" />
{$t('wish.pity')}
5★ {$t('wish.pity')}
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: legendaryPity } })}</span>
</span>
{#if isEdit}
<Input type="number" min={1} bind:value={legendaryEdit} />
{:else}<span class="font-black text-3xl text-legendary-from ml-4">{legendary}</span>{/if}
{:else}
{#if guaranteed.legendary}
<span class="rate-tooltip" style="margin-bottom: 2px; margin-left: 2px;">
<Icon size={1} path={mdiArrowUpCircle} className="text-legendary-from" />
<span class="tooltip-content legendary">{$t('wish.detail.guaranteed')}</span>
</span>
{/if}
<span class="font-black text-3xl text-legendary-from ml-4">{legendary}</span>
{/if}
</div>
<div
class={`${
@ -349,14 +367,20 @@
</div>
{/if}
<span class="text-gray-200 whitespace-no-wrap flex-1">
4
<Icon path={mdiStar} size={0.75} className="mb-1" />
{$t('wish.pity')}
4★ {$t('wish.pity')}
<br /><span class="text-gray-600">{$t('wish.guarantee', { values: { pity: 10 } })}</span>
</span>
{#if isEdit}
<Input type="number" min={1} bind:value={rareEdit} />
{:else}<span class="font-black text-3xl text-rare-from ml-4">{rare}</span>{/if}
{:else}
{#if guaranteed.rare}
<span class="rate-tooltip" style="margin-bottom: 2px; margin-left: 2px;">
<Icon size={1} path={mdiArrowUpCircle} className="text-rare-from" />
<span class="tooltip-content rare">{$t('wish.detail.guaranteed')}</span>
</span>
{/if}
<span class="font-black text-3xl text-rare-from ml-4">{rare}</span>
{/if}
</div>
{#if isEdit}
<Button on:click={saveEdit} className="mt-4">Save</Button>
@ -491,4 +515,31 @@
}
}
.rate-tooltip {
@apply relative;
.tooltip-content {
top: 30px;
right: 0px;
width: 250px;
@apply absolute;
@apply hidden;
@apply text-background;
@apply rounded-xl;
@apply p-2;
@apply text-sm z-20;
@apply border-background border-2;
&.legendary {
@apply bg-legendary-from;
}
&.rare {
@apply bg-rare-from;
}
}
&:hover .tooltip-content {
@apply block;
}
}
</style>

View file

@ -21,8 +21,9 @@
import Input from '../../components/Input.svelte';
import Select from '../../components/Select.svelte';
import Icon from '../../components/Icon.svelte';
import { server } from '../../stores/server';
import { getTimeOffset, server } from '../../stores/server';
import ImportFaqModal from './_importFaq.svelte';
import BackupReminderModal from './_backupReminder.svelte';
import Textarea from '../../components/Textarea.svelte';
import { getAccountPrefix } from '../../stores/account';
import { getLocalSaveJson, readSave, updateSave } from '../../stores/saveManager';
@ -32,6 +33,8 @@
import { submitWishTally } from '../../functions/wishTally';
import Ad from '../../components/Ad.svelte';
import Checkbox from '../../components/Checkbox.svelte';
import { driveSignedIn } from '../../stores/dataSync';
import { banners } from '../../data/banners';
const numberFormat = Intl.NumberFormat();
let fetchController;
@ -107,6 +110,8 @@
let error = '';
let bannerList = [];
let wishes = {};
async function downloadBackup() {
@ -370,6 +375,8 @@
manualInput: false,
});
if ($driveSignedIn === false) openBackupReminder();
pushToast($t('wish.import.success'));
goto('/wish');
}
@ -394,6 +401,9 @@
const combined = [...localWishes, ...importedWishes];
let latestLegendary = null;
let latestRare = null;
let rare = 0;
let legendary = 0;
for (let i = 0; i < combined.length; i++) {
@ -408,10 +418,12 @@
}
if (rarity === 5) {
latestLegendary = combined[i];
combined[i].pity = legendary;
legendary = 0;
// rare = 0;
} else if (rarity === 4) {
latestRare = combined[i];
combined[i].pity = rare;
rare = 0;
} else {
@ -419,11 +431,37 @@
}
}
let rateUpLegendary = false;
let rateUpRare = false;
if (type.id === 'character-event' || type.id === 'weapon-event') {
processBannerList(type.id);
if (latestLegendary !== null) {
const itemBanner = getBannerByTime(latestLegendary.time);
console.log(latestLegendary.time, itemBanner);
if (itemBanner && itemBanner.featured) {
rateUpLegendary = !itemBanner.featured.includes(latestLegendary.id);
}
}
if (latestRare !== null) {
const itemBanner = getBannerByTime(latestRare.time);
console.log(latestRare.time, itemBanner);
if (itemBanner && itemBanner.featured) {
rateUpRare = !itemBanner.featuredRare.includes(latestRare.id);
}
}
}
const data = {
total: combined.length,
legendary,
rare,
pulls: combined,
guaranteed: {
legendary: rateUpLegendary,
rare: rateUpRare,
},
};
await updateSave(`${prefix}${path}`, data);
@ -600,6 +638,19 @@
);
}
function openBackupReminder() {
openModal(
BackupReminderModal,
{
close: closeModal,
},
{
closeButton: false,
styleWindow: { background: '#25294A', width: '500px' },
},
);
}
function detectPlatform() {
const userAgent = navigator.userAgent || navigator.vendor;
if (/android/i.test(userAgent)) {
@ -628,6 +679,35 @@
}, 2000);
}
function processBannerList(bannerType) {
const type = bannerType === 'character-event' ? 'characters' : 'weapons';
bannerList = banners[type].map((e) => {
// banner data based on Asia time
const diff = e.timezoneDependent === true ? 8 - getTimeOffset() : 0;
const id = `${e.name} ${e.image}`;
const start = dayjs(e.start, 'YYYY-MM-DD HH:mm:ss').subtract(diff, 'hour');
const end = dayjs(e.end, 'YYYY-MM-DD HH:mm:ss');
return {
...e,
id,
start: start.unix(),
end: end.unix(),
};
});
}
function getBannerByTime(time) {
const unixTime = dayjs(time).unix();
for (let i = bannerList.length - 1; i >= 0; i--) {
if (unixTime >= bannerList[i].start && unixTime < bannerList[i].end) {
return bannerList[i];
}
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}