Specify transition in view object.

This commit is contained in:
flash 2024-04-23 20:13:01 +00:00
parent 66aea64da1
commit 9cb3c1e1d9
7 changed files with 147 additions and 98 deletions

View file

@ -19,11 +19,11 @@
.sndtest-view button { .sndtest-view button {
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
background: #f99; background: #f55;
color: #fff; color: #fff;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
border-bottom: #f33; border-bottom: #f00;
padding: 10px; padding: 10px;
} }
@ -31,6 +31,7 @@
display: flex; display: flex;
gap: 10px; gap: 10px;
margin: 10px; margin: 10px;
overflow: auto;
} }
.sndtest-library { .sndtest-library {

View file

@ -27,16 +27,6 @@ const MamiViewsControl = function(options) {
return element; return element;
}; };
const doTransition = async (transition, ctx) => {
if(transition === undefined)
return;
if(typeof transition !== 'function')
return;
await transition(ctx);
};
const updateZIncides = () => { const updateZIncides = () => {
let index = 0; let index = 0;
for(const view of views) for(const view of views)
@ -73,12 +63,18 @@ const MamiViewsControl = function(options) {
if(typeof prevElemInfo.onViewBackground === 'function') if(typeof prevElemInfo.onViewBackground === 'function')
await prevElemInfo.onViewBackground(); await prevElemInfo.onViewBackground();
await doTransition(transition, { if(transition !== false) {
toInfo: elementInfo, if(typeof transition !== 'function' && typeof elementInfo.getViewTransition === 'function')
toElem: element, transition = elementInfo.getViewTransition('push');
fromInfo: prevElemInfo,
fromElem: prevElem, if(typeof transition === 'function')
}); await transition({
toInfo: elementInfo,
toElem: element,
fromInfo: prevElemInfo,
fromElem: prevElem,
});
}
} }
}; };
@ -100,12 +96,18 @@ const MamiViewsControl = function(options) {
if(typeof nextElemInfo.onViewForeground === 'function') if(typeof nextElemInfo.onViewForeground === 'function')
await nextElemInfo.onViewForeground(); await nextElemInfo.onViewForeground();
await doTransition(transition, { if(transition !== false) {
toInfo: nextElemInfo, if(typeof transition !== 'function' && typeof elementInfo.getViewTransition === 'function')
toElem: nextElem, transition = elementInfo.getViewTransition('pop');
fromInfo: elementInfo,
fromElem: element, if(typeof transition === 'function')
}); await transition({
toInfo: nextElemInfo,
toElem: nextElem,
fromInfo: elementInfo,
fromElem: element,
});
}
} }
if(typeof elementInfo.onViewBackground === 'function') if(typeof elementInfo.onViewBackground === 'function')

View file

@ -121,7 +121,7 @@ const MamiSockChatHandlers = function(ctx, client, setLoadingOverlay, sockChatRe
if(dumpEvents) console.log('session:fail', ev.detail); if(dumpEvents) console.log('session:fail', ev.detail);
if(ev.detail.baka !== undefined) { if(ev.detail.baka !== undefined) {
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views); ctx.views.push(new MamiForceDisconnectNotice(ev.detail.baka));
return; return;
} }
@ -135,7 +135,7 @@ const MamiSockChatHandlers = function(ctx, client, setLoadingOverlay, sockChatRe
handlers['session:term'] = ev => { handlers['session:term'] = ev => {
if(dumpEvents) console.log('session:term', ev.detail); if(dumpEvents) console.log('session:term', ev.detail);
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views); ctx.views.push(new MamiForceDisconnectNotice(ev.detail.baka));
}; };

View file

