From bd9fe8a09311692dc3dd9e1c7ec5d615fdb5cfd3 Mon Sep 17 00:00:00 2001 From: Patrick McDonald <764290+WhatsThatItsPat@users.noreply.github.com> Date: Thu, 6 Jan 2022 13:19:04 -0500 Subject: [PATCH 1/4] feat(refresher): add ionEnd event --- core/src/components.d.ts | 4 ++ core/src/components/refresher/refresher.tsx | 47 ++++++++++++++++++- .../components/refresher/test/spec/index.html | 4 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/core/src/components.d.ts b/core/src/components.d.ts index fa3c05f3e6b..e193d4aafbb 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -5758,6 +5758,10 @@ declare namespace LocalJSX { * If `true`, the refresher will be hidden. */ "disabled"?: boolean; + /** + * Emitted after the pull gesture has ended and the refresher has returned to the INACTIVE state. It doesn't matter where the pull gesture ended; whether the user pulled far enough for a refresh, let go in the middle of a pull, or reversed the pull and released with the content at the top. + */ + "onIonEnd"?: (event: CustomEvent) => void; /** * Emitted while the user is pulling down the content and exposing the refresher. */ diff --git a/core/src/components/refresher/refresher.tsx b/core/src/components/refresher/refresher.tsx index d31eabf929b..8a063cbfc83 100644 --- a/core/src/components/refresher/refresher.tsx +++ b/core/src/components/refresher/refresher.tsx @@ -133,6 +133,14 @@ export class Refresher implements ComponentInterface { */ @Event() ionStart!: EventEmitter; + /** + * Emitted after the pull gesture has ended and the refresher has returned to + * the INACTIVE state. It doesn't matter where the pull gesture ended; whether + * the user pulled far enough for a refresh, let go in the middle of a pull, + * or reversed the pull and released with the content at the top. + */ + @Event() ionEnd!: EventEmitter; + private async checkNativeRefresher() { const useNativeRefresher = await shouldUseNativeRefresher(this.el, getIonMode(this)); if (useNativeRefresher && !this.nativeRefresher) { @@ -159,6 +167,10 @@ export class Refresher implements ComponentInterface { await translateElement(el, undefined, 300); } else { await transitionEndAsync(this.el.querySelector('.refresher-refreshing-icon'), 200); + // TODO Does something have to happen here to emit the ionEnd event? + // And if so, can it happen anywhere in resetNativeRefresher()? + // Or does something have to happen in the onEnd gesture events that + // are created within the setup[iOS/MD]NativeRefresher functions? } this.didRefresh = false; @@ -561,6 +573,8 @@ export class Refresher implements ComponentInterface { this.progress = 0; this.state = RefresherState.Inactive; + console.log('deltaY <= 0'); // TODO remove + if (this.appliedStyles) { // reset the styles only if they were applied this.setCss(0, '', false, ''); @@ -636,20 +650,41 @@ export class Refresher implements ComponentInterface { } private onEnd() { + console.log('onEnd'); // TODO remove // only run in a zone when absolutely necessary if (this.state === RefresherState.Ready) { // they pulled down far enough, so it's ready to refresh this.beginRefresh(); + console.log('onEnd > Ready'); // TODO remove } else if (this.state === RefresherState.Pulling) { // they were pulling down, but didn't pull down far enough // set the content back to it's original location // and close the refresher // set that the refresh is actively cancelling + console.log('onEnd > Pulling'); // TODO remove this.cancel(); + } else if (this.state === RefresherState.Inactive) { + // they pulled down, but reversed the gesture and released + // when deltaY was <= 0 (i.e. getProgress was at 0). + console.log('onEnd > Inactive'); // TODO remove + this.ionEnd.emit(); + } else { + // TODO remove whole else clause + // just curious what else can happen here + console.log(`onEnd (other) > ${this.getEnumKeyByEnumValue(RefresherState, this.state)})}`); } } + // TODO remove + // RefresherState can't be a const for this to work, + // but this is just for experimenting. + getEnumKeyByEnumValue(myEnum: any, enumValue: any) { + let keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue); + return keys.length > 0 ? keys[0] : null; + } + + private beginRefresh() { // assumes we're already back in a zone // they pulled down far enough, so it's ready to refresh @@ -669,6 +704,16 @@ export class Refresher implements ComponentInterface { // create fallback timer incase something goes wrong with transitionEnd event setTimeout(() => { + + // The comment above setTimeout() is worrisome because I don't want this to + // emit more than once (though that wouldn't be a big deal). I don't know + // enough about transitionEnd to know if that's possible and this + // conditional might not be necessary. + if (this.state !== RefresherState.Inactive) { + console.log(`ionEnd emit after setTimeout() fallback`); // TODO remove + this.ionEnd.emit(); + } + this.state = RefresherState.Inactive; this.progress = 0; this.didStart = false; @@ -723,7 +768,7 @@ export class Refresher implements ComponentInterface { } } -const enum RefresherState { +enum RefresherState { Inactive = 1 << 0, Pulling = 1 << 1, Ready = 1 << 2, diff --git a/core/src/components/refresher/test/spec/index.html b/core/src/components/refresher/test/spec/index.html index 0132030c1b2..82a879379d7 100644 --- a/core/src/components/refresher/test/spec/index.html +++ b/core/src/components/refresher/test/spec/index.html @@ -92,6 +92,10 @@ refresher.addEventListener('ionStart', () => { console.log('ionStart'); }); + + refresher.addEventListener('ionEnd', () => { + console.log('ionEnd'); + }); refresher.addEventListener('ionRefresh', async function () { console.log('Loading data...'); From a32b72e2fad449f34b37cc17087be74c6f6e3790 Mon Sep 17 00:00:00 2001 From: Patrick McDonald <764290+WhatsThatItsPat@users.noreply.github.com> Date: Thu, 6 Jan 2022 13:20:37 -0500 Subject: [PATCH 2/4] feat(refresher): see what's going on with the bg --- .../src/components/refresher/test/spec/index.html | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/components/refresher/test/spec/index.html b/core/src/components/refresher/test/spec/index.html index 82a879379d7..4903b5f21c4 100644 --- a/core/src/components/refresher/test/spec/index.html +++ b/core/src/components/refresher/test/spec/index.html @@ -29,21 +29,21 @@ - + - + - + @@ -85,8 +85,9 @@ const list = document.getElementById('list'); const refresher = document.getElementById('refresher'); - refresher.addEventListener('ionPull', () => { - console.log('ionPull'); + refresher.addEventListener('ionPull', async () => { + const progress = await refresher.getProgress(); + console.log('ionPull', progress); }); refresher.addEventListener('ionStart', () => { @@ -108,7 +109,7 @@ function render() { let html = ''; for (let item of items) { - html += `${item}`; + html += `${item}`; } list.innerHTML = html; } From aa41159319c5e79ad8b6278b2d36e0fa0d3374e8 Mon Sep 17 00:00:00 2001 From: Patrick McDonald <764290+WhatsThatItsPat@users.noreply.github.com> Date: Thu, 6 Jan 2022 14:49:33 -0500 Subject: [PATCH 3/4] feat(refresher): remove logs, etc. --- core/src/components/refresher/refresher.tsx | 25 ++----------------- .../components/refresher/test/spec/index.html | 15 ++++++----- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/core/src/components/refresher/refresher.tsx b/core/src/components/refresher/refresher.tsx index 8a063cbfc83..03314576321 100644 --- a/core/src/components/refresher/refresher.tsx +++ b/core/src/components/refresher/refresher.tsx @@ -573,8 +573,6 @@ export class Refresher implements ComponentInterface { this.progress = 0; this.state = RefresherState.Inactive; - console.log('deltaY <= 0'); // TODO remove - if (this.appliedStyles) { // reset the styles only if they were applied this.setCss(0, '', false, ''); @@ -650,41 +648,23 @@ export class Refresher implements ComponentInterface { } private onEnd() { - console.log('onEnd'); // TODO remove // only run in a zone when absolutely necessary if (this.state === RefresherState.Ready) { // they pulled down far enough, so it's ready to refresh this.beginRefresh(); - console.log('onEnd > Ready'); // TODO remove - } else if (this.state === RefresherState.Pulling) { // they were pulling down, but didn't pull down far enough // set the content back to it's original location // and close the refresher // set that the refresh is actively cancelling - console.log('onEnd > Pulling'); // TODO remove this.cancel(); } else if (this.state === RefresherState.Inactive) { // they pulled down, but reversed the gesture and released // when deltaY was <= 0 (i.e. getProgress was at 0). - console.log('onEnd > Inactive'); // TODO remove this.ionEnd.emit(); - } else { - // TODO remove whole else clause - // just curious what else can happen here - console.log(`onEnd (other) > ${this.getEnumKeyByEnumValue(RefresherState, this.state)})}`); } } - // TODO remove - // RefresherState can't be a const for this to work, - // but this is just for experimenting. - getEnumKeyByEnumValue(myEnum: any, enumValue: any) { - let keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue); - return keys.length > 0 ? keys[0] : null; - } - - private beginRefresh() { // assumes we're already back in a zone // they pulled down far enough, so it's ready to refresh @@ -710,10 +690,9 @@ export class Refresher implements ComponentInterface { // enough about transitionEnd to know if that's possible and this // conditional might not be necessary. if (this.state !== RefresherState.Inactive) { - console.log(`ionEnd emit after setTimeout() fallback`); // TODO remove this.ionEnd.emit(); } - + this.state = RefresherState.Inactive; this.progress = 0; this.didStart = false; @@ -768,7 +747,7 @@ export class Refresher implements ComponentInterface { } } -enum RefresherState { +const enum RefresherState { Inactive = 1 << 0, Pulling = 1 << 1, Ready = 1 << 2, diff --git a/core/src/components/refresher/test/spec/index.html b/core/src/components/refresher/test/spec/index.html index 4903b5f21c4..82a879379d7 100644 --- a/core/src/components/refresher/test/spec/index.html +++ b/core/src/components/refresher/test/spec/index.html @@ -29,21 +29,21 @@ - + - + - + @@ -85,9 +85,8 @@ const list = document.getElementById('list'); const refresher = document.getElementById('refresher'); - refresher.addEventListener('ionPull', async () => { - const progress = await refresher.getProgress(); - console.log('ionPull', progress); + refresher.addEventListener('ionPull', () => { + console.log('ionPull'); }); refresher.addEventListener('ionStart', () => { @@ -109,7 +108,7 @@ function render() { let html = ''; for (let item of items) { - html += `${item}`; + html += `${item}`; } list.innerHTML = html; } From ad6623770d9ad731516609b8fe428e5b51f3f623 Mon Sep 17 00:00:00 2001 From: Patrick McDonald <764290+WhatsThatItsPat@users.noreply.github.com> Date: Thu, 6 Jan 2022 14:51:58 -0500 Subject: [PATCH 4/4] feat(refresher): add auto-generated files --- angular/src/directives/proxies.ts | 9 ++++++++- core/api.txt | 1 + core/src/components/refresher/readme.md | 11 ++++++----- packages/vue/src/proxies.ts | 3 ++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index 529ac88d23a..24846b4c9f6 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -1324,6 +1324,13 @@ called when the async operation has completed. * Emitted when the user begins to start pulling down. */ ionStart: EventEmitter>; + /** + * Emitted after the pull gesture has ended and the refresher has returned to +the INACTIVE state. It doesn't matter where the pull gesture ended; whether +the user pulled far enough for a refresh, let go in the middle of a pull, +or reversed the pull and released with the content at the top. + */ + ionEnd: EventEmitter>; } @@ -1343,7 +1350,7 @@ export class IonRefresher { constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionRefresh', 'ionPull', 'ionStart']); + proxyOutputs(this, this.el, ['ionRefresh', 'ionPull', 'ionStart', 'ionEnd']); } } diff --git a/core/api.txt b/core/api.txt index ce9578268f2..9d42918f3b9 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1006,6 +1006,7 @@ ion-refresher,prop,snapbackDuration,string,'280ms',false,false ion-refresher,method,cancel,cancel() => Promise ion-refresher,method,complete,complete() => Promise ion-refresher,method,getProgress,getProgress() => Promise +ion-refresher,event,ionEnd,void,true ion-refresher,event,ionPull,void,true ion-refresher,event,ionRefresh,RefresherEventDetail,true ion-refresher,event,ionStart,void,true diff --git a/core/src/components/refresher/readme.md b/core/src/components/refresher/readme.md index 65bdcd972d6..0411fb45abc 100644 --- a/core/src/components/refresher/readme.md +++ b/core/src/components/refresher/readme.md @@ -304,11 +304,12 @@ export default defineComponent({ ## Events -| Event | Description | Type | -| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| `ionPull` | Emitted while the user is pulling down the content and exposing the refresher. | `CustomEvent` | -| `ionRefresh` | Emitted when the user lets go of the content and has pulled down further than the `pullMin` or pulls the content down and exceeds the pullMax. Updates the refresher state to `refreshing`. The `complete()` method should be called when the async operation has completed. | `CustomEvent` | -| `ionStart` | Emitted when the user begins to start pulling down. | `CustomEvent` | +| Event | Description | Type | +| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | +| `ionEnd` | Emitted after the pull gesture has ended and the refresher has returned to the INACTIVE state. It doesn't matter where the pull gesture ended; whether the user pulled far enough for a refresh, let go in the middle of a pull, or reversed the pull and released with the content at the top. | `CustomEvent` | +| `ionPull` | Emitted while the user is pulling down the content and exposing the refresher. | `CustomEvent` | +| `ionRefresh` | Emitted when the user lets go of the content and has pulled down further than the `pullMin` or pulls the content down and exceeds the pullMax. Updates the refresher state to `refreshing`. The `complete()` method should be called when the async operation has completed. | `CustomEvent` | +| `ionStart` | Emitted when the user begins to start pulling down. | `CustomEvent` | ## Methods diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index f265a759a9f..5cb7248f319 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -603,7 +603,8 @@ export const IonRefresher = /*@__PURE__*/ defineContainer('ion 'disabled', 'ionRefresh', 'ionPull', - 'ionStart' + 'ionStart', + 'ionEnd' ]);