From be5ab1646044323039cf1d50a3500fbf79303d9d Mon Sep 17 00:00:00 2001 From: Julien BIANCHI Date: Tue, 3 Nov 2026 23:34:57 +0100 Subject: [PATCH 1/2] build(deps): add the Lottie refresh indicator plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Log's pull to refresh is going to play the /dev/null logo instead of the platform spinner. That needs two packages that aren't released yet, so Composer pulls them from GitHub, like toastkit: - nativephp/mobile-ui from the feat/refresh-indicator-registry branch of jubianchi/mobile-ui (NativePHP/mobile-ui#198), aliased as 0.9.0. A list can name a pull-to-refresh indicator that a plugin registers, and mobile-ui draws it on Android and iOS. - jubianchi/nativephp-lottie-refresh-indicator from main, which registers the "lottie" indicator and copies resources/animations into the native projects. The plugin is added to NativeServiceProvider::plugins() by hand: native:plugin:register can't find the method behind the conditional spread at the end of the array. Only those two packages change in the lock. The README lists them with toastkit. 🤖 Généré avec Claude Code --- README.md | 6 +- app/Providers/NativeServiceProvider.php | 2 + composer.json | 11 ++- composer.lock | 102 +++++++++++++++++++++--- 4 files changed, 107 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index def4e182..6554f743 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,11 @@ composer setup `nativephp/mobile-secure-storage` is a paid plugin from `plugins.nativephp.com`, so `composer install` needs your NativePHP plugin credentials. See below if you don't have access to the plugin. -For now the app tracks one unreleased package, which Composer pulls straight from GitHub: `victorycodedev/toastkit` from the `fix/android-toasts-above-sheets` branch of [simonhamp/toastkit](https://github.com/simonhamp/toastkit), which draws Android toasts above bottom sheets instead of behind them ([victorycodedev/toastkit#5](https://github.com/victorycodedev/toastkit/pull/5)). Once that is released, the app goes back to a tagged version. +For now the app tracks unreleased packages, which Composer pulls straight from GitHub. Once each is released, the app goes back to a tagged version. + +- `victorycodedev/toastkit` from the `fix/android-toasts-above-sheets` branch of [simonhamp/toastkit](https://github.com/simonhamp/toastkit), which draws Android toasts above bottom sheets instead of behind them ([victorycodedev/toastkit#5](https://github.com/victorycodedev/toastkit/pull/5)). +- `nativephp/mobile-ui` from the `feat/refresh-indicator-registry` branch of [jubianchi/mobile-ui](https://github.com/jubianchi/mobile-ui), which lets a plugin draw a list's pull-to-refresh indicator ([NativePHP/mobile-ui#198](https://github.com/NativePHP/mobile-ui/pull/198)). +- `jubianchi/nativephp-lottie-refresh-indicator` from the `main` branch of [jubianchi/nativephp-lottie-refresh-indicator](https://github.com/jubianchi/nativephp-lottie-refresh-indicator), the plugin that plays the logo animation when the Log is pulled. ### Without plugin credentials diff --git a/app/Providers/NativeServiceProvider.php b/app/Providers/NativeServiceProvider.php index 15a87320..daa2b14d 100644 --- a/app/Providers/NativeServiceProvider.php +++ b/app/Providers/NativeServiceProvider.php @@ -5,6 +5,7 @@ use Codingwithrk\NativephpSocialAuth\NativephpSocialAuthServiceProvider; use Devnull\Calls\CallsServiceProvider; use Illuminate\Support\ServiceProvider; +use Jubianchi\NativePHP\LottieRefreshIndicator\LottieRefreshIndicatorServiceProvider; use Native\Mobile\Providers\BrowserServiceProvider; use Native\Mobile\Providers\CameraServiceProvider; use Native\Mobile\Providers\MicrophoneServiceProvider; @@ -60,6 +61,7 @@ public function plugins(): array ToastKitServiceProvider::class, ClipboardServiceProvider::class, CallsServiceProvider::class, + LottieRefreshIndicatorServiceProvider::class, ...(config('devnull.apple_sign_in') ? [NativephpSocialAuthServiceProvider::class] : []), ]; } diff --git a/composer.json b/composer.json index 2c9c1ca0..07e68784 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,14 @@ "type": "vcs", "url": "https://github.com/simonhamp/toastkit" }, + { + "type": "vcs", + "url": "https://github.com/jubianchi/mobile-ui" + }, + { + "type": "vcs", + "url": "https://github.com/jubianchi/nativephp-lottie-refresh-indicator" + }, { "name": "nativephp-plugins", "type": "composer", @@ -30,6 +38,7 @@ "php": "^8.3", "codingwithrk/nativephp-social-auth": "^1.0", "devnull/nativephp-calls": "^1.0", + "jubianchi/nativephp-lottie-refresh-indicator": "dev-main", "laravel/boost": "^2.0", "laravel/framework": "^13.0", "laravel/tinker": "^3.0", @@ -41,7 +50,7 @@ "nativephp/mobile-microphone": "^1.2", "nativephp/mobile-secure-storage": "^1.1", "nativephp/mobile-share": "^1.1", - "nativephp/mobile-ui": "^0.9", + "nativephp/mobile-ui": "dev-feat/refresh-indicator-registry as 0.9.0", "s2br/nativephp-mobile-splashscreen": "^1.4", "victorycodedev/toastkit": "dev-fix/android-toasts-above-sheets as 1.4.0" }, diff --git a/composer.lock b/composer.lock index cc2ce130..c95543dc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "860c34d693a5afa83bca97fb6690af2c", + "content-hash": "2588425ca9159a6ccae695e685bdc40f", "packages": [ { "name": "bacon/bacon-qr-code", @@ -1465,6 +1465,67 @@ ], "time": "2026-08-24T17:13:02+00:00" }, + { + "name": "jubianchi/nativephp-lottie-refresh-indicator", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/jubianchi/nativephp-lottie-refresh-indicator.git", + "reference": "974d66cd22f2bb5a031d84c60e7416185078906a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jubianchi/nativephp-lottie-refresh-indicator/zipball/974d66cd22f2bb5a031d84c60e7416185078906a", + "reference": "974d66cd22f2bb5a031d84c60e7416185078906a", + "shasum": "" + }, + "require": { + "ext-zip": "*", + "nativephp/mobile": "^4.7", + "nativephp/mobile-ui": "*", + "php": "^8.3" + }, + "require-dev": { + "orchestra/testbench": "^10.0", + "pestphp/pest": "^3.0" + }, + "default-branch": true, + "type": "nativephp-plugin", + "extra": { + "laravel": { + "providers": [ + "Jubianchi\\NativePHP\\LottieRefreshIndicator\\LottieRefreshIndicatorServiceProvider" + ] + }, + "nativephp": { + "manifest": "nativephp.json" + } + }, + "autoload": { + "psr-4": { + "Jubianchi\\NativePHP\\LottieRefreshIndicator\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Jubianchi\\NativePHP\\LottieRefreshIndicator\\Tests\\": "tests/php/" + } + }, + "scripts": { + "test": [ + "pest" + ] + }, + "license": [ + "MIT" + ], + "description": "A Lottie pull-to-refresh indicator for nativephp/mobile-ui lists, on Android and iOS", + "support": { + "source": "https://github.com/jubianchi/nativephp-lottie-refresh-indicator/tree/main", + "issues": "https://github.com/jubianchi/nativephp-lottie-refresh-indicator/issues" + }, + "time": "2026-11-03T22:25:09+00:00" + }, { "name": "laravel/boost", "version": "v2.10.3", @@ -3237,16 +3298,16 @@ }, { "name": "nativephp/mobile-ui", - "version": "0.9.0", + "version": "dev-feat/refresh-indicator-registry", "source": { "type": "git", - "url": "https://github.com/NativePHP/mobile-ui.git", - "reference": "9cee87cbc676a6500247bec99be5d19f633a04e9" + "url": "https://github.com/jubianchi/mobile-ui.git", + "reference": "fcedb3145679c9d1982cfc9773a5154ca0874e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/NativePHP/mobile-ui/zipball/9cee87cbc676a6500247bec99be5d19f633a04e9", - "reference": "9cee87cbc676a6500247bec99be5d19f633a04e9", + "url": "https://api.github.com/repos/jubianchi/mobile-ui/zipball/fcedb3145679c9d1982cfc9773a5154ca0874e08", + "reference": "fcedb3145679c9d1982cfc9773a5154ca0874e08", "shasum": "" }, "require": { @@ -3274,7 +3335,17 @@ "Native\\Mobile\\UI\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", + "scripts": { + "test": [ + "pest" + ], + "lint": [ + "pint" + ], + "lint:test": [ + "pint --test" + ] + }, "license": [ "MIT" ], @@ -3286,16 +3357,15 @@ ], "description": "Native SwiftUI and Jetpack Composer components for NativePHP", "support": { - "issues": "https://github.com/NativePHP/mobile-ui/issues", - "source": "https://github.com/NativePHP/mobile-ui/tree/0.9.0" + "source": "https://github.com/jubianchi/mobile-ui/tree/feat/refresh-indicator-registry" }, "funding": [ { - "url": "https://nativephp.com/sponsor", - "type": "other" + "type": "other", + "url": "https://nativephp.com/sponsor" } ], - "time": "2026-10-29T17:44:09+00:00" + "time": "2026-11-03T20:49:42+00:00" }, { "name": "nesbot/carbon", @@ -11444,6 +11514,12 @@ } ], "aliases": [ + { + "package": "nativephp/mobile-ui", + "version": "dev-feat/refresh-indicator-registry", + "alias": "0.9.0", + "alias_normalized": "0.9.0.0" + }, { "package": "victorycodedev/toastkit", "version": "dev-fix/android-toasts-above-sheets", @@ -11453,6 +11529,8 @@ ], "minimum-stability": "stable", "stability-flags": { + "jubianchi/nativephp-lottie-refresh-indicator": 20, + "nativephp/mobile-ui": 20, "victorycodedev/toastkit": 20 }, "prefer-stable": true, From 4e235b280859e8fc74ff85f61c2a6cab5df626b2 Mon Sep 17 00:00:00 2001 From: Julien BIANCHI Date: Tue, 3 Nov 2026 23:34:57 +0100 Subject: [PATCH 2/2] feat(log): draw the logo while pulling the Log to refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pulling a Log page now draws the /dev/null logo in place of the platform spinner, through the plugin's "lottie" indicator. refresh.lottie and refresh-dark.lottie are made from the splash animation with two markers. "pull" (frames 0-60) follows the finger: the ink slash grows linearly over the first half and the lane outline draws on linearly until frame 60, so the logo is whole exactly at the refresh threshold, where mobile-ui bounces it and plays a haptic. The splash's eased curves drew most of the outline in the first half of the pull, so the logo looked done well before letting go would refresh. "refresh" (frames 60-120) loops forward while loading: the outline erases from its start, then draws on again the same way, and frame 120 matches frame 60, so there is no seam and the ink slash stays. The splash keeps its own animation. 🤖 Généré avec Claude Code --- resources/animations/refresh-dark.lottie | Bin 0 -> 1298 bytes resources/animations/refresh.lottie | Bin 0 -> 1296 bytes .../views/native/partials/log-page.blade.php | 2 ++ tests/Feature/Screens/LogTest.php | 11 +++++++++++ 4 files changed, 13 insertions(+) create mode 100644 resources/animations/refresh-dark.lottie create mode 100644 resources/animations/refresh.lottie diff --git a/resources/animations/refresh-dark.lottie b/resources/animations/refresh-dark.lottie new file mode 100644 index 0000000000000000000000000000000000000000..c435fc9cbf0b7f81735136e5b571169a3177938b GIT binary patch literal 1298 zcmWIWW@Zs#U|`??;(*vAE3&O>fULtn%nQW1iFui6sl_FFS;hHzp=S;G4jJ&UUa(!> zVZ^*hJKT|{O(NywMs4+yl~v_)LYOxGdHA!wlGkt<>)J_PyN;O5J@@j$+twyF-?iDt zT<@JZzNkFu4!1(cf}d-u9={TLY;`Gr%I{SSCtvVs&)T?ph3JF%=|(kM{{H=P)k^u9 zed5)d4>@BBZ#=8yj{dUtmcaly|#~zg*NsG_w^&V0=uyjgb;#;fZ){0N_xKi>`M0Z6@(%$fP zQfbB1q+2Y@E8CcSeK8 zjN{5Y{})CWY~(PpJhVf@NAz<%%c_u5VL$w)iFAoOPP)XPdFrQT_D`XCGL!Y6ysY`~ z#b?6_7R|e?uVy9ZRWPu49CkfX`dpb||Buv{$tlg7+$%c8QtNo9d|bkIbZ%+OqZroI zoQk6idL2E7uPt0;x?H%O{cUV!z6{fBMV7n}YY`@{_X$@ovI_=nmR`0o&-}~E?e4Q( zM6c(xxReU7&`xOfOPhMsKq2K;Lw@D_DVu@?{;h7j$e6j%sP=r?FNc4Qj{`E^3B0_a zxYq85Vgt8Tq_Dx}osI`Oj%FYA>0S3{FL%+}wHrVGTO6Ie>d@r(osW8+d9GYrothlF z)NqPU!G-Fy!nQL_ZD*AJ@4DBOXR(>*;@@Ate_ZtK`Lxh%&)G7W=2cUd?pn3=h104_ zuD@e>ism19|K(f8BO&%_7M~?m0`klBqc>Kq583+rTh{UCTiv(|`uqPiy|FkIeTr@2 zgrHcBKTF~cO_S!@^YBFPedXP`CI>bq6eK^L_aXXr@`cwd^Tl??$86%wnPmN!H^)kT ziLGrQ&%1wd89K%s!mg{AF23@vc4vR+v7k9?`j&B>4s!fwtv9hhZjPkx)Rn?=x~(Ur zHlA2r@-9DbmCKc~k2kiZhWTG!y6(V1O<_ysbU%dT?BqH%BPKcKwZtNZJBder-rHin z&-1Xrr?*?2%{?EM8mh&(?P{5S_1WIi=rPZ-6LX50l3Fmp370&znlh=o!dA#24}D1bCTv@Qp-uoV#j-mGjORZKuw3#98=Ks*4x CLOiDc literal 0 HcmV?d00001 diff --git a/resources/animations/refresh.lottie b/resources/animations/refresh.lottie new file mode 100644 index 0000000000000000000000000000000000000000..bb7774c81a08f56608b96292472c424df8a2adc9 GIT binary patch literal 1296 zcmWIWW@Zs#U|`??;(*vAE3&O>fULtn%nQW1iFui6sl_FFS;hHzp=S;G4jJ&UUa(!> zVZ^*hJKT|{O(NywMs4+yl~v_)LYOxGdHA!wlGkt<>)J_PyN;O5J@@j$+twyF-?iDt zT<@JZzNkFu4!1(cf}d-u9={TLY;`Gr%I{SSCtvVs&)T?ph3JF%=|(kM{{H=P)k^u9 zed5)d4>@BBZ#=8yj{dQh5U6_|p7QCA6=UGW{R{ZtM$fM*<`3Ce#AL-eZ|}~J`^B4zRBkG`e0V2Q zQ*a}8(|x^2v)Aj^i#h#}taq+3n$;WgM|F9)NwN>;e!lXXrG-1s>gO(3;QKS}QB~|t zzeh1QjVk=U1-4{tSi~4Do;Ce+>dMpUIv$a3b~Z&;pW>NLz3g#%F}1!s+d@{&GIx5( zuSpa0JjGs2oX--^dF$O}4Iic$FGK}latrAkG@@*o1cDo z6ubE-zbKo~Q?1B_a*hH2Z5?KEuJBcn>0oq@p2T_MK9}IpYyb2Tm=-0-^&9+|o^$Ye_%;guQZ~{2p6j9V17t?~S{j zO%ah}V7ycySakO%#{qr2$a@lk0pB?EFD^Qh-)J=N%7Ptn?i%NO1CF)%^E_xeVUZ)N z6;*6iSaIRr)NjWWH^@3Y@Z0LFxZp!ym~5?xqUrKPsn>poRlo9Q%wF+mR`Z3hyDYD` zZY#Xc1>oSkk{AC;un*6S@ z^q8A-NNlWFJ7eX=ssA4|#bjr{+4KL!wOOk^Jh2U&b8(O6*3$JkYgU=GO=9J%IER`BL;7CycpD|O|%EZtobR+U`*C(?XJT{)jg z#&zd`k22!ZCUib`6e`_cZP|PEZO~P@TdQT`uSw}1NVcnDx>-1-d@AoE#ihG4ez^W^ zS-VZ-$3*4tb^dRzF*4@uJb3I>?!)ifjxV^&d2{iW9`9|9zD1k&H~LO*-m=`h>mcs~ z?cP+j#6=lfOQzg9px?jglt+`>N zY~I^$8OjMOZLX3sC}rj2oArkKK~`M*p~&FL42k?3u7roJyi_vNA)MvV%591NSnq|# z7FLL!JKDo^eSg&QgOAwL;+}p9wfM^UKFIfA_UyKU>~i^5%VZjKKNaXVhZxQ;auiR# zGM}$#?pEJAi(r$#dH(hF^AcaZ5u5DzTTLVRx0rDBaRJr`e8K1Xm+k$i##?;i`(?h| zNrzr11?}i6;j~|UwmN6W1j(6MzqE|~uNTe~W}j5EppQGWYM=Aw $request->url() === 'http://devnull.test/api/v1/log/following'))->toHaveCount(2); }); +it('draws the logo while pulling to refresh', function () { + Http::fake(['devnull.test/*' => Http::response(pageJson([]))]); + + Native::visit('/log') + ->assertElement('list', fn (array $node): bool => ($node['props']['refresh_indicator'] ?? null) === 'lottie' + && json_decode($node['props']['refresh_indicator_options'] ?? '[]', true) === [ + 'asset' => 'animations/refresh.lottie', + 'dark_asset' => 'animations/refresh-dark.lottie', + ]); +}); + it('marks pending commits', function () { Http::fake(['devnull.test/*' => Http::response(pageJson([commitJson(['status' => 'pending', 'body' => 'Waiting on a mod'])]))]);