@ -1,6 +1,6 @@
#include awaitable.js #include awaitable.js
const MamiSoundTest = function(settings, audio, manager, library) { const MamiSoundTest = function(settings, audio, manager, library, clickPos) {
if(!settings.defined('soundRate')) if(!settings.defined('soundRate'))
settings.define('soundRate').default(1.0).min(0.001).max(2.0).virtual().create(); settings.define('soundRate').default(1.0).min(0.001).max(2.0).virtual().create();
if(!settings.defined('soundDetune')) if(!settings.defined('soundDetune'))
@ -12,6 +12,7 @@ const MamiSoundTest = function(settings, audio, manager, library) {
if(!settings.defined('soundReverse')) if(!settings.defined('soundReverse'))
settings.define('soundReverse').default(false).virtual().create(); settings.define('soundReverse').default(false).virtual().create();
const hasClickPos = Array.isArray(clickPos) && clickPos.length > 1;
const volumeSetting = settings.info('soundVolume'); const volumeSetting = settings.info('soundVolume');
const rateSetting = settings.info('soundRate'); const rateSetting = settings.info('soundRate');
const detuneSetting = settings.info('soundDetune'); const detuneSetting = settings.info('soundDetune');
@ -153,5 +154,41 @@ const MamiSoundTest = function(settings, audio, manager, library) {
for(const source of sources) for(const source of sources)
source.stop(); source.stop();
}, },
getViewTransition: mode => {
if(!hasClickPos)
return;
if(mode === 'push')
return ctx => MamiAnimate({
async: true,
duration: 1500,
easing: 'inQuad',
start: () => {
library.play('mario:keyhole');
ctx.toElem.style.transform = 'scale(0) translate(25%, 25%)';
ctx.toElem.style.transformOrigin = `${clickPos[0]}px ${clickPos[1]}px`;
},
update: (t, rt) => ctx.toElem.style.transform = `scale(${t}) translate(${25 * (1 - rt)}%, ${25 * (1 - rt)}%)`,
end: () => {
ctx.toElem.style.transform = null;
ctx.toElem.style.transformOrigin = null;
},
});
if(mode === 'pop')
return ctx => MamiAnimate({
async: true,
duration: 1000,
easing: 'outQuad',
start: () => {
ctx.fromElem.style.transformOrigin = `${clickPos[0]}px ${clickPos[1]}px`;
},
update: (t, rt) => ctx.fromElem.style.transform = `scale(${1 - t}) rotate(${-1080 * t}deg) translate(${50 * rt}%, ${50 * rt}%)`,
end: () => {
ctx.fromElem.style.transform = null;
ctx.fromElem.style.transformOrigin = null;
},
});
},
}; };
}; };

View file

@ -47,61 +47,64 @@ const MamiForceDisconnectNotice = function(banInfo) {
} }
}, },
onViewPop: async () => { onViewPop: async () => {
bgmSrc?.stop(); try {
bgmSrc?.stop();
} catch(ex) {}
bgmSrc = sfxBuf = undefined; bgmSrc = sfxBuf = undefined;
}, },
pushOn: async views => { getViewTransition: mode => {
await views.push(pub, ctx => MamiAnimate({ if(mode === 'push')
async: true, return ctx => MamiAnimate({
duration: (sfxBuf?.duration ?? 1.4) * 1000, async: true,
start: () => { duration: (sfxBuf?.duration ?? 1.4) * 1000,
if(sfxBuf !== undefined) start: () => {
mami.sound.audio.createSource(sfxBuf).play(); if(sfxBuf !== undefined)
mami.sound.audio.createSource(sfxBuf).play();
ctx.toElem.style.top = '-100%'; ctx.toElem.style.top = '-100%';
}, },
update: t => { update: t => {
const tOutBounce = MamiEasings.outBounce(t); const tOutBounce = MamiEasings.outBounce(t);
ctx.toElem.style.top = `${-100 + (tOutBounce * 100)}%`; ctx.toElem.style.top = `${-100 + (tOutBounce * 100)}%`;
const tOutExpo = MamiEasings.outExpo(t); const tOutExpo = MamiEasings.outExpo(t);
ctx.fromElem.style.transform = `scale(${1 - (1 * tOutExpo)}) rotate(${rotate * tOutExpo}deg)`; ctx.fromElem.style.transform = `scale(${1 - (1 * tOutExpo)}) rotate(${rotate * tOutExpo}deg)`;
ctx.fromElem.style.filter = `grayscale(${tOutExpo * 100}%)`; ctx.fromElem.style.filter = `grayscale(${tOutExpo * 100}%)`;
}, },
end: () => { end: () => {
bgmSrc?.play(); bgmSrc?.play();
ctx.toElem.style.top = null; ctx.toElem.style.top = null;
ctx.fromElem.style.transform = null; ctx.fromElem.style.transform = null;
ctx.fromElem.style.filter = null; ctx.fromElem.style.filter = null;
}, },
})); });
},
popOff: async views => {
await views.pop(ctx => MamiAnimate({
async: true,
duration: (sfxBuf?.duration ?? 1.4) * 1000,
start: () => {
bgmSrc?.stop();
if(sfxBuf !== undefined)
mami.sound.audio.createSource(sfxBuf, true).play();
ctx.toElem.style.transform = `scale(1) rotate(${rotate}deg)`; if(mode === 'pop')
ctx.toElem.style.filter = 'grayscale(100%)'; return ctx => MamiAnimate({
}, async: true,
update: t => { duration: (sfxBuf?.duration ?? 1.4) * 1000,
const tOutBounce = MamiEasings.inBounce(t); start: () => {
ctx.fromElem.style.top = `${tOutBounce * -100}%`; bgmSrc?.stop();
if(sfxBuf !== undefined)
mami.sound.audio.createSource(sfxBuf, true).play();
const tOutExpo = MamiEasings.inExpo(t); ctx.toElem.style.transform = `scale(1) rotate(${rotate}deg)`;
ctx.toElem.style.transform = `scale(${1 * tOutExpo}) rotate(${rotate - (rotate * tOutExpo)}deg)`; ctx.toElem.style.filter = 'grayscale(100%)';
ctx.toElem.style.filter = `grayscale(${100 - (tOutExpo * 100)}%)`; },
}, update: t => {
end: () => { const tOutBounce = MamiEasings.inBounce(t);
ctx.fromElem.style.top = null; ctx.fromElem.style.top = `${tOutBounce * -100}%`;
ctx.toElem.style.transform = null;
ctx.toElem.style.filter = null; const tOutExpo = MamiEasings.inExpo(t);
}, ctx.toElem.style.transform = `scale(${1 * tOutExpo}) rotate(${rotate - (rotate * tOutExpo)}deg)`;
})); ctx.toElem.style.filter = `grayscale(${100 - (tOutExpo * 100)}%)`;
},
end: () => {
ctx.fromElem.style.top = null;
ctx.toElem.style.transform = null;
ctx.toElem.style.filter = null;
},
});
}, },
}; };

View file

@ -438,10 +438,9 @@ Umi.UI.Settings = (function() {
type: 'button', type: 'button',
invoke: async button => { invoke: async button => {
button.disabled = true; button.disabled = true;
const notice = new MamiForceDisconnectNotice({ perma: true, type: 'ban' }); await mami.views.push(new MamiForceDisconnectNotice({ perma: true, type: 'ban' }));
await notice.pushOn(mami.views);
await MamiSleep(5000); await MamiSleep(5000);
await notice.popOff(mami.views); await mami.views.pop();
button.disabled = false; button.disabled = false;
}, },
}, },
@ -450,20 +449,21 @@ Umi.UI.Settings = (function() {
type: 'button', type: 'button',
invoke: async button => { invoke: async button => {
button.disabled = true; button.disabled = true;
await (new MamiYouAreAnIdiot()).pushOn(mami.views); await mami.views.push(new MamiYouAreAnIdiot(mami.sound.library, mami.views));
button.disabled = false; button.disabled = false;
}, },
}, },
{ {
title: 'Sound Test', title: 'Sound Test',
type: 'button', type: 'button',
invoke: async button => { invoke: async (button, ev) => {
button.disabled = true; button.disabled = true;
mami.views.push(new MamiSoundTest( await mami.views.push(new MamiSoundTest(
mami.settings, mami.settings,
mami.sound.audio, mami.sound.audio,
mami.sound.manager, mami.sound.manager,
mami.sound.library, mami.sound.library,
[ev.clientX, ev.clientY],
)); ));
button.disabled = false; button.disabled = false;
}, },
@ -471,7 +471,7 @@ Umi.UI.Settings = (function() {
{ {
title: 'Reset audio context', title: 'Reset audio context',
type: 'button', type: 'button',
invoke: async () => { invoke: () => {
mami.sound.reset(); mami.sound.reset();
}, },
}, },
@ -512,15 +512,15 @@ Umi.UI.Settings = (function() {
updateSelectOptions(); updateSelectOptions();
} else if(display.type === 'button') { } else if(display.type === 'button') {
input.value = display.title; input.value = display.title;
input.addEventListener('click', () => { input.addEventListener('click', ev => {
if(display.confirm !== undefined) if(display.confirm !== undefined)
mami.msgbox.show({ mami.msgbox.show({
body: display.confirm, body: display.confirm,
yes: { primary: false }, yes: { primary: false },
no: { primary: true }, no: { primary: true },
}).then(() => { display.invoke(input); }).catch(() => {}); }).then(() => { display.invoke(input, ev); }).catch(() => {});
else else
display.invoke(input); display.invoke(input, ev);
}); });
} }

View file

@ -1,13 +1,13 @@
#include animate.js #include animate.js
const MamiYouAreAnIdiot = function() { const MamiYouAreAnIdiot = function(sndLibrary, views) {
const html = <div class="youare"> const html = <div class="youare">
<div class="youare-content"> <div class="youare-content">
<div class="youare-text"> <div class="youare-text" title="Double click to dismiss!">
<div class="youare-big">you are an idiot</div> <div class="youare-big">you are an idiot</div>
<div class="youare-small">!</div> <div class="youare-small">!</div>
</div> </div>
<div class="youare-smiles"> <div class="youare-smiles" title="Double click to dismiss!">
<div class="youare-smile"></div> <div class="youare-smile"></div>
<div class="youare-smile"></div> <div class="youare-smile"></div>
<div class="youare-smile"></div> <div class="youare-smile"></div>
@ -15,13 +15,16 @@ const MamiYouAreAnIdiot = function() {
</div> </div>
</div>; </div>;
if(views !== undefined)
html.addEventListener('dblclick', () => { views.pop(); });
let soundSrc; let soundSrc;
const pub = { const pub = {
getElement: () => html, getElement: () => html,
onViewPush: async () => { onViewPush: async () => {
try { try {
soundSrc = await mami.sound.library.loadSource('misc:youare'); soundSrc = await sndLibrary.loadSource('misc:youare');
soundSrc.setMuted(true); soundSrc.setMuted(true);
soundSrc.setLoop(true, 0.21, 5); soundSrc.setLoop(true, 0.21, 5);
soundSrc.play(); soundSrc.play();
@ -42,14 +45,17 @@ const MamiYouAreAnIdiot = function() {
soundSrc.stop(); soundSrc.stop();
soundSrc = undefined; soundSrc = undefined;
}, },
pushOn: async views => views.push(pub, ctx => MamiAnimate({ getViewTransition: mode => {
async: true, if(mode === 'push')
duration: 1500, return ctx => MamiAnimate({
easing: 'outBounce', async: true,
start: () => ctx.toElem.style.top = '-100%', duration: 1500,
update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`, easing: 'outBounce',
end: () => ctx.toElem.style.top = null, start: () => ctx.toElem.style.top = '-100%',
})), update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`,
end: () => ctx.toElem.style.top = null,
});
},
}; };
return pub; return pub;