Squashed commit of the following:

commit 0f1620ae21ed9ae1d279fa7527b1824e01b4ea08
Author: Benoy Bose <benoybose@gmail.com>
Date:   Mon Nov 4 14:45:08 2024 +0530

    Squashed commit of the following:

    commit f9f34ff304
    Author: Benoy Bose <benoybose@gmail.com>
    Date:   Mon Nov 4 14:30:56 2024 +0530

        Updated pub lock

commit 214cf48f9b63bc59425d59a2add17c13bb5ce186
Author: Benoy Bose <benoybose@gmail.com>
Date:   Mon Nov 4 14:39:32 2024 +0530

    Update pubspec.lock

commit faebb4b341d01933bbe6112c982dda36ae744288
Author: Benoy Bose <benoybose@gmail.com>
Date:   Mon Nov 4 14:32:49 2024 +0530

    Squashed commit of the following:

    commit f9f34ff304
    Author: Benoy Bose <benoybose@gmail.com>
    Date:   Mon Nov 4 14:30:56 2024 +0530

        Updated pub lock

commit 4a529e7ef6a237a7551a73e72de2638d2ebc246f
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Nov 4 13:09:05 2024 +0530

    Update doctor_personal_profile_screen.dart

commit 190e3a4058583d27418a9d10fb495da185b2a703
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Nov 4 13:07:40 2024 +0530

    completed doctor consultation center

commit 1b8196d50976975fd41a32201b9d024f5986cba2
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Sun Nov 3 21:04:53 2024 +0530

    completed doctors schedule creation

commit 033e1b74a811a3eaebf430dbe5cf2ea5a8f30fe4
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Sun Nov 3 14:41:25 2024 +0530

    commit

commit aa92bebd0b897ab96c04dd9ae4a2ec101b95d1c0
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Sun Nov 3 14:19:56 2024 +0530

    commit

commit e0a60c600872281d3915175f5dc5c311e7193be9
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Sun Nov 3 01:58:21 2024 +0530

    doctor dashboard

commit 94009dd6e3791a7082a885af300ae04c38fe0207
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Sat Nov 2 20:58:04 2024 +0530

    Update doctor_dashboard.dart

commit bdb14d29584cc993391322f762f6bd0b8956d40a
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Nov 1 23:56:38 2024 +0530

    appoinment booking complete

commit dc61667a1ccee87b06b9accc6d6f2364126ea6a6
Merge: e08b4b3 17d6c60
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Nov 1 22:15:16 2024 +0530

    Merge branch 'feature/medora-108' into feature/medora-55

commit 17d6c6036cd97e5290369f2b14f49cf5b52d3c2b
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Nov 1 22:01:16 2024 +0530

    Completed service profile creation

commit 691e34bd721c6137699676c12f0c0b59bcdac953
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Nov 1 18:52:28 2024 +0530

    created doctor business center

commit 68bef5ab271f3ce8dc26b79a4cedb64debf6c410
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Nov 1 15:38:45 2024 +0530

    dev changes

commit e08b4b3bddad1ef74e05870c55e9371db67fe687
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Nov 1 12:02:47 2024 +0530

    deleted booking controller

commit c8901aa51f9d3b78f10b85d24bb76190631ded56
Merge: abdf59e 01e27a1
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Nov 1 11:40:20 2024 +0530

    Merge branch 'dev' into feature/medora-108

commit 9d25eca33b1be0093a5e41551315b0cb3b4c100c
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 31 23:07:14 2024 +0530

    route changed and deleted unwanted files

commit b07982a56048c12609daabc166cadc6353674d2d
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 31 22:04:04 2024 +0530

    deleted duplicated files

commit 6a94bccec91037ade1f47d6d107df010ce6bd8a2
Merge: e5e7b55 01e27a1
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 31 22:03:37 2024 +0530

    Merge branch 'dev' into feature/medora-55

commit e5e7b5597ec2a4be9849b5d52efb6baf21d3aa01
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 31 16:34:52 2024 +0530

    consultation booking

commit abdf59e4d5221a00c04a5bec10ec15a934c66956
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 30 18:48:11 2024 +0530

    commit

commit 42e7bb160530c65ef4ebaff2f9cc4b403dbb4109
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Wed Oct 30 11:17:58 2024 +0530

    booking appoinments

commit a117b98fa21ae6bd42b2a2b99d97cbcc11ec1ccb
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 30 11:08:01 2024 +0530

    Update pubspec.yaml

commit 64e7201a1e6b1d3fefd4952e3e4afa4031daccc8
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 18:02:38 2024 +0530

    Update navigation_service.dart

commit 677bb639fa1d71545bd1a8d3c81582965ead3e64
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 15:09:06 2024 +0530

    Revert "Merge branch 'feature/medora-71' into feature/medora-79"

    This reverts commit eaa30a50553f3b0d9c1d73426dace8c5c384d05c, reversing
    changes made to 176a6797be31c5bd16f77a1fb595a12451e8000c.

commit 3283d1b30bb0c69270b10d06cf9d00f61377e7dc
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 14:16:45 2024 +0530

    commit

commit eaa30a50553f3b0d9c1d73426dace8c5c384d05c
Merge: 176a679 2404999
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 12:00:14 2024 +0530

    Merge branch 'feature/medora-71' into feature/medora-79

commit 176a6797be31c5bd16f77a1fb595a12451e8000c
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 11:53:27 2024 +0530

    commit doctor profile

commit 23bf668914c000c6d98108c50d60e2e12d827b36
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 29 11:14:16 2024 +0530

    Doctor profile

commit 110753ddcfab9f16657ff71ad30a07054e5b1f09
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 28 18:19:42 2024 +0530

    commit

commit 67613bf3d9d0e0171a152de093e6b01ccf95820f
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 28 15:10:56 2024 +0530

    commit

commit 036aabbeae4ec637f601dc07d13eaf15b93ba2ec
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 28 14:00:17 2024 +0530

    commit

commit 240499983bb6864a602efad335c494d5424c2da6
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Mon Oct 28 12:39:02 2024 +0530

    common elements added and some error fixed

commit 08f3be051569cfcb6b35db78f416efb862ed5de9
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 28 11:19:21 2024 +0530

    commit

commit 62d4d739b84fbd8e6d0d9f0c4a18fc87989bb198
Merge: 6947ba5 66e54bc
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Oct 25 18:45:42 2024 +0530

    Merge branch 'feature/medora-71' into feature/medora-79

commit 6947ba519fef2ac77a6dc778a397b9eb30a384b8
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Oct 25 18:40:12 2024 +0530

    commit

commit 66e54bcb94d3a68b6421fbc5c9205eee2a21b64b
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 25 17:58:46 2024 +0530

    color update

commit 74f216b6d39b1108e8beb43d9fd153468237d8cf
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 25 17:58:23 2024 +0530

    fixed some bugs and added common files

commit 180976cceafee37eb64786939315febd6c41d1a7
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Oct 25 15:12:20 2024 +0530

    commit

commit a717f95af85022158bd5130b52a0894fd4d04b5d
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 25 14:25:04 2024 +0530

    date and ui changes in family list screen

commit d463c805e271438a4324959543fd2f688e908a7f
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 25 13:07:29 2024 +0530

    sign up issue solved

commit 2a3fb82c2d7fa25f8bb6707966cdcbbb7b7f6711
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Oct 25 01:19:32 2024 +0530

    commit

commit 1000963818dfc4050bdd81a756ebb5207410d876
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 25 01:06:07 2024 +0530

    validation added flow corrected and patient registration complete

commit fd5b472830b6c3cffd40262109ee370d58b138a3
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Thu Oct 24 19:25:08 2024 +0530

    commit

commit 59387828aec1042eab06d1fc1855c7a8ba1e441d
Merge: f1bd18e ee9163b
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 24 16:28:12 2024 +0530

    Merge remote-tracking branch 'origin/feature/medora-79' into feature/medora-71

commit f1bd18e5c1f17926ed6aaf3f14b2875bce0d64d8
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 24 16:27:48 2024 +0530

    added roles while creating user

commit a4de95274cbcf3249b325e0ae73d9a4f52fe9272
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Thu Oct 24 16:26:49 2024 +0530

    commit

commit ee9163b67061fbd9d2510cee02e4d0aead7c73ef
Merge: cd87cd7 2c6d7b7
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Thu Oct 24 14:18:52 2024 +0530

    Merge branch 'feature/medora-71' into feature/medora-79

commit cd87cd748729dc9b95f91a07eeec5104c5b33f5e
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Thu Oct 24 14:15:13 2024 +0530

    commit

commit 2c6d7b75abe5541a8a06dbdabcdc98cfc1bd70ff
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 24 12:15:51 2024 +0530

    Validation added

commit 95fedc1b7979a5d6a039c5be5819252e6f988b1d
Merge: bc759fa ca23730
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Thu Oct 24 11:12:36 2024 +0530

    Merge branch 'feature/medora-71' into feature/medora-79

commit ca237309b4455202a61cd21a07ab8fb97d1487b3
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 24 00:28:42 2024 +0530

    Controller added

commit bc759fa390e623cd9a0a7c805e81cc1f8c60bd28
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 23 19:07:35 2024 +0530

    Update doctor_profile_service.dart

commit b93514e0f94b0532e0e518a785de946baa1a413c
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 23 19:06:33 2024 +0530

    commit

commit b99611c83072a28aa966328072d1c7f4b74890cd
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 23 15:42:48 2024 +0530

    Update Doctor_profile_screen.dart

commit 9f2ddf623b7a0dc07c620a2073f93e3a2aae4c86
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Wed Oct 23 12:21:02 2024 +0530

    commit

commit fa2cdbacf31716dfdf52881f544ccbd740df5102
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 22 11:19:15 2024 +0530

    commit

commit 7adbf395869c2c2e8912509c802aa3dba467ac0c
Merge: 1dec3a4 561174f
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Tue Oct 22 11:19:07 2024 +0530

    Merge remote-tracking branch 'origin/feature/medora-71' into feature/medora-79

commit 561174f58b5240746d451a068e45e8abd99a31c9
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Tue Oct 22 11:17:01 2024 +0530

    Firebase service and model with controller has been added

commit 1dec3a44bd1fe6383eb79e5049dd40e2daaf5930
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 18:20:20 2024 +0530

    Update profile_description_screen.dart

commit 2f093115e17c3a53cbe1e5659cbcc0d2f4e173aa
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 18:16:34 2024 +0530

    commit

commit e40f9afc88dfd0144ee8023b71736f95ef09ff4b
Merge: 14ebc23 8dcff6c
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 17:06:43 2024 +0530

    Merge remote-tracking branch 'origin/feature/medora-70' into feature/medora-79

commit 14ebc23a5772e92c74b2a0c1ebc2d301f5b7ba0f
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 17:06:23 2024 +0530

    commit

commit 8dcff6cbff5be921a99c0a3315dfe309f28bfb4a
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Mon Oct 21 17:06:05 2024 +0530

    UI complete patient registration

commit 091029b056351afb410f542fb5db81253f59d07a
Merge: 9cbf16f 9f988ce
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 16:05:47 2024 +0530

    Merge remote-tracking branch 'origin/feature/medora-70' into feature/medora-79

commit 9f988cebc7659b65626b0706f09bda59246710d2
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Mon Oct 21 16:01:29 2024 +0530

    UI for patient registartion

commit 9cbf16f14700cf2d7a36720ca796f46614cb5bec
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 16:01:17 2024 +0530

    commit

commit bd5561bf21b612d07730f6c4330f1aee6a63f652
Merge: 2fb3f01 5a12155
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 11:35:59 2024 +0530

    Merge remote-tracking branch 'origin/feature/medora-70' into feature/medora-79

commit 2fb3f010fe0ead574de0d25da7f03e0e4f4abd5c
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Mon Oct 21 11:34:41 2024 +0530

    doctor profile

commit 5a12155ababfb41606986e9a1e9481a7738a7e8c
Merge: 2090099 6530b5a
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 18 18:17:35 2024 +0530

    Merge branch 'feature/medora-78' into feature/medora-70

commit 2090099d7496c1f6c8490462addce2226f4c9397
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 18 18:17:05 2024 +0530

    added user selection screen

commit 6530b5ad45c6d6a46577af90c2e82981ce1baa68
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Fri Oct 18 16:47:35 2024 +0530

    App deployed

commit b742de48b851369a59e83819762d706607176c70
Author: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Date:   Fri Oct 18 15:41:19 2024 +0530

    commit

commit 33190bb1a324e0a48831087c77336138171a49d9
Merge: 8e3d05d 4809c9a
Author: DhanshCOSQ <dhanshas@cosq.net>
Date:   Thu Oct 17 17:17:27 2024 +0530

    Merge branch 'dev' into feature/medora-70

commit 8e3d05de97
Author: Benoy Bose <benoybose@gmail.com>
Date:   Tue Oct 15 20:00:08 2024 +0530

    Reconfigured Firebase

commit 1f12d4cb5d
Author: Benoy Bose <benoybose@gmail.com>
Date:   Tue Oct 15 19:50:40 2024 +0530

    Updated launch screen

commit 810548880a
Author: Benoy Bose <benoybose@gmail.com>
Date:   Mon Oct 14 18:29:27 2024 +0530

    Added user screen
This commit is contained in:
Benoy Bose 2024-11-04 14:46:39 +05:30
parent f9f34ff304
commit 266fca3bf7
97 changed files with 169220 additions and 2742 deletions

3
.env
View File

@ -1,4 +1,5 @@
CUSTOM_SCHEME=com.cosqnet.telemednet
PROFILE_COLLECTION_NAME=telemednetusers
PATIENT_PROFILE_COLLECTION_NAME=patientprofiles
DOCTOR_PROFILE_COLLECTION_NAME=doctorprofiles
DOCTOR_PROFILE_COLLECTION_NAME=doctorprofiles
CONSULTATION_CENTER_COLLECTION_NAME=businesscenters

View File

@ -0,0 +1 @@
309b0ca34262b8503b61880a5e0ec018

View File

@ -0,0 +1,2 @@
CUSTOM_SCHEME=com.cosqnet.telemednet
PROFILE_COLLECTION_NAME=telemednetusers

View File

@ -0,0 +1 @@
.env  asset.envimages/cover-picture.jpg  assetimages/cover-picture.jpg2packages/cupertino_icons/assets/CupertinoIcons.ttf  asset2packages/cupertino_icons/assets/CupertinoIcons.ttf

View File

@ -0,0 +1 @@
"DQMHBC5lbnYMAQ0BBwVhc3NldAcELmVudgcYaW1hZ2VzL2NvdmVyLXBpY3R1cmUuanBnDAENAQcFYXNzZXQHGGltYWdlcy9jb3Zlci1waWN0dXJlLmpwZwcycGFja2FnZXMvY3VwZXJ0aW5vX2ljb25zL2Fzc2V0cy9DdXBlcnRpbm9JY29ucy50dGYMAQ0BBwVhc3NldAcycGFja2FnZXMvY3VwZXJ0aW5vX2ljb25zL2Fzc2V0cy9DdXBlcnRpbm9JY29ucy50dGY="

View File

@ -0,0 +1 @@
{".env":[".env"],"images/cover-picture.jpg":["images/cover-picture.jpg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"]}

View File

@ -0,0 +1 @@
[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}]

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,215 @@
var CanvasKitInit = (() => {
var _scriptDir = import.meta.url;
return (
async function(moduleArg = {}) {
var r=moduleArg,aa,ba;r.ready=new Promise((a,b)=>{aa=a;ba=b});
(function(a){a.Md=a.Md||[];a.Md.push(function(){a.MakeSWCanvasSurface=function(b){var c=b,e="undefined"!==typeof OffscreenCanvas&&c instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&c instanceof HTMLCanvasElement||e||(c=document.getElementById(b),c)))throw"Canvas with id "+b+" was not found";if(b=a.MakeSurface(c.width,c.height))b.me=c;return b};a.MakeCanvasSurface||(a.MakeCanvasSurface=a.MakeSWCanvasSurface);a.MakeSurface=function(b,c){var e={width:b,height:c,colorType:a.ColorType.RGBA_8888,
alphaType:a.AlphaType.Unpremul,colorSpace:a.ColorSpace.SRGB},f=b*c*4,k=a._malloc(f);if(e=a.Surface._makeRasterDirect(e,k,4*b))e.me=null,e.Ue=b,e.Re=c,e.Se=f,e.xe=k,e.getCanvas().clear(a.TRANSPARENT);return e};a.MakeRasterDirectSurface=function(b,c,e){return a.Surface._makeRasterDirect(b,c.byteOffset,e)};a.Surface.prototype.flush=function(b){a.Jd(this.Id);this._flush();if(this.me){var c=new Uint8ClampedArray(a.HEAPU8.buffer,this.xe,this.Se);c=new ImageData(c,this.Ue,this.Re);b?this.me.getContext("2d").putImageData(c,
0,0,b[0],b[1],b[2]-b[0],b[3]-b[1]):this.me.getContext("2d").putImageData(c,0,0)}};a.Surface.prototype.dispose=function(){this.xe&&a._free(this.xe);this.delete()};a.Jd=a.Jd||function(){};a.ne=a.ne||function(){return null}})})(r);
(function(a){a.Md=a.Md||[];a.Md.push(function(){function b(m,p,w){return m&&m.hasOwnProperty(p)?m[p]:w}function c(m){var p=da(ea);ea[p]=m;return p}function e(m){return m.naturalHeight||m.videoHeight||m.displayHeight||m.height}function f(m){return m.naturalWidth||m.videoWidth||m.displayWidth||m.width}function k(m,p,w,y){m.bindTexture(m.TEXTURE_2D,p);y||w.alphaType!==a.AlphaType.Premul||m.pixelStorei(m.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);return p}function l(m,p,w){w||p.alphaType!==a.AlphaType.Premul||
m.pixelStorei(m.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);m.bindTexture(m.TEXTURE_2D,null)}a.GetWebGLContext=function(m,p){if(!m)throw"null canvas passed into makeWebGLContext";var w={alpha:b(p,"alpha",1),depth:b(p,"depth",1),stencil:b(p,"stencil",8),antialias:b(p,"antialias",0),premultipliedAlpha:b(p,"premultipliedAlpha",1),preserveDrawingBuffer:b(p,"preserveDrawingBuffer",0),preferLowPowerToHighPerformance:b(p,"preferLowPowerToHighPerformance",0),failIfMajorPerformanceCaveat:b(p,"failIfMajorPerformanceCaveat",
0),enableExtensionsByDefault:b(p,"enableExtensionsByDefault",1),explicitSwapControl:b(p,"explicitSwapControl",0),renderViaOffscreenBackBuffer:b(p,"renderViaOffscreenBackBuffer",0)};w.majorVersion=p&&p.majorVersion?p.majorVersion:"undefined"!==typeof WebGL2RenderingContext?2:1;if(w.explicitSwapControl)throw"explicitSwapControl is not supported";m=fa(m,w);if(!m)return 0;ha(m);v.Ud.getExtension("WEBGL_debug_renderer_info");return m};a.deleteContext=function(m){v===ia[m]&&(v=null);"object"==typeof JSEvents&&
JSEvents.yf(ia[m].Ud.canvas);ia[m]&&ia[m].Ud.canvas&&(ia[m].Ud.canvas.Oe=void 0);ia[m]=null};a._setTextureCleanup({deleteTexture:function(m,p){var w=ea[p];w&&ia[m].Ud.deleteTexture(w);ea[p]=null}});a.MakeWebGLContext=function(m){if(!this.Jd(m))return null;var p=this._MakeGrContext();if(!p)return null;p.Id=m;var w=p.delete.bind(p);p["delete"]=function(){a.Jd(this.Id);w()}.bind(p);return v.ze=p};a.MakeGrContext=a.MakeWebGLContext;a.GrDirectContext.prototype.getResourceCacheLimitBytes=function(){a.Jd(this.Id);
this._getResourceCacheLimitBytes()};a.GrDirectContext.prototype.getResourceCacheUsageBytes=function(){a.Jd(this.Id);this._getResourceCacheUsageBytes()};a.GrDirectContext.prototype.releaseResourcesAndAbandonContext=function(){a.Jd(this.Id);this._releaseResourcesAndAbandonContext()};a.GrDirectContext.prototype.setResourceCacheLimitBytes=function(m){a.Jd(this.Id);this._setResourceCacheLimitBytes(m)};a.MakeOnScreenGLSurface=function(m,p,w,y,B,D){if(!this.Jd(m.Id))return null;p=void 0===B||void 0===D?
this._MakeOnScreenGLSurface(m,p,w,y):this._MakeOnScreenGLSurface(m,p,w,y,B,D);if(!p)return null;p.Id=m.Id;return p};a.MakeRenderTarget=function(){var m=arguments[0];if(!this.Jd(m.Id))return null;if(3===arguments.length){var p=this._MakeRenderTargetWH(m,arguments[1],arguments[2]);if(!p)return null}else if(2===arguments.length){if(p=this._MakeRenderTargetII(m,arguments[1]),!p)return null}else return null;p.Id=m.Id;return p};a.MakeWebGLCanvasSurface=function(m,p,w){p=p||null;var y=m,B="undefined"!==
typeof OffscreenCanvas&&y instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&y instanceof HTMLCanvasElement||B||(y=document.getElementById(m),y)))throw"Canvas with id "+m+" was not found";m=this.GetWebGLContext(y,w);if(!m||0>m)throw"failed to create webgl context: err "+m;m=this.MakeWebGLContext(m);p=this.MakeOnScreenGLSurface(m,y.width,y.height,p);return p?p:(p=y.cloneNode(!0),y.parentNode.replaceChild(p,y),p.classList.add("ck-replaced"),a.MakeSWCanvasSurface(p))};a.MakeCanvasSurface=
a.MakeWebGLCanvasSurface;a.Surface.prototype.makeImageFromTexture=function(m,p){a.Jd(this.Id);m=c(m);if(p=this._makeImageFromTexture(this.Id,m,p))p.he=m;return p};a.Surface.prototype.makeImageFromTextureSource=function(m,p,w){p||(p={height:e(m),width:f(m),colorType:a.ColorType.RGBA_8888,alphaType:w?a.AlphaType.Premul:a.AlphaType.Unpremul});p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);a.Jd(this.Id);var y=v.Ud;w=k(y,y.createTexture(),p,w);2===v.version?y.texImage2D(y.TEXTURE_2D,0,y.RGBA,p.width,p.height,
0,y.RGBA,y.UNSIGNED_BYTE,m):y.texImage2D(y.TEXTURE_2D,0,y.RGBA,y.RGBA,y.UNSIGNED_BYTE,m);l(y,p);this._resetContext();return this.makeImageFromTexture(w,p)};a.Surface.prototype.updateTextureFromSource=function(m,p,w){if(m.he){a.Jd(this.Id);var y=m.getImageInfo(),B=v.Ud,D=k(B,ea[m.he],y,w);2===v.version?B.texImage2D(B.TEXTURE_2D,0,B.RGBA,f(p),e(p),0,B.RGBA,B.UNSIGNED_BYTE,p):B.texImage2D(B.TEXTURE_2D,0,B.RGBA,B.RGBA,B.UNSIGNED_BYTE,p);l(B,y,w);this._resetContext();ea[m.he]=null;m.he=c(D);y.colorSpace=
m.getColorSpace();p=this._makeImageFromTexture(this.Id,m.he,y);w=m.kd.Kd;B=m.kd.Pd;m.kd.Kd=p.kd.Kd;m.kd.Pd=p.kd.Pd;p.kd.Kd=w;p.kd.Pd=B;p.delete();y.colorSpace.delete()}};a.MakeLazyImageFromTextureSource=function(m,p,w){p||(p={height:e(m),width:f(m),colorType:a.ColorType.RGBA_8888,alphaType:w?a.AlphaType.Premul:a.AlphaType.Unpremul});p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);var y={makeTexture:function(){var B=v,D=B.Ud,u=k(D,D.createTexture(),p,w);2===B.version?D.texImage2D(D.TEXTURE_2D,0,D.RGBA,
p.width,p.height,0,D.RGBA,D.UNSIGNED_BYTE,m):D.texImage2D(D.TEXTURE_2D,0,D.RGBA,D.RGBA,D.UNSIGNED_BYTE,m);l(D,p,w);return c(u)},freeSrc:function(){}};"VideoFrame"===m.constructor.name&&(y.freeSrc=function(){m.close()});return a.Image._makeFromGenerator(p,y)};a.Jd=function(m){return m?ha(m):!1};a.ne=function(){return v&&v.ze&&!v.ze.isDeleted()?v.ze:null}})})(r);
(function(a){function b(g){return(f(255*g[3])<<24|f(255*g[0])<<16|f(255*g[1])<<8|f(255*g[2])<<0)>>>0}function c(g){if(g&&g._ck)return g;if(g instanceof Float32Array){for(var d=Math.floor(g.length/4),h=new Uint32Array(d),n=0;n<d;n++)h[n]=b(g.slice(4*n,4*(n+1)));return h}if(g instanceof Uint32Array)return g;if(g instanceof Array&&g[0]instanceof Float32Array)return g.map(b)}function e(g){if(void 0===g)return 1;var d=parseFloat(g);return g&&-1!==g.indexOf("%")?d/100:d}function f(g){return Math.round(Math.max(0,
Math.min(g||0,255)))}function k(g,d){d&&d._ck||a._free(g)}function l(g,d,h){if(!g||!g.length)return M;if(g&&g._ck)return g.byteOffset;var n=a[d].BYTES_PER_ELEMENT;h||(h=a._malloc(g.length*n));a[d].set(g,h/n);return h}function m(g){var d={Rd:M,count:g.length,colorType:a.ColorType.RGBA_F32};if(g instanceof Float32Array)d.Rd=l(g,"HEAPF32"),d.count=g.length/4;else if(g instanceof Uint32Array)d.Rd=l(g,"HEAPU32"),d.colorType=a.ColorType.RGBA_8888;else if(g instanceof Array){if(g&&g.length){for(var h=a._malloc(16*
g.length),n=0,t=h/4,x=0;x<g.length;x++)for(var z=0;4>z;z++)a.HEAPF32[t+n]=g[x][z],n++;g=h}else g=M;d.Rd=g}else throw"Invalid argument to copyFlexibleColorArray, Not a color array "+typeof g;return d}function p(g){if(!g)return M;var d=T.toTypedArray();if(g.length){if(6===g.length||9===g.length)return l(g,"HEAPF32",H),6===g.length&&a.HEAPF32.set(fd,6+H/4),H;if(16===g.length)return d[0]=g[0],d[1]=g[1],d[2]=g[3],d[3]=g[4],d[4]=g[5],d[5]=g[7],d[6]=g[12],d[7]=g[13],d[8]=g[15],H;throw"invalid matrix size";
}if(void 0===g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m41;d[3]=g.m12;d[4]=g.m22;d[5]=g.m42;d[6]=g.m14;d[7]=g.m24;d[8]=g.m44;return H}function w(g){if(!g)return M;var d=Y.toTypedArray();if(g.length){if(16!==g.length&&6!==g.length&&9!==g.length)throw"invalid matrix size";if(16===g.length)return l(g,"HEAPF32",ca);d.fill(0);d[0]=g[0];d[1]=g[1];d[3]=g[2];d[4]=g[3];d[5]=g[4];d[7]=g[5];d[10]=1;d[12]=g[6];d[13]=g[7];d[15]=g[8];6===g.length&&(d[12]=0,d[13]=0,d[15]=1);return ca}if(void 0===
g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m31;d[3]=g.m41;d[4]=g.m12;d[5]=g.m22;d[6]=g.m32;d[7]=g.m42;d[8]=g.m13;d[9]=g.m23;d[10]=g.m33;d[11]=g.m43;d[12]=g.m14;d[13]=g.m24;d[14]=g.m34;d[15]=g.m44;return ca}function y(g,d){return l(g,"HEAPF32",d||va)}function B(g,d,h,n){var t=Na.toTypedArray();t[0]=g;t[1]=d;t[2]=h;t[3]=n;return va}function D(g){for(var d=new Float32Array(4),h=0;4>h;h++)d[h]=a.HEAPF32[g/4+h];return d}function u(g,d){return l(g,"HEAPF32",d||X)}function F(g,d){return l(g,
"HEAPF32",d||Eb)}a.Color=function(g,d,h,n){void 0===n&&(n=1);return a.Color4f(f(g)/255,f(d)/255,f(h)/255,n)};a.ColorAsInt=function(g,d,h,n){void 0===n&&(n=255);return(f(n)<<24|f(g)<<16|f(d)<<8|f(h)<<0&268435455)>>>0};a.Color4f=function(g,d,h,n){void 0===n&&(n=1);return Float32Array.of(g,d,h,n)};Object.defineProperty(a,"TRANSPARENT",{get:function(){return a.Color4f(0,0,0,0)}});Object.defineProperty(a,"BLACK",{get:function(){return a.Color4f(0,0,0,1)}});Object.defineProperty(a,"WHITE",{get:function(){return a.Color4f(1,
1,1,1)}});Object.defineProperty(a,"RED",{get:function(){return a.Color4f(1,0,0,1)}});Object.defineProperty(a,"GREEN",{get:function(){return a.Color4f(0,1,0,1)}});Object.defineProperty(a,"BLUE",{get:function(){return a.Color4f(0,0,1,1)}});Object.defineProperty(a,"YELLOW",{get:function(){return a.Color4f(1,1,0,1)}});Object.defineProperty(a,"CYAN",{get:function(){return a.Color4f(0,1,1,1)}});Object.defineProperty(a,"MAGENTA",{get:function(){return a.Color4f(1,0,1,1)}});a.getColorComponents=function(g){return[Math.floor(255*
g[0]),Math.floor(255*g[1]),Math.floor(255*g[2]),g[3]]};a.parseColorString=function(g,d){g=g.toLowerCase();if(g.startsWith("#")){d=255;switch(g.length){case 9:d=parseInt(g.slice(7,9),16);case 7:var h=parseInt(g.slice(1,3),16);var n=parseInt(g.slice(3,5),16);var t=parseInt(g.slice(5,7),16);break;case 5:d=17*parseInt(g.slice(4,5),16);case 4:h=17*parseInt(g.slice(1,2),16),n=17*parseInt(g.slice(2,3),16),t=17*parseInt(g.slice(3,4),16)}return a.Color(h,n,t,d/255)}return g.startsWith("rgba")?(g=g.slice(5,
-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("rgb")?(g=g.slice(4,-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("gray(")||g.startsWith("hsl")||!d||(g=d[g],void 0===g)?a.BLACK:g};a.multiplyByAlpha=function(g,d){g=g.slice();g[3]=Math.max(0,Math.min(g[3]*d,1));return g};a.Malloc=function(g,d){var h=a._malloc(d*g.BYTES_PER_ELEMENT);return{_ck:!0,length:d,byteOffset:h,be:null,subarray:function(n,t){n=this.toTypedArray().subarray(n,t);n._ck=!0;return n},toTypedArray:function(){if(this.be&&
this.be.length)return this.be;this.be=new g(a.HEAPU8.buffer,h,d);this.be._ck=!0;return this.be}}};a.Free=function(g){a._free(g.byteOffset);g.byteOffset=M;g.toTypedArray=null;g.be=null};var H=M,T,ca=M,Y,va=M,Na,na,X=M,fc,Ba=M,gc,Fb=M,hc,Gb=M,hb,Sa=M,ic,Eb=M,jc,kc=M,fd=Float32Array.of(0,0,1),M=0;a.onRuntimeInitialized=function(){function g(d,h,n,t,x,z,E){z||(z=4*t.width,t.colorType===a.ColorType.RGBA_F16?z*=2:t.colorType===a.ColorType.RGBA_F32&&(z*=4));var J=z*t.height;var I=x?x.byteOffset:a._malloc(J);
if(E?!d._readPixels(t,I,z,h,n,E):!d._readPixels(t,I,z,h,n))return x||a._free(I),null;if(x)return x.toTypedArray();switch(t.colorType){case a.ColorType.RGBA_8888:case a.ColorType.RGBA_F16:d=(new Uint8Array(a.HEAPU8.buffer,I,J)).slice();break;case a.ColorType.RGBA_F32:d=(new Float32Array(a.HEAPU8.buffer,I,J)).slice();break;default:return null}a._free(I);return d}Na=a.Malloc(Float32Array,4);va=Na.byteOffset;Y=a.Malloc(Float32Array,16);ca=Y.byteOffset;T=a.Malloc(Float32Array,9);H=T.byteOffset;ic=a.Malloc(Float32Array,
12);Eb=ic.byteOffset;jc=a.Malloc(Float32Array,12);kc=jc.byteOffset;na=a.Malloc(Float32Array,4);X=na.byteOffset;fc=a.Malloc(Float32Array,4);Ba=fc.byteOffset;gc=a.Malloc(Float32Array,3);Fb=gc.byteOffset;hc=a.Malloc(Float32Array,3);Gb=hc.byteOffset;hb=a.Malloc(Int32Array,4);Sa=hb.byteOffset;a.ColorSpace.SRGB=a.ColorSpace._MakeSRGB();a.ColorSpace.DISPLAY_P3=a.ColorSpace._MakeDisplayP3();a.ColorSpace.ADOBE_RGB=a.ColorSpace._MakeAdobeRGB();a.GlyphRunFlags={IsWhiteSpace:a._GlyphRunFlags_isWhiteSpace};a.Path.MakeFromCmds=
function(d){var h=l(d,"HEAPF32"),n=a.Path._MakeFromCmds(h,d.length);k(h,d);return n};a.Path.MakeFromVerbsPointsWeights=function(d,h,n){var t=l(d,"HEAPU8"),x=l(h,"HEAPF32"),z=l(n,"HEAPF32"),E=a.Path._MakeFromVerbsPointsWeights(t,d.length,x,h.length,z,n&&n.length||0);k(t,d);k(x,h);k(z,n);return E};a.Path.prototype.addArc=function(d,h,n){d=u(d);this._addArc(d,h,n);return this};a.Path.prototype.addCircle=function(d,h,n,t){this._addCircle(d,h,n,!!t);return this};a.Path.prototype.addOval=function(d,h,n){void 0===
n&&(n=1);d=u(d);this._addOval(d,!!h,n);return this};a.Path.prototype.addPath=function(){var d=Array.prototype.slice.call(arguments),h=d[0],n=!1;"boolean"===typeof d[d.length-1]&&(n=d.pop());if(1===d.length)this._addPath(h,1,0,0,0,1,0,0,0,1,n);else if(2===d.length)d=d[1],this._addPath(h,d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1,n);else if(7===d.length||10===d.length)this._addPath(h,d[1],d[2],d[3],d[4],d[5],d[6],d[7]||0,d[8]||0,d[9]||1,n);else return null;return this};a.Path.prototype.addPoly=
function(d,h){var n=l(d,"HEAPF32");this._addPoly(n,d.length/2,h);k(n,d);return this};a.Path.prototype.addRect=function(d,h){d=u(d);this._addRect(d,!!h);return this};a.Path.prototype.addRRect=function(d,h){d=F(d);this._addRRect(d,!!h);return this};a.Path.prototype.addVerbsPointsWeights=function(d,h,n){var t=l(d,"HEAPU8"),x=l(h,"HEAPF32"),z=l(n,"HEAPF32");this._addVerbsPointsWeights(t,d.length,x,h.length,z,n&&n.length||0);k(t,d);k(x,h);k(z,n)};a.Path.prototype.arc=function(d,h,n,t,x,z){d=a.LTRBRect(d-
n,h-n,d+n,h+n);x=(x-t)/Math.PI*180-360*!!z;z=new a.Path;z.addArc(d,t/Math.PI*180,x);this.addPath(z,!0);z.delete();return this};a.Path.prototype.arcToOval=function(d,h,n,t){d=u(d);this._arcToOval(d,h,n,t);return this};a.Path.prototype.arcToRotated=function(d,h,n,t,x,z,E){this._arcToRotated(d,h,n,!!t,!!x,z,E);return this};a.Path.prototype.arcToTangent=function(d,h,n,t,x){this._arcToTangent(d,h,n,t,x);return this};a.Path.prototype.close=function(){this._close();return this};a.Path.prototype.conicTo=
function(d,h,n,t,x){this._conicTo(d,h,n,t,x);return this};a.Path.prototype.computeTightBounds=function(d){this._computeTightBounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.cubicTo=function(d,h,n,t,x,z){this._cubicTo(d,h,n,t,x,z);return this};a.Path.prototype.dash=function(d,h,n){return this._dash(d,h,n)?this:null};a.Path.prototype.getBounds=function(d){this._getBounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.lineTo=function(d,
h){this._lineTo(d,h);return this};a.Path.prototype.moveTo=function(d,h){this._moveTo(d,h);return this};a.Path.prototype.offset=function(d,h){this._transform(1,0,d,0,1,h,0,0,1);return this};a.Path.prototype.quadTo=function(d,h,n,t){this._quadTo(d,h,n,t);return this};a.Path.prototype.rArcTo=function(d,h,n,t,x,z,E){this._rArcTo(d,h,n,t,x,z,E);return this};a.Path.prototype.rConicTo=function(d,h,n,t,x){this._rConicTo(d,h,n,t,x);return this};a.Path.prototype.rCubicTo=function(d,h,n,t,x,z){this._rCubicTo(d,
h,n,t,x,z);return this};a.Path.prototype.rLineTo=function(d,h){this._rLineTo(d,h);return this};a.Path.prototype.rMoveTo=function(d,h){this._rMoveTo(d,h);return this};a.Path.prototype.rQuadTo=function(d,h,n,t){this._rQuadTo(d,h,n,t);return this};a.Path.prototype.stroke=function(d){d=d||{};d.width=d.width||1;d.miter_limit=d.miter_limit||4;d.cap=d.cap||a.StrokeCap.Butt;d.join=d.join||a.StrokeJoin.Miter;d.precision=d.precision||1;return this._stroke(d)?this:null};a.Path.prototype.transform=function(){if(1===
arguments.length){var d=arguments[0];this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1)}else if(6===arguments.length||9===arguments.length)d=arguments,this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1);else throw"transform expected to take 1 or 9 arguments. Got "+arguments.length;return this};a.Path.prototype.trim=function(d,h,n){return this._trim(d,h,!!n)?this:null};a.Image.prototype.encodeToBytes=function(d,h){var n=a.ne();d=d||a.ImageFormat.PNG;h=h||100;
return n?this._encodeToBytes(d,h,n):this._encodeToBytes(d,h)};a.Image.prototype.makeShaderCubic=function(d,h,n,t,x){x=p(x);return this._makeShaderCubic(d,h,n,t,x)};a.Image.prototype.makeShaderOptions=function(d,h,n,t,x){x=p(x);return this._makeShaderOptions(d,h,n,t,x)};a.Image.prototype.readPixels=function(d,h,n,t,x){var z=a.ne();return g(this,d,h,n,t,x,z)};a.Canvas.prototype.clear=function(d){a.Jd(this.Id);d=y(d);this._clear(d)};a.Canvas.prototype.clipRRect=function(d,h,n){a.Jd(this.Id);d=F(d);this._clipRRect(d,
h,n)};a.Canvas.prototype.clipRect=function(d,h,n){a.Jd(this.Id);d=u(d);this._clipRect(d,h,n)};a.Canvas.prototype.concat=function(d){a.Jd(this.Id);d=w(d);this._concat(d)};a.Canvas.prototype.drawArc=function(d,h,n,t,x){a.Jd(this.Id);d=u(d);this._drawArc(d,h,n,t,x)};a.Canvas.prototype.drawAtlas=function(d,h,n,t,x,z,E){if(d&&t&&h&&n&&h.length===n.length){a.Jd(this.Id);x||(x=a.BlendMode.SrcOver);var J=l(h,"HEAPF32"),I=l(n,"HEAPF32"),U=n.length/4,V=l(c(z),"HEAPU32");if(E&&"B"in E&&"C"in E)this._drawAtlasCubic(d,
I,J,V,U,x,E.B,E.C,t);else{let q=a.FilterMode.Linear,A=a.MipmapMode.None;E&&(q=E.filter,"mipmap"in E&&(A=E.mipmap));this._drawAtlasOptions(d,I,J,V,U,x,q,A,t)}k(J,h);k(I,n);k(V,z)}};a.Canvas.prototype.drawCircle=function(d,h,n,t){a.Jd(this.Id);this._drawCircle(d,h,n,t)};a.Canvas.prototype.drawColor=function(d,h){a.Jd(this.Id);d=y(d);void 0!==h?this._drawColor(d,h):this._drawColor(d)};a.Canvas.prototype.drawColorInt=function(d,h){a.Jd(this.Id);this._drawColorInt(d,h||a.BlendMode.SrcOver)};a.Canvas.prototype.drawColorComponents=
function(d,h,n,t,x){a.Jd(this.Id);d=B(d,h,n,t);void 0!==x?this._drawColor(d,x):this._drawColor(d)};a.Canvas.prototype.drawDRRect=function(d,h,n){a.Jd(this.Id);d=F(d,Eb);h=F(h,kc);this._drawDRRect(d,h,n)};a.Canvas.prototype.drawImage=function(d,h,n,t){a.Jd(this.Id);this._drawImage(d,h,n,t||null)};a.Canvas.prototype.drawImageCubic=function(d,h,n,t,x,z){a.Jd(this.Id);this._drawImageCubic(d,h,n,t,x,z||null)};a.Canvas.prototype.drawImageOptions=function(d,h,n,t,x,z){a.Jd(this.Id);this._drawImageOptions(d,
h,n,t,x,z||null)};a.Canvas.prototype.drawImageNine=function(d,h,n,t,x){a.Jd(this.Id);h=l(h,"HEAP32",Sa);n=u(n);this._drawImageNine(d,h,n,t,x||null)};a.Canvas.prototype.drawImageRect=function(d,h,n,t,x){a.Jd(this.Id);u(h,X);u(n,Ba);this._drawImageRect(d,X,Ba,t,!!x)};a.Canvas.prototype.drawImageRectCubic=function(d,h,n,t,x,z){a.Jd(this.Id);u(h,X);u(n,Ba);this._drawImageRectCubic(d,X,Ba,t,x,z||null)};a.Canvas.prototype.drawImageRectOptions=function(d,h,n,t,x,z){a.Jd(this.Id);u(h,X);u(n,Ba);this._drawImageRectOptions(d,
X,Ba,t,x,z||null)};a.Canvas.prototype.drawLine=function(d,h,n,t,x){a.Jd(this.Id);this._drawLine(d,h,n,t,x)};a.Canvas.prototype.drawOval=function(d,h){a.Jd(this.Id);d=u(d);this._drawOval(d,h)};a.Canvas.prototype.drawPaint=function(d){a.Jd(this.Id);this._drawPaint(d)};a.Canvas.prototype.drawParagraph=function(d,h,n){a.Jd(this.Id);this._drawParagraph(d,h,n)};a.Canvas.prototype.drawPatch=function(d,h,n,t,x){if(24>d.length)throw"Need 12 cubic points";if(h&&4>h.length)throw"Need 4 colors";if(n&&8>n.length)throw"Need 4 shader coordinates";
a.Jd(this.Id);const z=l(d,"HEAPF32"),E=h?l(c(h),"HEAPU32"):M,J=n?l(n,"HEAPF32"):M;t||(t=a.BlendMode.Modulate);this._drawPatch(z,E,J,t,x);k(J,n);k(E,h);k(z,d)};a.Canvas.prototype.drawPath=function(d,h){a.Jd(this.Id);this._drawPath(d,h)};a.Canvas.prototype.drawPicture=function(d){a.Jd(this.Id);this._drawPicture(d)};a.Canvas.prototype.drawPoints=function(d,h,n){a.Jd(this.Id);var t=l(h,"HEAPF32");this._drawPoints(d,t,h.length/2,n);k(t,h)};a.Canvas.prototype.drawRRect=function(d,h){a.Jd(this.Id);d=F(d);
this._drawRRect(d,h)};a.Canvas.prototype.drawRect=function(d,h){a.Jd(this.Id);d=u(d);this._drawRect(d,h)};a.Canvas.prototype.drawRect4f=function(d,h,n,t,x){a.Jd(this.Id);this._drawRect4f(d,h,n,t,x)};a.Canvas.prototype.drawShadow=function(d,h,n,t,x,z,E){a.Jd(this.Id);var J=l(x,"HEAPF32"),I=l(z,"HEAPF32");h=l(h,"HEAPF32",Fb);n=l(n,"HEAPF32",Gb);this._drawShadow(d,h,n,t,J,I,E);k(J,x);k(I,z)};a.getShadowLocalBounds=function(d,h,n,t,x,z,E){d=p(d);n=l(n,"HEAPF32",Fb);t=l(t,"HEAPF32",Gb);if(!this._getShadowLocalBounds(d,
h,n,t,x,z,X))return null;h=na.toTypedArray();return E?(E.set(h),E):h.slice()};a.Canvas.prototype.drawTextBlob=function(d,h,n,t){a.Jd(this.Id);this._drawTextBlob(d,h,n,t)};a.Canvas.prototype.drawVertices=function(d,h,n){a.Jd(this.Id);this._drawVertices(d,h,n)};a.Canvas.prototype.getDeviceClipBounds=function(d){this._getDeviceClipBounds(Sa);var h=hb.toTypedArray();d?d.set(h):d=h.slice();return d};a.Canvas.prototype.getLocalToDevice=function(){this._getLocalToDevice(ca);for(var d=ca,h=Array(16),n=0;16>
n;n++)h[n]=a.HEAPF32[d/4+n];return h};a.Canvas.prototype.getTotalMatrix=function(){this._getTotalMatrix(H);for(var d=Array(9),h=0;9>h;h++)d[h]=a.HEAPF32[H/4+h];return d};a.Canvas.prototype.makeSurface=function(d){d=this._makeSurface(d);d.Id=this.Id;return d};a.Canvas.prototype.readPixels=function(d,h,n,t,x){a.Jd(this.Id);return g(this,d,h,n,t,x)};a.Canvas.prototype.saveLayer=function(d,h,n,t){h=u(h);return this._saveLayer(d||null,h,n||null,t||0)};a.Canvas.prototype.writePixels=function(d,h,n,t,x,
z,E,J){if(d.byteLength%(h*n))throw"pixels length must be a multiple of the srcWidth * srcHeight";a.Jd(this.Id);var I=d.byteLength/(h*n);z=z||a.AlphaType.Unpremul;E=E||a.ColorType.RGBA_8888;J=J||a.ColorSpace.SRGB;var U=I*h;I=l(d,"HEAPU8");h=this._writePixels({width:h,height:n,colorType:E,alphaType:z,colorSpace:J},I,U,t,x);k(I,d);return h};a.ColorFilter.MakeBlend=function(d,h,n){d=y(d);n=n||a.ColorSpace.SRGB;return a.ColorFilter._MakeBlend(d,h,n)};a.ColorFilter.MakeMatrix=function(d){if(!d||20!==d.length)throw"invalid color matrix";
var h=l(d,"HEAPF32"),n=a.ColorFilter._makeMatrix(h);k(h,d);return n};a.ContourMeasure.prototype.getPosTan=function(d,h){this._getPosTan(d,X);d=na.toTypedArray();return h?(h.set(d),h):d.slice()};a.ImageFilter.prototype.getOutputBounds=function(d,h,n){d=u(d,X);h=p(h);this._getOutputBounds(d,h,Sa);h=hb.toTypedArray();return n?(n.set(h),n):h.slice()};a.ImageFilter.MakeDropShadow=function(d,h,n,t,x,z){x=y(x,va);return a.ImageFilter._MakeDropShadow(d,h,n,t,x,z)};a.ImageFilter.MakeDropShadowOnly=function(d,
h,n,t,x,z){x=y(x,va);return a.ImageFilter._MakeDropShadowOnly(d,h,n,t,x,z)};a.ImageFilter.MakeImage=function(d,h,n,t){n=u(n,X);t=u(t,Ba);if("B"in h&&"C"in h)return a.ImageFilter._MakeImageCubic(d,h.B,h.C,n,t);const x=h.filter;let z=a.MipmapMode.None;"mipmap"in h&&(z=h.mipmap);return a.ImageFilter._MakeImageOptions(d,x,z,n,t)};a.ImageFilter.MakeMatrixTransform=function(d,h,n){d=p(d);if("B"in h&&"C"in h)return a.ImageFilter._MakeMatrixTransformCubic(d,h.B,h.C,n);const t=h.filter;let x=a.MipmapMode.None;
"mipmap"in h&&(x=h.mipmap);return a.ImageFilter._MakeMatrixTransformOptions(d,t,x,n)};a.Paint.prototype.getColor=function(){this._getColor(va);return D(va)};a.Paint.prototype.setColor=function(d,h){h=h||null;d=y(d);this._setColor(d,h)};a.Paint.prototype.setColorComponents=function(d,h,n,t,x){x=x||null;d=B(d,h,n,t);this._setColor(d,x)};a.Path.prototype.getPoint=function(d,h){this._getPoint(d,X);d=na.toTypedArray();return h?(h[0]=d[0],h[1]=d[1],h):d.slice(0,2)};a.Picture.prototype.makeShader=function(d,
h,n,t,x){t=p(t);x=u(x);return this._makeShader(d,h,n,t,x)};a.Picture.prototype.cullRect=function(d){this._cullRect(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.PictureRecorder.prototype.beginRecording=function(d,h){d=u(d);return this._beginRecording(d,!!h)};a.Surface.prototype.getCanvas=function(){var d=this._getCanvas();d.Id=this.Id;return d};a.Surface.prototype.makeImageSnapshot=function(d){a.Jd(this.Id);d=l(d,"HEAP32",Sa);return this._makeImageSnapshot(d)};a.Surface.prototype.makeSurface=
function(d){a.Jd(this.Id);d=this._makeSurface(d);d.Id=this.Id;return d};a.Surface.prototype.Te=function(d,h){this.ge||(this.ge=this.getCanvas());return requestAnimationFrame(function(){a.Jd(this.Id);d(this.ge);this.flush(h)}.bind(this))};a.Surface.prototype.requestAnimationFrame||(a.Surface.prototype.requestAnimationFrame=a.Surface.prototype.Te);a.Surface.prototype.Qe=function(d,h){this.ge||(this.ge=this.getCanvas());requestAnimationFrame(function(){a.Jd(this.Id);d(this.ge);this.flush(h);this.dispose()}.bind(this))};
a.Surface.prototype.drawOnce||(a.Surface.prototype.drawOnce=a.Surface.prototype.Qe);a.PathEffect.MakeDash=function(d,h){h||(h=0);if(!d.length||1===d.length%2)throw"Intervals array must have even length";var n=l(d,"HEAPF32");h=a.PathEffect._MakeDash(n,d.length,h);k(n,d);return h};a.PathEffect.MakeLine2D=function(d,h){h=p(h);return a.PathEffect._MakeLine2D(d,h)};a.PathEffect.MakePath2D=function(d,h){d=p(d);return a.PathEffect._MakePath2D(d,h)};a.Shader.MakeColor=function(d,h){h=h||null;d=y(d);return a.Shader._MakeColor(d,
h)};a.Shader.Blend=a.Shader.MakeBlend;a.Shader.Color=a.Shader.MakeColor;a.Shader.MakeLinearGradient=function(d,h,n,t,x,z,E,J){J=J||null;var I=m(n),U=l(t,"HEAPF32");E=E||0;z=p(z);var V=na.toTypedArray();V.set(d);V.set(h,2);d=a.Shader._MakeLinearGradient(X,I.Rd,I.colorType,U,I.count,x,E,z,J);k(I.Rd,n);t&&k(U,t);return d};a.Shader.MakeRadialGradient=function(d,h,n,t,x,z,E,J){J=J||null;var I=m(n),U=l(t,"HEAPF32");E=E||0;z=p(z);d=a.Shader._MakeRadialGradient(d[0],d[1],h,I.Rd,I.colorType,U,I.count,x,E,
z,J);k(I.Rd,n);t&&k(U,t);return d};a.Shader.MakeSweepGradient=function(d,h,n,t,x,z,E,J,I,U){U=U||null;var V=m(n),q=l(t,"HEAPF32");E=E||0;J=J||0;I=I||360;z=p(z);d=a.Shader._MakeSweepGradient(d,h,V.Rd,V.colorType,q,V.count,x,J,I,E,z,U);k(V.Rd,n);t&&k(q,t);return d};a.Shader.MakeTwoPointConicalGradient=function(d,h,n,t,x,z,E,J,I,U){U=U||null;var V=m(x),q=l(z,"HEAPF32");I=I||0;J=p(J);var A=na.toTypedArray();A.set(d);A.set(n,2);d=a.Shader._MakeTwoPointConicalGradient(X,h,t,V.Rd,V.colorType,q,V.count,E,
I,J,U);k(V.Rd,x);z&&k(q,z);return d};a.Vertices.prototype.bounds=function(d){this._bounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Md&&a.Md.forEach(function(d){d()})};a.computeTonalColors=function(g){var d=l(g.ambient,"HEAPF32"),h=l(g.spot,"HEAPF32");this._computeTonalColors(d,h);var n={ambient:D(d),spot:D(h)};k(d,g.ambient);k(h,g.spot);return n};a.LTRBRect=function(g,d,h,n){return Float32Array.of(g,d,h,n)};a.XYWHRect=function(g,d,h,n){return Float32Array.of(g,d,g+h,d+n)};a.LTRBiRect=
function(g,d,h,n){return Int32Array.of(g,d,h,n)};a.XYWHiRect=function(g,d,h,n){return Int32Array.of(g,d,g+h,d+n)};a.RRectXY=function(g,d,h){return Float32Array.of(g[0],g[1],g[2],g[3],d,h,d,h,d,h,d,h)};a.MakeAnimatedImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeAnimatedImage(d,g.byteLength))?g:null};a.MakeImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeImage(d,g.byteLength))?
g:null};var Ta=null;a.MakeImageFromCanvasImageSource=function(g){var d=g.width,h=g.height;Ta||(Ta=document.createElement("canvas"));Ta.width=d;Ta.height=h;var n=Ta.getContext("2d",{willReadFrequently:!0});n.drawImage(g,0,0);g=n.getImageData(0,0,d,h);return a.MakeImage({width:d,height:h,alphaType:a.AlphaType.Unpremul,colorType:a.ColorType.RGBA_8888,colorSpace:a.ColorSpace.SRGB},g.data,4*d)};a.MakeImage=function(g,d,h){var n=a._malloc(d.length);a.HEAPU8.set(d,n);return a._MakeImage(g,n,d.length,h)};
a.MakeVertices=function(g,d,h,n,t,x){var z=t&&t.length||0,E=0;h&&h.length&&(E|=1);n&&n.length&&(E|=2);void 0===x||x||(E|=4);g=new a._VerticesBuilder(g,d.length/2,z,E);l(d,"HEAPF32",g.positions());g.texCoords()&&l(h,"HEAPF32",g.texCoords());g.colors()&&l(c(n),"HEAPU32",g.colors());g.indices()&&l(t,"HEAPU16",g.indices());return g.detach()};(function(g){g.Md=g.Md||[];g.Md.push(function(){function d(q){q&&(q.dir=0===q.dir?g.TextDirection.RTL:g.TextDirection.LTR);return q}function h(q){if(!q||!q.length)return[];
for(var A=[],P=0;P<q.length;P+=5){var Z=g.LTRBRect(q[P],q[P+1],q[P+2],q[P+3]),za=g.TextDirection.LTR;0===q[P+4]&&(za=g.TextDirection.RTL);A.push({rect:Z,dir:za})}g._free(q.byteOffset);return A}function n(q){q=q||{};void 0===q.weight&&(q.weight=g.FontWeight.Normal);q.width=q.width||g.FontWidth.Normal;q.slant=q.slant||g.FontSlant.Upright;return q}function t(q){if(!q||!q.length)return M;for(var A=[],P=0;P<q.length;P++){var Z=x(q[P]);A.push(Z)}return l(A,"HEAPU32")}function x(q){if(J[q])return J[q];var A=
ja(q)+1,P=g._malloc(A);ka(q,C,P,A);return J[q]=P}function z(q){q._colorPtr=y(q.color);q._foregroundColorPtr=M;q._backgroundColorPtr=M;q._decorationColorPtr=M;q.foregroundColor&&(q._foregroundColorPtr=y(q.foregroundColor,I));q.backgroundColor&&(q._backgroundColorPtr=y(q.backgroundColor,U));q.decorationColor&&(q._decorationColorPtr=y(q.decorationColor,V));Array.isArray(q.fontFamilies)&&q.fontFamilies.length?(q._fontFamiliesPtr=t(q.fontFamilies),q._fontFamiliesLen=q.fontFamilies.length):(q._fontFamiliesPtr=
M,q._fontFamiliesLen=0);if(q.locale){var A=q.locale;q._localePtr=x(A);q._localeLen=ja(A)}else q._localePtr=M,q._localeLen=0;if(Array.isArray(q.shadows)&&q.shadows.length){A=q.shadows;var P=A.map(function(qa){return qa.color||g.BLACK}),Z=A.map(function(qa){return qa.blurRadius||0});q._shadowLen=A.length;for(var za=g._malloc(8*A.length),Hb=za/4,Ib=0;Ib<A.length;Ib++){var lc=A[Ib].offset||[0,0];g.HEAPF32[Hb]=lc[0];g.HEAPF32[Hb+1]=lc[1];Hb+=2}q._shadowColorsPtr=m(P).Rd;q._shadowOffsetsPtr=za;q._shadowBlurRadiiPtr=
l(Z,"HEAPF32")}else q._shadowLen=0,q._shadowColorsPtr=M,q._shadowOffsetsPtr=M,q._shadowBlurRadiiPtr=M;Array.isArray(q.fontFeatures)&&q.fontFeatures.length?(A=q.fontFeatures,P=A.map(function(qa){return qa.name}),Z=A.map(function(qa){return qa.value}),q._fontFeatureLen=A.length,q._fontFeatureNamesPtr=t(P),q._fontFeatureValuesPtr=l(Z,"HEAPU32")):(q._fontFeatureLen=0,q._fontFeatureNamesPtr=M,q._fontFeatureValuesPtr=M);Array.isArray(q.fontVariations)&&q.fontVariations.length?(A=q.fontVariations,P=A.map(function(qa){return qa.axis}),
Z=A.map(function(qa){return qa.value}),q._fontVariationLen=A.length,q._fontVariationAxesPtr=t(P),q._fontVariationValuesPtr=l(Z,"HEAPF32")):(q._fontVariationLen=0,q._fontVariationAxesPtr=M,q._fontVariationValuesPtr=M)}function E(q){g._free(q._fontFamiliesPtr);g._free(q._shadowColorsPtr);g._free(q._shadowOffsetsPtr);g._free(q._shadowBlurRadiiPtr);g._free(q._fontFeatureNamesPtr);g._free(q._fontFeatureValuesPtr);g._free(q._fontVariationAxesPtr);g._free(q._fontVariationValuesPtr)}g.Paragraph.prototype.getRectsForRange=
function(q,A,P,Z){q=this._getRectsForRange(q,A,P,Z);return h(q)};g.Paragraph.prototype.getRectsForPlaceholders=function(){var q=this._getRectsForPlaceholders();return h(q)};g.Paragraph.prototype.getGlyphInfoAt=function(q){return d(this._getGlyphInfoAt(q))};g.Paragraph.prototype.getClosestGlyphInfoAtCoordinate=function(q,A){return d(this._getClosestGlyphInfoAtCoordinate(q,A))};g.TypefaceFontProvider.prototype.registerFont=function(q,A){q=g.Typeface.MakeTypefaceFromData(q);if(!q)return null;A=x(A);
this._registerFont(q,A)};g.ParagraphStyle=function(q){q.disableHinting=q.disableHinting||!1;if(q.ellipsis){var A=q.ellipsis;q._ellipsisPtr=x(A);q._ellipsisLen=ja(A)}else q._ellipsisPtr=M,q._ellipsisLen=0;null==q.heightMultiplier&&(q.heightMultiplier=-1);q.maxLines=q.maxLines||0;q.replaceTabCharacters=q.replaceTabCharacters||!1;A=(A=q.strutStyle)||{};A.strutEnabled=A.strutEnabled||!1;A.strutEnabled&&Array.isArray(A.fontFamilies)&&A.fontFamilies.length?(A._fontFamiliesPtr=t(A.fontFamilies),A._fontFamiliesLen=
A.fontFamilies.length):(A._fontFamiliesPtr=M,A._fontFamiliesLen=0);A.fontStyle=n(A.fontStyle);null==A.fontSize&&(A.fontSize=-1);null==A.heightMultiplier&&(A.heightMultiplier=-1);A.halfLeading=A.halfLeading||!1;A.leading=A.leading||0;A.forceStrutHeight=A.forceStrutHeight||!1;q.strutStyle=A;q.textAlign=q.textAlign||g.TextAlign.Start;q.textDirection=q.textDirection||g.TextDirection.LTR;q.textHeightBehavior=q.textHeightBehavior||g.TextHeightBehavior.All;q.textStyle=g.TextStyle(q.textStyle);q.applyRoundingHack=
!1!==q.applyRoundingHack;return q};g.TextStyle=function(q){q.color||(q.color=g.BLACK);q.decoration=q.decoration||0;q.decorationThickness=q.decorationThickness||0;q.decorationStyle=q.decorationStyle||g.DecorationStyle.Solid;q.textBaseline=q.textBaseline||g.TextBaseline.Alphabetic;null==q.fontSize&&(q.fontSize=-1);q.letterSpacing=q.letterSpacing||0;q.wordSpacing=q.wordSpacing||0;null==q.heightMultiplier&&(q.heightMultiplier=-1);q.halfLeading=q.halfLeading||!1;q.fontStyle=n(q.fontStyle);return q};var J=
{},I=g._malloc(16),U=g._malloc(16),V=g._malloc(16);g.ParagraphBuilder.Make=function(q,A){z(q.textStyle);A=g.ParagraphBuilder._Make(q,A);E(q.textStyle);return A};g.ParagraphBuilder.MakeFromFontProvider=function(q,A){z(q.textStyle);A=g.ParagraphBuilder._MakeFromFontProvider(q,A);E(q.textStyle);return A};g.ParagraphBuilder.MakeFromFontCollection=function(q,A){z(q.textStyle);A=g.ParagraphBuilder._MakeFromFontCollection(q,A);E(q.textStyle);return A};g.ParagraphBuilder.ShapeText=function(q,A,P){let Z=0;
for(const za of A)Z+=za.length;if(Z!==q.length)throw"Accumulated block lengths must equal text.length";return g.ParagraphBuilder._ShapeText(q,A,P)};g.ParagraphBuilder.prototype.pushStyle=function(q){z(q);this._pushStyle(q);E(q)};g.ParagraphBuilder.prototype.pushPaintStyle=function(q,A,P){z(q);this._pushPaintStyle(q,A,P);E(q)};g.ParagraphBuilder.prototype.addPlaceholder=function(q,A,P,Z,za){P=P||g.PlaceholderAlignment.Baseline;Z=Z||g.TextBaseline.Alphabetic;this._addPlaceholder(q||0,A||0,P,Z,za||0)};
g.ParagraphBuilder.prototype.setWordsUtf8=function(q){var A=l(q,"HEAPU32");this._setWordsUtf8(A,q&&q.length||0);k(A,q)};g.ParagraphBuilder.prototype.setWordsUtf16=function(q){var A=l(q,"HEAPU32");this._setWordsUtf16(A,q&&q.length||0);k(A,q)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf8=function(q){var A=l(q,"HEAPU32");this._setGraphemeBreaksUtf8(A,q&&q.length||0);k(A,q)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf16=function(q){var A=l(q,"HEAPU32");this._setGraphemeBreaksUtf16(A,q&&q.length||
0);k(A,q)};g.ParagraphBuilder.prototype.setLineBreaksUtf8=function(q){var A=l(q,"HEAPU32");this._setLineBreaksUtf8(A,q&&q.length||0);k(A,q)};g.ParagraphBuilder.prototype.setLineBreaksUtf16=function(q){var A=l(q,"HEAPU32");this._setLineBreaksUtf16(A,q&&q.length||0);k(A,q)}})})(r);a.Md=a.Md||[];a.Md.push(function(){a.Path.prototype.op=function(g,d){return this._op(g,d)?this:null};a.Path.prototype.simplify=function(){return this._simplify()?this:null}});a.Md=a.Md||[];a.Md.push(function(){a.Canvas.prototype.drawText=
function(g,d,h,n,t){var x=ja(g),z=a._malloc(x+1);ka(g,C,z,x+1);this._drawSimpleText(z,x,d,h,t,n);a._free(z)};a.Canvas.prototype.drawGlyphs=function(g,d,h,n,t,x){if(!(2*g.length<=d.length))throw"Not enough positions for the array of gyphs";a.Jd(this.Id);const z=l(g,"HEAPU16"),E=l(d,"HEAPF32");this._drawGlyphs(g.length,z,E,h,n,t,x);k(E,d);k(z,g)};a.Font.prototype.getGlyphBounds=function(g,d,h){var n=l(g,"HEAPU16"),t=a._malloc(16*g.length);this._getGlyphWidthBounds(n,g.length,M,t,d||null);d=new Float32Array(a.HEAPU8.buffer,
t,4*g.length);k(n,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.Font.prototype.getGlyphIDs=function(g,d,h){d||(d=g.length);var n=ja(g)+1,t=a._malloc(n);ka(g,C,t,n);g=a._malloc(2*d);d=this._getGlyphIDs(t,n-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.Font.prototype.getGlyphIntercepts=function(g,d,h,n){var t=l(g,"HEAPU16"),x=l(d,"HEAPF32");return this._getGlyphIntercepts(t,
g.length,!(g&&g._ck),x,d.length,!(d&&d._ck),h,n)};a.Font.prototype.getGlyphWidths=function(g,d,h){var n=l(g,"HEAPU16"),t=a._malloc(4*g.length);this._getGlyphWidthBounds(n,g.length,t,M,d||null);d=new Float32Array(a.HEAPU8.buffer,t,g.length);k(n,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.FontMgr.FromData=function(){if(!arguments.length)return null;var g=arguments;1===g.length&&Array.isArray(g[0])&&(g=arguments[0]);if(!g.length)return null;for(var d=[],h=[],n=
0;n<g.length;n++){var t=new Uint8Array(g[n]),x=l(t,"HEAPU8");d.push(x);h.push(t.byteLength)}d=l(d,"HEAPU32");h=l(h,"HEAPU32");g=a.FontMgr._fromData(d,h,g.length);a._free(d);a._free(h);return g};a.Typeface.MakeTypefaceFromData=function(g){g=new Uint8Array(g);var d=l(g,"HEAPU8");return(g=a.Typeface._MakeTypefaceFromData(d,g.byteLength))?g:null};a.Typeface.MakeFreeTypeFaceFromData=a.Typeface.MakeTypefaceFromData;a.Typeface.prototype.getGlyphIDs=function(g,d,h){d||(d=g.length);var n=ja(g)+1,t=a._malloc(n);
ka(g,C,t,n);g=a._malloc(2*d);d=this._getGlyphIDs(t,n-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.TextBlob.MakeOnPath=function(g,d,h,n){if(g&&g.length&&d&&d.countPoints()){if(1===d.countPoints())return this.MakeFromText(g,h);n||(n=0);var t=h.getGlyphIDs(g);t=h.getGlyphWidths(t);var x=[];d=new a.ContourMeasureIter(d,!1,1);for(var z=d.next(),E=new Float32Array(4),J=0;J<g.length&&
z;J++){var I=t[J];n+=I/2;if(n>z.length()){z.delete();z=d.next();if(!z){g=g.substring(0,J);break}n=I/2}z.getPosTan(n,E);var U=E[2],V=E[3];x.push(U,V,E[0]-I/2*U,E[1]-I/2*V);n+=I/2}g=this.MakeFromRSXform(g,x,h);z&&z.delete();d.delete();return g}};a.TextBlob.MakeFromRSXform=function(g,d,h){var n=ja(g)+1,t=a._malloc(n);ka(g,C,t,n);g=l(d,"HEAPF32");h=a.TextBlob._MakeFromRSXform(t,n-1,g,h);a._free(t);return h?h:null};a.TextBlob.MakeFromRSXformGlyphs=function(g,d,h){var n=l(g,"HEAPU16");d=l(d,"HEAPF32");
h=a.TextBlob._MakeFromRSXformGlyphs(n,2*g.length,d,h);k(n,g);return h?h:null};a.TextBlob.MakeFromGlyphs=function(g,d){var h=l(g,"HEAPU16");d=a.TextBlob._MakeFromGlyphs(h,2*g.length,d);k(h,g);return d?d:null};a.TextBlob.MakeFromText=function(g,d){var h=ja(g)+1,n=a._malloc(h);ka(g,C,n,h);g=a.TextBlob._MakeFromText(n,h-1,d);a._free(n);return g?g:null};a.MallocGlyphIDs=function(g){return a.Malloc(Uint16Array,g)}});a.Md=a.Md||[];a.Md.push(function(){a.MakePicture=function(g){g=new Uint8Array(g);var d=
a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._MakePicture(d,g.byteLength))?g:null}});a.Md=a.Md||[];a.Md.push(function(){a.RuntimeEffect.Make=function(g,d){return a.RuntimeEffect._Make(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.MakeForBlender=function(g,d){return a.RuntimeEffect._MakeForBlender(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.prototype.makeShader=function(g,d){var h=!g._ck,n=l(g,"HEAPF32");d=p(d);return this._makeShader(n,
4*g.length,h,d)};a.RuntimeEffect.prototype.makeShaderWithChildren=function(g,d,h){var n=!g._ck,t=l(g,"HEAPF32");h=p(h);for(var x=[],z=0;z<d.length;z++)x.push(d[z].kd.Kd);d=l(x,"HEAPU32");return this._makeShaderWithChildren(t,4*g.length,n,d,x.length,h)};a.RuntimeEffect.prototype.makeBlender=function(g){var d=!g._ck,h=l(g,"HEAPF32");return this._makeBlender(h,4*g.length,d)}})})(r);
var la=Object.assign({},r),ma="./this.program",oa=(a,b)=>{throw b;},pa="object"==typeof window,ra="function"==typeof importScripts,sa="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,ta="",ua,wa,xa;
if(sa){const {createRequire:a}=await import("module");var require=a(import.meta.url),fs=require("fs"),ya=require("path");ra?ta=ya.dirname(ta)+"/":ta=require("url").fileURLToPath(new URL("./",import.meta.url));ua=(b,c)=>{b=b.startsWith("file://")?new URL(b):ya.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")};xa=b=>{b=ua(b,!0);b.buffer||(b=new Uint8Array(b));return b};wa=(b,c,e,f=!0)=>{b=b.startsWith("file://")?new URL(b):ya.normalize(b);fs.readFile(b,f?void 0:
"utf8",(k,l)=>{k?e(k):c(f?l.buffer:l)})};!r.thisProgram&&1<process.argv.length&&(ma=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);oa=(b,c)=>{process.exitCode=b;throw c;};r.inspect=()=>"[Emscripten Module object]"}else if(pa||ra)ra?ta=self.location.href:"undefined"!=typeof document&&document.currentScript&&(ta=document.currentScript.src),_scriptDir&&(ta=_scriptDir),0!==ta.indexOf("blob:")?ta=ta.substr(0,ta.replace(/[?#].*/,"").lastIndexOf("/")+1):ta="",ua=a=>{var b=new XMLHttpRequest;b.open("GET",
a,!1);b.send(null);return b.responseText},ra&&(xa=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),wa=(a,b,c)=>{var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?b(e.response):c()};e.onerror=c;e.send(null)};var Aa=r.print||console.log.bind(console),Ca=r.printErr||console.error.bind(console);Object.assign(r,la);la=null;r.thisProgram&&(ma=r.thisProgram);
r.quit&&(oa=r.quit);var Da;r.wasmBinary&&(Da=r.wasmBinary);var noExitRuntime=r.noExitRuntime||!0;"object"!=typeof WebAssembly&&Ea("no native wasm support detected");var Fa,G,Ga=!1,Ha,C,Ia,Ja,K,L,N,Ka;function La(){var a=Fa.buffer;r.HEAP8=Ha=new Int8Array(a);r.HEAP16=Ia=new Int16Array(a);r.HEAP32=K=new Int32Array(a);r.HEAPU8=C=new Uint8Array(a);r.HEAPU16=Ja=new Uint16Array(a);r.HEAPU32=L=new Uint32Array(a);r.HEAPF32=N=new Float32Array(a);r.HEAPF64=Ka=new Float64Array(a)}var Ma,Oa=[],Pa=[],Qa=[];
function Ra(){var a=r.preRun.shift();Oa.unshift(a)}var Ua=0,Va=null,Wa=null;function Ea(a){if(r.onAbort)r.onAbort(a);a="Aborted("+a+")";Ca(a);Ga=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ba(a);throw a;}function Xa(a){return a.startsWith("data:application/octet-stream;base64,")}var Ya;if(r.locateFile){if(Ya="canvaskit.wasm",!Xa(Ya)){var Za=Ya;Ya=r.locateFile?r.locateFile(Za,ta):ta+Za}}else Ya=(new URL("canvaskit.wasm",import.meta.url)).href;
function $a(a){if(a==Ya&&Da)return new Uint8Array(Da);if(xa)return xa(a);throw"both async and sync fetching of the wasm failed";}function ab(a){if(!Da&&(pa||ra)){if("function"==typeof fetch&&!a.startsWith("file://"))return fetch(a,{credentials:"same-origin"}).then(b=>{if(!b.ok)throw"failed to load wasm binary file at '"+a+"'";return b.arrayBuffer()}).catch(()=>$a(a));if(wa)return new Promise((b,c)=>{wa(a,e=>b(new Uint8Array(e)),c)})}return Promise.resolve().then(()=>$a(a))}
function bb(a,b,c){return ab(a).then(e=>WebAssembly.instantiate(e,b)).then(e=>e).then(c,e=>{Ca("failed to asynchronously prepare wasm: "+e);Ea(e)})}
function cb(a,b){var c=Ya;return Da||"function"!=typeof WebAssembly.instantiateStreaming||Xa(c)||c.startsWith("file://")||sa||"function"!=typeof fetch?bb(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){Ca("wasm streaming compile failed: "+f);Ca("falling back to ArrayBuffer instantiation");return bb(c,a,b)}))}function db(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var eb=a=>{for(;0<a.length;)a.shift()(r)};
function fb(a){this.Kd=a-24;this.Pe=function(b){L[this.Kd+4>>2]=b};this.we=function(b){L[this.Kd+8>>2]=b};this.Zd=function(b,c){this.ve();this.Pe(b);this.we(c)};this.ve=function(){L[this.Kd+16>>2]=0}}
var gb=0,ib=0,jb="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,kb=(a,b,c)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16<c-b&&a.buffer&&jb)return jb.decode(a.subarray(b,c));for(e="";b<c;){var f=a[b++];if(f&128){var k=a[b++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|k);else{var l=a[b++]&63;f=224==(f&240)?(f&15)<<12|k<<6|l:(f&7)<<18|k<<12|l<<6|a[b++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e},
lb={};function mb(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function nb(a){return this.fromWireType(K[a>>2])}var ob={},pb={},qb={},rb=void 0;function sb(a){throw new rb(a);}
function tb(a,b,c){function e(m){m=c(m);m.length!==a.length&&sb("Mismatched type converter count");for(var p=0;p<a.length;++p)ub(a[p],m[p])}a.forEach(function(m){qb[m]=b});var f=Array(b.length),k=[],l=0;b.forEach((m,p)=>{pb.hasOwnProperty(m)?f[p]=pb[m]:(k.push(m),ob.hasOwnProperty(m)||(ob[m]=[]),ob[m].push(()=>{f[p]=pb[m];++l;l===k.length&&e(f)}))});0===k.length&&e(f)}
function vb(a){switch(a){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError(`Unknown type size: ${a}`);}}var wb=void 0;function O(a){for(var b="";C[a];)b+=wb[C[a++]];return b}var xb=void 0;function Q(a){throw new xb(a);}
function yb(a,b,c={}){var e=b.name;a||Q(`type "${e}" must have a positive integer typeid pointer`);if(pb.hasOwnProperty(a)){if(c.ff)return;Q(`Cannot register type '${e}' twice`)}pb[a]=b;delete qb[a];ob.hasOwnProperty(a)&&(b=ob[a],delete ob[a],b.forEach(f=>f()))}function ub(a,b,c={}){if(!("argPackAdvance"in b))throw new TypeError("registerType registeredInstance requires argPackAdvance");yb(a,b,c)}function zb(a){Q(a.kd.Nd.Ld.name+" instance already deleted")}var Ab=!1;function Bb(){}
function Cb(a){--a.count.value;0===a.count.value&&(a.Pd?a.Td.Xd(a.Pd):a.Nd.Ld.Xd(a.Kd))}function Db(a,b,c){if(b===c)return a;if(void 0===c.Qd)return null;a=Db(a,b,c.Qd);return null===a?null:c.Ye(a)}var Jb={},Kb=[];function Lb(){for(;Kb.length;){var a=Kb.pop();a.kd.ee=!1;a["delete"]()}}var Mb=void 0,Nb={};function Ob(a,b){for(void 0===b&&Q("ptr should not be undefined");a.Qd;)b=a.ke(b),a=a.Qd;return Nb[b]}
function Pb(a,b){b.Nd&&b.Kd||sb("makeClassHandle requires ptr and ptrType");!!b.Td!==!!b.Pd&&sb("Both smartPtrType and smartPtr must be specified");b.count={value:1};return Qb(Object.create(a,{kd:{value:b}}))}function Qb(a){if("undefined"===typeof FinalizationRegistry)return Qb=b=>b,a;Ab=new FinalizationRegistry(b=>{Cb(b.kd)});Qb=b=>{var c=b.kd;c.Pd&&Ab.register(b,{kd:c},b);return b};Bb=b=>{Ab.unregister(b)};return Qb(a)}function Rb(){}
function Sb(a){if(void 0===a)return"_unknown";a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?`_${a}`:a}function Tb(a,b){a=Sb(a);return{[a]:function(){return b.apply(this,arguments)}}[a]}
function Ub(a,b,c){if(void 0===a[b].Od){var e=a[b];a[b]=function(){a[b].Od.hasOwnProperty(arguments.length)||Q(`Function '${c}' called with an invalid number of arguments (${arguments.length}) - expects one of (${a[b].Od})!`);return a[b].Od[arguments.length].apply(this,arguments)};a[b].Od=[];a[b].Od[e.ce]=e}}
function Vb(a,b,c){r.hasOwnProperty(a)?((void 0===c||void 0!==r[a].Od&&void 0!==r[a].Od[c])&&Q(`Cannot register public name '${a}' twice`),Ub(r,a,a),r.hasOwnProperty(c)&&Q(`Cannot register multiple overloads of a function with the same number of arguments (${c})!`),r[a].Od[c]=b):(r[a]=b,void 0!==c&&(r[a].xf=c))}function Wb(a,b,c,e,f,k,l,m){this.name=a;this.constructor=b;this.fe=c;this.Xd=e;this.Qd=f;this.af=k;this.ke=l;this.Ye=m;this.kf=[]}
function Xb(a,b,c){for(;b!==c;)b.ke||Q(`Expected null or instance of ${c.name}, got an instance of ${b.name}`),a=b.ke(a),b=b.Qd;return a}function Yb(a,b){if(null===b)return this.Ae&&Q(`null is not a valid ${this.name}`),0;b.kd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.kd.Kd||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);return Xb(b.kd.Kd,b.kd.Nd.Ld,this.Ld)}
function $b(a,b){if(null===b){this.Ae&&Q(`null is not a valid ${this.name}`);if(this.pe){var c=this.Be();null!==a&&a.push(this.Xd,c);return c}return 0}b.kd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.kd.Kd||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);!this.oe&&b.kd.Nd.oe&&Q(`Cannot convert argument of type ${b.kd.Td?b.kd.Td.name:b.kd.Nd.name} to parameter type ${this.name}`);c=Xb(b.kd.Kd,b.kd.Nd.Ld,this.Ld);if(this.pe)switch(void 0===b.kd.Pd&&Q("Passing raw pointer to smart pointer is illegal"),
this.qf){case 0:b.kd.Td===this?c=b.kd.Pd:Q(`Cannot convert argument of type ${b.kd.Td?b.kd.Td.name:b.kd.Nd.name} to parameter type ${this.name}`);break;case 1:c=b.kd.Pd;break;case 2:if(b.kd.Td===this)c=b.kd.Pd;else{var e=b.clone();c=this.lf(c,ac(function(){e["delete"]()}));null!==a&&a.push(this.Xd,c)}break;default:Q("Unsupporting sharing policy")}return c}
function bc(a,b){if(null===b)return this.Ae&&Q(`null is not a valid ${this.name}`),0;b.kd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.kd.Kd||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);b.kd.Nd.oe&&Q(`Cannot convert argument of type ${b.kd.Nd.name} to parameter type ${this.name}`);return Xb(b.kd.Kd,b.kd.Nd.Ld,this.Ld)}
function cc(a,b,c,e,f,k,l,m,p,w,y){this.name=a;this.Ld=b;this.Ae=c;this.oe=e;this.pe=f;this.jf=k;this.qf=l;this.Ke=m;this.Be=p;this.lf=w;this.Xd=y;f||void 0!==b.Qd?this.toWireType=$b:(this.toWireType=e?Yb:bc,this.Sd=null)}function dc(a,b,c){r.hasOwnProperty(a)||sb("Replacing nonexistant public symbol");void 0!==r[a].Od&&void 0!==c?r[a].Od[c]=b:(r[a]=b,r[a].ce=c)}
var ec=(a,b)=>{var c=[];return function(){c.length=0;Object.assign(c,arguments);if(a.includes("j")){var e=r["dynCall_"+a];e=c&&c.length?e.apply(null,[b].concat(c)):e.call(null,b)}else e=Ma.get(b).apply(null,c);return e}};function mc(a,b){a=O(a);var c=a.includes("j")?ec(a,b):Ma.get(b);"function"!=typeof c&&Q(`unknown function pointer with signature ${a}: ${b}`);return c}var nc=void 0;function oc(a){a=pc(a);var b=O(a);qc(a);return b}
function rc(a,b){function c(k){f[k]||pb[k]||(qb[k]?qb[k].forEach(c):(e.push(k),f[k]=!0))}var e=[],f={};b.forEach(c);throw new nc(`${a}: `+e.map(oc).join([", "]));}
function sc(a,b,c,e,f){var k=b.length;2>k&&Q("argTypes array size mismatch! Must at least get return value and 'this' types!");var l=null!==b[1]&&null!==c,m=!1;for(c=1;c<b.length;++c)if(null!==b[c]&&void 0===b[c].Sd){m=!0;break}var p="void"!==b[0].name,w=k-2,y=Array(w),B=[],D=[];return function(){arguments.length!==w&&Q(`function ${a} called with ${arguments.length} arguments, expected ${w} args!`);D.length=0;B.length=l?2:1;B[0]=f;if(l){var u=b[1].toWireType(D,this);B[1]=u}for(var F=0;F<w;++F)y[F]=
b[F+2].toWireType(D,arguments[F]),B.push(y[F]);F=e.apply(null,B);if(m)mb(D);else for(var H=l?1:2;H<b.length;H++){var T=1===H?u:y[H-2];null!==b[H].Sd&&b[H].Sd(T)}u=p?b[0].fromWireType(F):void 0;return u}}function tc(a,b){for(var c=[],e=0;e<a;e++)c.push(L[b+4*e>>2]);return c}function uc(){this.Wd=[void 0];this.Ie=[]}var vc=new uc;function wc(a){a>=vc.Zd&&0===--vc.get(a).Le&&vc.we(a)}
var xc=a=>{a||Q("Cannot use deleted val. handle = "+a);return vc.get(a).value},ac=a=>{switch(a){case void 0:return 1;case null:return 2;case !0:return 3;case !1:return 4;default:return vc.ve({Le:1,value:a})}};function yc(a,b,c){switch(b){case 0:return function(e){return this.fromWireType((c?Ha:C)[e])};case 1:return function(e){return this.fromWireType((c?Ia:Ja)[e>>1])};case 2:return function(e){return this.fromWireType((c?K:L)[e>>2])};default:throw new TypeError("Unknown integer type: "+a);}}
function zc(a,b){var c=pb[a];void 0===c&&Q(b+" has unknown type "+oc(a));return c}function Zb(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a}function Ac(a,b){switch(b){case 2:return function(c){return this.fromWireType(N[c>>2])};case 3:return function(c){return this.fromWireType(Ka[c>>3])};default:throw new TypeError("Unknown float type: "+a);}}
function Bc(a,b,c){switch(b){case 0:return c?function(e){return Ha[e]}:function(e){return C[e]};case 1:return c?function(e){return Ia[e>>1]}:function(e){return Ja[e>>1]};case 2:return c?function(e){return K[e>>2]}:function(e){return L[e>>2]};default:throw new TypeError("Unknown integer type: "+a);}}
var ka=(a,b,c,e)=>{if(!(0<e))return 0;var f=c;e=c+e-1;for(var k=0;k<a.length;++k){var l=a.charCodeAt(k);if(55296<=l&&57343>=l){var m=a.charCodeAt(++k);l=65536+((l&1023)<<10)|m&1023}if(127>=l){if(c>=e)break;b[c++]=l}else{if(2047>=l){if(c+1>=e)break;b[c++]=192|l>>6}else{if(65535>=l){if(c+2>=e)break;b[c++]=224|l>>12}else{if(c+3>=e)break;b[c++]=240|l>>18;b[c++]=128|l>>12&63}b[c++]=128|l>>6&63}b[c++]=128|l&63}}b[c]=0;return c-f},ja=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);127>=e?b++:2047>=
e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},Cc="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,Dc=(a,b)=>{var c=a>>1;for(var e=c+b/2;!(c>=e)&&Ja[c];)++c;c<<=1;if(32<c-a&&Cc)return Cc.decode(C.subarray(a,c));c="";for(e=0;!(e>=b/2);++e){var f=Ia[a+2*e>>1];if(0==f)break;c+=String.fromCharCode(f)}return c},Ec=(a,b,c)=>{void 0===c&&(c=2147483647);if(2>c)return 0;c-=2;var e=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)Ia[b>>1]=a.charCodeAt(f),b+=2;Ia[b>>1]=0;return b-e},
Fc=a=>2*a.length,Gc=(a,b)=>{for(var c=0,e="";!(c>=b/4);){var f=K[a+4*c>>2];if(0==f)break;++c;65536<=f?(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023)):e+=String.fromCharCode(f)}return e},Hc=(a,b,c)=>{void 0===c&&(c=2147483647);if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f<a.length;++f){var k=a.charCodeAt(f);if(55296<=k&&57343>=k){var l=a.charCodeAt(++f);k=65536+((k&1023)<<10)|l&1023}K[b>>2]=k;b+=4;if(b+4>c)break}K[b>>2]=0;return b-e},Ic=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);
55296<=e&&57343>=e&&++c;b+=4}return b},Jc={};function Kc(a){var b=Jc[a];return void 0===b?O(a):b}var Lc=[];
function Mc(){function a(b){b.$$$embind_global$$$=b;var c="object"==typeof $$$embind_global$$$&&b.$$$embind_global$$$==b;c||delete b.$$$embind_global$$$;return c}if("object"==typeof globalThis)return globalThis;if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;"object"==typeof global&&a(global)?$$$embind_global$$$=global:"object"==typeof self&&a(self)&&($$$embind_global$$$=self);if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;throw Error("unable to get global object.");
}function Nc(a){var b=Lc.length;Lc.push(a);return b}function Oc(a,b){for(var c=Array(a),e=0;e<a;++e)c[e]=zc(L[b+4*e>>2],"parameter "+e);return c}var Pc=[];function Qc(a){var b=Array(a+1);return function(c,e,f){b[0]=c;for(var k=0;k<a;++k){var l=zc(L[e+4*k>>2],"parameter "+k);b[k+1]=l.readValueFromPointer(f);f+=l.argPackAdvance}c=new (c.bind.apply(c,b));return ac(c)}}var Rc={};
function Sc(a){var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=function(c,e){b.vertexAttribDivisorANGLE(c,e)},a.drawArraysInstanced=function(c,e,f,k){b.drawArraysInstancedANGLE(c,e,f,k)},a.drawElementsInstanced=function(c,e,f,k,l){b.drawElementsInstancedANGLE(c,e,f,k,l)})}
function Tc(a){var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=function(){return b.createVertexArrayOES()},a.deleteVertexArray=function(c){b.deleteVertexArrayOES(c)},a.bindVertexArray=function(c){b.bindVertexArrayOES(c)},a.isVertexArray=function(c){return b.isVertexArrayOES(c)})}function Uc(a){var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=function(c,e){b.drawBuffersWEBGL(c,e)})}
var Vc=1,Wc=[],Xc=[],Yc=[],Zc=[],ea=[],$c=[],ad=[],ia=[],bd=[],cd=[],dd={},ed={},gd=4;function R(a){hd||(hd=a)}function da(a){for(var b=Vc++,c=a.length;c<b;c++)a[c]=null;return b}function fa(a,b){a.Zd||(a.Zd=a.getContext,a.getContext=function(e,f){f=a.Zd(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1<b.majorVersion?a.getContext("webgl2",b):a.getContext("webgl",b);return c?jd(c,b):0}
function jd(a,b){var c=da(ia),e={handle:c,attributes:b,version:b.majorVersion,Ud:a};a.canvas&&(a.canvas.Oe=e);ia[c]=e;("undefined"==typeof b.Ze||b.Ze)&&kd(e);return c}function ha(a){v=ia[a];r.vf=S=v&&v.Ud;return!(a&&!S)}
function kd(a){a||(a=v);if(!a.gf){a.gf=!0;var b=a.Ud;Sc(b);Tc(b);Uc(b);b.Fe=b.getExtension("WEBGL_draw_instanced_base_vertex_base_instance");b.Je=b.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");2<=a.version&&(b.Ge=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.Ge)b.Ge=b.getExtension("EXT_disjoint_timer_query");b.wf=b.getExtension("WEBGL_multi_draw");(b.getSupportedExtensions()||[]).forEach(function(c){c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}}
var v,hd,ld={},nd=()=>{if(!md){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:ma||"./this.program"},b;for(b in ld)void 0===ld[b]?delete a[b]:a[b]=ld[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);md=c}return md},md,od=[null,[],[]];function pd(a){S.bindVertexArray(ad[a])}
function qd(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2];S.deleteVertexArray(ad[e]);ad[e]=null}}var rd=[];function sd(a,b,c,e){S.drawElements(a,b,c,e)}function td(a,b,c,e){for(var f=0;f<a;f++){var k=S[c](),l=k&&da(e);k?(k.name=l,e[l]=k):R(1282);K[b+4*f>>2]=l}}function ud(a,b){td(a,b,"createVertexArray",ad)}
function vd(a,b,c){if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&R(1280);return;case 34814:case 36345:e=0;break;case 34466:var f=S.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>v.version){R(1282);return}e=2*(S.getSupportedExtensions()||[]).length;break;case 33307:case 33308:if(2>v.version){R(1280);return}e=33307==a?3:0}if(void 0===e)switch(f=S.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":R(1280);return;case "object":if(null===
f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e=0;break;default:R(1280);return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a<f.length;++a)switch(c){case 0:K[b+4*a>>2]=f[a];break;case 2:N[b+4*a>>2]=f[a];break;case 4:Ha[b+a>>0]=f[a]?1:0}return}try{e=f.name|0}catch(k){R(1280);
Ca("GL_INVALID_ENUM in glGet"+c+"v: Unknown object returned from WebGL getParameter("+a+")! (error: "+k+")");return}}break;default:R(1280);Ca("GL_INVALID_ENUM in glGet"+c+"v: Native code calling glGet"+c+"v("+a+") and it returns "+f+" of type "+typeof f+"!");return}switch(c){case 1:c=e;L[b>>2]=c;L[b+4>>2]=(c-L[b>>2])/4294967296;break;case 0:K[b>>2]=e;break;case 2:N[b>>2]=e;break;case 4:Ha[b>>0]=e?1:0}}else R(1281)}var xd=a=>{var b=ja(a)+1,c=wd(b);c&&ka(a,C,c,b);return c};
function yd(a){return"]"==a.slice(-1)&&a.lastIndexOf("[")}function zd(a){a-=5120;return 0==a?Ha:1==a?C:2==a?Ia:4==a?K:6==a?N:5==a||28922==a||28520==a||30779==a||30782==a?L:Ja}function Ad(a,b,c,e,f){a=zd(a);var k=31-Math.clz32(a.BYTES_PER_ELEMENT),l=gd;return a.subarray(f>>k,f+e*(c*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*(1<<k)+l-1&-l)>>k)}
function W(a){var b=S.We;if(b){var c=b.je[a];"number"==typeof c&&(b.je[a]=c=S.getUniformLocation(b,b.Me[a]+(0<c?"["+c+"]":"")));return c}R(1282)}var Bd=[],Cd=[],Dd=a=>0===a%4&&(0!==a%100||0===a%400),Ed=[31,29,31,30,31,30,31,31,30,31,30,31],Fd=[31,28,31,30,31,30,31,31,30,31,30,31];function Gd(a){var b=Array(ja(a)+1);ka(a,b,0,b.length);return b}
var Hd=(a,b,c,e)=>{function f(u,F,H){for(u="number"==typeof u?u.toString():u||"";u.length<F;)u=H[0]+u;return u}function k(u,F){return f(u,F,"0")}function l(u,F){function H(ca){return 0>ca?-1:0<ca?1:0}var T;0===(T=H(u.getFullYear()-F.getFullYear()))&&0===(T=H(u.getMonth()-F.getMonth()))&&(T=H(u.getDate()-F.getDate()));return T}function m(u){switch(u.getDay()){case 0:return new Date(u.getFullYear()-1,11,29);case 1:return u;case 2:return new Date(u.getFullYear(),0,3);case 3:return new Date(u.getFullYear(),
0,2);case 4:return new Date(u.getFullYear(),0,1);case 5:return new Date(u.getFullYear()-1,11,31);case 6:return new Date(u.getFullYear()-1,11,30)}}function p(u){var F=u.$d;for(u=new Date((new Date(u.ae+1900,0,1)).getTime());0<F;){var H=u.getMonth(),T=(Dd(u.getFullYear())?Ed:Fd)[H];if(F>T-u.getDate())F-=T-u.getDate()+1,u.setDate(1),11>H?u.setMonth(H+1):(u.setMonth(0),u.setFullYear(u.getFullYear()+1));else{u.setDate(u.getDate()+F);break}}H=new Date(u.getFullYear()+1,0,4);F=m(new Date(u.getFullYear(),
0,4));H=m(H);return 0>=l(F,u)?0>=l(H,u)?u.getFullYear()+1:u.getFullYear():u.getFullYear()-1}var w=K[e+40>>2];e={tf:K[e>>2],sf:K[e+4>>2],te:K[e+8>>2],Ce:K[e+12>>2],ue:K[e+16>>2],ae:K[e+20>>2],Vd:K[e+24>>2],$d:K[e+28>>2],zf:K[e+32>>2],rf:K[e+36>>2],uf:w?w?kb(C,w):"":""};c=c?kb(C,c):"";w={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y",
"%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var y in w)c=c.replace(new RegExp(y,"g"),w[y]);var B="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),D="January February March April May June July August September October November December".split(" ");w={"%a":u=>B[u.Vd].substring(0,3),"%A":u=>B[u.Vd],"%b":u=>D[u.ue].substring(0,3),"%B":u=>D[u.ue],"%C":u=>k((u.ae+1900)/
100|0,2),"%d":u=>k(u.Ce,2),"%e":u=>f(u.Ce,2," "),"%g":u=>p(u).toString().substring(2),"%G":u=>p(u),"%H":u=>k(u.te,2),"%I":u=>{u=u.te;0==u?u=12:12<u&&(u-=12);return k(u,2)},"%j":u=>{for(var F=0,H=0;H<=u.ue-1;F+=(Dd(u.ae+1900)?Ed:Fd)[H++]);return k(u.Ce+F,3)},"%m":u=>k(u.ue+1,2),"%M":u=>k(u.sf,2),"%n":()=>"\n","%p":u=>0<=u.te&&12>u.te?"AM":"PM","%S":u=>k(u.tf,2),"%t":()=>"\t","%u":u=>u.Vd||7,"%U":u=>k(Math.floor((u.$d+7-u.Vd)/7),2),"%V":u=>{var F=Math.floor((u.$d+7-(u.Vd+6)%7)/7);2>=(u.Vd+371-u.$d-
2)%7&&F++;if(F)53==F&&(H=(u.Vd+371-u.$d)%7,4==H||3==H&&Dd(u.ae)||(F=1));else{F=52;var H=(u.Vd+7-u.$d-1)%7;(4==H||5==H&&Dd(u.ae%400-1))&&F++}return k(F,2)},"%w":u=>u.Vd,"%W":u=>k(Math.floor((u.$d+7-(u.Vd+6)%7)/7),2),"%y":u=>(u.ae+1900).toString().substring(2),"%Y":u=>u.ae+1900,"%z":u=>{u=u.rf;var F=0<=u;u=Math.abs(u)/60;return(F?"+":"-")+String("0000"+(u/60*100+u%60)).slice(-4)},"%Z":u=>u.uf,"%%":()=>"%"};c=c.replace(/%%/g,"\x00\x00");for(y in w)c.includes(y)&&(c=c.replace(new RegExp(y,"g"),w[y](e)));
c=c.replace(/\0\0/g,"%");y=Gd(c);if(y.length>b)return 0;Ha.set(y,a);return y.length-1};rb=r.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};for(var Id=Array(256),Jd=0;256>Jd;++Jd)Id[Jd]=String.fromCharCode(Jd);wb=Id;xb=r.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}};
Rb.prototype.isAliasOf=function(a){if(!(this instanceof Rb&&a instanceof Rb))return!1;var b=this.kd.Nd.Ld,c=this.kd.Kd,e=a.kd.Nd.Ld;for(a=a.kd.Kd;b.Qd;)c=b.ke(c),b=b.Qd;for(;e.Qd;)a=e.ke(a),e=e.Qd;return b===e&&c===a};
Rb.prototype.clone=function(){this.kd.Kd||zb(this);if(this.kd.ie)return this.kd.count.value+=1,this;var a=Qb,b=Object,c=b.create,e=Object.getPrototypeOf(this),f=this.kd;a=a(c.call(b,e,{kd:{value:{count:f.count,ee:f.ee,ie:f.ie,Kd:f.Kd,Nd:f.Nd,Pd:f.Pd,Td:f.Td}}}));a.kd.count.value+=1;a.kd.ee=!1;return a};Rb.prototype["delete"]=function(){this.kd.Kd||zb(this);this.kd.ee&&!this.kd.ie&&Q("Object already scheduled for deletion");Bb(this);Cb(this.kd);this.kd.ie||(this.kd.Pd=void 0,this.kd.Kd=void 0)};
Rb.prototype.isDeleted=function(){return!this.kd.Kd};Rb.prototype.deleteLater=function(){this.kd.Kd||zb(this);this.kd.ee&&!this.kd.ie&&Q("Object already scheduled for deletion");Kb.push(this);1===Kb.length&&Mb&&Mb(Lb);this.kd.ee=!0;return this};r.getInheritedInstanceCount=function(){return Object.keys(Nb).length};r.getLiveInheritedInstances=function(){var a=[],b;for(b in Nb)Nb.hasOwnProperty(b)&&a.push(Nb[b]);return a};r.flushPendingDeletes=Lb;r.setDelayFunction=function(a){Mb=a;Kb.length&&Mb&&Mb(Lb)};
cc.prototype.bf=function(a){this.Ke&&(a=this.Ke(a));return a};cc.prototype.Ee=function(a){this.Xd&&this.Xd(a)};cc.prototype.argPackAdvance=8;cc.prototype.readValueFromPointer=nb;cc.prototype.deleteObject=function(a){if(null!==a)a["delete"]()};
cc.prototype.fromWireType=function(a){function b(){return this.pe?Pb(this.Ld.fe,{Nd:this.jf,Kd:c,Td:this,Pd:a}):Pb(this.Ld.fe,{Nd:this,Kd:a})}var c=this.bf(a);if(!c)return this.Ee(a),null;var e=Ob(this.Ld,c);if(void 0!==e){if(0===e.kd.count.value)return e.kd.Kd=c,e.kd.Pd=a,e.clone();e=e.clone();this.Ee(a);return e}e=this.Ld.af(c);e=Jb[e];if(!e)return b.call(this);e=this.oe?e.Ve:e.pointerType;var f=Db(c,this.Ld,e.Ld);return null===f?b.call(this):this.pe?Pb(e.Ld.fe,{Nd:e,Kd:f,Td:this,Pd:a}):Pb(e.Ld.fe,
{Nd:e,Kd:f})};nc=r.UnboundTypeError=function(a,b){var c=Tb(b,function(e){this.name=b;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(a.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`};return c}(Error,"UnboundTypeError");
Object.assign(uc.prototype,{get(a){return this.Wd[a]},has(a){return void 0!==this.Wd[a]},ve(a){var b=this.Ie.pop()||this.Wd.length;this.Wd[b]=a;return b},we(a){this.Wd[a]=void 0;this.Ie.push(a)}});vc.Wd.push({value:void 0},{value:null},{value:!0},{value:!1});vc.Zd=vc.Wd.length;r.count_emval_handles=function(){for(var a=0,b=vc.Zd;b<vc.Wd.length;++b)void 0!==vc.Wd[b]&&++a;return a};for(var S,Kd=0;32>Kd;++Kd)rd.push(Array(Kd));var Ld=new Float32Array(288);
for(Kd=0;288>Kd;++Kd)Bd[Kd]=Ld.subarray(0,Kd+1);var Md=new Int32Array(288);for(Kd=0;288>Kd;++Kd)Cd[Kd]=Md.subarray(0,Kd+1);
var $d={H:function(a,b,c){(new fb(a)).Zd(b,c);gb=a;ib++;throw gb;},$:function(){return 0},$c:()=>{},_c:function(){return 0},Zc:()=>{},Yc:()=>{},_:function(){},Xc:()=>{},D:function(a){var b=lb[a];delete lb[a];var c=b.Be,e=b.Xd,f=b.He,k=f.map(l=>l.ef).concat(f.map(l=>l.nf));tb([a],k,l=>{var m={};f.forEach((p,w)=>{var y=l[w],B=p.cf,D=p.df,u=l[w+f.length],F=p.mf,H=p.pf;m[p.$e]={read:T=>y.fromWireType(B(D,T)),write:(T,ca)=>{var Y=[];F(H,T,u.toWireType(Y,ca));mb(Y)}}});return[{name:b.name,fromWireType:function(p){var w=
{},y;for(y in m)w[y]=m[y].read(p);e(p);return w},toWireType:function(p,w){for(var y in m)if(!(y in w))throw new TypeError(`Missing field: "${y}"`);var B=c();for(y in m)m[y].write(B,w[y]);null!==p&&p.push(e,B);return B},argPackAdvance:8,readValueFromPointer:nb,Sd:e}]})},fa:function(){},Tc:function(a,b,c,e,f){var k=vb(c);b=O(b);ub(a,{name:b,fromWireType:function(l){return!!l},toWireType:function(l,m){return m?e:f},argPackAdvance:8,readValueFromPointer:function(l){if(1===c)var m=Ha;else if(2===c)m=Ia;
else if(4===c)m=K;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(m[l>>k])},Sd:null})},l:function(a,b,c,e,f,k,l,m,p,w,y,B,D){y=O(y);k=mc(f,k);m&&(m=mc(l,m));w&&(w=mc(p,w));D=mc(B,D);var u=Sb(y);Vb(u,function(){rc(`Cannot construct ${y} due to unbound types`,[e])});tb([a,b,c],e?[e]:[],function(F){F=F[0];if(e){var H=F.Ld;var T=H.fe}else T=Rb.prototype;F=Tb(u,function(){if(Object.getPrototypeOf(this)!==ca)throw new xb("Use 'new' to construct "+y);if(void 0===Y.Yd)throw new xb(y+
" has no accessible constructor");var Na=Y.Yd[arguments.length];if(void 0===Na)throw new xb(`Tried to invoke ctor of ${y} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(Y.Yd).toString()}) parameters instead!`);return Na.apply(this,arguments)});var ca=Object.create(T,{constructor:{value:F}});F.prototype=ca;var Y=new Wb(y,F,ca,D,H,k,m,w);Y.Qd&&(void 0===Y.Qd.le&&(Y.Qd.le=[]),Y.Qd.le.push(Y));H=new cc(y,Y,!0,!1,!1);T=new cc(y+"*",Y,!1,!1,!1);var va=new cc(y+" const*",
Y,!1,!0,!1);Jb[a]={pointerType:T,Ve:va};dc(u,F);return[H,T,va]})},e:function(a,b,c,e,f,k,l){var m=tc(c,e);b=O(b);k=mc(f,k);tb([],[a],function(p){function w(){rc(`Cannot call ${y} due to unbound types`,m)}p=p[0];var y=`${p.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);var B=p.Ld.constructor;void 0===B[b]?(w.ce=c-1,B[b]=w):(Ub(B,b,y),B[b].Od[c-1]=w);tb([],m,function(D){D=[D[0],null].concat(D.slice(1));D=sc(y,D,null,k,l);void 0===B[b].Od?(D.ce=c-1,B[b]=D):B[b].Od[c-1]=D;if(p.Ld.le)for(const u of p.Ld.le)u.constructor.hasOwnProperty(b)||
(u.constructor[b]=D);return[]});return[]})},B:function(a,b,c,e,f,k){var l=tc(b,c);f=mc(e,f);tb([],[a],function(m){m=m[0];var p=`constructor ${m.name}`;void 0===m.Ld.Yd&&(m.Ld.Yd=[]);if(void 0!==m.Ld.Yd[b-1])throw new xb(`Cannot register multiple constructors with identical number of parameters (${b-1}) for class '${m.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);m.Ld.Yd[b-1]=()=>{rc(`Cannot construct ${m.name} due to unbound types`,l)};
tb([],l,function(w){w.splice(1,0,null);m.Ld.Yd[b-1]=sc(p,w,null,f,k);return[]});return[]})},a:function(a,b,c,e,f,k,l,m){var p=tc(c,e);b=O(b);k=mc(f,k);tb([],[a],function(w){function y(){rc(`Cannot call ${B} due to unbound types`,p)}w=w[0];var B=`${w.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);m&&w.Ld.kf.push(b);var D=w.Ld.fe,u=D[b];void 0===u||void 0===u.Od&&u.className!==w.name&&u.ce===c-2?(y.ce=c-2,y.className=w.name,D[b]=y):(Ub(D,b,B),D[b].Od[c-2]=y);tb([],p,function(F){F=sc(B,F,
w,k,l);void 0===D[b].Od?(F.ce=c-2,D[b]=F):D[b].Od[c-2]=F;return[]});return[]})},s:function(a,b,c){a=O(a);tb([],[b],function(e){e=e[0];r[a]=e.fromWireType(c);return[]})},Sc:function(a,b){b=O(b);ub(a,{name:b,fromWireType:function(c){var e=xc(c);wc(c);return e},toWireType:function(c,e){return ac(e)},argPackAdvance:8,readValueFromPointer:nb,Sd:null})},j:function(a,b,c,e){function f(){}c=vb(c);b=O(b);f.values={};ub(a,{name:b,constructor:f,fromWireType:function(k){return this.constructor.values[k]},toWireType:function(k,
l){return l.value},argPackAdvance:8,readValueFromPointer:yc(b,c,e),Sd:null});Vb(b,f)},b:function(a,b,c){var e=zc(a,"enum");b=O(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Tb(`${e.name}_${b}`,function(){})}});a.values[c]=e;a[b]=e},Y:function(a,b,c){c=vb(c);b=O(b);ub(a,{name:b,fromWireType:function(e){return e},toWireType:function(e,f){return f},argPackAdvance:8,readValueFromPointer:Ac(b,c),Sd:null})},v:function(a,b,c,e,f,k){var l=tc(b,c);a=O(a);f=
mc(e,f);Vb(a,function(){rc(`Cannot call ${a} due to unbound types`,l)},b-1);tb([],l,function(m){m=[m[0],null].concat(m.slice(1));dc(a,sc(a,m,null,f,k),b-1);return[]})},E:function(a,b,c,e,f){b=O(b);-1===f&&(f=4294967295);f=vb(c);var k=m=>m;if(0===e){var l=32-8*c;k=m=>m<<l>>>l}c=b.includes("unsigned")?function(m,p){return p>>>0}:function(m,p){return p};ub(a,{name:b,fromWireType:k,toWireType:c,argPackAdvance:8,readValueFromPointer:Bc(b,f,0!==e),Sd:null})},r:function(a,b,c){function e(k){k>>=2;var l=
L;return new f(l.buffer,l[k+1],l[k])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=O(c);ub(a,{name:c,fromWireType:e,argPackAdvance:8,readValueFromPointer:e},{ff:!0})},o:function(a,b,c,e,f,k,l,m,p,w,y,B){c=O(c);k=mc(f,k);m=mc(l,m);w=mc(p,w);B=mc(y,B);tb([a],[b],function(D){D=D[0];return[new cc(c,D.Ld,!1,!1,!0,D,e,k,m,w,B)]})},X:function(a,b){b=O(b);var c="std::string"===b;ub(a,{name:b,fromWireType:function(e){var f=L[e>>2],k=e+4;if(c)for(var l=
k,m=0;m<=f;++m){var p=k+m;if(m==f||0==C[p]){l=l?kb(C,l,p-l):"";if(void 0===w)var w=l;else w+=String.fromCharCode(0),w+=l;l=p+1}}else{w=Array(f);for(m=0;m<f;++m)w[m]=String.fromCharCode(C[k+m]);w=w.join("")}qc(e);return w},toWireType:function(e,f){f instanceof ArrayBuffer&&(f=new Uint8Array(f));var k="string"==typeof f;k||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array||Q("Cannot pass non-string to std::string");var l=c&&k?ja(f):f.length;var m=wd(4+l+1),p=m+4;L[m>>2]=
l;if(c&&k)ka(f,C,p,l+1);else if(k)for(k=0;k<l;++k){var w=f.charCodeAt(k);255<w&&(qc(p),Q("String has UTF-16 code units that do not fit in 8 bits"));C[p+k]=w}else for(k=0;k<l;++k)C[p+k]=f[k];null!==e&&e.push(qc,m);return m},argPackAdvance:8,readValueFromPointer:nb,Sd:function(e){qc(e)}})},O:function(a,b,c){c=O(c);if(2===b){var e=Dc;var f=Ec;var k=Fc;var l=()=>Ja;var m=1}else 4===b&&(e=Gc,f=Hc,k=Ic,l=()=>L,m=2);ub(a,{name:c,fromWireType:function(p){for(var w=L[p>>2],y=l(),B,D=p+4,u=0;u<=w;++u){var F=
p+4+u*b;if(u==w||0==y[F>>m])D=e(D,F-D),void 0===B?B=D:(B+=String.fromCharCode(0),B+=D),D=F+b}qc(p);return B},toWireType:function(p,w){"string"!=typeof w&&Q(`Cannot pass non-string to C++ string type ${c}`);var y=k(w),B=wd(4+y+b);L[B>>2]=y>>m;f(w,B+4,y+b);null!==p&&p.push(qc,B);return B},argPackAdvance:8,readValueFromPointer:nb,Sd:function(p){qc(p)}})},C:function(a,b,c,e,f,k){lb[a]={name:O(b),Be:mc(c,e),Xd:mc(f,k),He:[]}},d:function(a,b,c,e,f,k,l,m,p,w){lb[a].He.push({$e:O(b),ef:c,cf:mc(e,f),df:k,
nf:l,mf:mc(m,p),pf:w})},Rc:function(a,b){b=O(b);ub(a,{hf:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},Qc:()=>!0,Pc:()=>{throw Infinity;},G:function(a,b,c){a=xc(a);b=zc(b,"emval::as");var e=[],f=ac(e);L[c>>2]=f;return b.toWireType(e,a)},N:function(a,b,c,e,f){a=Lc[a];b=xc(b);c=Kc(c);var k=[];L[e>>2]=ac(k);return a(b,c,k,f)},t:function(a,b,c,e){a=Lc[a];b=xc(b);c=Kc(c);a(b,c,null,e)},c:wc,M:function(a){if(0===a)return ac(Mc());a=Kc(a);return ac(Mc()[a])},p:function(a,
b){var c=Oc(a,b),e=c[0];b=e.name+"_$"+c.slice(1).map(function(l){return l.name}).join("_")+"$";var f=Pc[b];if(void 0!==f)return f;var k=Array(a-1);f=Nc((l,m,p,w)=>{for(var y=0,B=0;B<a-1;++B)k[B]=c[B+1].readValueFromPointer(w+y),y+=c[B+1].argPackAdvance;l=l[m].apply(l,k);for(B=0;B<a-1;++B)c[B+1].Xe&&c[B+1].Xe(k[B]);if(!e.hf)return e.toWireType(p,l)});return Pc[b]=f},A:function(a,b){a=xc(a);b=xc(b);return ac(a[b])},m:function(a){4<a&&(vc.get(a).Le+=1)},L:function(a,b,c,e){a=xc(a);var f=Rc[b];f||(f=
Qc(b),Rc[b]=f);return f(a,c,e)},I:function(){return ac([])},f:function(a){return ac(Kc(a))},F:function(){return ac({})},Oc:function(a){a=xc(a);return!a},z:function(a){var b=xc(a);mb(b);wc(a)},i:function(a,b,c){a=xc(a);b=xc(b);c=xc(c);a[b]=c},g:function(a,b){a=zc(a,"_emval_take_value");a=a.readValueFromPointer(b);return ac(a)},ea:function(){return-52},da:function(){},h:()=>{Ea("")},Nc:()=>performance.now(),Mc:a=>{var b=C.length;a>>>=0;if(2147483648<a)return!1;for(var c=1;4>=c;c*=2){var e=b*(1+.2/c);
e=Math.min(e,a+100663296);var f=Math;e=Math.max(a,e);a:{f=f.min.call(f,2147483648,e+(65536-e%65536)%65536)-Fa.buffer.byteLength+65535>>>16;try{Fa.grow(f);La();var k=1;break a}catch(l){}k=void 0}if(k)return!0}return!1},Lc:function(){return v?v.handle:0},Wc:(a,b)=>{var c=0;nd().forEach(function(e,f){var k=b+c;f=L[a+4*f>>2]=k;for(k=0;k<e.length;++k)Ha[f++>>0]=e.charCodeAt(k);Ha[f>>0]=0;c+=e.length+1});return 0},Vc:(a,b)=>{var c=nd();L[a>>2]=c.length;var e=0;c.forEach(function(f){e+=f.length+1});L[b>>
2]=e;return 0},Kc:a=>{if(!noExitRuntime){if(r.onExit)r.onExit(a);Ga=!0}oa(a,new db(a))},P:()=>52,ha:function(){return 52},Uc:()=>52,ga:function(){return 70},Z:(a,b,c,e)=>{for(var f=0,k=0;k<c;k++){var l=L[b>>2],m=L[b+4>>2];b+=8;for(var p=0;p<m;p++){var w=C[l+p],y=od[a];0===w||10===w?((1===a?Aa:Ca)(kb(y,0)),y.length=0):y.push(w)}f+=m}L[e>>2]=f;return 0},Jc:function(a){S.activeTexture(a)},Ic:function(a,b){S.attachShader(Xc[a],$c[b])},Hc:function(a,b,c){S.bindAttribLocation(Xc[a],b,c?kb(C,c):"")},Gc:function(a,
b){35051==a?S.ye=b:35052==a&&(S.de=b);S.bindBuffer(a,Wc[b])},W:function(a,b){S.bindFramebuffer(a,Yc[b])},Fc:function(a,b){S.bindRenderbuffer(a,Zc[b])},Ec:function(a,b){S.bindSampler(a,bd[b])},Dc:function(a,b){S.bindTexture(a,ea[b])},Cc:pd,Bc:pd,Ac:function(a,b,c,e){S.blendColor(a,b,c,e)},zc:function(a){S.blendEquation(a)},yc:function(a,b){S.blendFunc(a,b)},xc:function(a,b,c,e,f,k,l,m,p,w){S.blitFramebuffer(a,b,c,e,f,k,l,m,p,w)},wc:function(a,b,c,e){2<=v.version?c&&b?S.bufferData(a,C,e,c,b):S.bufferData(a,
b,e):S.bufferData(a,c?C.subarray(c,c+b):b,e)},vc:function(a,b,c,e){2<=v.version?c&&S.bufferSubData(a,b,C,e,c):S.bufferSubData(a,b,C.subarray(e,e+c))},uc:function(a){return S.checkFramebufferStatus(a)},V:function(a){S.clear(a)},U:function(a,b,c,e){S.clearColor(a,b,c,e)},T:function(a){S.clearStencil(a)},ca:function(a,b,c,e){return S.clientWaitSync(cd[a],b,(c>>>0)+4294967296*e)},tc:function(a,b,c,e){S.colorMask(!!a,!!b,!!c,!!e)},sc:function(a){S.compileShader($c[a])},rc:function(a,b,c,e,f,k,l,m){2<=
v.version?S.de||!l?S.compressedTexImage2D(a,b,c,e,f,k,l,m):S.compressedTexImage2D(a,b,c,e,f,k,C,m,l):S.compressedTexImage2D(a,b,c,e,f,k,m?C.subarray(m,m+l):null)},qc:function(a,b,c,e,f,k,l,m,p){2<=v.version?S.de||!m?S.compressedTexSubImage2D(a,b,c,e,f,k,l,m,p):S.compressedTexSubImage2D(a,b,c,e,f,k,l,C,p,m):S.compressedTexSubImage2D(a,b,c,e,f,k,l,p?C.subarray(p,p+m):null)},pc:function(a,b,c,e,f){S.copyBufferSubData(a,b,c,e,f)},oc:function(a,b,c,e,f,k,l,m){S.copyTexSubImage2D(a,b,c,e,f,k,l,m)},nc:function(){var a=
da(Xc),b=S.createProgram();b.name=a;b.se=b.qe=b.re=0;b.De=1;Xc[a]=b;return a},mc:function(a){var b=da($c);$c[b]=S.createShader(a);return b},lc:function(a){S.cullFace(a)},kc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=Wc[e];f&&(S.deleteBuffer(f),f.name=0,Wc[e]=null,e==S.ye&&(S.ye=0),e==S.de&&(S.de=0))}},jc:function(a,b){for(var c=0;c<a;++c){var e=K[b+4*c>>2],f=Yc[e];f&&(S.deleteFramebuffer(f),f.name=0,Yc[e]=null)}},ic:function(a){if(a){var b=Xc[a];b?(S.deleteProgram(b),b.name=0,Xc[a]=null):
R(1281)}},hc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=Zc[e];f&&(S.deleteRenderbuffer(f),f.name=0,Zc[e]=null)}},gc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=bd[e];f&&(S.deleteSampler(f),f.name=0,bd[e]=null)}},fc:function(a){if(a){var b=$c[a];b?(S.deleteShader(b),$c[a]=null):R(1281)}},ec:function(a){if(a){var b=cd[a];b?(S.deleteSync(b),b.name=0,cd[a]=null):R(1281)}},dc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=ea[e];f&&(S.deleteTexture(f),f.name=0,ea[e]=null)}},
cc:qd,bc:qd,ac:function(a){S.depthMask(!!a)},$b:function(a){S.disable(a)},_b:function(a){S.disableVertexAttribArray(a)},Zb:function(a,b,c){S.drawArrays(a,b,c)},Yb:function(a,b,c,e){S.drawArraysInstanced(a,b,c,e)},Xb:function(a,b,c,e,f){S.Fe.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},Wb:function(a,b){for(var c=rd[a],e=0;e<a;e++)c[e]=K[b+4*e>>2];S.drawBuffers(c)},Vb:sd,Ub:function(a,b,c,e,f){S.drawElementsInstanced(a,b,c,e,f)},Tb:function(a,b,c,e,f,k,l){S.Fe.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,
b,c,e,f,k,l)},Sb:function(a,b,c,e,f,k){sd(a,e,f,k)},Rb:function(a){S.enable(a)},Qb:function(a){S.enableVertexAttribArray(a)},Pb:function(a,b){return(a=S.fenceSync(a,b))?(b=da(cd),a.name=b,cd[b]=a,b):0},Ob:function(){S.finish()},Nb:function(){S.flush()},Mb:function(a,b,c,e){S.framebufferRenderbuffer(a,b,c,Zc[e])},Lb:function(a,b,c,e,f){S.framebufferTexture2D(a,b,c,ea[e],f)},Kb:function(a){S.frontFace(a)},Jb:function(a,b){td(a,b,"createBuffer",Wc)},Ib:function(a,b){td(a,b,"createFramebuffer",Yc)},Hb:function(a,
b){td(a,b,"createRenderbuffer",Zc)},Gb:function(a,b){td(a,b,"createSampler",bd)},Fb:function(a,b){td(a,b,"createTexture",ea)},Eb:ud,Db:ud,Cb:function(a){S.generateMipmap(a)},Bb:function(a,b,c){c?K[c>>2]=S.getBufferParameter(a,b):R(1281)},Ab:function(){var a=S.getError()||hd;hd=0;return a},zb:function(a,b){vd(a,b,2)},yb:function(a,b,c,e){a=S.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;K[e>>2]=a},K:function(a,b){vd(a,b,0)},xb:function(a,
b,c,e){a=S.getProgramInfoLog(Xc[a]);null===a&&(a="(unknown error)");b=0<b&&e?ka(a,C,e,b):0;c&&(K[c>>2]=b)},wb:function(a,b,c){if(c)if(a>=Vc)R(1281);else if(a=Xc[a],35716==b)a=S.getProgramInfoLog(a),null===a&&(a="(unknown error)"),K[c>>2]=a.length+1;else if(35719==b){if(!a.se)for(b=0;b<S.getProgramParameter(a,35718);++b)a.se=Math.max(a.se,S.getActiveUniform(a,b).name.length+1);K[c>>2]=a.se}else if(35722==b){if(!a.qe)for(b=0;b<S.getProgramParameter(a,35721);++b)a.qe=Math.max(a.qe,S.getActiveAttrib(a,
b).name.length+1);K[c>>2]=a.qe}else if(35381==b){if(!a.re)for(b=0;b<S.getProgramParameter(a,35382);++b)a.re=Math.max(a.re,S.getActiveUniformBlockName(a,b).length+1);K[c>>2]=a.re}else K[c>>2]=S.getProgramParameter(a,b);else R(1281)},vb:function(a,b,c){c?K[c>>2]=S.getRenderbufferParameter(a,b):R(1281)},ub:function(a,b,c,e){a=S.getShaderInfoLog($c[a]);null===a&&(a="(unknown error)");b=0<b&&e?ka(a,C,e,b):0;c&&(K[c>>2]=b)},tb:function(a,b,c,e){a=S.getShaderPrecisionFormat(a,b);K[c>>2]=a.rangeMin;K[c+4>>
2]=a.rangeMax;K[e>>2]=a.precision},sb:function(a,b,c){c?35716==b?(a=S.getShaderInfoLog($c[a]),null===a&&(a="(unknown error)"),K[c>>2]=a?a.length+1:0):35720==b?(a=S.getShaderSource($c[a]),K[c>>2]=a?a.length+1:0):K[c>>2]=S.getShaderParameter($c[a],b):R(1281)},S:function(a){var b=dd[a];if(!b){switch(a){case 7939:b=S.getSupportedExtensions()||[];b=b.concat(b.map(function(e){return"GL_"+e}));b=xd(b.join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=S.getParameter(a))||R(1280);b=b&&xd(b);break;
case 7938:b=S.getParameter(7938);b=2<=v.version?"OpenGL ES 3.0 ("+b+")":"OpenGL ES 2.0 ("+b+")";b=xd(b);break;case 35724:b=S.getParameter(35724);var c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b="OpenGL ES GLSL ES "+c[1]+" ("+b+")");b=xd(b);break;default:R(1280)}dd[a]=b}return b},rb:function(a,b){if(2>v.version)return R(1282),0;var c=ed[a];if(c)return 0>b||b>=c.length?(R(1281),0):c[b];switch(a){case 7939:return c=S.getSupportedExtensions()||[],
c=c.concat(c.map(function(e){return"GL_"+e})),c=c.map(function(e){return xd(e)}),c=ed[a]=c,0>b||b>=c.length?(R(1281),0):c[b];default:return R(1280),0}},qb:function(a,b){b=b?kb(C,b):"";if(a=Xc[a]){var c=a,e=c.je,f=c.Ne,k;if(!e)for(c.je=e={},c.Me={},k=0;k<S.getProgramParameter(c,35718);++k){var l=S.getActiveUniform(c,k);var m=l.name;l=l.size;var p=yd(m);p=0<p?m.slice(0,p):m;var w=c.De;c.De+=l;f[p]=[l,w];for(m=0;m<l;++m)e[w]=m,c.Me[w++]=p}c=a.je;e=0;f=b;k=yd(b);0<k&&(e=parseInt(b.slice(k+1))>>>0,f=b.slice(0,
k));if((f=a.Ne[f])&&e<f[0]&&(e+=f[1],c[e]=c[e]||S.getUniformLocation(a,b)))return e}else R(1281);return-1},pb:function(a,b,c){for(var e=rd[b],f=0;f<b;f++)e[f]=K[c+4*f>>2];S.invalidateFramebuffer(a,e)},ob:function(a,b,c,e,f,k,l){for(var m=rd[b],p=0;p<b;p++)m[p]=K[c+4*p>>2];S.invalidateSubFramebuffer(a,m,e,f,k,l)},nb:function(a){return S.isSync(cd[a])},mb:function(a){return(a=ea[a])?S.isTexture(a):0},lb:function(a){S.lineWidth(a)},kb:function(a){a=Xc[a];S.linkProgram(a);a.je=0;a.Ne={}},jb:function(a,
b,c,e,f,k){S.Je.multiDrawArraysInstancedBaseInstanceWEBGL(a,K,b>>2,K,c>>2,K,e>>2,L,f>>2,k)},ib:function(a,b,c,e,f,k,l,m){S.Je.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,K,b>>2,c,K,e>>2,K,f>>2,K,k>>2,L,l>>2,m)},hb:function(a,b){3317==a&&(gd=b);S.pixelStorei(a,b)},gb:function(a){S.readBuffer(a)},fb:function(a,b,c,e,f,k,l){if(2<=v.version)if(S.ye)S.readPixels(a,b,c,e,f,k,l);else{var m=zd(k);S.readPixels(a,b,c,e,f,k,m,l>>31-Math.clz32(m.BYTES_PER_ELEMENT))}else(l=Ad(k,f,c,e,l))?S.readPixels(a,
b,c,e,f,k,l):R(1280)},eb:function(a,b,c,e){S.renderbufferStorage(a,b,c,e)},db:function(a,b,c,e,f){S.renderbufferStorageMultisample(a,b,c,e,f)},cb:function(a,b,c){S.samplerParameterf(bd[a],b,c)},bb:function(a,b,c){S.samplerParameteri(bd[a],b,c)},ab:function(a,b,c){S.samplerParameteri(bd[a],b,K[c>>2])},$a:function(a,b,c,e){S.scissor(a,b,c,e)},_a:function(a,b,c,e){for(var f="",k=0;k<b;++k){var l=e?K[e+4*k>>2]:-1,m=K[c+4*k>>2];l=m?kb(C,m,0>l?void 0:l):"";f+=l}S.shaderSource($c[a],f)},Za:function(a,b,
c){S.stencilFunc(a,b,c)},Ya:function(a,b,c,e){S.stencilFuncSeparate(a,b,c,e)},Xa:function(a){S.stencilMask(a)},Wa:function(a,b){S.stencilMaskSeparate(a,b)},Va:function(a,b,c){S.stencilOp(a,b,c)},Ua:function(a,b,c,e){S.stencilOpSeparate(a,b,c,e)},Ta:function(a,b,c,e,f,k,l,m,p){if(2<=v.version)if(S.de)S.texImage2D(a,b,c,e,f,k,l,m,p);else if(p){var w=zd(m);S.texImage2D(a,b,c,e,f,k,l,m,w,p>>31-Math.clz32(w.BYTES_PER_ELEMENT))}else S.texImage2D(a,b,c,e,f,k,l,m,null);else S.texImage2D(a,b,c,e,f,k,l,m,p?
Ad(m,l,e,f,p):null)},Sa:function(a,b,c){S.texParameterf(a,b,c)},Ra:function(a,b,c){S.texParameterf(a,b,N[c>>2])},Qa:function(a,b,c){S.texParameteri(a,b,c)},Pa:function(a,b,c){S.texParameteri(a,b,K[c>>2])},Oa:function(a,b,c,e,f){S.texStorage2D(a,b,c,e,f)},Na:function(a,b,c,e,f,k,l,m,p){if(2<=v.version)if(S.de)S.texSubImage2D(a,b,c,e,f,k,l,m,p);else if(p){var w=zd(m);S.texSubImage2D(a,b,c,e,f,k,l,m,w,p>>31-Math.clz32(w.BYTES_PER_ELEMENT))}else S.texSubImage2D(a,b,c,e,f,k,l,m,null);else w=null,p&&(w=
Ad(m,l,f,k,p)),S.texSubImage2D(a,b,c,e,f,k,l,m,w)},Ma:function(a,b){S.uniform1f(W(a),b)},La:function(a,b,c){if(2<=v.version)b&&S.uniform1fv(W(a),N,c>>2,b);else{if(288>=b)for(var e=Bd[b-1],f=0;f<b;++f)e[f]=N[c+4*f>>2];else e=N.subarray(c>>2,c+4*b>>2);S.uniform1fv(W(a),e)}},Ka:function(a,b){S.uniform1i(W(a),b)},Ja:function(a,b,c){if(2<=v.version)b&&S.uniform1iv(W(a),K,c>>2,b);else{if(288>=b)for(var e=Cd[b-1],f=0;f<b;++f)e[f]=K[c+4*f>>2];else e=K.subarray(c>>2,c+4*b>>2);S.uniform1iv(W(a),e)}},Ia:function(a,
b,c){S.uniform2f(W(a),b,c)},Ha:function(a,b,c){if(2<=v.version)b&&S.uniform2fv(W(a),N,c>>2,2*b);else{if(144>=b)for(var e=Bd[2*b-1],f=0;f<2*b;f+=2)e[f]=N[c+4*f>>2],e[f+1]=N[c+(4*f+4)>>2];else e=N.subarray(c>>2,c+8*b>>2);S.uniform2fv(W(a),e)}},Ga:function(a,b,c){S.uniform2i(W(a),b,c)},Fa:function(a,b,c){if(2<=v.version)b&&S.uniform2iv(W(a),K,c>>2,2*b);else{if(144>=b)for(var e=Cd[2*b-1],f=0;f<2*b;f+=2)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2];else e=K.subarray(c>>2,c+8*b>>2);S.uniform2iv(W(a),e)}},Ea:function(a,
b,c,e){S.uniform3f(W(a),b,c,e)},Da:function(a,b,c){if(2<=v.version)b&&S.uniform3fv(W(a),N,c>>2,3*b);else{if(96>=b)for(var e=Bd[3*b-1],f=0;f<3*b;f+=3)e[f]=N[c+4*f>>2],e[f+1]=N[c+(4*f+4)>>2],e[f+2]=N[c+(4*f+8)>>2];else e=N.subarray(c>>2,c+12*b>>2);S.uniform3fv(W(a),e)}},Ca:function(a,b,c,e){S.uniform3i(W(a),b,c,e)},Ba:function(a,b,c){if(2<=v.version)b&&S.uniform3iv(W(a),K,c>>2,3*b);else{if(96>=b)for(var e=Cd[3*b-1],f=0;f<3*b;f+=3)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2],e[f+2]=K[c+(4*f+8)>>2];else e=
K.subarray(c>>2,c+12*b>>2);S.uniform3iv(W(a),e)}},Aa:function(a,b,c,e,f){S.uniform4f(W(a),b,c,e,f)},za:function(a,b,c){if(2<=v.version)b&&S.uniform4fv(W(a),N,c>>2,4*b);else{if(72>=b){var e=Bd[4*b-1],f=N;c>>=2;for(var k=0;k<4*b;k+=4){var l=c+k;e[k]=f[l];e[k+1]=f[l+1];e[k+2]=f[l+2];e[k+3]=f[l+3]}}else e=N.subarray(c>>2,c+16*b>>2);S.uniform4fv(W(a),e)}},ya:function(a,b,c,e,f){S.uniform4i(W(a),b,c,e,f)},xa:function(a,b,c){if(2<=v.version)b&&S.uniform4iv(W(a),K,c>>2,4*b);else{if(72>=b)for(var e=Cd[4*b-
1],f=0;f<4*b;f+=4)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2],e[f+2]=K[c+(4*f+8)>>2],e[f+3]=K[c+(4*f+12)>>2];else e=K.subarray(c>>2,c+16*b>>2);S.uniform4iv(W(a),e)}},wa:function(a,b,c,e){if(2<=v.version)b&&S.uniformMatrix2fv(W(a),!!c,N,e>>2,4*b);else{if(72>=b)for(var f=Bd[4*b-1],k=0;k<4*b;k+=4)f[k]=N[e+4*k>>2],f[k+1]=N[e+(4*k+4)>>2],f[k+2]=N[e+(4*k+8)>>2],f[k+3]=N[e+(4*k+12)>>2];else f=N.subarray(e>>2,e+16*b>>2);S.uniformMatrix2fv(W(a),!!c,f)}},va:function(a,b,c,e){if(2<=v.version)b&&S.uniformMatrix3fv(W(a),
!!c,N,e>>2,9*b);else{if(32>=b)for(var f=Bd[9*b-1],k=0;k<9*b;k+=9)f[k]=N[e+4*k>>2],f[k+1]=N[e+(4*k+4)>>2],f[k+2]=N[e+(4*k+8)>>2],f[k+3]=N[e+(4*k+12)>>2],f[k+4]=N[e+(4*k+16)>>2],f[k+5]=N[e+(4*k+20)>>2],f[k+6]=N[e+(4*k+24)>>2],f[k+7]=N[e+(4*k+28)>>2],f[k+8]=N[e+(4*k+32)>>2];else f=N.subarray(e>>2,e+36*b>>2);S.uniformMatrix3fv(W(a),!!c,f)}},ua:function(a,b,c,e){if(2<=v.version)b&&S.uniformMatrix4fv(W(a),!!c,N,e>>2,16*b);else{if(18>=b){var f=Bd[16*b-1],k=N;e>>=2;for(var l=0;l<16*b;l+=16){var m=e+l;f[l]=
k[m];f[l+1]=k[m+1];f[l+2]=k[m+2];f[l+3]=k[m+3];f[l+4]=k[m+4];f[l+5]=k[m+5];f[l+6]=k[m+6];f[l+7]=k[m+7];f[l+8]=k[m+8];f[l+9]=k[m+9];f[l+10]=k[m+10];f[l+11]=k[m+11];f[l+12]=k[m+12];f[l+13]=k[m+13];f[l+14]=k[m+14];f[l+15]=k[m+15]}}else f=N.subarray(e>>2,e+64*b>>2);S.uniformMatrix4fv(W(a),!!c,f)}},ta:function(a){a=Xc[a];S.useProgram(a);S.We=a},sa:function(a,b){S.vertexAttrib1f(a,b)},ra:function(a,b){S.vertexAttrib2f(a,N[b>>2],N[b+4>>2])},qa:function(a,b){S.vertexAttrib3f(a,N[b>>2],N[b+4>>2],N[b+8>>2])},
pa:function(a,b){S.vertexAttrib4f(a,N[b>>2],N[b+4>>2],N[b+8>>2],N[b+12>>2])},oa:function(a,b){S.vertexAttribDivisor(a,b)},na:function(a,b,c,e,f){S.vertexAttribIPointer(a,b,c,e,f)},ma:function(a,b,c,e,f,k){S.vertexAttribPointer(a,b,c,!!e,f,k)},la:function(a,b,c,e){S.viewport(a,b,c,e)},ba:function(a,b,c,e){S.waitSync(cd[a],b,(c>>>0)+4294967296*e)},n:Nd,u:Od,k:Pd,J:Qd,R:Rd,Q:Sd,x:Td,y:Ud,q:Vd,w:Wd,ka:Xd,ja:Yd,ia:Zd,aa:(a,b,c,e)=>Hd(a,b,c,e)};
(function(){function a(c){G=c=c.exports;Fa=G.ad;La();Ma=G.dd;Pa.unshift(G.bd);Ua--;r.monitorRunDependencies&&r.monitorRunDependencies(Ua);if(0==Ua&&(null!==Va&&(clearInterval(Va),Va=null),Wa)){var e=Wa;Wa=null;e()}return c}var b={a:$d};Ua++;r.monitorRunDependencies&&r.monitorRunDependencies(Ua);if(r.instantiateWasm)try{return r.instantiateWasm(b,a)}catch(c){Ca("Module.instantiateWasm callback failed with error: "+c),ba(c)}cb(b,function(c){a(c.instance)}).catch(ba);return{}})();
var wd=r._malloc=a=>(wd=r._malloc=G.cd)(a),qc=r._free=a=>(qc=r._free=G.ed)(a),pc=a=>(pc=G.fd)(a);r.__embind_initialize_bindings=()=>(r.__embind_initialize_bindings=G.gd)();var ae=(a,b)=>(ae=G.hd)(a,b),be=()=>(be=G.id)(),ce=a=>(ce=G.jd)(a);r.dynCall_viji=(a,b,c,e,f)=>(r.dynCall_viji=G.ld)(a,b,c,e,f);r.dynCall_vijiii=(a,b,c,e,f,k,l)=>(r.dynCall_vijiii=G.md)(a,b,c,e,f,k,l);r.dynCall_viiiiij=(a,b,c,e,f,k,l,m)=>(r.dynCall_viiiiij=G.nd)(a,b,c,e,f,k,l,m);
r.dynCall_iiiji=(a,b,c,e,f,k)=>(r.dynCall_iiiji=G.od)(a,b,c,e,f,k);r.dynCall_jii=(a,b,c)=>(r.dynCall_jii=G.pd)(a,b,c);r.dynCall_vij=(a,b,c,e)=>(r.dynCall_vij=G.qd)(a,b,c,e);r.dynCall_iiij=(a,b,c,e,f)=>(r.dynCall_iiij=G.rd)(a,b,c,e,f);r.dynCall_iiiij=(a,b,c,e,f,k)=>(r.dynCall_iiiij=G.sd)(a,b,c,e,f,k);r.dynCall_viij=(a,b,c,e,f)=>(r.dynCall_viij=G.td)(a,b,c,e,f);r.dynCall_viiij=(a,b,c,e,f,k)=>(r.dynCall_viiij=G.ud)(a,b,c,e,f,k);
r.dynCall_jiiiiii=(a,b,c,e,f,k,l)=>(r.dynCall_jiiiiii=G.vd)(a,b,c,e,f,k,l);r.dynCall_jiiiiji=(a,b,c,e,f,k,l,m)=>(r.dynCall_jiiiiji=G.wd)(a,b,c,e,f,k,l,m);r.dynCall_ji=(a,b)=>(r.dynCall_ji=G.xd)(a,b);r.dynCall_iijj=(a,b,c,e,f,k)=>(r.dynCall_iijj=G.yd)(a,b,c,e,f,k);r.dynCall_iiji=(a,b,c,e,f)=>(r.dynCall_iiji=G.zd)(a,b,c,e,f);r.dynCall_iijjiii=(a,b,c,e,f,k,l,m,p)=>(r.dynCall_iijjiii=G.Ad)(a,b,c,e,f,k,l,m,p);r.dynCall_iij=(a,b,c,e)=>(r.dynCall_iij=G.Bd)(a,b,c,e);
r.dynCall_vijjjii=(a,b,c,e,f,k,l,m,p,w)=>(r.dynCall_vijjjii=G.Cd)(a,b,c,e,f,k,l,m,p,w);r.dynCall_jiji=(a,b,c,e,f)=>(r.dynCall_jiji=G.Dd)(a,b,c,e,f);r.dynCall_viijii=(a,b,c,e,f,k,l)=>(r.dynCall_viijii=G.Ed)(a,b,c,e,f,k,l);r.dynCall_iiiiij=(a,b,c,e,f,k,l)=>(r.dynCall_iiiiij=G.Fd)(a,b,c,e,f,k,l);r.dynCall_iiiiijj=(a,b,c,e,f,k,l,m,p)=>(r.dynCall_iiiiijj=G.Gd)(a,b,c,e,f,k,l,m,p);r.dynCall_iiiiiijj=(a,b,c,e,f,k,l,m,p,w)=>(r.dynCall_iiiiiijj=G.Hd)(a,b,c,e,f,k,l,m,p,w);
function Wd(a,b,c,e,f){var k=be();try{Ma.get(a)(b,c,e,f)}catch(l){ce(k);if(l!==l+0)throw l;ae(1,0)}}function Od(a,b,c){var e=be();try{return Ma.get(a)(b,c)}catch(f){ce(e);if(f!==f+0)throw f;ae(1,0)}}function Ud(a,b,c){var e=be();try{Ma.get(a)(b,c)}catch(f){ce(e);if(f!==f+0)throw f;ae(1,0)}}function Nd(a,b){var c=be();try{return Ma.get(a)(b)}catch(e){ce(c);if(e!==e+0)throw e;ae(1,0)}}function Td(a,b){var c=be();try{Ma.get(a)(b)}catch(e){ce(c);if(e!==e+0)throw e;ae(1,0)}}
function Pd(a,b,c,e){var f=be();try{return Ma.get(a)(b,c,e)}catch(k){ce(f);if(k!==k+0)throw k;ae(1,0)}}function Zd(a,b,c,e,f,k,l,m,p,w){var y=be();try{Ma.get(a)(b,c,e,f,k,l,m,p,w)}catch(B){ce(y);if(B!==B+0)throw B;ae(1,0)}}function Vd(a,b,c,e){var f=be();try{Ma.get(a)(b,c,e)}catch(k){ce(f);if(k!==k+0)throw k;ae(1,0)}}function Yd(a,b,c,e,f,k,l){var m=be();try{Ma.get(a)(b,c,e,f,k,l)}catch(p){ce(m);if(p!==p+0)throw p;ae(1,0)}}
function Qd(a,b,c,e,f){var k=be();try{return Ma.get(a)(b,c,e,f)}catch(l){ce(k);if(l!==l+0)throw l;ae(1,0)}}function Rd(a,b,c,e,f,k,l){var m=be();try{return Ma.get(a)(b,c,e,f,k,l)}catch(p){ce(m);if(p!==p+0)throw p;ae(1,0)}}function Xd(a,b,c,e,f,k){var l=be();try{Ma.get(a)(b,c,e,f,k)}catch(m){ce(l);if(m!==m+0)throw m;ae(1,0)}}function Sd(a,b,c,e,f,k,l,m,p,w){var y=be();try{return Ma.get(a)(b,c,e,f,k,l,m,p,w)}catch(B){ce(y);if(B!==B+0)throw B;ae(1,0)}}var de;Wa=function ee(){de||fe();de||(Wa=ee)};
function fe(){function a(){if(!de&&(de=!0,r.calledRun=!0,!Ga)){eb(Pa);aa(r);if(r.onRuntimeInitialized)r.onRuntimeInitialized();if(r.postRun)for("function"==typeof r.postRun&&(r.postRun=[r.postRun]);r.postRun.length;){var b=r.postRun.shift();Qa.unshift(b)}eb(Qa)}}if(!(0<Ua)){if(r.preRun)for("function"==typeof r.preRun&&(r.preRun=[r.preRun]);r.preRun.length;)Ra();eb(Oa);0<Ua||(r.setStatus?(r.setStatus("Running..."),setTimeout(function(){setTimeout(function(){r.setStatus("")},1);a()},1)):a())}}
if(r.preInit)for("function"==typeof r.preInit&&(r.preInit=[r.preInit]);0<r.preInit.length;)r.preInit.pop()();fe();
return moduleArg.ready
}
);
})();
export default CanvasKitInit;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,214 @@
var CanvasKitInit = (() => {
var _scriptDir = import.meta.url;
return (
async function(moduleArg = {}) {
var r=moduleArg,aa,ba;r.ready=new Promise((a,b)=>{aa=a;ba=b});
(function(a){a.Gd=a.Gd||[];a.Gd.push(function(){a.MakeSWCanvasSurface=function(b){var c=b,e="undefined"!==typeof OffscreenCanvas&&c instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&c instanceof HTMLCanvasElement||e||(c=document.getElementById(b),c)))throw"Canvas with id "+b+" was not found";if(b=a.MakeSurface(c.width,c.height))b.ge=c;return b};a.MakeCanvasSurface||(a.MakeCanvasSurface=a.MakeSWCanvasSurface);a.MakeSurface=function(b,c){var e={width:b,height:c,colorType:a.ColorType.RGBA_8888,
alphaType:a.AlphaType.Unpremul,colorSpace:a.ColorSpace.SRGB},f=b*c*4,k=a._malloc(f);if(e=a.Surface._makeRasterDirect(e,k,4*b))e.ge=null,e.Oe=b,e.Le=c,e.Me=f,e.re=k,e.getCanvas().clear(a.TRANSPARENT);return e};a.MakeRasterDirectSurface=function(b,c,e){return a.Surface._makeRasterDirect(b,c.byteOffset,e)};a.Surface.prototype.flush=function(b){a.Dd(this.Cd);this._flush();if(this.ge){var c=new Uint8ClampedArray(a.HEAPU8.buffer,this.re,this.Me);c=new ImageData(c,this.Oe,this.Le);b?this.ge.getContext("2d").putImageData(c,
0,0,b[0],b[1],b[2]-b[0],b[3]-b[1]):this.ge.getContext("2d").putImageData(c,0,0)}};a.Surface.prototype.dispose=function(){this.re&&a._free(this.re);this.delete()};a.Dd=a.Dd||function(){};a.he=a.he||function(){return null}})})(r);
(function(a){a.Gd=a.Gd||[];a.Gd.push(function(){function b(m,q,w){return m&&m.hasOwnProperty(q)?m[q]:w}function c(m){var q=da(ea);ea[q]=m;return q}function e(m){return m.naturalHeight||m.videoHeight||m.displayHeight||m.height}function f(m){return m.naturalWidth||m.videoWidth||m.displayWidth||m.width}function k(m,q,w,y){m.bindTexture(m.TEXTURE_2D,q);y||w.alphaType!==a.AlphaType.Premul||m.pixelStorei(m.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);return q}function l(m,q,w){w||q.alphaType!==a.AlphaType.Premul||
m.pixelStorei(m.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);m.bindTexture(m.TEXTURE_2D,null)}a.GetWebGLContext=function(m,q){if(!m)throw"null canvas passed into makeWebGLContext";var w={alpha:b(q,"alpha",1),depth:b(q,"depth",1),stencil:b(q,"stencil",8),antialias:b(q,"antialias",0),premultipliedAlpha:b(q,"premultipliedAlpha",1),preserveDrawingBuffer:b(q,"preserveDrawingBuffer",0),preferLowPowerToHighPerformance:b(q,"preferLowPowerToHighPerformance",0),failIfMajorPerformanceCaveat:b(q,"failIfMajorPerformanceCaveat",
0),enableExtensionsByDefault:b(q,"enableExtensionsByDefault",1),explicitSwapControl:b(q,"explicitSwapControl",0),renderViaOffscreenBackBuffer:b(q,"renderViaOffscreenBackBuffer",0)};w.majorVersion=q&&q.majorVersion?q.majorVersion:"undefined"!==typeof WebGL2RenderingContext?2:1;if(w.explicitSwapControl)throw"explicitSwapControl is not supported";m=fa(m,w);if(!m)return 0;ha(m);x.Od.getExtension("WEBGL_debug_renderer_info");return m};a.deleteContext=function(m){x===ia[m]&&(x=null);"object"==typeof JSEvents&&
JSEvents.sf(ia[m].Od.canvas);ia[m]&&ia[m].Od.canvas&&(ia[m].Od.canvas.Je=void 0);ia[m]=null};a._setTextureCleanup({deleteTexture:function(m,q){var w=ea[q];w&&ia[m].Od.deleteTexture(w);ea[q]=null}});a.MakeWebGLContext=function(m){if(!this.Dd(m))return null;var q=this._MakeGrContext();if(!q)return null;q.Cd=m;var w=q.delete.bind(q);q["delete"]=function(){a.Dd(this.Cd);w()}.bind(q);return x.te=q};a.MakeGrContext=a.MakeWebGLContext;a.GrDirectContext.prototype.getResourceCacheLimitBytes=function(){a.Dd(this.Cd);
this._getResourceCacheLimitBytes()};a.GrDirectContext.prototype.getResourceCacheUsageBytes=function(){a.Dd(this.Cd);this._getResourceCacheUsageBytes()};a.GrDirectContext.prototype.releaseResourcesAndAbandonContext=function(){a.Dd(this.Cd);this._releaseResourcesAndAbandonContext()};a.GrDirectContext.prototype.setResourceCacheLimitBytes=function(m){a.Dd(this.Cd);this._setResourceCacheLimitBytes(m)};a.MakeOnScreenGLSurface=function(m,q,w,y,B,D){if(!this.Dd(m.Cd))return null;q=void 0===B||void 0===D?
this._MakeOnScreenGLSurface(m,q,w,y):this._MakeOnScreenGLSurface(m,q,w,y,B,D);if(!q)return null;q.Cd=m.Cd;return q};a.MakeRenderTarget=function(){var m=arguments[0];if(!this.Dd(m.Cd))return null;if(3===arguments.length){var q=this._MakeRenderTargetWH(m,arguments[1],arguments[2]);if(!q)return null}else if(2===arguments.length){if(q=this._MakeRenderTargetII(m,arguments[1]),!q)return null}else return null;q.Cd=m.Cd;return q};a.MakeWebGLCanvasSurface=function(m,q,w){q=q||null;var y=m,B="undefined"!==
typeof OffscreenCanvas&&y instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&y instanceof HTMLCanvasElement||B||(y=document.getElementById(m),y)))throw"Canvas with id "+m+" was not found";m=this.GetWebGLContext(y,w);if(!m||0>m)throw"failed to create webgl context: err "+m;m=this.MakeWebGLContext(m);q=this.MakeOnScreenGLSurface(m,y.width,y.height,q);return q?q:(q=y.cloneNode(!0),y.parentNode.replaceChild(q,y),q.classList.add("ck-replaced"),a.MakeSWCanvasSurface(q))};a.MakeCanvasSurface=
a.MakeWebGLCanvasSurface;a.Surface.prototype.makeImageFromTexture=function(m,q){a.Dd(this.Cd);m=c(m);if(q=this._makeImageFromTexture(this.Cd,m,q))q.be=m;return q};a.Surface.prototype.makeImageFromTextureSource=function(m,q,w){q||(q={height:e(m),width:f(m),colorType:a.ColorType.RGBA_8888,alphaType:w?a.AlphaType.Premul:a.AlphaType.Unpremul});q.colorSpace||(q.colorSpace=a.ColorSpace.SRGB);a.Dd(this.Cd);var y=x.Od;w=k(y,y.createTexture(),q,w);2===x.version?y.texImage2D(y.TEXTURE_2D,0,y.RGBA,q.width,q.height,
0,y.RGBA,y.UNSIGNED_BYTE,m):y.texImage2D(y.TEXTURE_2D,0,y.RGBA,y.RGBA,y.UNSIGNED_BYTE,m);l(y,q);this._resetContext();return this.makeImageFromTexture(w,q)};a.Surface.prototype.updateTextureFromSource=function(m,q,w){if(m.be){a.Dd(this.Cd);var y=m.getImageInfo(),B=x.Od,D=k(B,ea[m.be],y,w);2===x.version?B.texImage2D(B.TEXTURE_2D,0,B.RGBA,f(q),e(q),0,B.RGBA,B.UNSIGNED_BYTE,q):B.texImage2D(B.TEXTURE_2D,0,B.RGBA,B.RGBA,B.UNSIGNED_BYTE,q);l(B,y,w);this._resetContext();ea[m.be]=null;m.be=c(D);y.colorSpace=
m.getColorSpace();q=this._makeImageFromTexture(this.Cd,m.be,y);w=m.jd.Ed;B=m.jd.Jd;m.jd.Ed=q.jd.Ed;m.jd.Jd=q.jd.Jd;q.jd.Ed=w;q.jd.Jd=B;q.delete();y.colorSpace.delete()}};a.MakeLazyImageFromTextureSource=function(m,q,w){q||(q={height:e(m),width:f(m),colorType:a.ColorType.RGBA_8888,alphaType:w?a.AlphaType.Premul:a.AlphaType.Unpremul});q.colorSpace||(q.colorSpace=a.ColorSpace.SRGB);var y={makeTexture:function(){var B=x,D=B.Od,u=k(D,D.createTexture(),q,w);2===B.version?D.texImage2D(D.TEXTURE_2D,0,D.RGBA,
q.width,q.height,0,D.RGBA,D.UNSIGNED_BYTE,m):D.texImage2D(D.TEXTURE_2D,0,D.RGBA,D.RGBA,D.UNSIGNED_BYTE,m);l(D,q,w);return c(u)},freeSrc:function(){}};"VideoFrame"===m.constructor.name&&(y.freeSrc=function(){m.close()});return a.Image._makeFromGenerator(q,y)};a.Dd=function(m){return m?ha(m):!1};a.he=function(){return x&&x.te&&!x.te.isDeleted()?x.te:null}})})(r);
(function(a){function b(g){return(f(255*g[3])<<24|f(255*g[0])<<16|f(255*g[1])<<8|f(255*g[2])<<0)>>>0}function c(g){if(g&&g._ck)return g;if(g instanceof Float32Array){for(var d=Math.floor(g.length/4),h=new Uint32Array(d),n=0;n<d;n++)h[n]=b(g.slice(4*n,4*(n+1)));return h}if(g instanceof Uint32Array)return g;if(g instanceof Array&&g[0]instanceof Float32Array)return g.map(b)}function e(g){if(void 0===g)return 1;var d=parseFloat(g);return g&&-1!==g.indexOf("%")?d/100:d}function f(g){return Math.round(Math.max(0,
Math.min(g||0,255)))}function k(g,d){d&&d._ck||a._free(g)}function l(g,d,h){if(!g||!g.length)return M;if(g&&g._ck)return g.byteOffset;var n=a[d].BYTES_PER_ELEMENT;h||(h=a._malloc(g.length*n));a[d].set(g,h/n);return h}function m(g){var d={Ld:M,count:g.length,colorType:a.ColorType.RGBA_F32};if(g instanceof Float32Array)d.Ld=l(g,"HEAPF32"),d.count=g.length/4;else if(g instanceof Uint32Array)d.Ld=l(g,"HEAPU32"),d.colorType=a.ColorType.RGBA_8888;else if(g instanceof Array){if(g&&g.length){for(var h=a._malloc(16*
g.length),n=0,t=h/4,v=0;v<g.length;v++)for(var z=0;4>z;z++)a.HEAPF32[t+n]=g[v][z],n++;g=h}else g=M;d.Ld=g}else throw"Invalid argument to copyFlexibleColorArray, Not a color array "+typeof g;return d}function q(g){if(!g)return M;var d=T.toTypedArray();if(g.length){if(6===g.length||9===g.length)return l(g,"HEAPF32",H),6===g.length&&a.HEAPF32.set(fd,6+H/4),H;if(16===g.length)return d[0]=g[0],d[1]=g[1],d[2]=g[3],d[3]=g[4],d[4]=g[5],d[5]=g[7],d[6]=g[12],d[7]=g[13],d[8]=g[15],H;throw"invalid matrix size";
}if(void 0===g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m41;d[3]=g.m12;d[4]=g.m22;d[5]=g.m42;d[6]=g.m14;d[7]=g.m24;d[8]=g.m44;return H}function w(g){if(!g)return M;var d=Y.toTypedArray();if(g.length){if(16!==g.length&&6!==g.length&&9!==g.length)throw"invalid matrix size";if(16===g.length)return l(g,"HEAPF32",ca);d.fill(0);d[0]=g[0];d[1]=g[1];d[3]=g[2];d[4]=g[3];d[5]=g[4];d[7]=g[5];d[10]=1;d[12]=g[6];d[13]=g[7];d[15]=g[8];6===g.length&&(d[12]=0,d[13]=0,d[15]=1);return ca}if(void 0===
g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m31;d[3]=g.m41;d[4]=g.m12;d[5]=g.m22;d[6]=g.m32;d[7]=g.m42;d[8]=g.m13;d[9]=g.m23;d[10]=g.m33;d[11]=g.m43;d[12]=g.m14;d[13]=g.m24;d[14]=g.m34;d[15]=g.m44;return ca}function y(g,d){return l(g,"HEAPF32",d||va)}function B(g,d,h,n){var t=Na.toTypedArray();t[0]=g;t[1]=d;t[2]=h;t[3]=n;return va}function D(g){for(var d=new Float32Array(4),h=0;4>h;h++)d[h]=a.HEAPF32[g/4+h];return d}function u(g,d){return l(g,"HEAPF32",d||X)}function F(g,d){return l(g,
"HEAPF32",d||Eb)}a.Color=function(g,d,h,n){void 0===n&&(n=1);return a.Color4f(f(g)/255,f(d)/255,f(h)/255,n)};a.ColorAsInt=function(g,d,h,n){void 0===n&&(n=255);return(f(n)<<24|f(g)<<16|f(d)<<8|f(h)<<0&268435455)>>>0};a.Color4f=function(g,d,h,n){void 0===n&&(n=1);return Float32Array.of(g,d,h,n)};Object.defineProperty(a,"TRANSPARENT",{get:function(){return a.Color4f(0,0,0,0)}});Object.defineProperty(a,"BLACK",{get:function(){return a.Color4f(0,0,0,1)}});Object.defineProperty(a,"WHITE",{get:function(){return a.Color4f(1,
1,1,1)}});Object.defineProperty(a,"RED",{get:function(){return a.Color4f(1,0,0,1)}});Object.defineProperty(a,"GREEN",{get:function(){return a.Color4f(0,1,0,1)}});Object.defineProperty(a,"BLUE",{get:function(){return a.Color4f(0,0,1,1)}});Object.defineProperty(a,"YELLOW",{get:function(){return a.Color4f(1,1,0,1)}});Object.defineProperty(a,"CYAN",{get:function(){return a.Color4f(0,1,1,1)}});Object.defineProperty(a,"MAGENTA",{get:function(){return a.Color4f(1,0,1,1)}});a.getColorComponents=function(g){return[Math.floor(255*
g[0]),Math.floor(255*g[1]),Math.floor(255*g[2]),g[3]]};a.parseColorString=function(g,d){g=g.toLowerCase();if(g.startsWith("#")){d=255;switch(g.length){case 9:d=parseInt(g.slice(7,9),16);case 7:var h=parseInt(g.slice(1,3),16);var n=parseInt(g.slice(3,5),16);var t=parseInt(g.slice(5,7),16);break;case 5:d=17*parseInt(g.slice(4,5),16);case 4:h=17*parseInt(g.slice(1,2),16),n=17*parseInt(g.slice(2,3),16),t=17*parseInt(g.slice(3,4),16)}return a.Color(h,n,t,d/255)}return g.startsWith("rgba")?(g=g.slice(5,
-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("rgb")?(g=g.slice(4,-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("gray(")||g.startsWith("hsl")||!d||(g=d[g],void 0===g)?a.BLACK:g};a.multiplyByAlpha=function(g,d){g=g.slice();g[3]=Math.max(0,Math.min(g[3]*d,1));return g};a.Malloc=function(g,d){var h=a._malloc(d*g.BYTES_PER_ELEMENT);return{_ck:!0,length:d,byteOffset:h,Wd:null,subarray:function(n,t){n=this.toTypedArray().subarray(n,t);n._ck=!0;return n},toTypedArray:function(){if(this.Wd&&
this.Wd.length)return this.Wd;this.Wd=new g(a.HEAPU8.buffer,h,d);this.Wd._ck=!0;return this.Wd}}};a.Free=function(g){a._free(g.byteOffset);g.byteOffset=M;g.toTypedArray=null;g.Wd=null};var H=M,T,ca=M,Y,va=M,Na,na,X=M,fc,Ba=M,gc,Fb=M,hc,Gb=M,hb,Sa=M,ic,Eb=M,jc,kc=M,fd=Float32Array.of(0,0,1),M=0;a.onRuntimeInitialized=function(){function g(d,h,n,t,v,z,E){z||(z=4*t.width,t.colorType===a.ColorType.RGBA_F16?z*=2:t.colorType===a.ColorType.RGBA_F32&&(z*=4));var J=z*t.height;var I=v?v.byteOffset:a._malloc(J);
if(E?!d._readPixels(t,I,z,h,n,E):!d._readPixels(t,I,z,h,n))return v||a._free(I),null;if(v)return v.toTypedArray();switch(t.colorType){case a.ColorType.RGBA_8888:case a.ColorType.RGBA_F16:d=(new Uint8Array(a.HEAPU8.buffer,I,J)).slice();break;case a.ColorType.RGBA_F32:d=(new Float32Array(a.HEAPU8.buffer,I,J)).slice();break;default:return null}a._free(I);return d}Na=a.Malloc(Float32Array,4);va=Na.byteOffset;Y=a.Malloc(Float32Array,16);ca=Y.byteOffset;T=a.Malloc(Float32Array,9);H=T.byteOffset;ic=a.Malloc(Float32Array,
12);Eb=ic.byteOffset;jc=a.Malloc(Float32Array,12);kc=jc.byteOffset;na=a.Malloc(Float32Array,4);X=na.byteOffset;fc=a.Malloc(Float32Array,4);Ba=fc.byteOffset;gc=a.Malloc(Float32Array,3);Fb=gc.byteOffset;hc=a.Malloc(Float32Array,3);Gb=hc.byteOffset;hb=a.Malloc(Int32Array,4);Sa=hb.byteOffset;a.ColorSpace.SRGB=a.ColorSpace._MakeSRGB();a.ColorSpace.DISPLAY_P3=a.ColorSpace._MakeDisplayP3();a.ColorSpace.ADOBE_RGB=a.ColorSpace._MakeAdobeRGB();a.GlyphRunFlags={IsWhiteSpace:a._GlyphRunFlags_isWhiteSpace};a.Path.MakeFromCmds=
function(d){var h=l(d,"HEAPF32"),n=a.Path._MakeFromCmds(h,d.length);k(h,d);return n};a.Path.MakeFromVerbsPointsWeights=function(d,h,n){var t=l(d,"HEAPU8"),v=l(h,"HEAPF32"),z=l(n,"HEAPF32"),E=a.Path._MakeFromVerbsPointsWeights(t,d.length,v,h.length,z,n&&n.length||0);k(t,d);k(v,h);k(z,n);return E};a.Path.prototype.addArc=function(d,h,n){d=u(d);this._addArc(d,h,n);return this};a.Path.prototype.addCircle=function(d,h,n,t){this._addCircle(d,h,n,!!t);return this};a.Path.prototype.addOval=function(d,h,n){void 0===
n&&(n=1);d=u(d);this._addOval(d,!!h,n);return this};a.Path.prototype.addPath=function(){var d=Array.prototype.slice.call(arguments),h=d[0],n=!1;"boolean"===typeof d[d.length-1]&&(n=d.pop());if(1===d.length)this._addPath(h,1,0,0,0,1,0,0,0,1,n);else if(2===d.length)d=d[1],this._addPath(h,d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1,n);else if(7===d.length||10===d.length)this._addPath(h,d[1],d[2],d[3],d[4],d[5],d[6],d[7]||0,d[8]||0,d[9]||1,n);else return null;return this};a.Path.prototype.addPoly=
function(d,h){var n=l(d,"HEAPF32");this._addPoly(n,d.length/2,h);k(n,d);return this};a.Path.prototype.addRect=function(d,h){d=u(d);this._addRect(d,!!h);return this};a.Path.prototype.addRRect=function(d,h){d=F(d);this._addRRect(d,!!h);return this};a.Path.prototype.addVerbsPointsWeights=function(d,h,n){var t=l(d,"HEAPU8"),v=l(h,"HEAPF32"),z=l(n,"HEAPF32");this._addVerbsPointsWeights(t,d.length,v,h.length,z,n&&n.length||0);k(t,d);k(v,h);k(z,n)};a.Path.prototype.arc=function(d,h,n,t,v,z){d=a.LTRBRect(d-
n,h-n,d+n,h+n);v=(v-t)/Math.PI*180-360*!!z;z=new a.Path;z.addArc(d,t/Math.PI*180,v);this.addPath(z,!0);z.delete();return this};a.Path.prototype.arcToOval=function(d,h,n,t){d=u(d);this._arcToOval(d,h,n,t);return this};a.Path.prototype.arcToRotated=function(d,h,n,t,v,z,E){this._arcToRotated(d,h,n,!!t,!!v,z,E);return this};a.Path.prototype.arcToTangent=function(d,h,n,t,v){this._arcToTangent(d,h,n,t,v);return this};a.Path.prototype.close=function(){this._close();return this};a.Path.prototype.conicTo=
function(d,h,n,t,v){this._conicTo(d,h,n,t,v);return this};a.Path.prototype.computeTightBounds=function(d){this._computeTightBounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.cubicTo=function(d,h,n,t,v,z){this._cubicTo(d,h,n,t,v,z);return this};a.Path.prototype.dash=function(d,h,n){return this._dash(d,h,n)?this:null};a.Path.prototype.getBounds=function(d){this._getBounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.lineTo=function(d,
h){this._lineTo(d,h);return this};a.Path.prototype.moveTo=function(d,h){this._moveTo(d,h);return this};a.Path.prototype.offset=function(d,h){this._transform(1,0,d,0,1,h,0,0,1);return this};a.Path.prototype.quadTo=function(d,h,n,t){this._quadTo(d,h,n,t);return this};a.Path.prototype.rArcTo=function(d,h,n,t,v,z,E){this._rArcTo(d,h,n,t,v,z,E);return this};a.Path.prototype.rConicTo=function(d,h,n,t,v){this._rConicTo(d,h,n,t,v);return this};a.Path.prototype.rCubicTo=function(d,h,n,t,v,z){this._rCubicTo(d,
h,n,t,v,z);return this};a.Path.prototype.rLineTo=function(d,h){this._rLineTo(d,h);return this};a.Path.prototype.rMoveTo=function(d,h){this._rMoveTo(d,h);return this};a.Path.prototype.rQuadTo=function(d,h,n,t){this._rQuadTo(d,h,n,t);return this};a.Path.prototype.stroke=function(d){d=d||{};d.width=d.width||1;d.miter_limit=d.miter_limit||4;d.cap=d.cap||a.StrokeCap.Butt;d.join=d.join||a.StrokeJoin.Miter;d.precision=d.precision||1;return this._stroke(d)?this:null};a.Path.prototype.transform=function(){if(1===
arguments.length){var d=arguments[0];this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1)}else if(6===arguments.length||9===arguments.length)d=arguments,this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1);else throw"transform expected to take 1 or 9 arguments. Got "+arguments.length;return this};a.Path.prototype.trim=function(d,h,n){return this._trim(d,h,!!n)?this:null};a.Image.prototype.encodeToBytes=function(d,h){var n=a.he();d=d||a.ImageFormat.PNG;h=h||100;
return n?this._encodeToBytes(d,h,n):this._encodeToBytes(d,h)};a.Image.prototype.makeShaderCubic=function(d,h,n,t,v){v=q(v);return this._makeShaderCubic(d,h,n,t,v)};a.Image.prototype.makeShaderOptions=function(d,h,n,t,v){v=q(v);return this._makeShaderOptions(d,h,n,t,v)};a.Image.prototype.readPixels=function(d,h,n,t,v){var z=a.he();return g(this,d,h,n,t,v,z)};a.Canvas.prototype.clear=function(d){a.Dd(this.Cd);d=y(d);this._clear(d)};a.Canvas.prototype.clipRRect=function(d,h,n){a.Dd(this.Cd);d=F(d);this._clipRRect(d,
h,n)};a.Canvas.prototype.clipRect=function(d,h,n){a.Dd(this.Cd);d=u(d);this._clipRect(d,h,n)};a.Canvas.prototype.concat=function(d){a.Dd(this.Cd);d=w(d);this._concat(d)};a.Canvas.prototype.drawArc=function(d,h,n,t,v){a.Dd(this.Cd);d=u(d);this._drawArc(d,h,n,t,v)};a.Canvas.prototype.drawAtlas=function(d,h,n,t,v,z,E){if(d&&t&&h&&n&&h.length===n.length){a.Dd(this.Cd);v||(v=a.BlendMode.SrcOver);var J=l(h,"HEAPF32"),I=l(n,"HEAPF32"),U=n.length/4,V=l(c(z),"HEAPU32");if(E&&"B"in E&&"C"in E)this._drawAtlasCubic(d,
I,J,V,U,v,E.B,E.C,t);else{let p=a.FilterMode.Linear,A=a.MipmapMode.None;E&&(p=E.filter,"mipmap"in E&&(A=E.mipmap));this._drawAtlasOptions(d,I,J,V,U,v,p,A,t)}k(J,h);k(I,n);k(V,z)}};a.Canvas.prototype.drawCircle=function(d,h,n,t){a.Dd(this.Cd);this._drawCircle(d,h,n,t)};a.Canvas.prototype.drawColor=function(d,h){a.Dd(this.Cd);d=y(d);void 0!==h?this._drawColor(d,h):this._drawColor(d)};a.Canvas.prototype.drawColorInt=function(d,h){a.Dd(this.Cd);this._drawColorInt(d,h||a.BlendMode.SrcOver)};a.Canvas.prototype.drawColorComponents=
function(d,h,n,t,v){a.Dd(this.Cd);d=B(d,h,n,t);void 0!==v?this._drawColor(d,v):this._drawColor(d)};a.Canvas.prototype.drawDRRect=function(d,h,n){a.Dd(this.Cd);d=F(d,Eb);h=F(h,kc);this._drawDRRect(d,h,n)};a.Canvas.prototype.drawImage=function(d,h,n,t){a.Dd(this.Cd);this._drawImage(d,h,n,t||null)};a.Canvas.prototype.drawImageCubic=function(d,h,n,t,v,z){a.Dd(this.Cd);this._drawImageCubic(d,h,n,t,v,z||null)};a.Canvas.prototype.drawImageOptions=function(d,h,n,t,v,z){a.Dd(this.Cd);this._drawImageOptions(d,
h,n,t,v,z||null)};a.Canvas.prototype.drawImageNine=function(d,h,n,t,v){a.Dd(this.Cd);h=l(h,"HEAP32",Sa);n=u(n);this._drawImageNine(d,h,n,t,v||null)};a.Canvas.prototype.drawImageRect=function(d,h,n,t,v){a.Dd(this.Cd);u(h,X);u(n,Ba);this._drawImageRect(d,X,Ba,t,!!v)};a.Canvas.prototype.drawImageRectCubic=function(d,h,n,t,v,z){a.Dd(this.Cd);u(h,X);u(n,Ba);this._drawImageRectCubic(d,X,Ba,t,v,z||null)};a.Canvas.prototype.drawImageRectOptions=function(d,h,n,t,v,z){a.Dd(this.Cd);u(h,X);u(n,Ba);this._drawImageRectOptions(d,
X,Ba,t,v,z||null)};a.Canvas.prototype.drawLine=function(d,h,n,t,v){a.Dd(this.Cd);this._drawLine(d,h,n,t,v)};a.Canvas.prototype.drawOval=function(d,h){a.Dd(this.Cd);d=u(d);this._drawOval(d,h)};a.Canvas.prototype.drawPaint=function(d){a.Dd(this.Cd);this._drawPaint(d)};a.Canvas.prototype.drawParagraph=function(d,h,n){a.Dd(this.Cd);this._drawParagraph(d,h,n)};a.Canvas.prototype.drawPatch=function(d,h,n,t,v){if(24>d.length)throw"Need 12 cubic points";if(h&&4>h.length)throw"Need 4 colors";if(n&&8>n.length)throw"Need 4 shader coordinates";
a.Dd(this.Cd);const z=l(d,"HEAPF32"),E=h?l(c(h),"HEAPU32"):M,J=n?l(n,"HEAPF32"):M;t||(t=a.BlendMode.Modulate);this._drawPatch(z,E,J,t,v);k(J,n);k(E,h);k(z,d)};a.Canvas.prototype.drawPath=function(d,h){a.Dd(this.Cd);this._drawPath(d,h)};a.Canvas.prototype.drawPicture=function(d){a.Dd(this.Cd);this._drawPicture(d)};a.Canvas.prototype.drawPoints=function(d,h,n){a.Dd(this.Cd);var t=l(h,"HEAPF32");this._drawPoints(d,t,h.length/2,n);k(t,h)};a.Canvas.prototype.drawRRect=function(d,h){a.Dd(this.Cd);d=F(d);
this._drawRRect(d,h)};a.Canvas.prototype.drawRect=function(d,h){a.Dd(this.Cd);d=u(d);this._drawRect(d,h)};a.Canvas.prototype.drawRect4f=function(d,h,n,t,v){a.Dd(this.Cd);this._drawRect4f(d,h,n,t,v)};a.Canvas.prototype.drawShadow=function(d,h,n,t,v,z,E){a.Dd(this.Cd);var J=l(v,"HEAPF32"),I=l(z,"HEAPF32");h=l(h,"HEAPF32",Fb);n=l(n,"HEAPF32",Gb);this._drawShadow(d,h,n,t,J,I,E);k(J,v);k(I,z)};a.getShadowLocalBounds=function(d,h,n,t,v,z,E){d=q(d);n=l(n,"HEAPF32",Fb);t=l(t,"HEAPF32",Gb);if(!this._getShadowLocalBounds(d,
h,n,t,v,z,X))return null;h=na.toTypedArray();return E?(E.set(h),E):h.slice()};a.Canvas.prototype.drawTextBlob=function(d,h,n,t){a.Dd(this.Cd);this._drawTextBlob(d,h,n,t)};a.Canvas.prototype.drawVertices=function(d,h,n){a.Dd(this.Cd);this._drawVertices(d,h,n)};a.Canvas.prototype.getDeviceClipBounds=function(d){this._getDeviceClipBounds(Sa);var h=hb.toTypedArray();d?d.set(h):d=h.slice();return d};a.Canvas.prototype.getLocalToDevice=function(){this._getLocalToDevice(ca);for(var d=ca,h=Array(16),n=0;16>
n;n++)h[n]=a.HEAPF32[d/4+n];return h};a.Canvas.prototype.getTotalMatrix=function(){this._getTotalMatrix(H);for(var d=Array(9),h=0;9>h;h++)d[h]=a.HEAPF32[H/4+h];return d};a.Canvas.prototype.makeSurface=function(d){d=this._makeSurface(d);d.Cd=this.Cd;return d};a.Canvas.prototype.readPixels=function(d,h,n,t,v){a.Dd(this.Cd);return g(this,d,h,n,t,v)};a.Canvas.prototype.saveLayer=function(d,h,n,t){h=u(h);return this._saveLayer(d||null,h,n||null,t||0)};a.Canvas.prototype.writePixels=function(d,h,n,t,v,
z,E,J){if(d.byteLength%(h*n))throw"pixels length must be a multiple of the srcWidth * srcHeight";a.Dd(this.Cd);var I=d.byteLength/(h*n);z=z||a.AlphaType.Unpremul;E=E||a.ColorType.RGBA_8888;J=J||a.ColorSpace.SRGB;var U=I*h;I=l(d,"HEAPU8");h=this._writePixels({width:h,height:n,colorType:E,alphaType:z,colorSpace:J},I,U,t,v);k(I,d);return h};a.ColorFilter.MakeBlend=function(d,h,n){d=y(d);n=n||a.ColorSpace.SRGB;return a.ColorFilter._MakeBlend(d,h,n)};a.ColorFilter.MakeMatrix=function(d){if(!d||20!==d.length)throw"invalid color matrix";
var h=l(d,"HEAPF32"),n=a.ColorFilter._makeMatrix(h);k(h,d);return n};a.ContourMeasure.prototype.getPosTan=function(d,h){this._getPosTan(d,X);d=na.toTypedArray();return h?(h.set(d),h):d.slice()};a.ImageFilter.prototype.getOutputBounds=function(d,h,n){d=u(d,X);h=q(h);this._getOutputBounds(d,h,Sa);h=hb.toTypedArray();return n?(n.set(h),n):h.slice()};a.ImageFilter.MakeDropShadow=function(d,h,n,t,v,z){v=y(v,va);return a.ImageFilter._MakeDropShadow(d,h,n,t,v,z)};a.ImageFilter.MakeDropShadowOnly=function(d,
h,n,t,v,z){v=y(v,va);return a.ImageFilter._MakeDropShadowOnly(d,h,n,t,v,z)};a.ImageFilter.MakeImage=function(d,h,n,t){n=u(n,X);t=u(t,Ba);if("B"in h&&"C"in h)return a.ImageFilter._MakeImageCubic(d,h.B,h.C,n,t);const v=h.filter;let z=a.MipmapMode.None;"mipmap"in h&&(z=h.mipmap);return a.ImageFilter._MakeImageOptions(d,v,z,n,t)};a.ImageFilter.MakeMatrixTransform=function(d,h,n){d=q(d);if("B"in h&&"C"in h)return a.ImageFilter._MakeMatrixTransformCubic(d,h.B,h.C,n);const t=h.filter;let v=a.MipmapMode.None;
"mipmap"in h&&(v=h.mipmap);return a.ImageFilter._MakeMatrixTransformOptions(d,t,v,n)};a.Paint.prototype.getColor=function(){this._getColor(va);return D(va)};a.Paint.prototype.setColor=function(d,h){h=h||null;d=y(d);this._setColor(d,h)};a.Paint.prototype.setColorComponents=function(d,h,n,t,v){v=v||null;d=B(d,h,n,t);this._setColor(d,v)};a.Path.prototype.getPoint=function(d,h){this._getPoint(d,X);d=na.toTypedArray();return h?(h[0]=d[0],h[1]=d[1],h):d.slice(0,2)};a.Picture.prototype.makeShader=function(d,
h,n,t,v){t=q(t);v=u(v);return this._makeShader(d,h,n,t,v)};a.Picture.prototype.cullRect=function(d){this._cullRect(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.PictureRecorder.prototype.beginRecording=function(d,h){d=u(d);return this._beginRecording(d,!!h)};a.Surface.prototype.getCanvas=function(){var d=this._getCanvas();d.Cd=this.Cd;return d};a.Surface.prototype.makeImageSnapshot=function(d){a.Dd(this.Cd);d=l(d,"HEAP32",Sa);return this._makeImageSnapshot(d)};a.Surface.prototype.makeSurface=
function(d){a.Dd(this.Cd);d=this._makeSurface(d);d.Cd=this.Cd;return d};a.Surface.prototype.Ne=function(d,h){this.ae||(this.ae=this.getCanvas());return requestAnimationFrame(function(){a.Dd(this.Cd);d(this.ae);this.flush(h)}.bind(this))};a.Surface.prototype.requestAnimationFrame||(a.Surface.prototype.requestAnimationFrame=a.Surface.prototype.Ne);a.Surface.prototype.Ke=function(d,h){this.ae||(this.ae=this.getCanvas());requestAnimationFrame(function(){a.Dd(this.Cd);d(this.ae);this.flush(h);this.dispose()}.bind(this))};
a.Surface.prototype.drawOnce||(a.Surface.prototype.drawOnce=a.Surface.prototype.Ke);a.PathEffect.MakeDash=function(d,h){h||(h=0);if(!d.length||1===d.length%2)throw"Intervals array must have even length";var n=l(d,"HEAPF32");h=a.PathEffect._MakeDash(n,d.length,h);k(n,d);return h};a.PathEffect.MakeLine2D=function(d,h){h=q(h);return a.PathEffect._MakeLine2D(d,h)};a.PathEffect.MakePath2D=function(d,h){d=q(d);return a.PathEffect._MakePath2D(d,h)};a.Shader.MakeColor=function(d,h){h=h||null;d=y(d);return a.Shader._MakeColor(d,
h)};a.Shader.Blend=a.Shader.MakeBlend;a.Shader.Color=a.Shader.MakeColor;a.Shader.MakeLinearGradient=function(d,h,n,t,v,z,E,J){J=J||null;var I=m(n),U=l(t,"HEAPF32");E=E||0;z=q(z);var V=na.toTypedArray();V.set(d);V.set(h,2);d=a.Shader._MakeLinearGradient(X,I.Ld,I.colorType,U,I.count,v,E,z,J);k(I.Ld,n);t&&k(U,t);return d};a.Shader.MakeRadialGradient=function(d,h,n,t,v,z,E,J){J=J||null;var I=m(n),U=l(t,"HEAPF32");E=E||0;z=q(z);d=a.Shader._MakeRadialGradient(d[0],d[1],h,I.Ld,I.colorType,U,I.count,v,E,
z,J);k(I.Ld,n);t&&k(U,t);return d};a.Shader.MakeSweepGradient=function(d,h,n,t,v,z,E,J,I,U){U=U||null;var V=m(n),p=l(t,"HEAPF32");E=E||0;J=J||0;I=I||360;z=q(z);d=a.Shader._MakeSweepGradient(d,h,V.Ld,V.colorType,p,V.count,v,J,I,E,z,U);k(V.Ld,n);t&&k(p,t);return d};a.Shader.MakeTwoPointConicalGradient=function(d,h,n,t,v,z,E,J,I,U){U=U||null;var V=m(v),p=l(z,"HEAPF32");I=I||0;J=q(J);var A=na.toTypedArray();A.set(d);A.set(n,2);d=a.Shader._MakeTwoPointConicalGradient(X,h,t,V.Ld,V.colorType,p,V.count,E,
I,J,U);k(V.Ld,v);z&&k(p,z);return d};a.Vertices.prototype.bounds=function(d){this._bounds(X);var h=na.toTypedArray();return d?(d.set(h),d):h.slice()};a.Gd&&a.Gd.forEach(function(d){d()})};a.computeTonalColors=function(g){var d=l(g.ambient,"HEAPF32"),h=l(g.spot,"HEAPF32");this._computeTonalColors(d,h);var n={ambient:D(d),spot:D(h)};k(d,g.ambient);k(h,g.spot);return n};a.LTRBRect=function(g,d,h,n){return Float32Array.of(g,d,h,n)};a.XYWHRect=function(g,d,h,n){return Float32Array.of(g,d,g+h,d+n)};a.LTRBiRect=
function(g,d,h,n){return Int32Array.of(g,d,h,n)};a.XYWHiRect=function(g,d,h,n){return Int32Array.of(g,d,g+h,d+n)};a.RRectXY=function(g,d,h){return Float32Array.of(g[0],g[1],g[2],g[3],d,h,d,h,d,h,d,h)};a.MakeAnimatedImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeAnimatedImage(d,g.byteLength))?g:null};a.MakeImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeImage(d,g.byteLength))?
g:null};var Ta=null;a.MakeImageFromCanvasImageSource=function(g){var d=g.width,h=g.height;Ta||(Ta=document.createElement("canvas"));Ta.width=d;Ta.height=h;var n=Ta.getContext("2d",{willReadFrequently:!0});n.drawImage(g,0,0);g=n.getImageData(0,0,d,h);return a.MakeImage({width:d,height:h,alphaType:a.AlphaType.Unpremul,colorType:a.ColorType.RGBA_8888,colorSpace:a.ColorSpace.SRGB},g.data,4*d)};a.MakeImage=function(g,d,h){var n=a._malloc(d.length);a.HEAPU8.set(d,n);return a._MakeImage(g,n,d.length,h)};
a.MakeVertices=function(g,d,h,n,t,v){var z=t&&t.length||0,E=0;h&&h.length&&(E|=1);n&&n.length&&(E|=2);void 0===v||v||(E|=4);g=new a._VerticesBuilder(g,d.length/2,z,E);l(d,"HEAPF32",g.positions());g.texCoords()&&l(h,"HEAPF32",g.texCoords());g.colors()&&l(c(n),"HEAPU32",g.colors());g.indices()&&l(t,"HEAPU16",g.indices());return g.detach()};(function(g){g.Gd=g.Gd||[];g.Gd.push(function(){function d(p){p&&(p.dir=0===p.dir?g.TextDirection.RTL:g.TextDirection.LTR);return p}function h(p){if(!p||!p.length)return[];
for(var A=[],O=0;O<p.length;O+=5){var Z=g.LTRBRect(p[O],p[O+1],p[O+2],p[O+3]),za=g.TextDirection.LTR;0===p[O+4]&&(za=g.TextDirection.RTL);A.push({rect:Z,dir:za})}g._free(p.byteOffset);return A}function n(p){p=p||{};void 0===p.weight&&(p.weight=g.FontWeight.Normal);p.width=p.width||g.FontWidth.Normal;p.slant=p.slant||g.FontSlant.Upright;return p}function t(p){if(!p||!p.length)return M;for(var A=[],O=0;O<p.length;O++){var Z=v(p[O]);A.push(Z)}return l(A,"HEAPU32")}function v(p){if(J[p])return J[p];var A=
ja(p)+1,O=g._malloc(A);ka(p,C,O,A);return J[p]=O}function z(p){p._colorPtr=y(p.color);p._foregroundColorPtr=M;p._backgroundColorPtr=M;p._decorationColorPtr=M;p.foregroundColor&&(p._foregroundColorPtr=y(p.foregroundColor,I));p.backgroundColor&&(p._backgroundColorPtr=y(p.backgroundColor,U));p.decorationColor&&(p._decorationColorPtr=y(p.decorationColor,V));Array.isArray(p.fontFamilies)&&p.fontFamilies.length?(p._fontFamiliesPtr=t(p.fontFamilies),p._fontFamiliesLen=p.fontFamilies.length):(p._fontFamiliesPtr=
M,p._fontFamiliesLen=0);if(p.locale){var A=p.locale;p._localePtr=v(A);p._localeLen=ja(A)}else p._localePtr=M,p._localeLen=0;if(Array.isArray(p.shadows)&&p.shadows.length){A=p.shadows;var O=A.map(function(qa){return qa.color||g.BLACK}),Z=A.map(function(qa){return qa.blurRadius||0});p._shadowLen=A.length;for(var za=g._malloc(8*A.length),Hb=za/4,Ib=0;Ib<A.length;Ib++){var lc=A[Ib].offset||[0,0];g.HEAPF32[Hb]=lc[0];g.HEAPF32[Hb+1]=lc[1];Hb+=2}p._shadowColorsPtr=m(O).Ld;p._shadowOffsetsPtr=za;p._shadowBlurRadiiPtr=
l(Z,"HEAPF32")}else p._shadowLen=0,p._shadowColorsPtr=M,p._shadowOffsetsPtr=M,p._shadowBlurRadiiPtr=M;Array.isArray(p.fontFeatures)&&p.fontFeatures.length?(A=p.fontFeatures,O=A.map(function(qa){return qa.name}),Z=A.map(function(qa){return qa.value}),p._fontFeatureLen=A.length,p._fontFeatureNamesPtr=t(O),p._fontFeatureValuesPtr=l(Z,"HEAPU32")):(p._fontFeatureLen=0,p._fontFeatureNamesPtr=M,p._fontFeatureValuesPtr=M);Array.isArray(p.fontVariations)&&p.fontVariations.length?(A=p.fontVariations,O=A.map(function(qa){return qa.axis}),
Z=A.map(function(qa){return qa.value}),p._fontVariationLen=A.length,p._fontVariationAxesPtr=t(O),p._fontVariationValuesPtr=l(Z,"HEAPF32")):(p._fontVariationLen=0,p._fontVariationAxesPtr=M,p._fontVariationValuesPtr=M)}function E(p){g._free(p._fontFamiliesPtr);g._free(p._shadowColorsPtr);g._free(p._shadowOffsetsPtr);g._free(p._shadowBlurRadiiPtr);g._free(p._fontFeatureNamesPtr);g._free(p._fontFeatureValuesPtr);g._free(p._fontVariationAxesPtr);g._free(p._fontVariationValuesPtr)}g.Paragraph.prototype.getRectsForRange=
function(p,A,O,Z){p=this._getRectsForRange(p,A,O,Z);return h(p)};g.Paragraph.prototype.getRectsForPlaceholders=function(){var p=this._getRectsForPlaceholders();return h(p)};g.Paragraph.prototype.getGlyphInfoAt=function(p){return d(this._getGlyphInfoAt(p))};g.Paragraph.prototype.getClosestGlyphInfoAtCoordinate=function(p,A){return d(this._getClosestGlyphInfoAtCoordinate(p,A))};g.TypefaceFontProvider.prototype.registerFont=function(p,A){p=g.Typeface.MakeTypefaceFromData(p);if(!p)return null;A=v(A);
this._registerFont(p,A)};g.ParagraphStyle=function(p){p.disableHinting=p.disableHinting||!1;if(p.ellipsis){var A=p.ellipsis;p._ellipsisPtr=v(A);p._ellipsisLen=ja(A)}else p._ellipsisPtr=M,p._ellipsisLen=0;null==p.heightMultiplier&&(p.heightMultiplier=-1);p.maxLines=p.maxLines||0;p.replaceTabCharacters=p.replaceTabCharacters||!1;A=(A=p.strutStyle)||{};A.strutEnabled=A.strutEnabled||!1;A.strutEnabled&&Array.isArray(A.fontFamilies)&&A.fontFamilies.length?(A._fontFamiliesPtr=t(A.fontFamilies),A._fontFamiliesLen=
A.fontFamilies.length):(A._fontFamiliesPtr=M,A._fontFamiliesLen=0);A.fontStyle=n(A.fontStyle);null==A.fontSize&&(A.fontSize=-1);null==A.heightMultiplier&&(A.heightMultiplier=-1);A.halfLeading=A.halfLeading||!1;A.leading=A.leading||0;A.forceStrutHeight=A.forceStrutHeight||!1;p.strutStyle=A;p.textAlign=p.textAlign||g.TextAlign.Start;p.textDirection=p.textDirection||g.TextDirection.LTR;p.textHeightBehavior=p.textHeightBehavior||g.TextHeightBehavior.All;p.textStyle=g.TextStyle(p.textStyle);p.applyRoundingHack=
!1!==p.applyRoundingHack;return p};g.TextStyle=function(p){p.color||(p.color=g.BLACK);p.decoration=p.decoration||0;p.decorationThickness=p.decorationThickness||0;p.decorationStyle=p.decorationStyle||g.DecorationStyle.Solid;p.textBaseline=p.textBaseline||g.TextBaseline.Alphabetic;null==p.fontSize&&(p.fontSize=-1);p.letterSpacing=p.letterSpacing||0;p.wordSpacing=p.wordSpacing||0;null==p.heightMultiplier&&(p.heightMultiplier=-1);p.halfLeading=p.halfLeading||!1;p.fontStyle=n(p.fontStyle);return p};var J=
{},I=g._malloc(16),U=g._malloc(16),V=g._malloc(16);g.ParagraphBuilder.Make=function(p,A){z(p.textStyle);A=g.ParagraphBuilder._Make(p,A);E(p.textStyle);return A};g.ParagraphBuilder.MakeFromFontProvider=function(p,A){z(p.textStyle);A=g.ParagraphBuilder._MakeFromFontProvider(p,A);E(p.textStyle);return A};g.ParagraphBuilder.MakeFromFontCollection=function(p,A){z(p.textStyle);A=g.ParagraphBuilder._MakeFromFontCollection(p,A);E(p.textStyle);return A};g.ParagraphBuilder.ShapeText=function(p,A,O){let Z=0;
for(const za of A)Z+=za.length;if(Z!==p.length)throw"Accumulated block lengths must equal text.length";return g.ParagraphBuilder._ShapeText(p,A,O)};g.ParagraphBuilder.prototype.pushStyle=function(p){z(p);this._pushStyle(p);E(p)};g.ParagraphBuilder.prototype.pushPaintStyle=function(p,A,O){z(p);this._pushPaintStyle(p,A,O);E(p)};g.ParagraphBuilder.prototype.addPlaceholder=function(p,A,O,Z,za){O=O||g.PlaceholderAlignment.Baseline;Z=Z||g.TextBaseline.Alphabetic;this._addPlaceholder(p||0,A||0,O,Z,za||0)};
g.ParagraphBuilder.prototype.setWordsUtf8=function(p){var A=l(p,"HEAPU32");this._setWordsUtf8(A,p&&p.length||0);k(A,p)};g.ParagraphBuilder.prototype.setWordsUtf16=function(p){var A=l(p,"HEAPU32");this._setWordsUtf16(A,p&&p.length||0);k(A,p)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf8=function(p){var A=l(p,"HEAPU32");this._setGraphemeBreaksUtf8(A,p&&p.length||0);k(A,p)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf16=function(p){var A=l(p,"HEAPU32");this._setGraphemeBreaksUtf16(A,p&&p.length||
0);k(A,p)};g.ParagraphBuilder.prototype.setLineBreaksUtf8=function(p){var A=l(p,"HEAPU32");this._setLineBreaksUtf8(A,p&&p.length||0);k(A,p)};g.ParagraphBuilder.prototype.setLineBreaksUtf16=function(p){var A=l(p,"HEAPU32");this._setLineBreaksUtf16(A,p&&p.length||0);k(A,p)}})})(r);a.Gd=a.Gd||[];a.Gd.push(function(){a.Path.prototype.op=function(g,d){return this._op(g,d)?this:null};a.Path.prototype.simplify=function(){return this._simplify()?this:null}});a.Gd=a.Gd||[];a.Gd.push(function(){a.Canvas.prototype.drawText=
function(g,d,h,n,t){var v=ja(g),z=a._malloc(v+1);ka(g,C,z,v+1);this._drawSimpleText(z,v,d,h,t,n);a._free(z)};a.Canvas.prototype.drawGlyphs=function(g,d,h,n,t,v){if(!(2*g.length<=d.length))throw"Not enough positions for the array of gyphs";a.Dd(this.Cd);const z=l(g,"HEAPU16"),E=l(d,"HEAPF32");this._drawGlyphs(g.length,z,E,h,n,t,v);k(E,d);k(z,g)};a.Font.prototype.getGlyphBounds=function(g,d,h){var n=l(g,"HEAPU16"),t=a._malloc(16*g.length);this._getGlyphWidthBounds(n,g.length,M,t,d||null);d=new Float32Array(a.HEAPU8.buffer,
t,4*g.length);k(n,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.Font.prototype.getGlyphIDs=function(g,d,h){d||(d=g.length);var n=ja(g)+1,t=a._malloc(n);ka(g,C,t,n);g=a._malloc(2*d);d=this._getGlyphIDs(t,n-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.Font.prototype.getGlyphIntercepts=function(g,d,h,n){var t=l(g,"HEAPU16"),v=l(d,"HEAPF32");return this._getGlyphIntercepts(t,
g.length,!(g&&g._ck),v,d.length,!(d&&d._ck),h,n)};a.Font.prototype.getGlyphWidths=function(g,d,h){var n=l(g,"HEAPU16"),t=a._malloc(4*g.length);this._getGlyphWidthBounds(n,g.length,t,M,d||null);d=new Float32Array(a.HEAPU8.buffer,t,g.length);k(n,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.FontMgr.FromData=function(){if(!arguments.length)return null;var g=arguments;1===g.length&&Array.isArray(g[0])&&(g=arguments[0]);if(!g.length)return null;for(var d=[],h=[],n=
0;n<g.length;n++){var t=new Uint8Array(g[n]),v=l(t,"HEAPU8");d.push(v);h.push(t.byteLength)}d=l(d,"HEAPU32");h=l(h,"HEAPU32");g=a.FontMgr._fromData(d,h,g.length);a._free(d);a._free(h);return g};a.Typeface.MakeTypefaceFromData=function(g){g=new Uint8Array(g);var d=l(g,"HEAPU8");return(g=a.Typeface._MakeTypefaceFromData(d,g.byteLength))?g:null};a.Typeface.MakeFreeTypeFaceFromData=a.Typeface.MakeTypefaceFromData;a.Typeface.prototype.getGlyphIDs=function(g,d,h){d||(d=g.length);var n=ja(g)+1,t=a._malloc(n);
ka(g,C,t,n);g=a._malloc(2*d);d=this._getGlyphIDs(t,n-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.TextBlob.MakeOnPath=function(g,d,h,n){if(g&&g.length&&d&&d.countPoints()){if(1===d.countPoints())return this.MakeFromText(g,h);n||(n=0);var t=h.getGlyphIDs(g);t=h.getGlyphWidths(t);var v=[];d=new a.ContourMeasureIter(d,!1,1);for(var z=d.next(),E=new Float32Array(4),J=0;J<g.length&&
z;J++){var I=t[J];n+=I/2;if(n>z.length()){z.delete();z=d.next();if(!z){g=g.substring(0,J);break}n=I/2}z.getPosTan(n,E);var U=E[2],V=E[3];v.push(U,V,E[0]-I/2*U,E[1]-I/2*V);n+=I/2}g=this.MakeFromRSXform(g,v,h);z&&z.delete();d.delete();return g}};a.TextBlob.MakeFromRSXform=function(g,d,h){var n=ja(g)+1,t=a._malloc(n);ka(g,C,t,n);g=l(d,"HEAPF32");h=a.TextBlob._MakeFromRSXform(t,n-1,g,h);a._free(t);return h?h:null};a.TextBlob.MakeFromRSXformGlyphs=function(g,d,h){var n=l(g,"HEAPU16");d=l(d,"HEAPF32");
h=a.TextBlob._MakeFromRSXformGlyphs(n,2*g.length,d,h);k(n,g);return h?h:null};a.TextBlob.MakeFromGlyphs=function(g,d){var h=l(g,"HEAPU16");d=a.TextBlob._MakeFromGlyphs(h,2*g.length,d);k(h,g);return d?d:null};a.TextBlob.MakeFromText=function(g,d){var h=ja(g)+1,n=a._malloc(h);ka(g,C,n,h);g=a.TextBlob._MakeFromText(n,h-1,d);a._free(n);return g?g:null};a.MallocGlyphIDs=function(g){return a.Malloc(Uint16Array,g)}});a.Gd=a.Gd||[];a.Gd.push(function(){a.MakePicture=function(g){g=new Uint8Array(g);var d=
a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._MakePicture(d,g.byteLength))?g:null}});a.Gd=a.Gd||[];a.Gd.push(function(){a.RuntimeEffect.Make=function(g,d){return a.RuntimeEffect._Make(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.MakeForBlender=function(g,d){return a.RuntimeEffect._MakeForBlender(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.prototype.makeShader=function(g,d){var h=!g._ck,n=l(g,"HEAPF32");d=q(d);return this._makeShader(n,
4*g.length,h,d)};a.RuntimeEffect.prototype.makeShaderWithChildren=function(g,d,h){var n=!g._ck,t=l(g,"HEAPF32");h=q(h);for(var v=[],z=0;z<d.length;z++)v.push(d[z].jd.Ed);d=l(v,"HEAPU32");return this._makeShaderWithChildren(t,4*g.length,n,d,v.length,h)};a.RuntimeEffect.prototype.makeBlender=function(g){var d=!g._ck,h=l(g,"HEAPF32");return this._makeBlender(h,4*g.length,d)}})})(r);
var la=Object.assign({},r),ma="./this.program",oa=(a,b)=>{throw b;},pa="object"==typeof window,ra="function"==typeof importScripts,sa="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,ta="",ua,wa,xa;
if(sa){const {createRequire:a}=await import("module");var require=a(import.meta.url),fs=require("fs"),ya=require("path");ra?ta=ya.dirname(ta)+"/":ta=require("url").fileURLToPath(new URL("./",import.meta.url));ua=(b,c)=>{b=b.startsWith("file://")?new URL(b):ya.normalize(b);return fs.readFileSync(b,c?void 0:"utf8")};xa=b=>{b=ua(b,!0);b.buffer||(b=new Uint8Array(b));return b};wa=(b,c,e,f=!0)=>{b=b.startsWith("file://")?new URL(b):ya.normalize(b);fs.readFile(b,f?void 0:
"utf8",(k,l)=>{k?e(k):c(f?l.buffer:l)})};!r.thisProgram&&1<process.argv.length&&(ma=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);oa=(b,c)=>{process.exitCode=b;throw c;};r.inspect=()=>"[Emscripten Module object]"}else if(pa||ra)ra?ta=self.location.href:"undefined"!=typeof document&&document.currentScript&&(ta=document.currentScript.src),_scriptDir&&(ta=_scriptDir),0!==ta.indexOf("blob:")?ta=ta.substr(0,ta.replace(/[?#].*/,"").lastIndexOf("/")+1):ta="",ua=a=>{var b=new XMLHttpRequest;b.open("GET",
a,!1);b.send(null);return b.responseText},ra&&(xa=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),wa=(a,b,c)=>{var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?b(e.response):c()};e.onerror=c;e.send(null)};var Aa=r.print||console.log.bind(console),Ca=r.printErr||console.error.bind(console);Object.assign(r,la);la=null;r.thisProgram&&(ma=r.thisProgram);
r.quit&&(oa=r.quit);var Da;r.wasmBinary&&(Da=r.wasmBinary);var noExitRuntime=r.noExitRuntime||!0;"object"!=typeof WebAssembly&&Ea("no native wasm support detected");var Fa,G,Ga=!1,Ha,C,Ia,Ja,K,L,N,Ka;function La(){var a=Fa.buffer;r.HEAP8=Ha=new Int8Array(a);r.HEAP16=Ia=new Int16Array(a);r.HEAP32=K=new Int32Array(a);r.HEAPU8=C=new Uint8Array(a);r.HEAPU16=Ja=new Uint16Array(a);r.HEAPU32=L=new Uint32Array(a);r.HEAPF32=N=new Float32Array(a);r.HEAPF64=Ka=new Float64Array(a)}var Ma,Oa=[],Pa=[],Qa=[];
function Ra(){var a=r.preRun.shift();Oa.unshift(a)}var Ua=0,Va=null,Wa=null;function Ea(a){if(r.onAbort)r.onAbort(a);a="Aborted("+a+")";Ca(a);Ga=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ba(a);throw a;}function Xa(a){return a.startsWith("data:application/octet-stream;base64,")}var Ya;if(r.locateFile){if(Ya="canvaskit.wasm",!Xa(Ya)){var Za=Ya;Ya=r.locateFile?r.locateFile(Za,ta):ta+Za}}else Ya=(new URL("canvaskit.wasm",import.meta.url)).href;
function $a(a){if(a==Ya&&Da)return new Uint8Array(Da);if(xa)return xa(a);throw"both async and sync fetching of the wasm failed";}function ab(a){if(!Da&&(pa||ra)){if("function"==typeof fetch&&!a.startsWith("file://"))return fetch(a,{credentials:"same-origin"}).then(b=>{if(!b.ok)throw"failed to load wasm binary file at '"+a+"'";return b.arrayBuffer()}).catch(()=>$a(a));if(wa)return new Promise((b,c)=>{wa(a,e=>b(new Uint8Array(e)),c)})}return Promise.resolve().then(()=>$a(a))}
function bb(a,b,c){return ab(a).then(e=>WebAssembly.instantiate(e,b)).then(e=>e).then(c,e=>{Ca("failed to asynchronously prepare wasm: "+e);Ea(e)})}
function cb(a,b){var c=Ya;return Da||"function"!=typeof WebAssembly.instantiateStreaming||Xa(c)||c.startsWith("file://")||sa||"function"!=typeof fetch?bb(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){Ca("wasm streaming compile failed: "+f);Ca("falling back to ArrayBuffer instantiation");return bb(c,a,b)}))}function db(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var eb=a=>{for(;0<a.length;)a.shift()(r)};
function fb(a){this.Ed=a-24;this.Ie=function(b){L[this.Ed+4>>2]=b};this.qe=function(b){L[this.Ed+8>>2]=b};this.Td=function(b,c){this.pe();this.Ie(b);this.qe(c)};this.pe=function(){L[this.Ed+16>>2]=0}}
var gb=0,ib=0,jb="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,kb=(a,b,c)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16<c-b&&a.buffer&&jb)return jb.decode(a.subarray(b,c));for(e="";b<c;){var f=a[b++];if(f&128){var k=a[b++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|k);else{var l=a[b++]&63;f=224==(f&240)?(f&15)<<12|k<<6|l:(f&7)<<18|k<<12|l<<6|a[b++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e},
lb={};function mb(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function nb(a){return this.fromWireType(K[a>>2])}var ob={},pb={},qb={},rb=void 0;function sb(a){throw new rb(a);}
function tb(a,b,c){function e(m){m=c(m);m.length!==a.length&&sb("Mismatched type converter count");for(var q=0;q<a.length;++q)ub(a[q],m[q])}a.forEach(function(m){qb[m]=b});var f=Array(b.length),k=[],l=0;b.forEach((m,q)=>{pb.hasOwnProperty(m)?f[q]=pb[m]:(k.push(m),ob.hasOwnProperty(m)||(ob[m]=[]),ob[m].push(()=>{f[q]=pb[m];++l;l===k.length&&e(f)}))});0===k.length&&e(f)}
function vb(a){switch(a){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError(`Unknown type size: ${a}`);}}var wb=void 0;function P(a){for(var b="";C[a];)b+=wb[C[a++]];return b}var xb=void 0;function Q(a){throw new xb(a);}
function yb(a,b,c={}){var e=b.name;a||Q(`type "${e}" must have a positive integer typeid pointer`);if(pb.hasOwnProperty(a)){if(c.$e)return;Q(`Cannot register type '${e}' twice`)}pb[a]=b;delete qb[a];ob.hasOwnProperty(a)&&(b=ob[a],delete ob[a],b.forEach(f=>f()))}function ub(a,b,c={}){if(!("argPackAdvance"in b))throw new TypeError("registerType registeredInstance requires argPackAdvance");yb(a,b,c)}function zb(a){Q(a.jd.Hd.Fd.name+" instance already deleted")}var Ab=!1;function Bb(){}
function Cb(a){--a.count.value;0===a.count.value&&(a.Jd?a.Nd.Rd(a.Jd):a.Hd.Fd.Rd(a.Ed))}function Db(a,b,c){if(b===c)return a;if(void 0===c.Kd)return null;a=Db(a,b,c.Kd);return null===a?null:c.Se(a)}var Jb={},Kb=[];function Lb(){for(;Kb.length;){var a=Kb.pop();a.jd.Zd=!1;a["delete"]()}}var Mb=void 0,Nb={};function Ob(a,b){for(void 0===b&&Q("ptr should not be undefined");a.Kd;)b=a.ee(b),a=a.Kd;return Nb[b]}
function Pb(a,b){b.Hd&&b.Ed||sb("makeClassHandle requires ptr and ptrType");!!b.Nd!==!!b.Jd&&sb("Both smartPtrType and smartPtr must be specified");b.count={value:1};return Qb(Object.create(a,{jd:{value:b}}))}function Qb(a){if("undefined"===typeof FinalizationRegistry)return Qb=b=>b,a;Ab=new FinalizationRegistry(b=>{Cb(b.jd)});Qb=b=>{var c=b.jd;c.Jd&&Ab.register(b,{jd:c},b);return b};Bb=b=>{Ab.unregister(b)};return Qb(a)}function Rb(){}
function Sb(a){if(void 0===a)return"_unknown";a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?`_${a}`:a}function Tb(a,b){a=Sb(a);return{[a]:function(){return b.apply(this,arguments)}}[a]}
function Ub(a,b,c){if(void 0===a[b].Id){var e=a[b];a[b]=function(){a[b].Id.hasOwnProperty(arguments.length)||Q(`Function '${c}' called with an invalid number of arguments (${arguments.length}) - expects one of (${a[b].Id})!`);return a[b].Id[arguments.length].apply(this,arguments)};a[b].Id=[];a[b].Id[e.Xd]=e}}
function Vb(a,b,c){r.hasOwnProperty(a)?((void 0===c||void 0!==r[a].Id&&void 0!==r[a].Id[c])&&Q(`Cannot register public name '${a}' twice`),Ub(r,a,a),r.hasOwnProperty(c)&&Q(`Cannot register multiple overloads of a function with the same number of arguments (${c})!`),r[a].Id[c]=b):(r[a]=b,void 0!==c&&(r[a].rf=c))}function Wb(a,b,c,e,f,k,l,m){this.name=a;this.constructor=b;this.$d=c;this.Rd=e;this.Kd=f;this.Ve=k;this.ee=l;this.Se=m;this.df=[]}
function Xb(a,b,c){for(;b!==c;)b.ee||Q(`Expected null or instance of ${c.name}, got an instance of ${b.name}`),a=b.ee(a),b=b.Kd;return a}function Yb(a,b){if(null===b)return this.ue&&Q(`null is not a valid ${this.name}`),0;b.jd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.jd.Ed||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);return Xb(b.jd.Ed,b.jd.Hd.Fd,this.Fd)}
function $b(a,b){if(null===b){this.ue&&Q(`null is not a valid ${this.name}`);if(this.je){var c=this.ve();null!==a&&a.push(this.Rd,c);return c}return 0}b.jd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.jd.Ed||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);!this.ie&&b.jd.Hd.ie&&Q(`Cannot convert argument of type ${b.jd.Nd?b.jd.Nd.name:b.jd.Hd.name} to parameter type ${this.name}`);c=Xb(b.jd.Ed,b.jd.Hd.Fd,this.Fd);if(this.je)switch(void 0===b.jd.Jd&&Q("Passing raw pointer to smart pointer is illegal"),
this.jf){case 0:b.jd.Nd===this?c=b.jd.Jd:Q(`Cannot convert argument of type ${b.jd.Nd?b.jd.Nd.name:b.jd.Hd.name} to parameter type ${this.name}`);break;case 1:c=b.jd.Jd;break;case 2:if(b.jd.Nd===this)c=b.jd.Jd;else{var e=b.clone();c=this.ef(c,ac(function(){e["delete"]()}));null!==a&&a.push(this.Rd,c)}break;default:Q("Unsupporting sharing policy")}return c}
function bc(a,b){if(null===b)return this.ue&&Q(`null is not a valid ${this.name}`),0;b.jd||Q(`Cannot pass "${Zb(b)}" as a ${this.name}`);b.jd.Ed||Q(`Cannot pass deleted object as a pointer of type ${this.name}`);b.jd.Hd.ie&&Q(`Cannot convert argument of type ${b.jd.Hd.name} to parameter type ${this.name}`);return Xb(b.jd.Ed,b.jd.Hd.Fd,this.Fd)}
function cc(a,b,c,e,f,k,l,m,q,w,y){this.name=a;this.Fd=b;this.ue=c;this.ie=e;this.je=f;this.cf=k;this.jf=l;this.Ee=m;this.ve=q;this.ef=w;this.Rd=y;f||void 0!==b.Kd?this.toWireType=$b:(this.toWireType=e?Yb:bc,this.Md=null)}function dc(a,b,c){r.hasOwnProperty(a)||sb("Replacing nonexistant public symbol");void 0!==r[a].Id&&void 0!==c?r[a].Id[c]=b:(r[a]=b,r[a].Xd=c)}
var ec=(a,b)=>{var c=[];return function(){c.length=0;Object.assign(c,arguments);if(a.includes("j")){var e=r["dynCall_"+a];e=c&&c.length?e.apply(null,[b].concat(c)):e.call(null,b)}else e=Ma.get(b).apply(null,c);return e}};function mc(a,b){a=P(a);var c=a.includes("j")?ec(a,b):Ma.get(b);"function"!=typeof c&&Q(`unknown function pointer with signature ${a}: ${b}`);return c}var nc=void 0;function oc(a){a=pc(a);var b=P(a);qc(a);return b}
function rc(a,b){function c(k){f[k]||pb[k]||(qb[k]?qb[k].forEach(c):(e.push(k),f[k]=!0))}var e=[],f={};b.forEach(c);throw new nc(`${a}: `+e.map(oc).join([", "]));}
function sc(a,b,c,e,f){var k=b.length;2>k&&Q("argTypes array size mismatch! Must at least get return value and 'this' types!");var l=null!==b[1]&&null!==c,m=!1;for(c=1;c<b.length;++c)if(null!==b[c]&&void 0===b[c].Md){m=!0;break}var q="void"!==b[0].name,w=k-2,y=Array(w),B=[],D=[];return function(){arguments.length!==w&&Q(`function ${a} called with ${arguments.length} arguments, expected ${w} args!`);D.length=0;B.length=l?2:1;B[0]=f;if(l){var u=b[1].toWireType(D,this);B[1]=u}for(var F=0;F<w;++F)y[F]=
b[F+2].toWireType(D,arguments[F]),B.push(y[F]);F=e.apply(null,B);if(m)mb(D);else for(var H=l?1:2;H<b.length;H++){var T=1===H?u:y[H-2];null!==b[H].Md&&b[H].Md(T)}u=q?b[0].fromWireType(F):void 0;return u}}function tc(a,b){for(var c=[],e=0;e<a;e++)c.push(L[b+4*e>>2]);return c}function uc(){this.Qd=[void 0];this.Ce=[]}var vc=new uc;function wc(a){a>=vc.Td&&0===--vc.get(a).Fe&&vc.qe(a)}
var xc=a=>{a||Q("Cannot use deleted val. handle = "+a);return vc.get(a).value},ac=a=>{switch(a){case void 0:return 1;case null:return 2;case !0:return 3;case !1:return 4;default:return vc.pe({Fe:1,value:a})}};function yc(a,b,c){switch(b){case 0:return function(e){return this.fromWireType((c?Ha:C)[e])};case 1:return function(e){return this.fromWireType((c?Ia:Ja)[e>>1])};case 2:return function(e){return this.fromWireType((c?K:L)[e>>2])};default:throw new TypeError("Unknown integer type: "+a);}}
function zc(a,b){var c=pb[a];void 0===c&&Q(b+" has unknown type "+oc(a));return c}function Zb(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a}function Ac(a,b){switch(b){case 2:return function(c){return this.fromWireType(N[c>>2])};case 3:return function(c){return this.fromWireType(Ka[c>>3])};default:throw new TypeError("Unknown float type: "+a);}}
function Bc(a,b,c){switch(b){case 0:return c?function(e){return Ha[e]}:function(e){return C[e]};case 1:return c?function(e){return Ia[e>>1]}:function(e){return Ja[e>>1]};case 2:return c?function(e){return K[e>>2]}:function(e){return L[e>>2]};default:throw new TypeError("Unknown integer type: "+a);}}
var ka=(a,b,c,e)=>{if(!(0<e))return 0;var f=c;e=c+e-1;for(var k=0;k<a.length;++k){var l=a.charCodeAt(k);if(55296<=l&&57343>=l){var m=a.charCodeAt(++k);l=65536+((l&1023)<<10)|m&1023}if(127>=l){if(c>=e)break;b[c++]=l}else{if(2047>=l){if(c+1>=e)break;b[c++]=192|l>>6}else{if(65535>=l){if(c+2>=e)break;b[c++]=224|l>>12}else{if(c+3>=e)break;b[c++]=240|l>>18;b[c++]=128|l>>12&63}b[c++]=128|l>>6&63}b[c++]=128|l&63}}b[c]=0;return c-f},ja=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);127>=e?b++:2047>=
e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},Cc="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,Dc=(a,b)=>{var c=a>>1;for(var e=c+b/2;!(c>=e)&&Ja[c];)++c;c<<=1;if(32<c-a&&Cc)return Cc.decode(C.subarray(a,c));c="";for(e=0;!(e>=b/2);++e){var f=Ia[a+2*e>>1];if(0==f)break;c+=String.fromCharCode(f)}return c},Ec=(a,b,c)=>{void 0===c&&(c=2147483647);if(2>c)return 0;c-=2;var e=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)Ia[b>>1]=a.charCodeAt(f),b+=2;Ia[b>>1]=0;return b-e},
Fc=a=>2*a.length,Gc=(a,b)=>{for(var c=0,e="";!(c>=b/4);){var f=K[a+4*c>>2];if(0==f)break;++c;65536<=f?(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023)):e+=String.fromCharCode(f)}return e},Hc=(a,b,c)=>{void 0===c&&(c=2147483647);if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f<a.length;++f){var k=a.charCodeAt(f);if(55296<=k&&57343>=k){var l=a.charCodeAt(++f);k=65536+((k&1023)<<10)|l&1023}K[b>>2]=k;b+=4;if(b+4>c)break}K[b>>2]=0;return b-e},Ic=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);
55296<=e&&57343>=e&&++c;b+=4}return b},Jc={};function Kc(a){var b=Jc[a];return void 0===b?P(a):b}var Lc=[];
function Mc(){function a(b){b.$$$embind_global$$$=b;var c="object"==typeof $$$embind_global$$$&&b.$$$embind_global$$$==b;c||delete b.$$$embind_global$$$;return c}if("object"==typeof globalThis)return globalThis;if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;"object"==typeof global&&a(global)?$$$embind_global$$$=global:"object"==typeof self&&a(self)&&($$$embind_global$$$=self);if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;throw Error("unable to get global object.");
}function Nc(a){var b=Lc.length;Lc.push(a);return b}function Oc(a,b){for(var c=Array(a),e=0;e<a;++e)c[e]=zc(L[b+4*e>>2],"parameter "+e);return c}var Pc=[];function Qc(a){var b=Array(a+1);return function(c,e,f){b[0]=c;for(var k=0;k<a;++k){var l=zc(L[e+4*k>>2],"parameter "+k);b[k+1]=l.readValueFromPointer(f);f+=l.argPackAdvance}c=new (c.bind.apply(c,b));return ac(c)}}var Rc={};
function Sc(a){var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=function(c,e){b.vertexAttribDivisorANGLE(c,e)},a.drawArraysInstanced=function(c,e,f,k){b.drawArraysInstancedANGLE(c,e,f,k)},a.drawElementsInstanced=function(c,e,f,k,l){b.drawElementsInstancedANGLE(c,e,f,k,l)})}
function Tc(a){var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=function(){return b.createVertexArrayOES()},a.deleteVertexArray=function(c){b.deleteVertexArrayOES(c)},a.bindVertexArray=function(c){b.bindVertexArrayOES(c)},a.isVertexArray=function(c){return b.isVertexArrayOES(c)})}function Uc(a){var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=function(c,e){b.drawBuffersWEBGL(c,e)})}
var Vc=1,Wc=[],Xc=[],Yc=[],Zc=[],ea=[],$c=[],ad=[],ia=[],bd=[],cd=[],dd={},ed={},gd=4;function R(a){hd||(hd=a)}function da(a){for(var b=Vc++,c=a.length;c<b;c++)a[c]=null;return b}function fa(a,b){a.Td||(a.Td=a.getContext,a.getContext=function(e,f){f=a.Td(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1<b.majorVersion?a.getContext("webgl2",b):a.getContext("webgl",b);return c?jd(c,b):0}
function jd(a,b){var c=da(ia),e={handle:c,attributes:b,version:b.majorVersion,Od:a};a.canvas&&(a.canvas.Je=e);ia[c]=e;("undefined"==typeof b.Te||b.Te)&&kd(e);return c}function ha(a){x=ia[a];r.pf=S=x&&x.Od;return!(a&&!S)}
function kd(a){a||(a=x);if(!a.af){a.af=!0;var b=a.Od;Sc(b);Tc(b);Uc(b);b.ze=b.getExtension("WEBGL_draw_instanced_base_vertex_base_instance");b.De=b.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");2<=a.version&&(b.Ae=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.Ae)b.Ae=b.getExtension("EXT_disjoint_timer_query");b.qf=b.getExtension("WEBGL_multi_draw");(b.getSupportedExtensions()||[]).forEach(function(c){c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}}
var x,hd,ld={},nd=()=>{if(!md){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:ma||"./this.program"},b;for(b in ld)void 0===ld[b]?delete a[b]:a[b]=ld[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);md=c}return md},md,od=[null,[],[]];function pd(a){S.bindVertexArray(ad[a])}
function qd(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2];S.deleteVertexArray(ad[e]);ad[e]=null}}var rd=[];function sd(a,b,c,e){S.drawElements(a,b,c,e)}function td(a,b,c,e){for(var f=0;f<a;f++){var k=S[c](),l=k&&da(e);k?(k.name=l,e[l]=k):R(1282);K[b+4*f>>2]=l}}function ud(a,b){td(a,b,"createVertexArray",ad)}
function vd(a,b,c){if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&R(1280);return;case 34814:case 36345:e=0;break;case 34466:var f=S.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>x.version){R(1282);return}e=2*(S.getSupportedExtensions()||[]).length;break;case 33307:case 33308:if(2>x.version){R(1280);return}e=33307==a?3:0}if(void 0===e)switch(f=S.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":R(1280);return;case "object":if(null===
f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e=0;break;default:R(1280);return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a<f.length;++a)switch(c){case 0:K[b+4*a>>2]=f[a];break;case 2:N[b+4*a>>2]=f[a];break;case 4:Ha[b+a>>0]=f[a]?1:0}return}try{e=f.name|0}catch(k){R(1280);
Ca("GL_INVALID_ENUM in glGet"+c+"v: Unknown object returned from WebGL getParameter("+a+")! (error: "+k+")");return}}break;default:R(1280);Ca("GL_INVALID_ENUM in glGet"+c+"v: Native code calling glGet"+c+"v("+a+") and it returns "+f+" of type "+typeof f+"!");return}switch(c){case 1:c=e;L[b>>2]=c;L[b+4>>2]=(c-L[b>>2])/4294967296;break;case 0:K[b>>2]=e;break;case 2:N[b>>2]=e;break;case 4:Ha[b>>0]=e?1:0}}else R(1281)}var xd=a=>{var b=ja(a)+1,c=wd(b);c&&ka(a,C,c,b);return c};
function yd(a){return"]"==a.slice(-1)&&a.lastIndexOf("[")}function zd(a){a-=5120;return 0==a?Ha:1==a?C:2==a?Ia:4==a?K:6==a?N:5==a||28922==a||28520==a||30779==a||30782==a?L:Ja}function Ad(a,b,c,e,f){a=zd(a);var k=31-Math.clz32(a.BYTES_PER_ELEMENT),l=gd;return a.subarray(f>>k,f+e*(c*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*(1<<k)+l-1&-l)>>k)}
function W(a){var b=S.Qe;if(b){var c=b.de[a];"number"==typeof c&&(b.de[a]=c=S.getUniformLocation(b,b.Ge[a]+(0<c?"["+c+"]":"")));return c}R(1282)}var Bd=[],Cd=[],Dd=a=>0===a%4&&(0!==a%100||0===a%400),Ed=[31,29,31,30,31,30,31,31,30,31,30,31],Fd=[31,28,31,30,31,30,31,31,30,31,30,31];function Gd(a){var b=Array(ja(a)+1);ka(a,b,0,b.length);return b}
var Hd=(a,b,c,e)=>{function f(u,F,H){for(u="number"==typeof u?u.toString():u||"";u.length<F;)u=H[0]+u;return u}function k(u,F){return f(u,F,"0")}function l(u,F){function H(ca){return 0>ca?-1:0<ca?1:0}var T;0===(T=H(u.getFullYear()-F.getFullYear()))&&0===(T=H(u.getMonth()-F.getMonth()))&&(T=H(u.getDate()-F.getDate()));return T}function m(u){switch(u.getDay()){case 0:return new Date(u.getFullYear()-1,11,29);case 1:return u;case 2:return new Date(u.getFullYear(),0,3);case 3:return new Date(u.getFullYear(),
0,2);case 4:return new Date(u.getFullYear(),0,1);case 5:return new Date(u.getFullYear()-1,11,31);case 6:return new Date(u.getFullYear()-1,11,30)}}function q(u){var F=u.Ud;for(u=new Date((new Date(u.Vd+1900,0,1)).getTime());0<F;){var H=u.getMonth(),T=(Dd(u.getFullYear())?Ed:Fd)[H];if(F>T-u.getDate())F-=T-u.getDate()+1,u.setDate(1),11>H?u.setMonth(H+1):(u.setMonth(0),u.setFullYear(u.getFullYear()+1));else{u.setDate(u.getDate()+F);break}}H=new Date(u.getFullYear()+1,0,4);F=m(new Date(u.getFullYear(),
0,4));H=m(H);return 0>=l(F,u)?0>=l(H,u)?u.getFullYear()+1:u.getFullYear():u.getFullYear()-1}var w=K[e+40>>2];e={mf:K[e>>2],lf:K[e+4>>2],ne:K[e+8>>2],we:K[e+12>>2],oe:K[e+16>>2],Vd:K[e+20>>2],Pd:K[e+24>>2],Ud:K[e+28>>2],tf:K[e+32>>2],kf:K[e+36>>2],nf:w?w?kb(C,w):"":""};c=c?kb(C,c):"";w={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y",
"%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var y in w)c=c.replace(new RegExp(y,"g"),w[y]);var B="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),D="January February March April May June July August September October November December".split(" ");w={"%a":u=>B[u.Pd].substring(0,3),"%A":u=>B[u.Pd],"%b":u=>D[u.oe].substring(0,3),"%B":u=>D[u.oe],"%C":u=>k((u.Vd+1900)/
100|0,2),"%d":u=>k(u.we,2),"%e":u=>f(u.we,2," "),"%g":u=>q(u).toString().substring(2),"%G":u=>q(u),"%H":u=>k(u.ne,2),"%I":u=>{u=u.ne;0==u?u=12:12<u&&(u-=12);return k(u,2)},"%j":u=>{for(var F=0,H=0;H<=u.oe-1;F+=(Dd(u.Vd+1900)?Ed:Fd)[H++]);return k(u.we+F,3)},"%m":u=>k(u.oe+1,2),"%M":u=>k(u.lf,2),"%n":()=>"\n","%p":u=>0<=u.ne&&12>u.ne?"AM":"PM","%S":u=>k(u.mf,2),"%t":()=>"\t","%u":u=>u.Pd||7,"%U":u=>k(Math.floor((u.Ud+7-u.Pd)/7),2),"%V":u=>{var F=Math.floor((u.Ud+7-(u.Pd+6)%7)/7);2>=(u.Pd+371-u.Ud-
2)%7&&F++;if(F)53==F&&(H=(u.Pd+371-u.Ud)%7,4==H||3==H&&Dd(u.Vd)||(F=1));else{F=52;var H=(u.Pd+7-u.Ud-1)%7;(4==H||5==H&&Dd(u.Vd%400-1))&&F++}return k(F,2)},"%w":u=>u.Pd,"%W":u=>k(Math.floor((u.Ud+7-(u.Pd+6)%7)/7),2),"%y":u=>(u.Vd+1900).toString().substring(2),"%Y":u=>u.Vd+1900,"%z":u=>{u=u.kf;var F=0<=u;u=Math.abs(u)/60;return(F?"+":"-")+String("0000"+(u/60*100+u%60)).slice(-4)},"%Z":u=>u.nf,"%%":()=>"%"};c=c.replace(/%%/g,"\x00\x00");for(y in w)c.includes(y)&&(c=c.replace(new RegExp(y,"g"),w[y](e)));
c=c.replace(/\0\0/g,"%");y=Gd(c);if(y.length>b)return 0;Ha.set(y,a);return y.length-1};rb=r.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};for(var Id=Array(256),Jd=0;256>Jd;++Jd)Id[Jd]=String.fromCharCode(Jd);wb=Id;xb=r.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}};
Rb.prototype.isAliasOf=function(a){if(!(this instanceof Rb&&a instanceof Rb))return!1;var b=this.jd.Hd.Fd,c=this.jd.Ed,e=a.jd.Hd.Fd;for(a=a.jd.Ed;b.Kd;)c=b.ee(c),b=b.Kd;for(;e.Kd;)a=e.ee(a),e=e.Kd;return b===e&&c===a};
Rb.prototype.clone=function(){this.jd.Ed||zb(this);if(this.jd.ce)return this.jd.count.value+=1,this;var a=Qb,b=Object,c=b.create,e=Object.getPrototypeOf(this),f=this.jd;a=a(c.call(b,e,{jd:{value:{count:f.count,Zd:f.Zd,ce:f.ce,Ed:f.Ed,Hd:f.Hd,Jd:f.Jd,Nd:f.Nd}}}));a.jd.count.value+=1;a.jd.Zd=!1;return a};Rb.prototype["delete"]=function(){this.jd.Ed||zb(this);this.jd.Zd&&!this.jd.ce&&Q("Object already scheduled for deletion");Bb(this);Cb(this.jd);this.jd.ce||(this.jd.Jd=void 0,this.jd.Ed=void 0)};
Rb.prototype.isDeleted=function(){return!this.jd.Ed};Rb.prototype.deleteLater=function(){this.jd.Ed||zb(this);this.jd.Zd&&!this.jd.ce&&Q("Object already scheduled for deletion");Kb.push(this);1===Kb.length&&Mb&&Mb(Lb);this.jd.Zd=!0;return this};r.getInheritedInstanceCount=function(){return Object.keys(Nb).length};r.getLiveInheritedInstances=function(){var a=[],b;for(b in Nb)Nb.hasOwnProperty(b)&&a.push(Nb[b]);return a};r.flushPendingDeletes=Lb;r.setDelayFunction=function(a){Mb=a;Kb.length&&Mb&&Mb(Lb)};
cc.prototype.We=function(a){this.Ee&&(a=this.Ee(a));return a};cc.prototype.ye=function(a){this.Rd&&this.Rd(a)};cc.prototype.argPackAdvance=8;cc.prototype.readValueFromPointer=nb;cc.prototype.deleteObject=function(a){if(null!==a)a["delete"]()};
cc.prototype.fromWireType=function(a){function b(){return this.je?Pb(this.Fd.$d,{Hd:this.cf,Ed:c,Nd:this,Jd:a}):Pb(this.Fd.$d,{Hd:this,Ed:a})}var c=this.We(a);if(!c)return this.ye(a),null;var e=Ob(this.Fd,c);if(void 0!==e){if(0===e.jd.count.value)return e.jd.Ed=c,e.jd.Jd=a,e.clone();e=e.clone();this.ye(a);return e}e=this.Fd.Ve(c);e=Jb[e];if(!e)return b.call(this);e=this.ie?e.Pe:e.pointerType;var f=Db(c,this.Fd,e.Fd);return null===f?b.call(this):this.je?Pb(e.Fd.$d,{Hd:e,Ed:f,Nd:this,Jd:a}):Pb(e.Fd.$d,
{Hd:e,Ed:f})};nc=r.UnboundTypeError=function(a,b){var c=Tb(b,function(e){this.name=b;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(a.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`};return c}(Error,"UnboundTypeError");
Object.assign(uc.prototype,{get(a){return this.Qd[a]},has(a){return void 0!==this.Qd[a]},pe(a){var b=this.Ce.pop()||this.Qd.length;this.Qd[b]=a;return b},qe(a){this.Qd[a]=void 0;this.Ce.push(a)}});vc.Qd.push({value:void 0},{value:null},{value:!0},{value:!1});vc.Td=vc.Qd.length;r.count_emval_handles=function(){for(var a=0,b=vc.Td;b<vc.Qd.length;++b)void 0!==vc.Qd[b]&&++a;return a};for(var S,Kd=0;32>Kd;++Kd)rd.push(Array(Kd));var Ld=new Float32Array(288);
for(Kd=0;288>Kd;++Kd)Bd[Kd]=Ld.subarray(0,Kd+1);var Md=new Int32Array(288);for(Kd=0;288>Kd;++Kd)Cd[Kd]=Md.subarray(0,Kd+1);
var $d={H:function(a,b,c){(new fb(a)).Td(b,c);gb=a;ib++;throw gb;},_:function(){return 0},_c:()=>{},Zc:function(){return 0},Yc:()=>{},Xc:function(){},Wc:()=>{},D:function(a){var b=lb[a];delete lb[a];var c=b.ve,e=b.Rd,f=b.Be,k=f.map(l=>l.Ze).concat(f.map(l=>l.gf));tb([a],k,l=>{var m={};f.forEach((q,w)=>{var y=l[w],B=q.Xe,D=q.Ye,u=l[w+f.length],F=q.ff,H=q.hf;m[q.Ue]={read:T=>y.fromWireType(B(D,T)),write:(T,ca)=>{var Y=[];F(H,T,u.toWireType(Y,ca));mb(Y)}}});return[{name:b.name,fromWireType:function(q){var w=
{},y;for(y in m)w[y]=m[y].read(q);e(q);return w},toWireType:function(q,w){for(var y in m)if(!(y in w))throw new TypeError(`Missing field: "${y}"`);var B=c();for(y in m)m[y].write(B,w[y]);null!==q&&q.push(e,B);return B},argPackAdvance:8,readValueFromPointer:nb,Md:e}]})},ea:function(){},Sc:function(a,b,c,e,f){var k=vb(c);b=P(b);ub(a,{name:b,fromWireType:function(l){return!!l},toWireType:function(l,m){return m?e:f},argPackAdvance:8,readValueFromPointer:function(l){if(1===c)var m=Ha;else if(2===c)m=Ia;
else if(4===c)m=K;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(m[l>>k])},Md:null})},l:function(a,b,c,e,f,k,l,m,q,w,y,B,D){y=P(y);k=mc(f,k);m&&(m=mc(l,m));w&&(w=mc(q,w));D=mc(B,D);var u=Sb(y);Vb(u,function(){rc(`Cannot construct ${y} due to unbound types`,[e])});tb([a,b,c],e?[e]:[],function(F){F=F[0];if(e){var H=F.Fd;var T=H.$d}else T=Rb.prototype;F=Tb(u,function(){if(Object.getPrototypeOf(this)!==ca)throw new xb("Use 'new' to construct "+y);if(void 0===Y.Sd)throw new xb(y+
" has no accessible constructor");var Na=Y.Sd[arguments.length];if(void 0===Na)throw new xb(`Tried to invoke ctor of ${y} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(Y.Sd).toString()}) parameters instead!`);return Na.apply(this,arguments)});var ca=Object.create(T,{constructor:{value:F}});F.prototype=ca;var Y=new Wb(y,F,ca,D,H,k,m,w);Y.Kd&&(void 0===Y.Kd.fe&&(Y.Kd.fe=[]),Y.Kd.fe.push(Y));H=new cc(y,Y,!0,!1,!1);T=new cc(y+"*",Y,!1,!1,!1);var va=new cc(y+" const*",
Y,!1,!0,!1);Jb[a]={pointerType:T,Pe:va};dc(u,F);return[H,T,va]})},e:function(a,b,c,e,f,k,l){var m=tc(c,e);b=P(b);k=mc(f,k);tb([],[a],function(q){function w(){rc(`Cannot call ${y} due to unbound types`,m)}q=q[0];var y=`${q.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);var B=q.Fd.constructor;void 0===B[b]?(w.Xd=c-1,B[b]=w):(Ub(B,b,y),B[b].Id[c-1]=w);tb([],m,function(D){D=[D[0],null].concat(D.slice(1));D=sc(y,D,null,k,l);void 0===B[b].Id?(D.Xd=c-1,B[b]=D):B[b].Id[c-1]=D;if(q.Fd.fe)for(const u of q.Fd.fe)u.constructor.hasOwnProperty(b)||
(u.constructor[b]=D);return[]});return[]})},B:function(a,b,c,e,f,k){var l=tc(b,c);f=mc(e,f);tb([],[a],function(m){m=m[0];var q=`constructor ${m.name}`;void 0===m.Fd.Sd&&(m.Fd.Sd=[]);if(void 0!==m.Fd.Sd[b-1])throw new xb(`Cannot register multiple constructors with identical number of parameters (${b-1}) for class '${m.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);m.Fd.Sd[b-1]=()=>{rc(`Cannot construct ${m.name} due to unbound types`,l)};
tb([],l,function(w){w.splice(1,0,null);m.Fd.Sd[b-1]=sc(q,w,null,f,k);return[]});return[]})},a:function(a,b,c,e,f,k,l,m){var q=tc(c,e);b=P(b);k=mc(f,k);tb([],[a],function(w){function y(){rc(`Cannot call ${B} due to unbound types`,q)}w=w[0];var B=`${w.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);m&&w.Fd.df.push(b);var D=w.Fd.$d,u=D[b];void 0===u||void 0===u.Id&&u.className!==w.name&&u.Xd===c-2?(y.Xd=c-2,y.className=w.name,D[b]=y):(Ub(D,b,B),D[b].Id[c-2]=y);tb([],q,function(F){F=sc(B,F,
w,k,l);void 0===D[b].Id?(F.Xd=c-2,D[b]=F):D[b].Id[c-2]=F;return[]});return[]})},s:function(a,b,c){a=P(a);tb([],[b],function(e){e=e[0];r[a]=e.fromWireType(c);return[]})},Rc:function(a,b){b=P(b);ub(a,{name:b,fromWireType:function(c){var e=xc(c);wc(c);return e},toWireType:function(c,e){return ac(e)},argPackAdvance:8,readValueFromPointer:nb,Md:null})},i:function(a,b,c,e){function f(){}c=vb(c);b=P(b);f.values={};ub(a,{name:b,constructor:f,fromWireType:function(k){return this.constructor.values[k]},toWireType:function(k,
l){return l.value},argPackAdvance:8,readValueFromPointer:yc(b,c,e),Md:null});Vb(b,f)},b:function(a,b,c){var e=zc(a,"enum");b=P(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Tb(`${e.name}_${b}`,function(){})}});a.values[c]=e;a[b]=e},X:function(a,b,c){c=vb(c);b=P(b);ub(a,{name:b,fromWireType:function(e){return e},toWireType:function(e,f){return f},argPackAdvance:8,readValueFromPointer:Ac(b,c),Md:null})},v:function(a,b,c,e,f,k){var l=tc(b,c);a=P(a);f=
mc(e,f);Vb(a,function(){rc(`Cannot call ${a} due to unbound types`,l)},b-1);tb([],l,function(m){m=[m[0],null].concat(m.slice(1));dc(a,sc(a,m,null,f,k),b-1);return[]})},E:function(a,b,c,e,f){b=P(b);-1===f&&(f=4294967295);f=vb(c);var k=m=>m;if(0===e){var l=32-8*c;k=m=>m<<l>>>l}c=b.includes("unsigned")?function(m,q){return q>>>0}:function(m,q){return q};ub(a,{name:b,fromWireType:k,toWireType:c,argPackAdvance:8,readValueFromPointer:Bc(b,f,0!==e),Md:null})},r:function(a,b,c){function e(k){k>>=2;var l=
L;return new f(l.buffer,l[k+1],l[k])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=P(c);ub(a,{name:c,fromWireType:e,argPackAdvance:8,readValueFromPointer:e},{$e:!0})},o:function(a,b,c,e,f,k,l,m,q,w,y,B){c=P(c);k=mc(f,k);m=mc(l,m);w=mc(q,w);B=mc(y,B);tb([a],[b],function(D){D=D[0];return[new cc(c,D.Fd,!1,!1,!0,D,e,k,m,w,B)]})},W:function(a,b){b=P(b);var c="std::string"===b;ub(a,{name:b,fromWireType:function(e){var f=L[e>>2],k=e+4;if(c)for(var l=
k,m=0;m<=f;++m){var q=k+m;if(m==f||0==C[q]){l=l?kb(C,l,q-l):"";if(void 0===w)var w=l;else w+=String.fromCharCode(0),w+=l;l=q+1}}else{w=Array(f);for(m=0;m<f;++m)w[m]=String.fromCharCode(C[k+m]);w=w.join("")}qc(e);return w},toWireType:function(e,f){f instanceof ArrayBuffer&&(f=new Uint8Array(f));var k="string"==typeof f;k||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array||Q("Cannot pass non-string to std::string");var l=c&&k?ja(f):f.length;var m=wd(4+l+1),q=m+4;L[m>>2]=
l;if(c&&k)ka(f,C,q,l+1);else if(k)for(k=0;k<l;++k){var w=f.charCodeAt(k);255<w&&(qc(q),Q("String has UTF-16 code units that do not fit in 8 bits"));C[q+k]=w}else for(k=0;k<l;++k)C[q+k]=f[k];null!==e&&e.push(qc,m);return m},argPackAdvance:8,readValueFromPointer:nb,Md:function(e){qc(e)}})},O:function(a,b,c){c=P(c);if(2===b){var e=Dc;var f=Ec;var k=Fc;var l=()=>Ja;var m=1}else 4===b&&(e=Gc,f=Hc,k=Ic,l=()=>L,m=2);ub(a,{name:c,fromWireType:function(q){for(var w=L[q>>2],y=l(),B,D=q+4,u=0;u<=w;++u){var F=
q+4+u*b;if(u==w||0==y[F>>m])D=e(D,F-D),void 0===B?B=D:(B+=String.fromCharCode(0),B+=D),D=F+b}qc(q);return B},toWireType:function(q,w){"string"!=typeof w&&Q(`Cannot pass non-string to C++ string type ${c}`);var y=k(w),B=wd(4+y+b);L[B>>2]=y>>m;f(w,B+4,y+b);null!==q&&q.push(qc,B);return B},argPackAdvance:8,readValueFromPointer:nb,Md:function(q){qc(q)}})},C:function(a,b,c,e,f,k){lb[a]={name:P(b),ve:mc(c,e),Rd:mc(f,k),Be:[]}},d:function(a,b,c,e,f,k,l,m,q,w){lb[a].Be.push({Ue:P(b),Ze:c,Xe:mc(e,f),Ye:k,
gf:l,ff:mc(m,q),hf:w})},Qc:function(a,b){b=P(b);ub(a,{bf:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},Pc:()=>!0,Oc:()=>{throw Infinity;},G:function(a,b,c){a=xc(a);b=zc(b,"emval::as");var e=[],f=ac(e);L[c>>2]=f;return b.toWireType(e,a)},N:function(a,b,c,e,f){a=Lc[a];b=xc(b);c=Kc(c);var k=[];L[e>>2]=ac(k);return a(b,c,k,f)},t:function(a,b,c,e){a=Lc[a];b=xc(b);c=Kc(c);a(b,c,null,e)},c:wc,M:function(a){if(0===a)return ac(Mc());a=Kc(a);return ac(Mc()[a])},p:function(a,
b){var c=Oc(a,b),e=c[0];b=e.name+"_$"+c.slice(1).map(function(l){return l.name}).join("_")+"$";var f=Pc[b];if(void 0!==f)return f;var k=Array(a-1);f=Nc((l,m,q,w)=>{for(var y=0,B=0;B<a-1;++B)k[B]=c[B+1].readValueFromPointer(w+y),y+=c[B+1].argPackAdvance;l=l[m].apply(l,k);for(B=0;B<a-1;++B)c[B+1].Re&&c[B+1].Re(k[B]);if(!e.bf)return e.toWireType(q,l)});return Pc[b]=f},A:function(a,b){a=xc(a);b=xc(b);return ac(a[b])},m:function(a){4<a&&(vc.get(a).Fe+=1)},L:function(a,b,c,e){a=xc(a);var f=Rc[b];f||(f=
Qc(b),Rc[b]=f);return f(a,c,e)},I:function(){return ac([])},f:function(a){return ac(Kc(a))},F:function(){return ac({})},Nc:function(a){a=xc(a);return!a},z:function(a){var b=xc(a);mb(b);wc(a)},h:function(a,b,c){a=xc(a);b=xc(b);c=xc(c);a[b]=c},g:function(a,b){a=zc(a,"_emval_take_value");a=a.readValueFromPointer(b);return ac(a)},da:function(){return-52},ca:function(){},k:()=>{Ea("")},Mc:()=>performance.now(),Lc:a=>{var b=C.length;a>>>=0;if(2147483648<a)return!1;for(var c=1;4>=c;c*=2){var e=b*(1+.2/c);
e=Math.min(e,a+100663296);var f=Math;e=Math.max(a,e);a:{f=f.min.call(f,2147483648,e+(65536-e%65536)%65536)-Fa.buffer.byteLength+65535>>>16;try{Fa.grow(f);La();var k=1;break a}catch(l){}k=void 0}if(k)return!0}return!1},Kc:function(){return x?x.handle:0},Vc:(a,b)=>{var c=0;nd().forEach(function(e,f){var k=b+c;f=L[a+4*f>>2]=k;for(k=0;k<e.length;++k)Ha[f++>>0]=e.charCodeAt(k);Ha[f>>0]=0;c+=e.length+1});return 0},Uc:(a,b)=>{var c=nd();L[a>>2]=c.length;var e=0;c.forEach(function(f){e+=f.length+1});L[b>>
2]=e;return 0},Jc:a=>{if(!noExitRuntime){if(r.onExit)r.onExit(a);Ga=!0}oa(a,new db(a))},Z:()=>52,ga:function(){return 52},Tc:()=>52,fa:function(){return 70},Y:(a,b,c,e)=>{for(var f=0,k=0;k<c;k++){var l=L[b>>2],m=L[b+4>>2];b+=8;for(var q=0;q<m;q++){var w=C[l+q],y=od[a];0===w||10===w?((1===a?Aa:Ca)(kb(y,0)),y.length=0):y.push(w)}f+=m}L[e>>2]=f;return 0},Ic:function(a){S.activeTexture(a)},Hc:function(a,b){S.attachShader(Xc[a],$c[b])},Gc:function(a,b,c){S.bindAttribLocation(Xc[a],b,c?kb(C,c):"")},Fc:function(a,
b){35051==a?S.se=b:35052==a&&(S.Yd=b);S.bindBuffer(a,Wc[b])},V:function(a,b){S.bindFramebuffer(a,Yc[b])},Ec:function(a,b){S.bindRenderbuffer(a,Zc[b])},Dc:function(a,b){S.bindSampler(a,bd[b])},Cc:function(a,b){S.bindTexture(a,ea[b])},Bc:pd,Ac:pd,zc:function(a,b,c,e){S.blendColor(a,b,c,e)},yc:function(a){S.blendEquation(a)},xc:function(a,b){S.blendFunc(a,b)},wc:function(a,b,c,e,f,k,l,m,q,w){S.blitFramebuffer(a,b,c,e,f,k,l,m,q,w)},vc:function(a,b,c,e){2<=x.version?c&&b?S.bufferData(a,C,e,c,b):S.bufferData(a,
b,e):S.bufferData(a,c?C.subarray(c,c+b):b,e)},uc:function(a,b,c,e){2<=x.version?c&&S.bufferSubData(a,b,C,e,c):S.bufferSubData(a,b,C.subarray(e,e+c))},tc:function(a){return S.checkFramebufferStatus(a)},U:function(a){S.clear(a)},T:function(a,b,c,e){S.clearColor(a,b,c,e)},S:function(a){S.clearStencil(a)},ba:function(a,b,c,e){return S.clientWaitSync(cd[a],b,(c>>>0)+4294967296*e)},sc:function(a,b,c,e){S.colorMask(!!a,!!b,!!c,!!e)},rc:function(a){S.compileShader($c[a])},qc:function(a,b,c,e,f,k,l,m){2<=
x.version?S.Yd||!l?S.compressedTexImage2D(a,b,c,e,f,k,l,m):S.compressedTexImage2D(a,b,c,e,f,k,C,m,l):S.compressedTexImage2D(a,b,c,e,f,k,m?C.subarray(m,m+l):null)},pc:function(a,b,c,e,f,k,l,m,q){2<=x.version?S.Yd||!m?S.compressedTexSubImage2D(a,b,c,e,f,k,l,m,q):S.compressedTexSubImage2D(a,b,c,e,f,k,l,C,q,m):S.compressedTexSubImage2D(a,b,c,e,f,k,l,q?C.subarray(q,q+m):null)},oc:function(a,b,c,e,f){S.copyBufferSubData(a,b,c,e,f)},nc:function(a,b,c,e,f,k,l,m){S.copyTexSubImage2D(a,b,c,e,f,k,l,m)},mc:function(){var a=
da(Xc),b=S.createProgram();b.name=a;b.me=b.ke=b.le=0;b.xe=1;Xc[a]=b;return a},lc:function(a){var b=da($c);$c[b]=S.createShader(a);return b},kc:function(a){S.cullFace(a)},jc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=Wc[e];f&&(S.deleteBuffer(f),f.name=0,Wc[e]=null,e==S.se&&(S.se=0),e==S.Yd&&(S.Yd=0))}},ic:function(a,b){for(var c=0;c<a;++c){var e=K[b+4*c>>2],f=Yc[e];f&&(S.deleteFramebuffer(f),f.name=0,Yc[e]=null)}},hc:function(a){if(a){var b=Xc[a];b?(S.deleteProgram(b),b.name=0,Xc[a]=null):
R(1281)}},gc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=Zc[e];f&&(S.deleteRenderbuffer(f),f.name=0,Zc[e]=null)}},fc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=bd[e];f&&(S.deleteSampler(f),f.name=0,bd[e]=null)}},ec:function(a){if(a){var b=$c[a];b?(S.deleteShader(b),$c[a]=null):R(1281)}},dc:function(a){if(a){var b=cd[a];b?(S.deleteSync(b),b.name=0,cd[a]=null):R(1281)}},cc:function(a,b){for(var c=0;c<a;c++){var e=K[b+4*c>>2],f=ea[e];f&&(S.deleteTexture(f),f.name=0,ea[e]=null)}},
bc:qd,ac:qd,$b:function(a){S.depthMask(!!a)},_b:function(a){S.disable(a)},Zb:function(a){S.disableVertexAttribArray(a)},Yb:function(a,b,c){S.drawArrays(a,b,c)},Xb:function(a,b,c,e){S.drawArraysInstanced(a,b,c,e)},Wb:function(a,b,c,e,f){S.ze.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},Vb:function(a,b){for(var c=rd[a],e=0;e<a;e++)c[e]=K[b+4*e>>2];S.drawBuffers(c)},Ub:sd,Tb:function(a,b,c,e,f){S.drawElementsInstanced(a,b,c,e,f)},Sb:function(a,b,c,e,f,k,l){S.ze.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,
b,c,e,f,k,l)},Rb:function(a,b,c,e,f,k){sd(a,e,f,k)},Qb:function(a){S.enable(a)},Pb:function(a){S.enableVertexAttribArray(a)},Ob:function(a,b){return(a=S.fenceSync(a,b))?(b=da(cd),a.name=b,cd[b]=a,b):0},Nb:function(){S.finish()},Mb:function(){S.flush()},Lb:function(a,b,c,e){S.framebufferRenderbuffer(a,b,c,Zc[e])},Kb:function(a,b,c,e,f){S.framebufferTexture2D(a,b,c,ea[e],f)},Jb:function(a){S.frontFace(a)},Ib:function(a,b){td(a,b,"createBuffer",Wc)},Hb:function(a,b){td(a,b,"createFramebuffer",Yc)},Gb:function(a,
b){td(a,b,"createRenderbuffer",Zc)},Fb:function(a,b){td(a,b,"createSampler",bd)},Eb:function(a,b){td(a,b,"createTexture",ea)},Db:ud,Cb:ud,Bb:function(a){S.generateMipmap(a)},Ab:function(a,b,c){c?K[c>>2]=S.getBufferParameter(a,b):R(1281)},zb:function(){var a=S.getError()||hd;hd=0;return a},yb:function(a,b){vd(a,b,2)},xb:function(a,b,c,e){a=S.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;K[e>>2]=a},K:function(a,b){vd(a,b,0)},wb:function(a,
b,c,e){a=S.getProgramInfoLog(Xc[a]);null===a&&(a="(unknown error)");b=0<b&&e?ka(a,C,e,b):0;c&&(K[c>>2]=b)},vb:function(a,b,c){if(c)if(a>=Vc)R(1281);else if(a=Xc[a],35716==b)a=S.getProgramInfoLog(a),null===a&&(a="(unknown error)"),K[c>>2]=a.length+1;else if(35719==b){if(!a.me)for(b=0;b<S.getProgramParameter(a,35718);++b)a.me=Math.max(a.me,S.getActiveUniform(a,b).name.length+1);K[c>>2]=a.me}else if(35722==b){if(!a.ke)for(b=0;b<S.getProgramParameter(a,35721);++b)a.ke=Math.max(a.ke,S.getActiveAttrib(a,
b).name.length+1);K[c>>2]=a.ke}else if(35381==b){if(!a.le)for(b=0;b<S.getProgramParameter(a,35382);++b)a.le=Math.max(a.le,S.getActiveUniformBlockName(a,b).length+1);K[c>>2]=a.le}else K[c>>2]=S.getProgramParameter(a,b);else R(1281)},ub:function(a,b,c){c?K[c>>2]=S.getRenderbufferParameter(a,b):R(1281)},tb:function(a,b,c,e){a=S.getShaderInfoLog($c[a]);null===a&&(a="(unknown error)");b=0<b&&e?ka(a,C,e,b):0;c&&(K[c>>2]=b)},sb:function(a,b,c,e){a=S.getShaderPrecisionFormat(a,b);K[c>>2]=a.rangeMin;K[c+4>>
2]=a.rangeMax;K[e>>2]=a.precision},rb:function(a,b,c){c?35716==b?(a=S.getShaderInfoLog($c[a]),null===a&&(a="(unknown error)"),K[c>>2]=a?a.length+1:0):35720==b?(a=S.getShaderSource($c[a]),K[c>>2]=a?a.length+1:0):K[c>>2]=S.getShaderParameter($c[a],b):R(1281)},R:function(a){var b=dd[a];if(!b){switch(a){case 7939:b=S.getSupportedExtensions()||[];b=b.concat(b.map(function(e){return"GL_"+e}));b=xd(b.join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=S.getParameter(a))||R(1280);b=b&&xd(b);break;
case 7938:b=S.getParameter(7938);b=2<=x.version?"OpenGL ES 3.0 ("+b+")":"OpenGL ES 2.0 ("+b+")";b=xd(b);break;case 35724:b=S.getParameter(35724);var c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b="OpenGL ES GLSL ES "+c[1]+" ("+b+")");b=xd(b);break;default:R(1280)}dd[a]=b}return b},qb:function(a,b){if(2>x.version)return R(1282),0;var c=ed[a];if(c)return 0>b||b>=c.length?(R(1281),0):c[b];switch(a){case 7939:return c=S.getSupportedExtensions()||[],
c=c.concat(c.map(function(e){return"GL_"+e})),c=c.map(function(e){return xd(e)}),c=ed[a]=c,0>b||b>=c.length?(R(1281),0):c[b];default:return R(1280),0}},pb:function(a,b){b=b?kb(C,b):"";if(a=Xc[a]){var c=a,e=c.de,f=c.He,k;if(!e)for(c.de=e={},c.Ge={},k=0;k<S.getProgramParameter(c,35718);++k){var l=S.getActiveUniform(c,k);var m=l.name;l=l.size;var q=yd(m);q=0<q?m.slice(0,q):m;var w=c.xe;c.xe+=l;f[q]=[l,w];for(m=0;m<l;++m)e[w]=m,c.Ge[w++]=q}c=a.de;e=0;f=b;k=yd(b);0<k&&(e=parseInt(b.slice(k+1))>>>0,f=b.slice(0,
k));if((f=a.He[f])&&e<f[0]&&(e+=f[1],c[e]=c[e]||S.getUniformLocation(a,b)))return e}else R(1281);return-1},ob:function(a,b,c){for(var e=rd[b],f=0;f<b;f++)e[f]=K[c+4*f>>2];S.invalidateFramebuffer(a,e)},nb:function(a,b,c,e,f,k,l){for(var m=rd[b],q=0;q<b;q++)m[q]=K[c+4*q>>2];S.invalidateSubFramebuffer(a,m,e,f,k,l)},mb:function(a){return S.isSync(cd[a])},lb:function(a){return(a=ea[a])?S.isTexture(a):0},kb:function(a){S.lineWidth(a)},jb:function(a){a=Xc[a];S.linkProgram(a);a.de=0;a.He={}},ib:function(a,
b,c,e,f,k){S.De.multiDrawArraysInstancedBaseInstanceWEBGL(a,K,b>>2,K,c>>2,K,e>>2,L,f>>2,k)},hb:function(a,b,c,e,f,k,l,m){S.De.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,K,b>>2,c,K,e>>2,K,f>>2,K,k>>2,L,l>>2,m)},gb:function(a,b){3317==a&&(gd=b);S.pixelStorei(a,b)},fb:function(a){S.readBuffer(a)},eb:function(a,b,c,e,f,k,l){if(2<=x.version)if(S.se)S.readPixels(a,b,c,e,f,k,l);else{var m=zd(k);S.readPixels(a,b,c,e,f,k,m,l>>31-Math.clz32(m.BYTES_PER_ELEMENT))}else(l=Ad(k,f,c,e,l))?S.readPixels(a,
b,c,e,f,k,l):R(1280)},db:function(a,b,c,e){S.renderbufferStorage(a,b,c,e)},cb:function(a,b,c,e,f){S.renderbufferStorageMultisample(a,b,c,e,f)},bb:function(a,b,c){S.samplerParameterf(bd[a],b,c)},ab:function(a,b,c){S.samplerParameteri(bd[a],b,c)},$a:function(a,b,c){S.samplerParameteri(bd[a],b,K[c>>2])},_a:function(a,b,c,e){S.scissor(a,b,c,e)},Za:function(a,b,c,e){for(var f="",k=0;k<b;++k){var l=e?K[e+4*k>>2]:-1,m=K[c+4*k>>2];l=m?kb(C,m,0>l?void 0:l):"";f+=l}S.shaderSource($c[a],f)},Ya:function(a,b,
c){S.stencilFunc(a,b,c)},Xa:function(a,b,c,e){S.stencilFuncSeparate(a,b,c,e)},Wa:function(a){S.stencilMask(a)},Va:function(a,b){S.stencilMaskSeparate(a,b)},Ua:function(a,b,c){S.stencilOp(a,b,c)},Ta:function(a,b,c,e){S.stencilOpSeparate(a,b,c,e)},Sa:function(a,b,c,e,f,k,l,m,q){if(2<=x.version)if(S.Yd)S.texImage2D(a,b,c,e,f,k,l,m,q);else if(q){var w=zd(m);S.texImage2D(a,b,c,e,f,k,l,m,w,q>>31-Math.clz32(w.BYTES_PER_ELEMENT))}else S.texImage2D(a,b,c,e,f,k,l,m,null);else S.texImage2D(a,b,c,e,f,k,l,m,q?
Ad(m,l,e,f,q):null)},Ra:function(a,b,c){S.texParameterf(a,b,c)},Qa:function(a,b,c){S.texParameterf(a,b,N[c>>2])},Pa:function(a,b,c){S.texParameteri(a,b,c)},Oa:function(a,b,c){S.texParameteri(a,b,K[c>>2])},Na:function(a,b,c,e,f){S.texStorage2D(a,b,c,e,f)},Ma:function(a,b,c,e,f,k,l,m,q){if(2<=x.version)if(S.Yd)S.texSubImage2D(a,b,c,e,f,k,l,m,q);else if(q){var w=zd(m);S.texSubImage2D(a,b,c,e,f,k,l,m,w,q>>31-Math.clz32(w.BYTES_PER_ELEMENT))}else S.texSubImage2D(a,b,c,e,f,k,l,m,null);else w=null,q&&(w=
Ad(m,l,f,k,q)),S.texSubImage2D(a,b,c,e,f,k,l,m,w)},La:function(a,b){S.uniform1f(W(a),b)},Ka:function(a,b,c){if(2<=x.version)b&&S.uniform1fv(W(a),N,c>>2,b);else{if(288>=b)for(var e=Bd[b-1],f=0;f<b;++f)e[f]=N[c+4*f>>2];else e=N.subarray(c>>2,c+4*b>>2);S.uniform1fv(W(a),e)}},Ja:function(a,b){S.uniform1i(W(a),b)},Ia:function(a,b,c){if(2<=x.version)b&&S.uniform1iv(W(a),K,c>>2,b);else{if(288>=b)for(var e=Cd[b-1],f=0;f<b;++f)e[f]=K[c+4*f>>2];else e=K.subarray(c>>2,c+4*b>>2);S.uniform1iv(W(a),e)}},Ha:function(a,
b,c){S.uniform2f(W(a),b,c)},Ga:function(a,b,c){if(2<=x.version)b&&S.uniform2fv(W(a),N,c>>2,2*b);else{if(144>=b)for(var e=Bd[2*b-1],f=0;f<2*b;f+=2)e[f]=N[c+4*f>>2],e[f+1]=N[c+(4*f+4)>>2];else e=N.subarray(c>>2,c+8*b>>2);S.uniform2fv(W(a),e)}},Fa:function(a,b,c){S.uniform2i(W(a),b,c)},Ea:function(a,b,c){if(2<=x.version)b&&S.uniform2iv(W(a),K,c>>2,2*b);else{if(144>=b)for(var e=Cd[2*b-1],f=0;f<2*b;f+=2)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2];else e=K.subarray(c>>2,c+8*b>>2);S.uniform2iv(W(a),e)}},Da:function(a,
b,c,e){S.uniform3f(W(a),b,c,e)},Ca:function(a,b,c){if(2<=x.version)b&&S.uniform3fv(W(a),N,c>>2,3*b);else{if(96>=b)for(var e=Bd[3*b-1],f=0;f<3*b;f+=3)e[f]=N[c+4*f>>2],e[f+1]=N[c+(4*f+4)>>2],e[f+2]=N[c+(4*f+8)>>2];else e=N.subarray(c>>2,c+12*b>>2);S.uniform3fv(W(a),e)}},Ba:function(a,b,c,e){S.uniform3i(W(a),b,c,e)},Aa:function(a,b,c){if(2<=x.version)b&&S.uniform3iv(W(a),K,c>>2,3*b);else{if(96>=b)for(var e=Cd[3*b-1],f=0;f<3*b;f+=3)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2],e[f+2]=K[c+(4*f+8)>>2];else e=
K.subarray(c>>2,c+12*b>>2);S.uniform3iv(W(a),e)}},za:function(a,b,c,e,f){S.uniform4f(W(a),b,c,e,f)},ya:function(a,b,c){if(2<=x.version)b&&S.uniform4fv(W(a),N,c>>2,4*b);else{if(72>=b){var e=Bd[4*b-1],f=N;c>>=2;for(var k=0;k<4*b;k+=4){var l=c+k;e[k]=f[l];e[k+1]=f[l+1];e[k+2]=f[l+2];e[k+3]=f[l+3]}}else e=N.subarray(c>>2,c+16*b>>2);S.uniform4fv(W(a),e)}},xa:function(a,b,c,e,f){S.uniform4i(W(a),b,c,e,f)},wa:function(a,b,c){if(2<=x.version)b&&S.uniform4iv(W(a),K,c>>2,4*b);else{if(72>=b)for(var e=Cd[4*b-
1],f=0;f<4*b;f+=4)e[f]=K[c+4*f>>2],e[f+1]=K[c+(4*f+4)>>2],e[f+2]=K[c+(4*f+8)>>2],e[f+3]=K[c+(4*f+12)>>2];else e=K.subarray(c>>2,c+16*b>>2);S.uniform4iv(W(a),e)}},va:function(a,b,c,e){if(2<=x.version)b&&S.uniformMatrix2fv(W(a),!!c,N,e>>2,4*b);else{if(72>=b)for(var f=Bd[4*b-1],k=0;k<4*b;k+=4)f[k]=N[e+4*k>>2],f[k+1]=N[e+(4*k+4)>>2],f[k+2]=N[e+(4*k+8)>>2],f[k+3]=N[e+(4*k+12)>>2];else f=N.subarray(e>>2,e+16*b>>2);S.uniformMatrix2fv(W(a),!!c,f)}},ua:function(a,b,c,e){if(2<=x.version)b&&S.uniformMatrix3fv(W(a),
!!c,N,e>>2,9*b);else{if(32>=b)for(var f=Bd[9*b-1],k=0;k<9*b;k+=9)f[k]=N[e+4*k>>2],f[k+1]=N[e+(4*k+4)>>2],f[k+2]=N[e+(4*k+8)>>2],f[k+3]=N[e+(4*k+12)>>2],f[k+4]=N[e+(4*k+16)>>2],f[k+5]=N[e+(4*k+20)>>2],f[k+6]=N[e+(4*k+24)>>2],f[k+7]=N[e+(4*k+28)>>2],f[k+8]=N[e+(4*k+32)>>2];else f=N.subarray(e>>2,e+36*b>>2);S.uniformMatrix3fv(W(a),!!c,f)}},ta:function(a,b,c,e){if(2<=x.version)b&&S.uniformMatrix4fv(W(a),!!c,N,e>>2,16*b);else{if(18>=b){var f=Bd[16*b-1],k=N;e>>=2;for(var l=0;l<16*b;l+=16){var m=e+l;f[l]=
k[m];f[l+1]=k[m+1];f[l+2]=k[m+2];f[l+3]=k[m+3];f[l+4]=k[m+4];f[l+5]=k[m+5];f[l+6]=k[m+6];f[l+7]=k[m+7];f[l+8]=k[m+8];f[l+9]=k[m+9];f[l+10]=k[m+10];f[l+11]=k[m+11];f[l+12]=k[m+12];f[l+13]=k[m+13];f[l+14]=k[m+14];f[l+15]=k[m+15]}}else f=N.subarray(e>>2,e+64*b>>2);S.uniformMatrix4fv(W(a),!!c,f)}},sa:function(a){a=Xc[a];S.useProgram(a);S.Qe=a},ra:function(a,b){S.vertexAttrib1f(a,b)},qa:function(a,b){S.vertexAttrib2f(a,N[b>>2],N[b+4>>2])},pa:function(a,b){S.vertexAttrib3f(a,N[b>>2],N[b+4>>2],N[b+8>>2])},
oa:function(a,b){S.vertexAttrib4f(a,N[b>>2],N[b+4>>2],N[b+8>>2],N[b+12>>2])},na:function(a,b){S.vertexAttribDivisor(a,b)},ma:function(a,b,c,e,f){S.vertexAttribIPointer(a,b,c,e,f)},la:function(a,b,c,e,f,k){S.vertexAttribPointer(a,b,c,!!e,f,k)},ka:function(a,b,c,e){S.viewport(a,b,c,e)},aa:function(a,b,c,e){S.waitSync(cd[a],b,(c>>>0)+4294967296*e)},n:Nd,u:Od,j:Pd,J:Qd,Q:Rd,P:Sd,x:Td,y:Ud,q:Vd,w:Wd,ja:Xd,ia:Yd,ha:Zd,$:(a,b,c,e)=>Hd(a,b,c,e)};
(function(){function a(c){G=c=c.exports;Fa=G.$c;La();Ma=G.cd;Pa.unshift(G.ad);Ua--;r.monitorRunDependencies&&r.monitorRunDependencies(Ua);if(0==Ua&&(null!==Va&&(clearInterval(Va),Va=null),Wa)){var e=Wa;Wa=null;e()}return c}var b={a:$d};Ua++;r.monitorRunDependencies&&r.monitorRunDependencies(Ua);if(r.instantiateWasm)try{return r.instantiateWasm(b,a)}catch(c){Ca("Module.instantiateWasm callback failed with error: "+c),ba(c)}cb(b,function(c){a(c.instance)}).catch(ba);return{}})();
var wd=r._malloc=a=>(wd=r._malloc=G.bd)(a),qc=r._free=a=>(qc=r._free=G.dd)(a),pc=a=>(pc=G.ed)(a);r.__embind_initialize_bindings=()=>(r.__embind_initialize_bindings=G.fd)();var ae=(a,b)=>(ae=G.gd)(a,b),be=()=>(be=G.hd)(),ce=a=>(ce=G.id)(a);r.dynCall_viji=(a,b,c,e,f)=>(r.dynCall_viji=G.kd)(a,b,c,e,f);r.dynCall_vijiii=(a,b,c,e,f,k,l)=>(r.dynCall_vijiii=G.ld)(a,b,c,e,f,k,l);r.dynCall_viiiiij=(a,b,c,e,f,k,l,m)=>(r.dynCall_viiiiij=G.md)(a,b,c,e,f,k,l,m);r.dynCall_jii=(a,b,c)=>(r.dynCall_jii=G.nd)(a,b,c);
r.dynCall_vij=(a,b,c,e)=>(r.dynCall_vij=G.od)(a,b,c,e);r.dynCall_iiij=(a,b,c,e,f)=>(r.dynCall_iiij=G.pd)(a,b,c,e,f);r.dynCall_iiiij=(a,b,c,e,f,k)=>(r.dynCall_iiiij=G.qd)(a,b,c,e,f,k);r.dynCall_viij=(a,b,c,e,f)=>(r.dynCall_viij=G.rd)(a,b,c,e,f);r.dynCall_viiij=(a,b,c,e,f,k)=>(r.dynCall_viiij=G.sd)(a,b,c,e,f,k);r.dynCall_jiiiiii=(a,b,c,e,f,k,l)=>(r.dynCall_jiiiiii=G.td)(a,b,c,e,f,k,l);r.dynCall_jiiiiji=(a,b,c,e,f,k,l,m)=>(r.dynCall_jiiiiji=G.ud)(a,b,c,e,f,k,l,m);
r.dynCall_ji=(a,b)=>(r.dynCall_ji=G.vd)(a,b);r.dynCall_iijj=(a,b,c,e,f,k)=>(r.dynCall_iijj=G.wd)(a,b,c,e,f,k);r.dynCall_jiji=(a,b,c,e,f)=>(r.dynCall_jiji=G.xd)(a,b,c,e,f);r.dynCall_viijii=(a,b,c,e,f,k,l)=>(r.dynCall_viijii=G.yd)(a,b,c,e,f,k,l);r.dynCall_iiiiij=(a,b,c,e,f,k,l)=>(r.dynCall_iiiiij=G.zd)(a,b,c,e,f,k,l);r.dynCall_iiiiijj=(a,b,c,e,f,k,l,m,q)=>(r.dynCall_iiiiijj=G.Ad)(a,b,c,e,f,k,l,m,q);r.dynCall_iiiiiijj=(a,b,c,e,f,k,l,m,q,w)=>(r.dynCall_iiiiiijj=G.Bd)(a,b,c,e,f,k,l,m,q,w);
function Wd(a,b,c,e,f){var k=be();try{Ma.get(a)(b,c,e,f)}catch(l){ce(k);if(l!==l+0)throw l;ae(1,0)}}function Od(a,b,c){var e=be();try{return Ma.get(a)(b,c)}catch(f){ce(e);if(f!==f+0)throw f;ae(1,0)}}function Ud(a,b,c){var e=be();try{Ma.get(a)(b,c)}catch(f){ce(e);if(f!==f+0)throw f;ae(1,0)}}function Nd(a,b){var c=be();try{return Ma.get(a)(b)}catch(e){ce(c);if(e!==e+0)throw e;ae(1,0)}}function Td(a,b){var c=be();try{Ma.get(a)(b)}catch(e){ce(c);if(e!==e+0)throw e;ae(1,0)}}
function Pd(a,b,c,e){var f=be();try{return Ma.get(a)(b,c,e)}catch(k){ce(f);if(k!==k+0)throw k;ae(1,0)}}function Zd(a,b,c,e,f,k,l,m,q,w){var y=be();try{Ma.get(a)(b,c,e,f,k,l,m,q,w)}catch(B){ce(y);if(B!==B+0)throw B;ae(1,0)}}function Vd(a,b,c,e){var f=be();try{Ma.get(a)(b,c,e)}catch(k){ce(f);if(k!==k+0)throw k;ae(1,0)}}function Yd(a,b,c,e,f,k,l){var m=be();try{Ma.get(a)(b,c,e,f,k,l)}catch(q){ce(m);if(q!==q+0)throw q;ae(1,0)}}
function Qd(a,b,c,e,f){var k=be();try{return Ma.get(a)(b,c,e,f)}catch(l){ce(k);if(l!==l+0)throw l;ae(1,0)}}function Rd(a,b,c,e,f,k,l){var m=be();try{return Ma.get(a)(b,c,e,f,k,l)}catch(q){ce(m);if(q!==q+0)throw q;ae(1,0)}}function Xd(a,b,c,e,f,k){var l=be();try{Ma.get(a)(b,c,e,f,k)}catch(m){ce(l);if(m!==m+0)throw m;ae(1,0)}}function Sd(a,b,c,e,f,k,l,m,q,w){var y=be();try{return Ma.get(a)(b,c,e,f,k,l,m,q,w)}catch(B){ce(y);if(B!==B+0)throw B;ae(1,0)}}var de;Wa=function ee(){de||fe();de||(Wa=ee)};
function fe(){function a(){if(!de&&(de=!0,r.calledRun=!0,!Ga)){eb(Pa);aa(r);if(r.onRuntimeInitialized)r.onRuntimeInitialized();if(r.postRun)for("function"==typeof r.postRun&&(r.postRun=[r.postRun]);r.postRun.length;){var b=r.postRun.shift();Qa.unshift(b)}eb(Qa)}}if(!(0<Ua)){if(r.preRun)for("function"==typeof r.preRun&&(r.preRun=[r.preRun]);r.preRun.length;)Ra();eb(Oa);0<Ua||(r.setStatus?(r.setStatus("Running..."),setTimeout(function(){setTimeout(function(){r.setStatus("")},1);a()},1)):a())}}
if(r.preInit)for("function"==typeof r.preInit&&(r.preInit=[r.preInit]);0<r.preInit.length;)r.preInit.pop()();fe();
return moduleArg.ready
}
);
})();
export default CanvasKitInit;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,169 @@
var skwasm = (() => {
var _scriptDir = import.meta.url;
return (
async function(moduleArg = {}) {
function aa(){d.buffer!=h.buffer&&l();return h}function p(){d.buffer!=h.buffer&&l();return ba}function q(){d.buffer!=h.buffer&&l();return da}function t(){d.buffer!=h.buffer&&l();return ea}function v(){d.buffer!=h.buffer&&l();return fa}function ha(){d.buffer!=h.buffer&&l();return ia}var w=moduleArg,ja,ka;w.ready=new Promise((a,b)=>{ja=a;ka=b});
var la=Object.assign({},w),ma="./this.program",na=(a,b)=>{throw b;},oa="object"==typeof window,pa="function"==typeof importScripts,x="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,A=w.ENVIRONMENT_IS_PTHREAD||!1,C="";function qa(a){return w.locateFile?w.locateFile(a,C):C+a}var ra,sa,ta;
if(x){const {createRequire:a}=await import("module");var require=a(import.meta.url),fs=require("fs"),ua=require("path");pa?C=ua.dirname(C)+"/":C=require("url").fileURLToPath(new URL("./",import.meta.url));ra=(c,e)=>{c=c.startsWith("file://")?new URL(c):ua.normalize(c);return fs.readFileSync(c,e?void 0:"utf8")};ta=c=>{c=ra(c,!0);c.buffer||(c=new Uint8Array(c));return c};sa=(c,e,f,g=!0)=>{c=c.startsWith("file://")?new URL(c):ua.normalize(c);fs.readFile(c,g?void 0:"utf8",
(k,n)=>{k?f(k):e(g?n.buffer:n)})};!w.thisProgram&&1<process.argv.length&&(ma=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);na=(c,e)=>{process.exitCode=c;throw e;};w.inspect=()=>"[Emscripten Module object]";let b;try{b=require("worker_threads")}catch(c){throw console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?'),c;}global.Worker=b.Worker}else if(oa||pa)pa?C=self.location.href:"undefined"!=typeof document&&document.currentScript&&
(C=document.currentScript.src),_scriptDir&&(C=_scriptDir),0!==C.indexOf("blob:")?C=C.substr(0,C.replace(/[?#].*/,"").lastIndexOf("/")+1):C="",x||(ra=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},pa&&(ta=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),sa=(a,b,c)=>{var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?
b(e.response):c()};e.onerror=c;e.send(null)});x&&"undefined"==typeof performance&&(global.performance=require("perf_hooks").performance);var va=console.log.bind(console),wa=console.error.bind(console);x&&(va=(...a)=>fs.writeSync(1,a.join(" ")+"\n"),wa=(...a)=>fs.writeSync(2,a.join(" ")+"\n"));var xa=w.print||va,D=w.printErr||wa;Object.assign(w,la);la=null;w.thisProgram&&(ma=w.thisProgram);w.quit&&(na=w.quit);var ya;w.wasmBinary&&(ya=w.wasmBinary);var noExitRuntime=w.noExitRuntime||!0;
"object"!=typeof WebAssembly&&za("no native wasm support detected");var d,F,Aa,Ba=!1,Ca,h,ba,Da,Ea,da,ea,fa,ia;function l(){var a=d.buffer;w.HEAP8=h=new Int8Array(a);w.HEAP16=Da=new Int16Array(a);w.HEAP32=da=new Int32Array(a);w.HEAPU8=ba=new Uint8Array(a);w.HEAPU16=Ea=new Uint16Array(a);w.HEAPU32=ea=new Uint32Array(a);w.HEAPF32=fa=new Float32Array(a);w.HEAPF64=ia=new Float64Array(a)}var Fa=w.INITIAL_MEMORY||16777216;65536<=Fa||za("INITIAL_MEMORY should be larger than STACK_SIZE, was "+Fa+"! (STACK_SIZE=65536)");
if(A)d=w.wasmMemory;else if(w.wasmMemory)d=w.wasmMemory;else if(d=new WebAssembly.Memory({initial:Fa/65536,maximum:32768,shared:!0}),!(d.buffer instanceof SharedArrayBuffer))throw D("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"),x&&D("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and/or recent version)"),
Error("bad memory");l();Fa=d.buffer.byteLength;var G,Ga=[],Ha=[],Ia=[],Ja=0;function Ka(){return noExitRuntime||0<Ja}var H=0,La=null,Ma=null;function Na(){H++;w.monitorRunDependencies&&w.monitorRunDependencies(H)}function Oa(){H--;w.monitorRunDependencies&&w.monitorRunDependencies(H);if(0==H&&(null!==La&&(clearInterval(La),La=null),Ma)){var a=Ma;Ma=null;a()}}
function za(a){if(w.onAbort)w.onAbort(a);a="Aborted("+a+")";D(a);Ba=!0;Ca=1;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ka(a);throw a;}function Pa(a){return a.startsWith("data:application/octet-stream;base64,")}var I;w.locateFile?(I="skwasm.wasm",Pa(I)||(I=qa(I))):I=(new URL("skwasm.wasm",import.meta.url)).href;function Qa(a){if(a==I&&ya)return new Uint8Array(ya);if(ta)return ta(a);throw"both async and sync fetching of the wasm failed";}
function Ra(a){if(!ya&&(oa||pa)){if("function"==typeof fetch&&!a.startsWith("file://"))return fetch(a,{credentials:"same-origin"}).then(b=>{if(!b.ok)throw"failed to load wasm binary file at '"+a+"'";return b.arrayBuffer()}).catch(()=>Qa(a));if(sa)return new Promise((b,c)=>{sa(a,e=>b(new Uint8Array(e)),c)})}return Promise.resolve().then(()=>Qa(a))}function Sa(a,b,c){return Ra(a).then(e=>WebAssembly.instantiate(e,b)).then(e=>e).then(c,e=>{D("failed to asynchronously prepare wasm: "+e);za(e)})}
function Ta(a,b){var c=I;return ya||"function"!=typeof WebAssembly.instantiateStreaming||Pa(c)||c.startsWith("file://")||x||"function"!=typeof fetch?Sa(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){D("wasm streaming compile failed: "+f);D("falling back to ArrayBuffer instantiation");return Sa(c,a,b)}))}function Ua(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}
function Va(a){a.terminate();a.onmessage=()=>{}}function Wa(a){(a=J.g[a])||za();J.Aa(a)}function Xa(a){var b=J.ma();if(!b)return 6;J.B.push(b);J.g[a.o]=b;b.o=a.o;var c={cmd:"run",start_routine:a.Ba,arg:a.ka,pthread_ptr:a.o};c.H=a.H;c.T=a.T;x&&b.unref();b.postMessage(c,a.Ha);return 0}
var Ya="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,Za=(a,b,c)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16<c-b&&a.buffer&&Ya)return Ya.decode(a.slice(b,c));for(e="";b<c;){var f=a[b++];if(f&128){var g=a[b++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|g);else{var k=a[b++]&63;f=224==(f&240)?(f&15)<<12|g<<6|k:(f&7)<<18|g<<12|k<<6|a[b++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e},
K=(a,b)=>a?Za(p(),a,b):"";function $a(a){if(A)return L(1,1,a);Ca=a;if(!Ka()){J.Ca();if(w.onExit)w.onExit(a);Ba=!0}na(a,new Ua(a))}
var bb=a=>{Ca=a;if(A)throw ab(a),"unwind";$a(a)},J={u:[],B:[],ha:[],g:{},S:function(){A?J.ra():J.qa()},qa:function(){for(var a=1;a--;)J.X();Ga.unshift(()=>{Na();J.ta(()=>Oa())})},ra:function(){J.receiveObjectTransfer=J.za;J.threadInitTLS=J.ga;J.setExitStatus=J.fa;noExitRuntime=!1},fa:function(a){Ca=a},Oa:["$terminateWorker"],Ca:function(){for(var a of J.B)Va(a);for(a of J.u)Va(a);J.u=[];J.B=[];J.g=[]},Aa:function(a){var b=a.o;delete J.g[b];J.u.push(a);J.B.splice(J.B.indexOf(a),1);a.o=0;cb(b)},za:function(a){"undefined"!=
typeof db&&(Object.assign(M,a.T),!w.canvas&&a.H&&M[a.H]&&(w.canvas=M[a.H].I,w.canvas.id=a.H))},ga:function(){J.ha.forEach(a=>a())},ba:a=>new Promise(b=>{a.onmessage=g=>{g=g.data;var k=g.cmd;if(g.targetThread&&g.targetThread!=eb()){var n=J.g[g.Na];n?n.postMessage(g,g.transferList):D('Internal error! Worker sent a message "'+k+'" to target pthread '+g.targetThread+", but that thread no longer exists!")}else if("checkMailbox"===k)fb();else if("spawnThread"===k)Xa(g);else if("cleanupThread"===k)Wa(g.thread);
else if("killThread"===k)g=g.thread,k=J.g[g],delete J.g[g],Va(k),cb(g),J.B.splice(J.B.indexOf(k),1),k.o=0;else if("cancelThread"===k)J.g[g.thread].postMessage({cmd:"cancel"});else if("loaded"===k)a.loaded=!0,x&&!a.o&&a.unref(),b(a);else if("alert"===k)alert("Thread "+g.threadId+": "+g.text);else if("setimmediate"===g.target)a.postMessage(g);else if("callHandler"===k)w[g.handler](...g.args);else k&&D("worker sent an unknown command "+k)};a.onerror=g=>{D("worker sent an error! "+g.filename+":"+g.lineno+
": "+g.message);throw g;};x&&(a.on("message",function(g){a.onmessage({data:g})}),a.on("error",function(g){a.onerror(g)}));var c=[],e=["onExit","onAbort","print","printErr"],f;for(f of e)w.hasOwnProperty(f)&&c.push(f);a.postMessage({cmd:"load",handlers:c,urlOrBlob:w.mainScriptUrlOrBlob,wasmMemory:d,wasmModule:Aa})}),ta:function(a){if(A)return a();Promise.all(J.u.map(J.ba)).then(a)},X:function(){if(w.locateFile){var a=qa("skwasm.worker.js");a=new Worker(a)}else a=new Worker(new URL("skwasm.worker.js",
import.meta.url));J.u.push(a)},ma:function(){0==J.u.length&&(J.X(),J.ba(J.u[0]));return J.u.pop()}};w.PThread=J;var gb=a=>{for(;0<a.length;)a.shift()(w)};w.establishStackSpace=function(){var a=eb(),b=q()[a+52>>2];a=q()[a+56>>2];hb(b,b-a);N(b)};function ab(a){if(A)return L(2,0,a);bb(a)}w.invokeEntryPoint=function(a,b){a=G.get(a)(b);Ka()?J.fa(a):ib(a)};
function jb(a){this.G=a-24;this.ua=function(b){t()[this.G+4>>2]=b};this.sa=function(b){t()[this.G+8>>2]=b};this.S=function(b,c){this.na();this.ua(b);this.sa(c)};this.na=function(){t()[this.G+16>>2]=0}}var kb=0,lb=0;function mb(a,b,c,e){return A?L(3,1,a,b,c,e):nb(a,b,c,e)}
function nb(a,b,c,e){if("undefined"==typeof SharedArrayBuffer)return D("Current environment does not support SharedArrayBuffer, pthreads are not available!"),6;var f=[],g=0,k=b?t()[b+40>>2]:0;4294967295==k?k="#canvas":k&&(k=K(k).trim());k&&(k=k.split(","));var n={},r=w.canvas?w.canvas.id:"",u;for(u in k){var y=k[u].trim();try{if("#canvas"==y){if(!w.canvas){D('pthread_create: could not find canvas with ID "'+y+'" to transfer to thread!');g=28;break}y=w.canvas.id}if(M[y]){var V=M[y];M[y]=null;w.canvas instanceof
OffscreenCanvas&&y===w.canvas.id&&(w.canvas=null)}else if(!A){var E=w.canvas&&w.canvas.id===y?w.canvas:document.querySelector(y);if(!E){D('pthread_create: could not find canvas with ID "'+y+'" to transfer to thread!');g=28;break}if(E.Y){D('pthread_create: cannot transfer canvas with ID "'+y+'" to thread, since the current thread does not have control over it!');g=63;break}if(E.transferControlToOffscreen)E.h||(E.h=ob(12),q()[E.h>>2]=E.width,q()[E.h+4>>2]=E.height,q()[E.h+8>>2]=0),V={I:E.transferControlToOffscreen(),
h:E.h,id:E.id},E.Y=!0;else return D('pthread_create: cannot transfer control of canvas "'+y+'" to pthread, because current browser does not support OffscreenCanvas!'),D("pthread_create: Build with -sOFFSCREEN_FRAMEBUFFER to enable fallback proxying of GL commands from pthread to main thread."),52}V&&(f.push(V.I),n[V.id]=V)}catch(m){return D('pthread_create: failed to transfer control of canvas "'+y+'" to OffscreenCanvas! Error: '+m),28}}if(A&&(0===f.length||g))return mb(a,b,c,e);if(g)return g;for(E of Object.values(n))q()[E.h+
8>>2]=a;a={Ba:c,o:a,ka:e,H:r,T:n,Ha:f};return A?(a.Ja="spawnThread",postMessage(a,f),0):Xa(a)}function pb(a,b,c){return A?L(4,1,a,b,c):0}function qb(a,b){if(A)return L(5,1,a,b)}function rb(a,b,c){return A?L(6,1,a,b,c):0}function sb(a,b,c,e){if(A)return L(7,1,a,b,c,e)}var tb=a=>{if(!Ba)try{if(a(),!Ka())try{A?ib(Ca):bb(Ca)}catch(b){b instanceof Ua||"unwind"==b||na(1,b)}}catch(b){b instanceof Ua||"unwind"==b||na(1,b)}};
function ub(a){"function"===typeof Atomics.Ia&&(Atomics.Ia(q(),a>>2,a).value.then(fb),a+=128,Atomics.store(q(),a>>2,1))}w.__emscripten_thread_mailbox_await=ub;function fb(){var a=eb();a&&(ub(a),tb(()=>vb()))}w.checkMailbox=fb;
var wb=a=>{var b=O();a=a();N(b);return a},xb=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);127>=e?b++:2047>=e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},yb=(a,b,c,e)=>{if(!(0<e))return 0;var f=c;e=c+e-1;for(var g=0;g<a.length;++g){var k=a.charCodeAt(g);if(55296<=k&&57343>=k){var n=a.charCodeAt(++g);k=65536+((k&1023)<<10)|n&1023}if(127>=k){if(c>=e)break;b[c++]=k}else{if(2047>=k){if(c+1>=e)break;b[c++]=192|k>>6}else{if(65535>=k){if(c+2>=e)break;b[c++]=224|k>>12}else{if(c+3>=e)break;
b[c++]=240|k>>18;b[c++]=128|k>>12&63}b[c++]=128|k>>6&63}b[c++]=128|k&63}}b[c]=0;return c-f},zb=a=>{var b=xb(a)+1,c=ob(b);c&&yb(a,p(),c,b);return c};function Ab(a,b,c,e){b=b?K(b):"";wb(function(){var f=Bb(12),g=0;b&&(g=zb(b));q()[f>>2]=g;q()[f+4>>2]=c;q()[f+8>>2]=e;Cb(a,654311424,0,g,f)})}
function Db(a){var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=function(c,e){b.vertexAttribDivisorANGLE(c,e)},a.drawArraysInstanced=function(c,e,f,g){b.drawArraysInstancedANGLE(c,e,f,g)},a.drawElementsInstanced=function(c,e,f,g,k){b.drawElementsInstancedANGLE(c,e,f,g,k)})}
function Eb(a){var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=function(){return b.createVertexArrayOES()},a.deleteVertexArray=function(c){b.deleteVertexArrayOES(c)},a.bindVertexArray=function(c){b.bindVertexArrayOES(c)},a.isVertexArray=function(c){return b.isVertexArrayOES(c)})}function Fb(a){var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=function(c,e){b.drawBuffersWEBGL(c,e)})}
function Gb(a){a.Z=a.getExtension("WEBGL_draw_instanced_base_vertex_base_instance")}function Hb(a){a.ea=a.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")}function Ib(a){a.Ma=a.getExtension("WEBGL_multi_draw")}var Jb=1,Kb=[],P=[],Lb=[],Mb=[],Q=[],R=[],Nb=[],Ob={},M={},Pb=[],Qb=[],Rb={},Sb={},Tb=4;function S(a){Ub||(Ub=a)}function Vb(a){for(var b=Jb++,c=a.length;c<b;c++)a[c]=null;return b}
function Wb(a){var b={da:2,alpha:!0,depth:!0,stencil:!0,antialias:!1,premultipliedAlpha:!0,preserveDrawingBuffer:!1,powerPreference:"default",failIfMajorPerformanceCaveat:!1,aa:!0};a.G||(a.G=a.getContext,a.getContext=function(e,f){f=a.G(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1<b.da?a.getContext("webgl2",b):a.getContext("webgl",b);return c?Xb(c,b):0}
function Xb(a,b){var c=ob(8);q()[c+4>>2]=eb();var e={handle:c,attributes:b,version:b.da,v:a};a.canvas&&(a.canvas.K=e);Ob[c]=e;("undefined"==typeof b.aa||b.aa)&&Yb(e);return c}
function Yb(a){a||(a=T);if(!a.pa){a.pa=!0;var b=a.v;Db(b);Eb(b);Fb(b);Gb(b);Hb(b);2<=a.version&&(b.$=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.$)b.$=b.getExtension("EXT_disjoint_timer_query");Ib(b);(b.getSupportedExtensions()||[]).forEach(function(c){c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}}var db={},Ub,T;
function Zb(a){a=2<a?K(a):a;return M[a.substr(1)]||"canvas"==a&&Object.keys(M)[0]||"undefined"!=typeof document&&document.querySelector(a)}function $b(a,b,c){var e=Zb(a);if(!e)return-4;e.h&&(q()[e.h>>2]=b,q()[e.h+4>>2]=c);if(e.I||!e.Y)e.I&&(e=e.I),a=!1,e.K&&e.K.v&&(a=e.K.v.getParameter(2978),a=0===a[0]&&0===a[1]&&a[2]===e.width&&a[3]===e.height),e.width=b,e.height=c,a&&e.K.v.viewport(0,0,b,c);else return e.h?(e=q()[e.h+8>>2],Ab(e,a,b,c),1):-4;return 0}
function ac(a,b,c){return A?L(8,1,a,b,c):$b(a,b,c)}function bc(a,b,c,e,f,g,k,n){return A?L(9,1,a,b,c,e,f,g,k,n):-52}function cc(a,b,c,e,f,g,k){if(A)return L(10,1,a,b,c,e,f,g,k)}function dc(a,b){U.bindFramebuffer(a,Lb[b])}function ec(a){U.clear(a)}function fc(a,b,c,e){U.clearColor(a,b,c,e)}function gc(a){U.clearStencil(a)}
function hc(a,b,c){if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&S(1280);return;case 34814:case 36345:e=0;break;case 34466:var f=U.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>T.version){S(1282);return}e=2*(U.getSupportedExtensions()||[]).length;break;case 33307:case 33308:if(2>T.version){S(1280);return}e=33307==a?3:0}if(void 0===e)switch(f=U.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":S(1280);return;case "object":if(null===
f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e=0;break;default:S(1280);return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a<f.length;++a)switch(c){case 0:q()[b+4*a>>2]=f[a];break;case 2:v()[b+4*a>>2]=f[a];break;case 4:aa()[b+a>>0]=f[a]?1:0}return}try{e=f.name|
0}catch(g){S(1280);D("GL_INVALID_ENUM in glGet"+c+"v: Unknown object returned from WebGL getParameter("+a+")! (error: "+g+")");return}}break;default:S(1280);D("GL_INVALID_ENUM in glGet"+c+"v: Native code calling glGet"+c+"v("+a+") and it returns "+f+" of type "+typeof f+"!");return}switch(c){case 1:c=e;t()[b>>2]=c;t()[b+4>>2]=(c-t()[b>>2])/4294967296;break;case 0:q()[b>>2]=e;break;case 2:v()[b>>2]=e;break;case 4:aa()[b>>0]=e?1:0}}else S(1281)}function ic(a,b){hc(a,b,0)}
function jc(a){a-=5120;0==a?a=aa():1==a?a=p():2==a?(d.buffer!=h.buffer&&l(),a=Da):4==a?a=q():6==a?a=v():5==a||28922==a||28520==a||30779==a||30782==a?a=t():(d.buffer!=h.buffer&&l(),a=Ea);return a}function kc(a,b,c,e,f){a=jc(a);var g=31-Math.clz32(a.BYTES_PER_ELEMENT),k=Tb;return a.subarray(f>>g,f+e*(c*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*(1<<g)+k-1&-k)>>g)}
function lc(a,b,c,e,f,g,k){if(2<=T.version)if(U.R)U.readPixels(a,b,c,e,f,g,k);else{var n=jc(g);U.readPixels(a,b,c,e,f,g,n,k>>31-Math.clz32(n.BYTES_PER_ELEMENT))}else(k=kc(g,f,c,e,k))?U.readPixels(a,b,c,e,f,g,k):S(1280)}function L(a,b){var c=arguments.length-2,e=arguments;return wb(()=>{for(var f=Bb(8*c),g=f>>3,k=0;k<c;k++){var n=e[2+k];ha()[g+k]=n}return mc(a,c,f,b)})}
var nc=[],oc={},qc=()=>{if(!pc){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:ma||"./this.program"},b;for(b in oc)void 0===oc[b]?delete a[b]:a[b]=oc[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);pc=c}return pc},pc;
function rc(a,b){if(A)return L(11,1,a,b);var c=0;qc().forEach(function(e,f){var g=b+c;f=t()[a+4*f>>2]=g;for(g=0;g<e.length;++g)aa()[f++>>0]=e.charCodeAt(g);aa()[f>>0]=0;c+=e.length+1});return 0}function sc(a,b){if(A)return L(12,1,a,b);var c=qc();t()[a>>2]=c.length;var e=0;c.forEach(function(f){e+=f.length+1});t()[b>>2]=e;return 0}function tc(a){return A?L(13,1,a):52}function uc(a,b,c,e,f,g){return A?L(14,1,a,b,c,e,f,g):52}function vc(a,b,c,e){return A?L(15,1,a,b,c,e):52}
function wc(a,b,c,e,f){return A?L(16,1,a,b,c,e,f):70}var xc=[null,[],[]];function yc(a,b,c,e){if(A)return L(17,1,a,b,c,e);for(var f=0,g=0;g<c;g++){var k=t()[b>>2],n=t()[b+4>>2];b+=8;for(var r=0;r<n;r++){var u=p()[k+r],y=xc[a];0===u||10===u?((1===a?xa:D)(Za(y,0)),y.length=0):y.push(u)}f+=n}t()[e>>2]=f;return 0}function zc(a){U.bindVertexArray(Nb[a])}function Ac(a,b){for(var c=0;c<a;c++){var e=q()[b+4*c>>2];U.deleteVertexArray(Nb[e]);Nb[e]=null}}var Bc=[];
function Cc(a,b,c,e){U.drawElements(a,b,c,e)}function Dc(a,b,c,e){for(var f=0;f<a;f++){var g=U[c](),k=g&&Vb(e);g?(g.name=k,e[k]=g):S(1282);q()[b+4*f>>2]=k}}function Ec(a,b){Dc(a,b,"createVertexArray",Nb)}function Fc(a){return"]"==a.slice(-1)&&a.lastIndexOf("[")}function W(a){var b=U.la;if(b){var c=b.J[a];"number"==typeof c&&(b.J[a]=c=U.getUniformLocation(b,b.ia[a]+(0<c?"["+c+"]":"")));return c}S(1282)}var X=[],Gc=[];function Hc(){}function Ic(){}function Jc(){}function Kc(){}function Lc(){}
function Mc(){}function Nc(){}function Pc(){}function Qc(){}function Rc(){}function Sc(){}function Tc(){}function Uc(){}function Vc(){}var Wc=a=>0===a%4&&(0!==a%100||0===a%400),Xc=[31,29,31,30,31,30,31,31,30,31,30,31],Yc=[31,28,31,30,31,30,31,31,30,31,30,31];function Zc(a){var b=Array(xb(a)+1);yb(a,b,0,b.length);return b}
var $c=(a,b)=>{aa().set(a,b)},ad=(a,b,c,e)=>{function f(m,z,B){for(m="number"==typeof m?m.toString():m||"";m.length<z;)m=B[0]+m;return m}function g(m,z){return f(m,z,"0")}function k(m,z){function B(Oc){return 0>Oc?-1:0<Oc?1:0}var ca;0===(ca=B(m.getFullYear()-z.getFullYear()))&&0===(ca=B(m.getMonth()-z.getMonth()))&&(ca=B(m.getDate()-z.getDate()));return ca}function n(m){switch(m.getDay()){case 0:return new Date(m.getFullYear()-1,11,29);case 1:return m;case 2:return new Date(m.getFullYear(),0,3);case 3:return new Date(m.getFullYear(),
0,2);case 4:return new Date(m.getFullYear(),0,1);case 5:return new Date(m.getFullYear()-1,11,31);case 6:return new Date(m.getFullYear()-1,11,30)}}function r(m){var z=m.C;for(m=new Date((new Date(m.D+1900,0,1)).getTime());0<z;){var B=m.getMonth(),ca=(Wc(m.getFullYear())?Xc:Yc)[B];if(z>ca-m.getDate())z-=ca-m.getDate()+1,m.setDate(1),11>B?m.setMonth(B+1):(m.setMonth(0),m.setFullYear(m.getFullYear()+1));else{m.setDate(m.getDate()+z);break}}B=new Date(m.getFullYear()+1,0,4);z=n(new Date(m.getFullYear(),
0,4));B=n(B);return 0>=k(z,m)?0>=k(B,m)?m.getFullYear()+1:m.getFullYear():m.getFullYear()-1}var u=q()[e+40>>2];e={Fa:q()[e>>2],Ea:q()[e+4>>2],O:q()[e+8>>2],V:q()[e+12>>2],P:q()[e+16>>2],D:q()[e+20>>2],l:q()[e+24>>2],C:q()[e+28>>2],Pa:q()[e+32>>2],Da:q()[e+36>>2],Ga:u?K(u):""};c=K(c);u={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y",
"%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var y in u)c=c.replace(new RegExp(y,"g"),u[y]);var V="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),E="January February March April May June July August September October November December".split(" ");u={"%a":m=>V[m.l].substring(0,3),"%A":m=>V[m.l],"%b":m=>E[m.P].substring(0,3),"%B":m=>E[m.P],"%C":m=>g((m.D+1900)/100|
0,2),"%d":m=>g(m.V,2),"%e":m=>f(m.V,2," "),"%g":m=>r(m).toString().substring(2),"%G":m=>r(m),"%H":m=>g(m.O,2),"%I":m=>{m=m.O;0==m?m=12:12<m&&(m-=12);return g(m,2)},"%j":m=>{for(var z=0,B=0;B<=m.P-1;z+=(Wc(m.D+1900)?Xc:Yc)[B++]);return g(m.V+z,3)},"%m":m=>g(m.P+1,2),"%M":m=>g(m.Ea,2),"%n":()=>"\n","%p":m=>0<=m.O&&12>m.O?"AM":"PM","%S":m=>g(m.Fa,2),"%t":()=>"\t","%u":m=>m.l||7,"%U":m=>g(Math.floor((m.C+7-m.l)/7),2),"%V":m=>{var z=Math.floor((m.C+7-(m.l+6)%7)/7);2>=(m.l+371-m.C-2)%7&&z++;if(z)53==z&&
(B=(m.l+371-m.C)%7,4==B||3==B&&Wc(m.D)||(z=1));else{z=52;var B=(m.l+7-m.C-1)%7;(4==B||5==B&&Wc(m.D%400-1))&&z++}return g(z,2)},"%w":m=>m.l,"%W":m=>g(Math.floor((m.C+7-(m.l+6)%7)/7),2),"%y":m=>(m.D+1900).toString().substring(2),"%Y":m=>m.D+1900,"%z":m=>{m=m.Da;var z=0<=m;m=Math.abs(m)/60;return(z?"+":"-")+String("0000"+(m/60*100+m%60)).slice(-4)},"%Z":m=>m.Ga,"%%":()=>"%"};c=c.replace(/%%/g,"\x00\x00");for(y in u)c.includes(y)&&(c=c.replace(new RegExp(y,"g"),u[y](e)));c=c.replace(/\0\0/g,"%");y=Zc(c);
if(y.length>b)return 0;$c(y,a);return y.length-1},bd=void 0,cd=[];J.S();for(var U,Y=0;32>Y;++Y)Bc.push(Array(Y));var dd=new Float32Array(288);for(Y=0;288>Y;++Y)X[Y]=dd.subarray(0,Y+1);var ed=new Int32Array(288);for(Y=0;288>Y;++Y)Gc[Y]=ed.subarray(0,Y+1);
(function(){const a=new Map,b=new Map;let c;Uc=function(e,f,g){J.g[e].postMessage({s:"setAssociatedObject",U:f,object:g},[g])};Pc=function(e){return b.get(e)};Vc=function(e){J.g[e].postMessage({s:"syncTimeOrigin",timeOrigin:performance.timeOrigin})};Rc=function(e){function f({data:g}){var k=g.s;if(k)switch(k){case "syncTimeOrigin":c=performance.timeOrigin-g.timeOrigin;break;case "renderPictures":fd(g.m,g.wa,g.va,g.A,performance.now()+c);break;case "onRenderComplete":gd(g.m,g.A,{imageBitmaps:g.oa,
rasterStartMilliseconds:g.ya,rasterEndMilliseconds:g.xa});break;case "setAssociatedObject":b.set(g.U,g.object);break;case "disposeAssociatedObject":g=g.U;k=b.get(g);k.close&&k.close();b.delete(g);break;case "disposeSurface":hd(g.m);break;case "rasterizeImage":jd(g.m,g.image,g.format,g.A);break;case "onRasterizeComplete":kd(g.m,g.data,g.A);break;default:console.warn(`unrecognized skwasm message: ${k}`)}}e?J.g[e].addEventListener("message",f):addEventListener("message",f)};Mc=function(e,f,g,k,n){J.g[e].postMessage({s:"renderPictures",
m:f,wa:g,va:k,A:n})};Jc=function(e,f){e=new OffscreenCanvas(e,f);f=Wb(e);a.set(f,e);return f};Sc=function(e,f,g){e=a.get(e);e.width=f;e.height=g};Hc=function(e,f,g,k){k||(k=[]);e=a.get(e);k.push(createImageBitmap(e,0,0,f,g));return k};Tc=async function(e,f,g,k){f=f?await Promise.all(f):[];postMessage({s:"onRenderComplete",m:e,A:k,oa:f,ya:g,xa:performance.now()+c},[...f])};Ic=function(e,f,g){const k=T.v,n=k.createTexture();k.bindTexture(k.TEXTURE_2D,n);k.pixelStorei(k.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
!0);k.texImage2D(k.TEXTURE_2D,0,k.RGBA,f,g,0,k.RGBA,k.UNSIGNED_BYTE,e);k.pixelStorei(k.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);k.bindTexture(k.TEXTURE_2D,null);e=Vb(Q);Q[e]=n;return e};Nc=function(e,f){J.g[e].postMessage({s:"disposeAssociatedObject",U:f})};Kc=function(e,f){J.g[e].postMessage({s:"disposeSurface",m:f})};Lc=function(e,f,g,k,n){J.g[e].postMessage({s:"rasterizeImage",m:f,image:g,format:k,A:n})};Qc=function(e,f,g){postMessage({s:"onRasterizeComplete",m:e,data:f,A:g})}})();
var ld=[null,$a,ab,mb,pb,qb,rb,sb,ac,bc,cc,rc,sc,tc,uc,vc,wc,yc],xd={__cxa_throw:function(a,b,c){(new jb(a)).S(b,c);kb=a;lb++;throw kb;},__emscripten_init_main_thread_js:function(a){md(a,!pa,1,!oa,65536,!1);J.ga()},__emscripten_thread_cleanup:function(a){A?postMessage({cmd:"cleanupThread",thread:a}):Wa(a)},__pthread_create_js:nb,__syscall_fcntl64:pb,__syscall_fstat64:qb,__syscall_ioctl:rb,__syscall_openat:sb,_emscripten_get_now_is_monotonic:()=>!0,_emscripten_notify_mailbox_postmessage:function(a,
b){a==b?setTimeout(()=>fb()):A?postMessage({targetThread:a,cmd:"checkMailbox"}):(a=J.g[a])&&a.postMessage({cmd:"checkMailbox"})},_emscripten_set_offscreencanvas_size:function(a,b,c){return Zb(a)?$b(a,b,c):ac(a,b,c)},_emscripten_thread_mailbox_await:ub,_emscripten_thread_set_strongref:function(a){x&&J.g[a].ref()},_emscripten_throw_longjmp:()=>{throw Infinity;},_mmap_js:bc,_munmap_js:cc,abort:()=>{za("")},emscripten_check_blocking_allowed:function(){},emscripten_exit_with_live_runtime:()=>{Ja+=1;throw"unwind";
},emscripten_get_now:()=>performance.timeOrigin+performance.now(),emscripten_glBindFramebuffer:dc,emscripten_glClear:ec,emscripten_glClearColor:fc,emscripten_glClearStencil:gc,emscripten_glGetIntegerv:ic,emscripten_glReadPixels:lc,emscripten_receive_on_main_thread_js:function(a,b,c,e){J.La=b;nc.length=c;b=e>>3;for(e=0;e<c;e++)nc[e]=ha()[b+e];return ld[a].apply(null,nc)},emscripten_resize_heap:a=>{var b=p().length;a>>>=0;if(a<=b||2147483648<a)return!1;for(var c=1;4>=c;c*=2){var e=b*(1+.2/c);e=Math.min(e,
a+100663296);var f=Math;e=Math.max(a,e);a:{f=f.min.call(f,2147483648,e+(65536-e%65536)%65536)-d.buffer.byteLength+65535>>>16;try{d.grow(f);l();var g=1;break a}catch(k){}g=void 0}if(g)return!0}return!1},emscripten_webgl_enable_extension:function(a,b){a=Ob[a];b=K(b);b.startsWith("GL_")&&(b=b.substr(3));"ANGLE_instanced_arrays"==b&&Db(U);"OES_vertex_array_object"==b&&Eb(U);"WEBGL_draw_buffers"==b&&Fb(U);"WEBGL_draw_instanced_base_vertex_base_instance"==b&&Gb(U);"WEBGL_multi_draw_instanced_base_vertex_base_instance"==
b&&Hb(U);"WEBGL_multi_draw"==b&&Ib(U);return!!a.v.getExtension(b)},emscripten_webgl_get_current_context:function(){return T?T.handle:0},emscripten_webgl_make_context_current:function(a){T=Ob[a];w.Ka=U=T&&T.v;return!a||U?0:-5},environ_get:rc,environ_sizes_get:sc,exit:bb,fd_close:tc,fd_pread:uc,fd_read:vc,fd_seek:wc,fd_write:yc,glActiveTexture:function(a){U.activeTexture(a)},glAttachShader:function(a,b){U.attachShader(P[a],R[b])},glBindAttribLocation:function(a,b,c){U.bindAttribLocation(P[a],b,K(c))},
glBindBuffer:function(a,b){35051==a?U.R=b:35052==a&&(U.F=b);U.bindBuffer(a,Kb[b])},glBindFramebuffer:dc,glBindRenderbuffer:function(a,b){U.bindRenderbuffer(a,Mb[b])},glBindSampler:function(a,b){U.bindSampler(a,Pb[b])},glBindTexture:function(a,b){U.bindTexture(a,Q[b])},glBindVertexArray:zc,glBindVertexArrayOES:zc,glBlendColor:function(a,b,c,e){U.blendColor(a,b,c,e)},glBlendEquation:function(a){U.blendEquation(a)},glBlendFunc:function(a,b){U.blendFunc(a,b)},glBlitFramebuffer:function(a,b,c,e,f,g,k,
n,r,u){U.blitFramebuffer(a,b,c,e,f,g,k,n,r,u)},glBufferData:function(a,b,c,e){2<=T.version?c&&b?U.bufferData(a,p(),e,c,b):U.bufferData(a,b,e):U.bufferData(a,c?p().subarray(c,c+b):b,e)},glBufferSubData:function(a,b,c,e){2<=T.version?c&&U.bufferSubData(a,b,p(),e,c):U.bufferSubData(a,b,p().subarray(e,e+c))},glCheckFramebufferStatus:function(a){return U.checkFramebufferStatus(a)},glClear:ec,glClearColor:fc,glClearStencil:gc,glClientWaitSync:function(a,b,c,e){return U.clientWaitSync(Qb[a],b,(c>>>0)+4294967296*
e)},glColorMask:function(a,b,c,e){U.colorMask(!!a,!!b,!!c,!!e)},glCompileShader:function(a){U.compileShader(R[a])},glCompressedTexImage2D:function(a,b,c,e,f,g,k,n){2<=T.version?U.F||!k?U.compressedTexImage2D(a,b,c,e,f,g,k,n):U.compressedTexImage2D(a,b,c,e,f,g,p(),n,k):U.compressedTexImage2D(a,b,c,e,f,g,n?p().subarray(n,n+k):null)},glCompressedTexSubImage2D:function(a,b,c,e,f,g,k,n,r){2<=T.version?U.F||!n?U.compressedTexSubImage2D(a,b,c,e,f,g,k,n,r):U.compressedTexSubImage2D(a,b,c,e,f,g,k,p(),r,n):
U.compressedTexSubImage2D(a,b,c,e,f,g,k,r?p().subarray(r,r+n):null)},glCopyBufferSubData:function(a,b,c,e,f){U.copyBufferSubData(a,b,c,e,f)},glCopyTexSubImage2D:function(a,b,c,e,f,g,k,n){U.copyTexSubImage2D(a,b,c,e,f,g,k,n)},glCreateProgram:function(){var a=Vb(P),b=U.createProgram();b.name=a;b.N=b.L=b.M=0;b.W=1;P[a]=b;return a},glCreateShader:function(a){var b=Vb(R);R[b]=U.createShader(a);return b},glCullFace:function(a){U.cullFace(a)},glDeleteBuffers:function(a,b){for(var c=0;c<a;c++){var e=q()[b+
4*c>>2],f=Kb[e];f&&(U.deleteBuffer(f),f.name=0,Kb[e]=null,e==U.R&&(U.R=0),e==U.F&&(U.F=0))}},glDeleteFramebuffers:function(a,b){for(var c=0;c<a;++c){var e=q()[b+4*c>>2],f=Lb[e];f&&(U.deleteFramebuffer(f),f.name=0,Lb[e]=null)}},glDeleteProgram:function(a){if(a){var b=P[a];b?(U.deleteProgram(b),b.name=0,P[a]=null):S(1281)}},glDeleteRenderbuffers:function(a,b){for(var c=0;c<a;c++){var e=q()[b+4*c>>2],f=Mb[e];f&&(U.deleteRenderbuffer(f),f.name=0,Mb[e]=null)}},glDeleteSamplers:function(a,b){for(var c=
0;c<a;c++){var e=q()[b+4*c>>2],f=Pb[e];f&&(U.deleteSampler(f),f.name=0,Pb[e]=null)}},glDeleteShader:function(a){if(a){var b=R[a];b?(U.deleteShader(b),R[a]=null):S(1281)}},glDeleteSync:function(a){if(a){var b=Qb[a];b?(U.deleteSync(b),b.name=0,Qb[a]=null):S(1281)}},glDeleteTextures:function(a,b){for(var c=0;c<a;c++){var e=q()[b+4*c>>2],f=Q[e];f&&(U.deleteTexture(f),f.name=0,Q[e]=null)}},glDeleteVertexArrays:Ac,glDeleteVertexArraysOES:Ac,glDepthMask:function(a){U.depthMask(!!a)},glDisable:function(a){U.disable(a)},
glDisableVertexAttribArray:function(a){U.disableVertexAttribArray(a)},glDrawArrays:function(a,b,c){U.drawArrays(a,b,c)},glDrawArraysInstanced:function(a,b,c,e){U.drawArraysInstanced(a,b,c,e)},glDrawArraysInstancedBaseInstanceWEBGL:function(a,b,c,e,f){U.Z.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},glDrawBuffers:function(a,b){for(var c=Bc[a],e=0;e<a;e++)c[e]=q()[b+4*e>>2];U.drawBuffers(c)},glDrawElements:Cc,glDrawElementsInstanced:function(a,b,c,e,f){U.drawElementsInstanced(a,b,c,e,f)},glDrawElementsInstancedBaseVertexBaseInstanceWEBGL:function(a,
b,c,e,f,g,k){U.Z.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,b,c,e,f,g,k)},glDrawRangeElements:function(a,b,c,e,f,g){Cc(a,e,f,g)},glEnable:function(a){U.enable(a)},glEnableVertexAttribArray:function(a){U.enableVertexAttribArray(a)},glFenceSync:function(a,b){return(a=U.fenceSync(a,b))?(b=Vb(Qb),a.name=b,Qb[b]=a,b):0},glFinish:function(){U.finish()},glFlush:function(){U.flush()},glFramebufferRenderbuffer:function(a,b,c,e){U.framebufferRenderbuffer(a,b,c,Mb[e])},glFramebufferTexture2D:function(a,
b,c,e,f){U.framebufferTexture2D(a,b,c,Q[e],f)},glFrontFace:function(a){U.frontFace(a)},glGenBuffers:function(a,b){Dc(a,b,"createBuffer",Kb)},glGenFramebuffers:function(a,b){Dc(a,b,"createFramebuffer",Lb)},glGenRenderbuffers:function(a,b){Dc(a,b,"createRenderbuffer",Mb)},glGenSamplers:function(a,b){Dc(a,b,"createSampler",Pb)},glGenTextures:function(a,b){Dc(a,b,"createTexture",Q)},glGenVertexArrays:Ec,glGenVertexArraysOES:Ec,glGenerateMipmap:function(a){U.generateMipmap(a)},glGetBufferParameteriv:function(a,
b,c){c?q()[c>>2]=U.getBufferParameter(a,b):S(1281)},glGetError:function(){var a=U.getError()||Ub;Ub=0;return a},glGetFloatv:function(a,b){hc(a,b,2)},glGetFramebufferAttachmentParameteriv:function(a,b,c,e){a=U.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;q()[e>>2]=a},glGetIntegerv:ic,glGetProgramInfoLog:function(a,b,c,e){a=U.getProgramInfoLog(P[a]);null===a&&(a="(unknown error)");var f;0<b&&e?f=yb(a,p(),e,b):f=0;b=f;c&&(q()[c>>2]=
b)},glGetProgramiv:function(a,b,c){if(c)if(a>=Jb)S(1281);else if(a=P[a],35716==b)a=U.getProgramInfoLog(a),null===a&&(a="(unknown error)"),q()[c>>2]=a.length+1;else if(35719==b){if(!a.N)for(b=0;b<U.getProgramParameter(a,35718);++b)a.N=Math.max(a.N,U.getActiveUniform(a,b).name.length+1);q()[c>>2]=a.N}else if(35722==b){if(!a.L)for(b=0;b<U.getProgramParameter(a,35721);++b)a.L=Math.max(a.L,U.getActiveAttrib(a,b).name.length+1);q()[c>>2]=a.L}else if(35381==b){if(!a.M)for(b=0;b<U.getProgramParameter(a,35382);++b)a.M=
Math.max(a.M,U.getActiveUniformBlockName(a,b).length+1);q()[c>>2]=a.M}else q()[c>>2]=U.getProgramParameter(a,b);else S(1281)},glGetRenderbufferParameteriv:function(a,b,c){c?q()[c>>2]=U.getRenderbufferParameter(a,b):S(1281)},glGetShaderInfoLog:function(a,b,c,e){a=U.getShaderInfoLog(R[a]);null===a&&(a="(unknown error)");var f;0<b&&e?f=yb(a,p(),e,b):f=0;b=f;c&&(q()[c>>2]=b)},glGetShaderPrecisionFormat:function(a,b,c,e){a=U.getShaderPrecisionFormat(a,b);q()[c>>2]=a.rangeMin;q()[c+4>>2]=a.rangeMax;q()[e>>
2]=a.precision},glGetShaderiv:function(a,b,c){c?35716==b?(a=U.getShaderInfoLog(R[a]),null===a&&(a="(unknown error)"),a=a?a.length+1:0,q()[c>>2]=a):35720==b?(a=(a=U.getShaderSource(R[a]))?a.length+1:0,q()[c>>2]=a):q()[c>>2]=U.getShaderParameter(R[a],b):S(1281)},glGetString:function(a){var b=Rb[a];if(!b){switch(a){case 7939:b=U.getSupportedExtensions()||[];b=b.concat(b.map(function(e){return"GL_"+e}));b=zb(b.join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=U.getParameter(a))||S(1280);b=
b&&zb(b);break;case 7938:b=U.getParameter(7938);b=2<=T.version?"OpenGL ES 3.0 ("+b+")":"OpenGL ES 2.0 ("+b+")";b=zb(b);break;case 35724:b=U.getParameter(35724);var c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b="OpenGL ES GLSL ES "+c[1]+" ("+b+")");b=zb(b);break;default:S(1280)}Rb[a]=b}return b},glGetStringi:function(a,b){if(2>T.version)return S(1282),0;var c=Sb[a];if(c)return 0>b||b>=c.length?(S(1281),0):c[b];switch(a){case 7939:return c=U.getSupportedExtensions()||
[],c=c.concat(c.map(function(e){return"GL_"+e})),c=c.map(function(e){return zb(e)}),c=Sb[a]=c,0>b||b>=c.length?(S(1281),0):c[b];default:return S(1280),0}},glGetUniformLocation:function(a,b){b=K(b);if(a=P[a]){var c=a,e=c.J,f=c.ja,g;if(!e)for(c.J=e={},c.ia={},g=0;g<U.getProgramParameter(c,35718);++g){var k=U.getActiveUniform(c,g);var n=k.name;k=k.size;var r=Fc(n);r=0<r?n.slice(0,r):n;var u=c.W;c.W+=k;f[r]=[k,u];for(n=0;n<k;++n)e[u]=n,c.ia[u++]=r}c=a.J;e=0;f=b;g=Fc(b);0<g&&(e=parseInt(b.slice(g+1))>>>
0,f=b.slice(0,g));if((f=a.ja[f])&&e<f[0]&&(e+=f[1],c[e]=c[e]||U.getUniformLocation(a,b)))return e}else S(1281);return-1},glInvalidateFramebuffer:function(a,b,c){for(var e=Bc[b],f=0;f<b;f++)e[f]=q()[c+4*f>>2];U.invalidateFramebuffer(a,e)},glInvalidateSubFramebuffer:function(a,b,c,e,f,g,k){for(var n=Bc[b],r=0;r<b;r++)n[r]=q()[c+4*r>>2];U.invalidateSubFramebuffer(a,n,e,f,g,k)},glIsSync:function(a){return U.isSync(Qb[a])},glIsTexture:function(a){return(a=Q[a])?U.isTexture(a):0},glLineWidth:function(a){U.lineWidth(a)},
glLinkProgram:function(a){a=P[a];U.linkProgram(a);a.J=0;a.ja={}},glMultiDrawArraysInstancedBaseInstanceWEBGL:function(a,b,c,e,f,g){U.ea.multiDrawArraysInstancedBaseInstanceWEBGL(a,q(),b>>2,q(),c>>2,q(),e>>2,t(),f>>2,g)},glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL:function(a,b,c,e,f,g,k,n){U.ea.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,q(),b>>2,c,q(),e>>2,q(),f>>2,q(),g>>2,t(),k>>2,n)},glPixelStorei:function(a,b){3317==a&&(Tb=b);U.pixelStorei(a,b)},glReadBuffer:function(a){U.readBuffer(a)},
glReadPixels:lc,glRenderbufferStorage:function(a,b,c,e){U.renderbufferStorage(a,b,c,e)},glRenderbufferStorageMultisample:function(a,b,c,e,f){U.renderbufferStorageMultisample(a,b,c,e,f)},glSamplerParameterf:function(a,b,c){U.samplerParameterf(Pb[a],b,c)},glSamplerParameteri:function(a,b,c){U.samplerParameteri(Pb[a],b,c)},glSamplerParameteriv:function(a,b,c){c=q()[c>>2];U.samplerParameteri(Pb[a],b,c)},glScissor:function(a,b,c,e){U.scissor(a,b,c,e)},glShaderSource:function(a,b,c,e){for(var f="",g=0;g<
b;++g){var k=e?q()[e+4*g>>2]:-1;f+=K(q()[c+4*g>>2],0>k?void 0:k)}U.shaderSource(R[a],f)},glStencilFunc:function(a,b,c){U.stencilFunc(a,b,c)},glStencilFuncSeparate:function(a,b,c,e){U.stencilFuncSeparate(a,b,c,e)},glStencilMask:function(a){U.stencilMask(a)},glStencilMaskSeparate:function(a,b){U.stencilMaskSeparate(a,b)},glStencilOp:function(a,b,c){U.stencilOp(a,b,c)},glStencilOpSeparate:function(a,b,c,e){U.stencilOpSeparate(a,b,c,e)},glTexImage2D:function(a,b,c,e,f,g,k,n,r){if(2<=T.version)if(U.F)U.texImage2D(a,
b,c,e,f,g,k,n,r);else if(r){var u=jc(n);U.texImage2D(a,b,c,e,f,g,k,n,u,r>>31-Math.clz32(u.BYTES_PER_ELEMENT))}else U.texImage2D(a,b,c,e,f,g,k,n,null);else U.texImage2D(a,b,c,e,f,g,k,n,r?kc(n,k,e,f,r):null)},glTexParameterf:function(a,b,c){U.texParameterf(a,b,c)},glTexParameterfv:function(a,b,c){c=v()[c>>2];U.texParameterf(a,b,c)},glTexParameteri:function(a,b,c){U.texParameteri(a,b,c)},glTexParameteriv:function(a,b,c){c=q()[c>>2];U.texParameteri(a,b,c)},glTexStorage2D:function(a,b,c,e,f){U.texStorage2D(a,
b,c,e,f)},glTexSubImage2D:function(a,b,c,e,f,g,k,n,r){if(2<=T.version)if(U.F)U.texSubImage2D(a,b,c,e,f,g,k,n,r);else if(r){var u=jc(n);U.texSubImage2D(a,b,c,e,f,g,k,n,u,r>>31-Math.clz32(u.BYTES_PER_ELEMENT))}else U.texSubImage2D(a,b,c,e,f,g,k,n,null);else u=null,r&&(u=kc(n,k,f,g,r)),U.texSubImage2D(a,b,c,e,f,g,k,n,u)},glUniform1f:function(a,b){U.uniform1f(W(a),b)},glUniform1fv:function(a,b,c){if(2<=T.version)b&&U.uniform1fv(W(a),v(),c>>2,b);else{if(288>=b)for(var e=X[b-1],f=0;f<b;++f)e[f]=v()[c+4*
f>>2];else e=v().subarray(c>>2,c+4*b>>2);U.uniform1fv(W(a),e)}},glUniform1i:function(a,b){U.uniform1i(W(a),b)},glUniform1iv:function(a,b,c){if(2<=T.version)b&&U.uniform1iv(W(a),q(),c>>2,b);else{if(288>=b)for(var e=Gc[b-1],f=0;f<b;++f)e[f]=q()[c+4*f>>2];else e=q().subarray(c>>2,c+4*b>>2);U.uniform1iv(W(a),e)}},glUniform2f:function(a,b,c){U.uniform2f(W(a),b,c)},glUniform2fv:function(a,b,c){if(2<=T.version)b&&U.uniform2fv(W(a),v(),c>>2,2*b);else{if(144>=b)for(var e=X[2*b-1],f=0;f<2*b;f+=2)e[f]=v()[c+
4*f>>2],e[f+1]=v()[c+(4*f+4)>>2];else e=v().subarray(c>>2,c+8*b>>2);U.uniform2fv(W(a),e)}},glUniform2i:function(a,b,c){U.uniform2i(W(a),b,c)},glUniform2iv:function(a,b,c){if(2<=T.version)b&&U.uniform2iv(W(a),q(),c>>2,2*b);else{if(144>=b)for(var e=Gc[2*b-1],f=0;f<2*b;f+=2)e[f]=q()[c+4*f>>2],e[f+1]=q()[c+(4*f+4)>>2];else e=q().subarray(c>>2,c+8*b>>2);U.uniform2iv(W(a),e)}},glUniform3f:function(a,b,c,e){U.uniform3f(W(a),b,c,e)},glUniform3fv:function(a,b,c){if(2<=T.version)b&&U.uniform3fv(W(a),v(),c>>
2,3*b);else{if(96>=b)for(var e=X[3*b-1],f=0;f<3*b;f+=3)e[f]=v()[c+4*f>>2],e[f+1]=v()[c+(4*f+4)>>2],e[f+2]=v()[c+(4*f+8)>>2];else e=v().subarray(c>>2,c+12*b>>2);U.uniform3fv(W(a),e)}},glUniform3i:function(a,b,c,e){U.uniform3i(W(a),b,c,e)},glUniform3iv:function(a,b,c){if(2<=T.version)b&&U.uniform3iv(W(a),q(),c>>2,3*b);else{if(96>=b)for(var e=Gc[3*b-1],f=0;f<3*b;f+=3)e[f]=q()[c+4*f>>2],e[f+1]=q()[c+(4*f+4)>>2],e[f+2]=q()[c+(4*f+8)>>2];else e=q().subarray(c>>2,c+12*b>>2);U.uniform3iv(W(a),e)}},glUniform4f:function(a,
b,c,e,f){U.uniform4f(W(a),b,c,e,f)},glUniform4fv:function(a,b,c){if(2<=T.version)b&&U.uniform4fv(W(a),v(),c>>2,4*b);else{if(72>=b){var e=X[4*b-1],f=v();c>>=2;for(var g=0;g<4*b;g+=4){var k=c+g;e[g]=f[k];e[g+1]=f[k+1];e[g+2]=f[k+2];e[g+3]=f[k+3]}}else e=v().subarray(c>>2,c+16*b>>2);U.uniform4fv(W(a),e)}},glUniform4i:function(a,b,c,e,f){U.uniform4i(W(a),b,c,e,f)},glUniform4iv:function(a,b,c){if(2<=T.version)b&&U.uniform4iv(W(a),q(),c>>2,4*b);else{if(72>=b)for(var e=Gc[4*b-1],f=0;f<4*b;f+=4)e[f]=q()[c+
4*f>>2],e[f+1]=q()[c+(4*f+4)>>2],e[f+2]=q()[c+(4*f+8)>>2],e[f+3]=q()[c+(4*f+12)>>2];else e=q().subarray(c>>2,c+16*b>>2);U.uniform4iv(W(a),e)}},glUniformMatrix2fv:function(a,b,c,e){if(2<=T.version)b&&U.uniformMatrix2fv(W(a),!!c,v(),e>>2,4*b);else{if(72>=b)for(var f=X[4*b-1],g=0;g<4*b;g+=4)f[g]=v()[e+4*g>>2],f[g+1]=v()[e+(4*g+4)>>2],f[g+2]=v()[e+(4*g+8)>>2],f[g+3]=v()[e+(4*g+12)>>2];else f=v().subarray(e>>2,e+16*b>>2);U.uniformMatrix2fv(W(a),!!c,f)}},glUniformMatrix3fv:function(a,b,c,e){if(2<=T.version)b&&
U.uniformMatrix3fv(W(a),!!c,v(),e>>2,9*b);else{if(32>=b)for(var f=X[9*b-1],g=0;g<9*b;g+=9)f[g]=v()[e+4*g>>2],f[g+1]=v()[e+(4*g+4)>>2],f[g+2]=v()[e+(4*g+8)>>2],f[g+3]=v()[e+(4*g+12)>>2],f[g+4]=v()[e+(4*g+16)>>2],f[g+5]=v()[e+(4*g+20)>>2],f[g+6]=v()[e+(4*g+24)>>2],f[g+7]=v()[e+(4*g+28)>>2],f[g+8]=v()[e+(4*g+32)>>2];else f=v().subarray(e>>2,e+36*b>>2);U.uniformMatrix3fv(W(a),!!c,f)}},glUniformMatrix4fv:function(a,b,c,e){if(2<=T.version)b&&U.uniformMatrix4fv(W(a),!!c,v(),e>>2,16*b);else{if(18>=b){var f=
X[16*b-1],g=v();e>>=2;for(var k=0;k<16*b;k+=16){var n=e+k;f[k]=g[n];f[k+1]=g[n+1];f[k+2]=g[n+2];f[k+3]=g[n+3];f[k+4]=g[n+4];f[k+5]=g[n+5];f[k+6]=g[n+6];f[k+7]=g[n+7];f[k+8]=g[n+8];f[k+9]=g[n+9];f[k+10]=g[n+10];f[k+11]=g[n+11];f[k+12]=g[n+12];f[k+13]=g[n+13];f[k+14]=g[n+14];f[k+15]=g[n+15]}}else f=v().subarray(e>>2,e+64*b>>2);U.uniformMatrix4fv(W(a),!!c,f)}},glUseProgram:function(a){a=P[a];U.useProgram(a);U.la=a},glVertexAttrib1f:function(a,b){U.vertexAttrib1f(a,b)},glVertexAttrib2fv:function(a,b){U.vertexAttrib2f(a,
v()[b>>2],v()[b+4>>2])},glVertexAttrib3fv:function(a,b){U.vertexAttrib3f(a,v()[b>>2],v()[b+4>>2],v()[b+8>>2])},glVertexAttrib4fv:function(a,b){U.vertexAttrib4f(a,v()[b>>2],v()[b+4>>2],v()[b+8>>2],v()[b+12>>2])},glVertexAttribDivisor:function(a,b){U.vertexAttribDivisor(a,b)},glVertexAttribIPointer:function(a,b,c,e,f){U.vertexAttribIPointer(a,b,c,e,f)},glVertexAttribPointer:function(a,b,c,e,f,g){U.vertexAttribPointer(a,b,c,!!e,f,g)},glViewport:function(a,b,c,e){U.viewport(a,b,c,e)},glWaitSync:function(a,
b,c,e){U.waitSync(Qb[a],b,(c>>>0)+4294967296*e)},invoke_ii:nd,invoke_iii:od,invoke_iiii:pd,invoke_iiiii:qd,invoke_iiiiiii:rd,invoke_vi:sd,invoke_vii:td,invoke_viii:ud,invoke_viiii:vd,invoke_viiiiiii:wd,memory:d||w.wasmMemory,skwasm_captureImageBitmap:Hc,skwasm_createGlTextureFromTextureSource:Ic,skwasm_createOffscreenCanvas:Jc,skwasm_dispatchDisposeSurface:Kc,skwasm_dispatchRasterizeImage:Lc,skwasm_dispatchRenderPictures:Mc,skwasm_disposeAssociatedObjectOnThread:Nc,skwasm_getAssociatedObject:Pc,skwasm_postRasterizeResult:Qc,
skwasm_registerMessageListener:Rc,skwasm_resizeCanvas:Sc,skwasm_resolveAndPostImages:Tc,skwasm_setAssociatedObjectOnThread:Uc,skwasm_syncTimeOriginForThread:Vc,strftime_l:(a,b,c,e)=>ad(a,b,c,e)};
(function(){function a(c,e){F=c=c.exports;w.wasmExports=F;J.ha.push(F._emscripten_tls_init);G=F.__indirect_function_table;Ha.unshift(F.__wasm_call_ctors);Aa=e;Oa();return c}var b={env:xd,wasi_snapshot_preview1:xd};Na();if(w.instantiateWasm)try{return w.instantiateWasm(b,a)}catch(c){D("Module.instantiateWasm callback failed with error: "+c),ka(c)}Ta(b,function(c){a(c.instance,c.module)}).catch(ka);return{}})();w._canvas_saveLayer=(a,b,c,e)=>(w._canvas_saveLayer=F.canvas_saveLayer)(a,b,c,e);
w._canvas_save=a=>(w._canvas_save=F.canvas_save)(a);w._canvas_restore=a=>(w._canvas_restore=F.canvas_restore)(a);w._canvas_restoreToCount=(a,b)=>(w._canvas_restoreToCount=F.canvas_restoreToCount)(a,b);w._canvas_getSaveCount=a=>(w._canvas_getSaveCount=F.canvas_getSaveCount)(a);w._canvas_translate=(a,b,c)=>(w._canvas_translate=F.canvas_translate)(a,b,c);w._canvas_scale=(a,b,c)=>(w._canvas_scale=F.canvas_scale)(a,b,c);w._canvas_rotate=(a,b)=>(w._canvas_rotate=F.canvas_rotate)(a,b);
w._canvas_skew=(a,b,c)=>(w._canvas_skew=F.canvas_skew)(a,b,c);w._canvas_transform=(a,b)=>(w._canvas_transform=F.canvas_transform)(a,b);w._canvas_clipRect=(a,b,c,e)=>(w._canvas_clipRect=F.canvas_clipRect)(a,b,c,e);w._canvas_clipRRect=(a,b,c)=>(w._canvas_clipRRect=F.canvas_clipRRect)(a,b,c);w._canvas_clipPath=(a,b,c)=>(w._canvas_clipPath=F.canvas_clipPath)(a,b,c);w._canvas_drawColor=(a,b,c)=>(w._canvas_drawColor=F.canvas_drawColor)(a,b,c);
w._canvas_drawLine=(a,b,c,e,f,g)=>(w._canvas_drawLine=F.canvas_drawLine)(a,b,c,e,f,g);w._canvas_drawPaint=(a,b)=>(w._canvas_drawPaint=F.canvas_drawPaint)(a,b);w._canvas_drawRect=(a,b,c)=>(w._canvas_drawRect=F.canvas_drawRect)(a,b,c);w._canvas_drawRRect=(a,b,c)=>(w._canvas_drawRRect=F.canvas_drawRRect)(a,b,c);w._canvas_drawDRRect=(a,b,c,e)=>(w._canvas_drawDRRect=F.canvas_drawDRRect)(a,b,c,e);w._canvas_drawOval=(a,b,c)=>(w._canvas_drawOval=F.canvas_drawOval)(a,b,c);
w._canvas_drawCircle=(a,b,c,e,f)=>(w._canvas_drawCircle=F.canvas_drawCircle)(a,b,c,e,f);w._canvas_drawArc=(a,b,c,e,f,g)=>(w._canvas_drawArc=F.canvas_drawArc)(a,b,c,e,f,g);w._canvas_drawPath=(a,b,c)=>(w._canvas_drawPath=F.canvas_drawPath)(a,b,c);w._canvas_drawShadow=(a,b,c,e,f,g)=>(w._canvas_drawShadow=F.canvas_drawShadow)(a,b,c,e,f,g);w._canvas_drawParagraph=(a,b,c,e)=>(w._canvas_drawParagraph=F.canvas_drawParagraph)(a,b,c,e);
w._canvas_drawPicture=(a,b)=>(w._canvas_drawPicture=F.canvas_drawPicture)(a,b);w._canvas_drawImage=(a,b,c,e,f,g)=>(w._canvas_drawImage=F.canvas_drawImage)(a,b,c,e,f,g);w._canvas_drawImageRect=(a,b,c,e,f,g)=>(w._canvas_drawImageRect=F.canvas_drawImageRect)(a,b,c,e,f,g);w._canvas_drawImageNine=(a,b,c,e,f,g)=>(w._canvas_drawImageNine=F.canvas_drawImageNine)(a,b,c,e,f,g);w._canvas_drawVertices=(a,b,c,e)=>(w._canvas_drawVertices=F.canvas_drawVertices)(a,b,c,e);
w._canvas_drawPoints=(a,b,c,e,f)=>(w._canvas_drawPoints=F.canvas_drawPoints)(a,b,c,e,f);w._canvas_drawAtlas=(a,b,c,e,f,g,k,n,r)=>(w._canvas_drawAtlas=F.canvas_drawAtlas)(a,b,c,e,f,g,k,n,r);w._canvas_getTransform=(a,b)=>(w._canvas_getTransform=F.canvas_getTransform)(a,b);w._canvas_getLocalClipBounds=(a,b)=>(w._canvas_getLocalClipBounds=F.canvas_getLocalClipBounds)(a,b);w._canvas_getDeviceClipBounds=(a,b)=>(w._canvas_getDeviceClipBounds=F.canvas_getDeviceClipBounds)(a,b);
w._contourMeasureIter_create=(a,b,c)=>(w._contourMeasureIter_create=F.contourMeasureIter_create)(a,b,c);w._contourMeasureIter_next=a=>(w._contourMeasureIter_next=F.contourMeasureIter_next)(a);w._contourMeasureIter_dispose=a=>(w._contourMeasureIter_dispose=F.contourMeasureIter_dispose)(a);w._contourMeasure_dispose=a=>(w._contourMeasure_dispose=F.contourMeasure_dispose)(a);w._contourMeasure_length=a=>(w._contourMeasure_length=F.contourMeasure_length)(a);
w._contourMeasure_isClosed=a=>(w._contourMeasure_isClosed=F.contourMeasure_isClosed)(a);w._contourMeasure_getPosTan=(a,b,c,e)=>(w._contourMeasure_getPosTan=F.contourMeasure_getPosTan)(a,b,c,e);w._contourMeasure_getSegment=(a,b,c,e)=>(w._contourMeasure_getSegment=F.contourMeasure_getSegment)(a,b,c,e);w._skData_create=a=>(w._skData_create=F.skData_create)(a);w._skData_getPointer=a=>(w._skData_getPointer=F.skData_getPointer)(a);w._skData_getConstPointer=a=>(w._skData_getConstPointer=F.skData_getConstPointer)(a);
w._skData_getSize=a=>(w._skData_getSize=F.skData_getSize)(a);w._skData_dispose=a=>(w._skData_dispose=F.skData_dispose)(a);w._imageFilter_createBlur=(a,b,c)=>(w._imageFilter_createBlur=F.imageFilter_createBlur)(a,b,c);w._imageFilter_createDilate=(a,b)=>(w._imageFilter_createDilate=F.imageFilter_createDilate)(a,b);w._imageFilter_createErode=(a,b)=>(w._imageFilter_createErode=F.imageFilter_createErode)(a,b);
w._imageFilter_createMatrix=(a,b)=>(w._imageFilter_createMatrix=F.imageFilter_createMatrix)(a,b);w._imageFilter_createFromColorFilter=a=>(w._imageFilter_createFromColorFilter=F.imageFilter_createFromColorFilter)(a);w._imageFilter_compose=(a,b)=>(w._imageFilter_compose=F.imageFilter_compose)(a,b);w._imageFilter_dispose=a=>(w._imageFilter_dispose=F.imageFilter_dispose)(a);w._imageFilter_getFilterBounds=(a,b)=>(w._imageFilter_getFilterBounds=F.imageFilter_getFilterBounds)(a,b);
w._colorFilter_createMode=(a,b)=>(w._colorFilter_createMode=F.colorFilter_createMode)(a,b);w._colorFilter_createMatrix=a=>(w._colorFilter_createMatrix=F.colorFilter_createMatrix)(a);w._colorFilter_createSRGBToLinearGamma=()=>(w._colorFilter_createSRGBToLinearGamma=F.colorFilter_createSRGBToLinearGamma)();w._colorFilter_createLinearToSRGBGamma=()=>(w._colorFilter_createLinearToSRGBGamma=F.colorFilter_createLinearToSRGBGamma)();
w._colorFilter_compose=(a,b)=>(w._colorFilter_compose=F.colorFilter_compose)(a,b);w._colorFilter_dispose=a=>(w._colorFilter_dispose=F.colorFilter_dispose)(a);w._maskFilter_createBlur=(a,b)=>(w._maskFilter_createBlur=F.maskFilter_createBlur)(a,b);w._maskFilter_dispose=a=>(w._maskFilter_dispose=F.maskFilter_dispose)(a);w._fontCollection_create=()=>(w._fontCollection_create=F.fontCollection_create)();w._fontCollection_dispose=a=>(w._fontCollection_dispose=F.fontCollection_dispose)(a);
w._typeface_create=a=>(w._typeface_create=F.typeface_create)(a);w._typeface_dispose=a=>(w._typeface_dispose=F.typeface_dispose)(a);w._typefaces_filterCoveredCodePoints=(a,b,c,e)=>(w._typefaces_filterCoveredCodePoints=F.typefaces_filterCoveredCodePoints)(a,b,c,e);w._fontCollection_registerTypeface=(a,b,c)=>(w._fontCollection_registerTypeface=F.fontCollection_registerTypeface)(a,b,c);w._fontCollection_clearCaches=a=>(w._fontCollection_clearCaches=F.fontCollection_clearCaches)(a);
w._image_createFromPicture=(a,b,c)=>(w._image_createFromPicture=F.image_createFromPicture)(a,b,c);w._image_createFromPixels=(a,b,c,e,f)=>(w._image_createFromPixels=F.image_createFromPixels)(a,b,c,e,f);w._image_createFromTextureSource=(a,b,c,e)=>(w._image_createFromTextureSource=F.image_createFromTextureSource)(a,b,c,e);w._image_ref=a=>(w._image_ref=F.image_ref)(a);w._image_dispose=a=>(w._image_dispose=F.image_dispose)(a);w._image_getWidth=a=>(w._image_getWidth=F.image_getWidth)(a);
w._image_getHeight=a=>(w._image_getHeight=F.image_getHeight)(a);w._paint_create=()=>(w._paint_create=F.paint_create)();w._paint_dispose=a=>(w._paint_dispose=F.paint_dispose)(a);w._paint_setBlendMode=(a,b)=>(w._paint_setBlendMode=F.paint_setBlendMode)(a,b);w._paint_setStyle=(a,b)=>(w._paint_setStyle=F.paint_setStyle)(a,b);w._paint_getStyle=a=>(w._paint_getStyle=F.paint_getStyle)(a);w._paint_setStrokeWidth=(a,b)=>(w._paint_setStrokeWidth=F.paint_setStrokeWidth)(a,b);
w._paint_getStrokeWidth=a=>(w._paint_getStrokeWidth=F.paint_getStrokeWidth)(a);w._paint_setStrokeCap=(a,b)=>(w._paint_setStrokeCap=F.paint_setStrokeCap)(a,b);w._paint_getStrokeCap=a=>(w._paint_getStrokeCap=F.paint_getStrokeCap)(a);w._paint_setStrokeJoin=(a,b)=>(w._paint_setStrokeJoin=F.paint_setStrokeJoin)(a,b);w._paint_getStrokeJoin=a=>(w._paint_getStrokeJoin=F.paint_getStrokeJoin)(a);w._paint_setAntiAlias=(a,b)=>(w._paint_setAntiAlias=F.paint_setAntiAlias)(a,b);
w._paint_getAntiAlias=a=>(w._paint_getAntiAlias=F.paint_getAntiAlias)(a);w._paint_setColorInt=(a,b)=>(w._paint_setColorInt=F.paint_setColorInt)(a,b);w._paint_getColorInt=a=>(w._paint_getColorInt=F.paint_getColorInt)(a);w._paint_setMiterLimit=(a,b)=>(w._paint_setMiterLimit=F.paint_setMiterLimit)(a,b);w._paint_getMiterLimit=a=>(w._paint_getMiterLimit=F.paint_getMiterLimit)(a);w._paint_setShader=(a,b)=>(w._paint_setShader=F.paint_setShader)(a,b);
w._paint_setImageFilter=(a,b)=>(w._paint_setImageFilter=F.paint_setImageFilter)(a,b);w._paint_setColorFilter=(a,b)=>(w._paint_setColorFilter=F.paint_setColorFilter)(a,b);w._paint_setMaskFilter=(a,b)=>(w._paint_setMaskFilter=F.paint_setMaskFilter)(a,b);w._path_create=()=>(w._path_create=F.path_create)();w._path_dispose=a=>(w._path_dispose=F.path_dispose)(a);w._path_copy=a=>(w._path_copy=F.path_copy)(a);w._path_setFillType=(a,b)=>(w._path_setFillType=F.path_setFillType)(a,b);
w._path_getFillType=a=>(w._path_getFillType=F.path_getFillType)(a);w._path_moveTo=(a,b,c)=>(w._path_moveTo=F.path_moveTo)(a,b,c);w._path_relativeMoveTo=(a,b,c)=>(w._path_relativeMoveTo=F.path_relativeMoveTo)(a,b,c);w._path_lineTo=(a,b,c)=>(w._path_lineTo=F.path_lineTo)(a,b,c);w._path_relativeLineTo=(a,b,c)=>(w._path_relativeLineTo=F.path_relativeLineTo)(a,b,c);w._path_quadraticBezierTo=(a,b,c,e,f)=>(w._path_quadraticBezierTo=F.path_quadraticBezierTo)(a,b,c,e,f);
w._path_relativeQuadraticBezierTo=(a,b,c,e,f)=>(w._path_relativeQuadraticBezierTo=F.path_relativeQuadraticBezierTo)(a,b,c,e,f);w._path_cubicTo=(a,b,c,e,f,g,k)=>(w._path_cubicTo=F.path_cubicTo)(a,b,c,e,f,g,k);w._path_relativeCubicTo=(a,b,c,e,f,g,k)=>(w._path_relativeCubicTo=F.path_relativeCubicTo)(a,b,c,e,f,g,k);w._path_conicTo=(a,b,c,e,f,g)=>(w._path_conicTo=F.path_conicTo)(a,b,c,e,f,g);w._path_relativeConicTo=(a,b,c,e,f,g)=>(w._path_relativeConicTo=F.path_relativeConicTo)(a,b,c,e,f,g);
w._path_arcToOval=(a,b,c,e,f)=>(w._path_arcToOval=F.path_arcToOval)(a,b,c,e,f);w._path_arcToRotated=(a,b,c,e,f,g,k,n)=>(w._path_arcToRotated=F.path_arcToRotated)(a,b,c,e,f,g,k,n);w._path_relativeArcToRotated=(a,b,c,e,f,g,k,n)=>(w._path_relativeArcToRotated=F.path_relativeArcToRotated)(a,b,c,e,f,g,k,n);w._path_addRect=(a,b)=>(w._path_addRect=F.path_addRect)(a,b);w._path_addOval=(a,b)=>(w._path_addOval=F.path_addOval)(a,b);w._path_addArc=(a,b,c,e)=>(w._path_addArc=F.path_addArc)(a,b,c,e);
w._path_addPolygon=(a,b,c,e)=>(w._path_addPolygon=F.path_addPolygon)(a,b,c,e);w._path_addRRect=(a,b)=>(w._path_addRRect=F.path_addRRect)(a,b);w._path_addPath=(a,b,c,e)=>(w._path_addPath=F.path_addPath)(a,b,c,e);w._path_close=a=>(w._path_close=F.path_close)(a);w._path_reset=a=>(w._path_reset=F.path_reset)(a);w._path_contains=(a,b,c)=>(w._path_contains=F.path_contains)(a,b,c);w._path_transform=(a,b)=>(w._path_transform=F.path_transform)(a,b);
w._path_getBounds=(a,b)=>(w._path_getBounds=F.path_getBounds)(a,b);w._path_combine=(a,b,c)=>(w._path_combine=F.path_combine)(a,b,c);w._pictureRecorder_create=()=>(w._pictureRecorder_create=F.pictureRecorder_create)();w._pictureRecorder_dispose=a=>(w._pictureRecorder_dispose=F.pictureRecorder_dispose)(a);w._pictureRecorder_beginRecording=(a,b)=>(w._pictureRecorder_beginRecording=F.pictureRecorder_beginRecording)(a,b);w._pictureRecorder_endRecording=a=>(w._pictureRecorder_endRecording=F.pictureRecorder_endRecording)(a);
w._picture_getCullRect=(a,b)=>(w._picture_getCullRect=F.picture_getCullRect)(a,b);w._picture_dispose=a=>(w._picture_dispose=F.picture_dispose)(a);w._picture_approximateBytesUsed=a=>(w._picture_approximateBytesUsed=F.picture_approximateBytesUsed)(a);w._shader_createLinearGradient=(a,b,c,e,f,g)=>(w._shader_createLinearGradient=F.shader_createLinearGradient)(a,b,c,e,f,g);w._shader_createRadialGradient=(a,b,c,e,f,g,k,n)=>(w._shader_createRadialGradient=F.shader_createRadialGradient)(a,b,c,e,f,g,k,n);
w._shader_createConicalGradient=(a,b,c,e,f,g,k,n)=>(w._shader_createConicalGradient=F.shader_createConicalGradient)(a,b,c,e,f,g,k,n);w._shader_createSweepGradient=(a,b,c,e,f,g,k,n,r)=>(w._shader_createSweepGradient=F.shader_createSweepGradient)(a,b,c,e,f,g,k,n,r);w._shader_dispose=a=>(w._shader_dispose=F.shader_dispose)(a);w._runtimeEffect_create=a=>(w._runtimeEffect_create=F.runtimeEffect_create)(a);w._runtimeEffect_dispose=a=>(w._runtimeEffect_dispose=F.runtimeEffect_dispose)(a);
w._runtimeEffect_getUniformSize=a=>(w._runtimeEffect_getUniformSize=F.runtimeEffect_getUniformSize)(a);w._shader_createRuntimeEffectShader=(a,b,c,e)=>(w._shader_createRuntimeEffectShader=F.shader_createRuntimeEffectShader)(a,b,c,e);w._shader_createFromImage=(a,b,c,e,f)=>(w._shader_createFromImage=F.shader_createFromImage)(a,b,c,e,f);w._skString_allocate=a=>(w._skString_allocate=F.skString_allocate)(a);w._skString_getData=a=>(w._skString_getData=F.skString_getData)(a);
w._skString_free=a=>(w._skString_free=F.skString_free)(a);w._skString16_allocate=a=>(w._skString16_allocate=F.skString16_allocate)(a);w._skString16_getData=a=>(w._skString16_getData=F.skString16_getData)(a);w._skString16_free=a=>(w._skString16_free=F.skString16_free)(a);w._surface_create=()=>(w._surface_create=F.surface_create)();w._surface_getThreadId=a=>(w._surface_getThreadId=F.surface_getThreadId)(a);
w._surface_setCallbackHandler=(a,b)=>(w._surface_setCallbackHandler=F.surface_setCallbackHandler)(a,b);w._surface_destroy=a=>(w._surface_destroy=F.surface_destroy)(a);var hd=w._surface_dispose=a=>(hd=w._surface_dispose=F.surface_dispose)(a);w._surface_renderPictures=(a,b,c)=>(w._surface_renderPictures=F.surface_renderPictures)(a,b,c);var fd=w._surface_renderPicturesOnWorker=(a,b,c,e,f)=>(fd=w._surface_renderPicturesOnWorker=F.surface_renderPicturesOnWorker)(a,b,c,e,f);
w._surface_rasterizeImage=(a,b,c)=>(w._surface_rasterizeImage=F.surface_rasterizeImage)(a,b,c);var jd=w._surface_rasterizeImageOnWorker=(a,b,c,e)=>(jd=w._surface_rasterizeImageOnWorker=F.surface_rasterizeImageOnWorker)(a,b,c,e),gd=w._surface_onRenderComplete=(a,b,c)=>(gd=w._surface_onRenderComplete=F.surface_onRenderComplete)(a,b,c),kd=w._surface_onRasterizeComplete=(a,b,c)=>(kd=w._surface_onRasterizeComplete=F.surface_onRasterizeComplete)(a,b,c);
w._lineMetrics_create=(a,b,c,e,f,g,k,n,r)=>(w._lineMetrics_create=F.lineMetrics_create)(a,b,c,e,f,g,k,n,r);w._lineMetrics_dispose=a=>(w._lineMetrics_dispose=F.lineMetrics_dispose)(a);w._lineMetrics_getHardBreak=a=>(w._lineMetrics_getHardBreak=F.lineMetrics_getHardBreak)(a);w._lineMetrics_getAscent=a=>(w._lineMetrics_getAscent=F.lineMetrics_getAscent)(a);w._lineMetrics_getDescent=a=>(w._lineMetrics_getDescent=F.lineMetrics_getDescent)(a);
w._lineMetrics_getUnscaledAscent=a=>(w._lineMetrics_getUnscaledAscent=F.lineMetrics_getUnscaledAscent)(a);w._lineMetrics_getHeight=a=>(w._lineMetrics_getHeight=F.lineMetrics_getHeight)(a);w._lineMetrics_getWidth=a=>(w._lineMetrics_getWidth=F.lineMetrics_getWidth)(a);w._lineMetrics_getLeft=a=>(w._lineMetrics_getLeft=F.lineMetrics_getLeft)(a);w._lineMetrics_getBaseline=a=>(w._lineMetrics_getBaseline=F.lineMetrics_getBaseline)(a);w._lineMetrics_getLineNumber=a=>(w._lineMetrics_getLineNumber=F.lineMetrics_getLineNumber)(a);
w._lineMetrics_getStartIndex=a=>(w._lineMetrics_getStartIndex=F.lineMetrics_getStartIndex)(a);w._lineMetrics_getEndIndex=a=>(w._lineMetrics_getEndIndex=F.lineMetrics_getEndIndex)(a);w._paragraph_dispose=a=>(w._paragraph_dispose=F.paragraph_dispose)(a);w._paragraph_getWidth=a=>(w._paragraph_getWidth=F.paragraph_getWidth)(a);w._paragraph_getHeight=a=>(w._paragraph_getHeight=F.paragraph_getHeight)(a);w._paragraph_getLongestLine=a=>(w._paragraph_getLongestLine=F.paragraph_getLongestLine)(a);
w._paragraph_getMinIntrinsicWidth=a=>(w._paragraph_getMinIntrinsicWidth=F.paragraph_getMinIntrinsicWidth)(a);w._paragraph_getMaxIntrinsicWidth=a=>(w._paragraph_getMaxIntrinsicWidth=F.paragraph_getMaxIntrinsicWidth)(a);w._paragraph_getAlphabeticBaseline=a=>(w._paragraph_getAlphabeticBaseline=F.paragraph_getAlphabeticBaseline)(a);w._paragraph_getIdeographicBaseline=a=>(w._paragraph_getIdeographicBaseline=F.paragraph_getIdeographicBaseline)(a);
w._paragraph_getDidExceedMaxLines=a=>(w._paragraph_getDidExceedMaxLines=F.paragraph_getDidExceedMaxLines)(a);w._paragraph_layout=(a,b)=>(w._paragraph_layout=F.paragraph_layout)(a,b);w._paragraph_getPositionForOffset=(a,b,c,e)=>(w._paragraph_getPositionForOffset=F.paragraph_getPositionForOffset)(a,b,c,e);w._paragraph_getClosestGlyphInfoAtCoordinate=(a,b,c,e,f,g)=>(w._paragraph_getClosestGlyphInfoAtCoordinate=F.paragraph_getClosestGlyphInfoAtCoordinate)(a,b,c,e,f,g);
w._paragraph_getGlyphInfoAt=(a,b,c,e,f)=>(w._paragraph_getGlyphInfoAt=F.paragraph_getGlyphInfoAt)(a,b,c,e,f);w._paragraph_getWordBoundary=(a,b,c)=>(w._paragraph_getWordBoundary=F.paragraph_getWordBoundary)(a,b,c);w._paragraph_getLineCount=a=>(w._paragraph_getLineCount=F.paragraph_getLineCount)(a);w._paragraph_getLineNumberAt=(a,b)=>(w._paragraph_getLineNumberAt=F.paragraph_getLineNumberAt)(a,b);
w._paragraph_getLineMetricsAtIndex=(a,b)=>(w._paragraph_getLineMetricsAtIndex=F.paragraph_getLineMetricsAtIndex)(a,b);w._textBoxList_dispose=a=>(w._textBoxList_dispose=F.textBoxList_dispose)(a);w._textBoxList_getLength=a=>(w._textBoxList_getLength=F.textBoxList_getLength)(a);w._textBoxList_getBoxAtIndex=(a,b,c)=>(w._textBoxList_getBoxAtIndex=F.textBoxList_getBoxAtIndex)(a,b,c);w._paragraph_getBoxesForRange=(a,b,c,e,f)=>(w._paragraph_getBoxesForRange=F.paragraph_getBoxesForRange)(a,b,c,e,f);
w._paragraph_getBoxesForPlaceholders=a=>(w._paragraph_getBoxesForPlaceholders=F.paragraph_getBoxesForPlaceholders)(a);w._paragraph_getUnresolvedCodePoints=(a,b,c)=>(w._paragraph_getUnresolvedCodePoints=F.paragraph_getUnresolvedCodePoints)(a,b,c);w._paragraphBuilder_create=(a,b)=>(w._paragraphBuilder_create=F.paragraphBuilder_create)(a,b);w._paragraphBuilder_dispose=a=>(w._paragraphBuilder_dispose=F.paragraphBuilder_dispose)(a);
w._paragraphBuilder_addPlaceholder=(a,b,c,e,f,g)=>(w._paragraphBuilder_addPlaceholder=F.paragraphBuilder_addPlaceholder)(a,b,c,e,f,g);w._paragraphBuilder_addText=(a,b)=>(w._paragraphBuilder_addText=F.paragraphBuilder_addText)(a,b);w._paragraphBuilder_getUtf8Text=(a,b)=>(w._paragraphBuilder_getUtf8Text=F.paragraphBuilder_getUtf8Text)(a,b);w._paragraphBuilder_pushStyle=(a,b)=>(w._paragraphBuilder_pushStyle=F.paragraphBuilder_pushStyle)(a,b);w._paragraphBuilder_pop=a=>(w._paragraphBuilder_pop=F.paragraphBuilder_pop)(a);
w._paragraphBuilder_build=a=>(w._paragraphBuilder_build=F.paragraphBuilder_build)(a);w._unicodePositionBuffer_create=a=>(w._unicodePositionBuffer_create=F.unicodePositionBuffer_create)(a);w._unicodePositionBuffer_getDataPointer=a=>(w._unicodePositionBuffer_getDataPointer=F.unicodePositionBuffer_getDataPointer)(a);w._unicodePositionBuffer_free=a=>(w._unicodePositionBuffer_free=F.unicodePositionBuffer_free)(a);w._lineBreakBuffer_create=a=>(w._lineBreakBuffer_create=F.lineBreakBuffer_create)(a);
w._lineBreakBuffer_getDataPointer=a=>(w._lineBreakBuffer_getDataPointer=F.lineBreakBuffer_getDataPointer)(a);w._lineBreakBuffer_free=a=>(w._lineBreakBuffer_free=F.lineBreakBuffer_free)(a);w._paragraphBuilder_setGraphemeBreaksUtf16=(a,b)=>(w._paragraphBuilder_setGraphemeBreaksUtf16=F.paragraphBuilder_setGraphemeBreaksUtf16)(a,b);w._paragraphBuilder_setWordBreaksUtf16=(a,b)=>(w._paragraphBuilder_setWordBreaksUtf16=F.paragraphBuilder_setWordBreaksUtf16)(a,b);
w._paragraphBuilder_setLineBreaksUtf16=(a,b)=>(w._paragraphBuilder_setLineBreaksUtf16=F.paragraphBuilder_setLineBreaksUtf16)(a,b);w._paragraphStyle_create=()=>(w._paragraphStyle_create=F.paragraphStyle_create)();w._paragraphStyle_dispose=a=>(w._paragraphStyle_dispose=F.paragraphStyle_dispose)(a);w._paragraphStyle_setTextAlign=(a,b)=>(w._paragraphStyle_setTextAlign=F.paragraphStyle_setTextAlign)(a,b);
w._paragraphStyle_setTextDirection=(a,b)=>(w._paragraphStyle_setTextDirection=F.paragraphStyle_setTextDirection)(a,b);w._paragraphStyle_setMaxLines=(a,b)=>(w._paragraphStyle_setMaxLines=F.paragraphStyle_setMaxLines)(a,b);w._paragraphStyle_setHeight=(a,b)=>(w._paragraphStyle_setHeight=F.paragraphStyle_setHeight)(a,b);w._paragraphStyle_setTextHeightBehavior=(a,b,c)=>(w._paragraphStyle_setTextHeightBehavior=F.paragraphStyle_setTextHeightBehavior)(a,b,c);
w._paragraphStyle_setEllipsis=(a,b)=>(w._paragraphStyle_setEllipsis=F.paragraphStyle_setEllipsis)(a,b);w._paragraphStyle_setStrutStyle=(a,b)=>(w._paragraphStyle_setStrutStyle=F.paragraphStyle_setStrutStyle)(a,b);w._paragraphStyle_setTextStyle=(a,b)=>(w._paragraphStyle_setTextStyle=F.paragraphStyle_setTextStyle)(a,b);w._paragraphStyle_setApplyRoundingHack=(a,b)=>(w._paragraphStyle_setApplyRoundingHack=F.paragraphStyle_setApplyRoundingHack)(a,b);w._strutStyle_create=()=>(w._strutStyle_create=F.strutStyle_create)();
w._strutStyle_dispose=a=>(w._strutStyle_dispose=F.strutStyle_dispose)(a);w._strutStyle_setFontFamilies=(a,b,c)=>(w._strutStyle_setFontFamilies=F.strutStyle_setFontFamilies)(a,b,c);w._strutStyle_setFontSize=(a,b)=>(w._strutStyle_setFontSize=F.strutStyle_setFontSize)(a,b);w._strutStyle_setHeight=(a,b)=>(w._strutStyle_setHeight=F.strutStyle_setHeight)(a,b);w._strutStyle_setHalfLeading=(a,b)=>(w._strutStyle_setHalfLeading=F.strutStyle_setHalfLeading)(a,b);
w._strutStyle_setLeading=(a,b)=>(w._strutStyle_setLeading=F.strutStyle_setLeading)(a,b);w._strutStyle_setFontStyle=(a,b,c)=>(w._strutStyle_setFontStyle=F.strutStyle_setFontStyle)(a,b,c);w._strutStyle_setForceStrutHeight=(a,b)=>(w._strutStyle_setForceStrutHeight=F.strutStyle_setForceStrutHeight)(a,b);w._textStyle_create=()=>(w._textStyle_create=F.textStyle_create)();w._textStyle_copy=a=>(w._textStyle_copy=F.textStyle_copy)(a);w._textStyle_dispose=a=>(w._textStyle_dispose=F.textStyle_dispose)(a);
w._textStyle_setColor=(a,b)=>(w._textStyle_setColor=F.textStyle_setColor)(a,b);w._textStyle_setDecoration=(a,b)=>(w._textStyle_setDecoration=F.textStyle_setDecoration)(a,b);w._textStyle_setDecorationColor=(a,b)=>(w._textStyle_setDecorationColor=F.textStyle_setDecorationColor)(a,b);w._textStyle_setDecorationStyle=(a,b)=>(w._textStyle_setDecorationStyle=F.textStyle_setDecorationStyle)(a,b);
w._textStyle_setDecorationThickness=(a,b)=>(w._textStyle_setDecorationThickness=F.textStyle_setDecorationThickness)(a,b);w._textStyle_setFontStyle=(a,b,c)=>(w._textStyle_setFontStyle=F.textStyle_setFontStyle)(a,b,c);w._textStyle_setTextBaseline=(a,b)=>(w._textStyle_setTextBaseline=F.textStyle_setTextBaseline)(a,b);w._textStyle_clearFontFamilies=a=>(w._textStyle_clearFontFamilies=F.textStyle_clearFontFamilies)(a);
w._textStyle_addFontFamilies=(a,b,c)=>(w._textStyle_addFontFamilies=F.textStyle_addFontFamilies)(a,b,c);w._textStyle_setFontSize=(a,b)=>(w._textStyle_setFontSize=F.textStyle_setFontSize)(a,b);w._textStyle_setLetterSpacing=(a,b)=>(w._textStyle_setLetterSpacing=F.textStyle_setLetterSpacing)(a,b);w._textStyle_setWordSpacing=(a,b)=>(w._textStyle_setWordSpacing=F.textStyle_setWordSpacing)(a,b);w._textStyle_setHeight=(a,b)=>(w._textStyle_setHeight=F.textStyle_setHeight)(a,b);
w._textStyle_setHalfLeading=(a,b)=>(w._textStyle_setHalfLeading=F.textStyle_setHalfLeading)(a,b);w._textStyle_setLocale=(a,b)=>(w._textStyle_setLocale=F.textStyle_setLocale)(a,b);w._textStyle_setBackground=(a,b)=>(w._textStyle_setBackground=F.textStyle_setBackground)(a,b);w._textStyle_setForeground=(a,b)=>(w._textStyle_setForeground=F.textStyle_setForeground)(a,b);w._textStyle_addShadow=(a,b,c,e,f)=>(w._textStyle_addShadow=F.textStyle_addShadow)(a,b,c,e,f);
w._textStyle_addFontFeature=(a,b,c)=>(w._textStyle_addFontFeature=F.textStyle_addFontFeature)(a,b,c);w._textStyle_setFontVariations=(a,b,c,e)=>(w._textStyle_setFontVariations=F.textStyle_setFontVariations)(a,b,c,e);w._vertices_create=(a,b,c,e,f,g,k)=>(w._vertices_create=F.vertices_create)(a,b,c,e,f,g,k);w._vertices_dispose=a=>(w._vertices_dispose=F.vertices_dispose)(a);var eb=w._pthread_self=()=>(eb=w._pthread_self=F.pthread_self)(),ob=a=>(ob=F.malloc)(a);
w.__emscripten_tls_init=()=>(w.__emscripten_tls_init=F._emscripten_tls_init)();var md=w.__emscripten_thread_init=(a,b,c,e,f,g)=>(md=w.__emscripten_thread_init=F._emscripten_thread_init)(a,b,c,e,f,g);w.__emscripten_thread_crashed=()=>(w.__emscripten_thread_crashed=F._emscripten_thread_crashed)();
var mc=(a,b,c,e)=>(mc=F._emscripten_run_in_main_runtime_thread_js)(a,b,c,e),Cb=(a,b,c,e,f)=>(Cb=F.emscripten_dispatch_to_thread_)(a,b,c,e,f),cb=a=>(cb=F._emscripten_thread_free_data)(a),ib=w.__emscripten_thread_exit=a=>(ib=w.__emscripten_thread_exit=F._emscripten_thread_exit)(a),vb=w.__emscripten_check_mailbox=()=>(vb=w.__emscripten_check_mailbox=F._emscripten_check_mailbox)(),Z=(a,b)=>(Z=F.setThrew)(a,b),hb=(a,b)=>(hb=F.emscripten_stack_set_limits)(a,b),O=()=>(O=F.stackSave)(),N=a=>(N=F.stackRestore)(a),
Bb=w.stackAlloc=a=>(Bb=w.stackAlloc=F.stackAlloc)(a);function od(a,b,c){var e=O();try{return G.get(a)(b,c)}catch(f){N(e);if(f!==f+0)throw f;Z(1,0)}}function td(a,b,c){var e=O();try{G.get(a)(b,c)}catch(f){N(e);if(f!==f+0)throw f;Z(1,0)}}function nd(a,b){var c=O();try{return G.get(a)(b)}catch(e){N(c);if(e!==e+0)throw e;Z(1,0)}}function ud(a,b,c,e){var f=O();try{G.get(a)(b,c,e)}catch(g){N(f);if(g!==g+0)throw g;Z(1,0)}}
function pd(a,b,c,e){var f=O();try{return G.get(a)(b,c,e)}catch(g){N(f);if(g!==g+0)throw g;Z(1,0)}}function vd(a,b,c,e,f){var g=O();try{G.get(a)(b,c,e,f)}catch(k){N(g);if(k!==k+0)throw k;Z(1,0)}}function wd(a,b,c,e,f,g,k,n){var r=O();try{G.get(a)(b,c,e,f,g,k,n)}catch(u){N(r);if(u!==u+0)throw u;Z(1,0)}}function sd(a,b){var c=O();try{G.get(a)(b)}catch(e){N(c);if(e!==e+0)throw e;Z(1,0)}}function rd(a,b,c,e,f,g,k){var n=O();try{return G.get(a)(b,c,e,f,g,k)}catch(r){N(n);if(r!==r+0)throw r;Z(1,0)}}
function qd(a,b,c,e,f){var g=O();try{return G.get(a)(b,c,e,f)}catch(k){N(g);if(k!==k+0)throw k;Z(1,0)}}w.keepRuntimeAlive=Ka;w.wasmMemory=d;w.wasmExports=F;
w.addFunction=function(a,b){if(!bd){bd=new WeakMap;var c=G.length;if(bd)for(var e=0;e<0+c;e++){var f=G.get(e);f&&bd.set(f,e)}}if(c=bd.get(a)||0)return c;if(cd.length)c=cd.pop();else{try{G.grow(1)}catch(n){if(!(n instanceof RangeError))throw n;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}c=G.length-1}try{G.set(c,a)}catch(n){if(!(n instanceof TypeError))throw n;if("function"==typeof WebAssembly.Function){e=WebAssembly.Function;f={i:"i32",j:"i64",f:"f32",d:"f64",p:"i32"};for(var g={parameters:[],
results:"v"==b[0]?[]:[f[b[0]]]},k=1;k<b.length;++k)g.parameters.push(f[b[k]]);b=new e(g,a)}else{e=[1];f=b.slice(0,1);b=b.slice(1);g={i:127,p:127,j:126,f:125,d:124};e.push(96);k=b.length;128>k?e.push(k):e.push(k%128|128,k>>7);for(k=0;k<b.length;++k)e.push(g[b[k]]);"v"==f?e.push(0):e.push(1,g[f]);b=[0,97,115,109,1,0,0,0,1];f=e.length;128>f?b.push(f):b.push(f%128|128,f>>7);b.push.apply(b,e);b.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);b=new WebAssembly.Module(new Uint8Array(b));b=(new WebAssembly.Instance(b,
{e:{f:a}})).exports.f}G.set(c,b)}bd.set(a,c);return c};w.ExitStatus=Ua;w.PThread=J;var yd;Ma=function zd(){yd||Ad();yd||(Ma=zd)};
function Ad(){function a(){if(!yd&&(yd=!0,w.calledRun=!0,!Ba)){A||gb(Ha);ja(w);if(w.onRuntimeInitialized)w.onRuntimeInitialized();if(!A){if(w.postRun)for("function"==typeof w.postRun&&(w.postRun=[w.postRun]);w.postRun.length;){var b=w.postRun.shift();Ia.unshift(b)}gb(Ia)}}}if(!(0<H))if(A)ja(w),A||gb(Ha),startWorker(w);else{if(w.preRun)for("function"==typeof w.preRun&&(w.preRun=[w.preRun]);w.preRun.length;)Ga.unshift(w.preRun.shift());gb(Ga);0<H||(w.setStatus?(w.setStatus("Running..."),setTimeout(function(){setTimeout(function(){w.setStatus("")},
1);a()},1)):a())}}if(w.preInit)for("function"==typeof w.preInit&&(w.preInit=[w.preInit]);0<w.preInit.length;)w.preInit.pop()();Ad();
return moduleArg.ready
}
);
})();
export default skwasm;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./skwasm.js")).then(exports=>exports.default(Module))}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0,/*canBlock=*/1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

View File

@ -0,0 +1,4 @@
(()=>{var L=()=>navigator.vendor==="Google Inc."||navigator.agent==="Edg/",W=()=>typeof ImageDecoder>"u"?!1:L(),E=()=>typeof Intl.v8BreakIterator<"u"&&typeof Intl.Segmenter<"u",P=()=>{let s=[0,97,115,109,1,0,0,0,1,5,1,95,1,120,0];return WebAssembly.validate(new Uint8Array(s))},p={hasImageCodecs:W(),hasChromiumBreakIterators:E(),supportsWasmGC:P(),crossOriginIsolated:window.crossOriginIsolated};function u(...s){return new URL(S(...s),document.baseURI).toString()}function S(...s){return s.filter(t=>!!t).map((t,i)=>i===0?_(t):j(_(t))).filter(t=>t.length).join("/")}function j(s){let t=0;for(;t<s.length&&s.charAt(t)==="/";)t++;return s.substring(t)}function _(s){let t=s.length;for(;t>0&&s.charAt(t-1)==="/";)t--;return s.substring(0,t)}function b(s,t){return s.canvasKitBaseUrl?s.canvasKitBaseUrl:t.engineRevision&&!t.useLocalCanvasKit?S("https://www.gstatic.com/flutter-canvaskit",t.engineRevision):"canvaskit"}var h=class{constructor(){this._scriptLoaded=!1}setTrustedTypesPolicy(t){this._ttPolicy=t}async loadEntrypoint(t){let{entrypointUrl:i=u("main.dart.js"),onEntrypointLoaded:r,nonce:e}=t||{};return this._loadJSEntrypoint(i,r,e)}async load(t,i,r,e,n){n??=o=>{o.initializeEngine(r).then(l=>l.runApp())};let{entryPointBaseUrl:a}=r;if(t.compileTarget==="dart2wasm")return this._loadWasmEntrypoint(t,i,a,n);{let o=t.mainJsPath??"main.dart.js",l=u(a,o);return this._loadJSEntrypoint(l,n,e)}}didCreateEngineInitializer(t){typeof this._didCreateEngineInitializerResolve=="function"&&(this._didCreateEngineInitializerResolve(t),this._didCreateEngineInitializerResolve=null,delete _flutter.loader.didCreateEngineInitializer),typeof this._onEntrypointLoaded=="function"&&this._onEntrypointLoaded(t)}_loadJSEntrypoint(t,i,r){let e=typeof i=="function";if(!this._scriptLoaded){this._scriptLoaded=!0;let n=this._createScriptTag(t,r);if(e)console.debug("Injecting <script> tag. Using callback."),this._onEntrypointLoaded=i,document.head.append(n);else return new Promise((a,o)=>{console.debug("Injecting <script> tag. Using Promises. Use the callback approach instead!"),this._didCreateEngineInitializerResolve=a,n.addEventListener("error",o),document.head.append(n)})}}async _loadWasmEntrypoint(t,i,r,e){if(!this._scriptLoaded){this._scriptLoaded=!0,this._onEntrypointLoaded=e;let{mainWasmPath:n,jsSupportRuntimePath:a}=t,o=u(r,n),l=u(r,a);this._ttPolicy!=null&&(l=this._ttPolicy.createScriptURL(l));let m=WebAssembly.compileStreaming(fetch(o)),c=await import(l),w;t.renderer==="skwasm"?w=(async()=>{let d=await i.skwasm;return window._flutter_skwasmInstance=d,{skwasm:d.wasmExports,skwasmWrapper:d,ffi:{memory:d.wasmMemory}}})():w={};let f=await c.instantiate(m,w);await c.invoke(f)}}_createScriptTag(t,i){let r=document.createElement("script");r.type="application/javascript",i&&(r.nonce=i);let e=t;return this._ttPolicy!=null&&(e=this._ttPolicy.createScriptURL(t)),r.src=e,r}};async function T(s,t,i){if(t<0)return s;let r,e=new Promise((n,a)=>{r=setTimeout(()=>{a(new Error(`${i} took more than ${t}ms to resolve. Moving on.`,{cause:T}))},t)});return Promise.race([s,e]).finally(()=>{clearTimeout(r)})}var v=class{setTrustedTypesPolicy(t){this._ttPolicy=t}loadServiceWorker(t){if(!t)return console.debug("Null serviceWorker configuration. Skipping."),Promise.resolve();if(!("serviceWorker"in navigator)){let o="Service Worker API unavailable.";return window.isSecureContext||(o+=`
The current context is NOT secure.`,o+=`
Read more: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts`),Promise.reject(new Error(o))}let{serviceWorkerVersion:i,serviceWorkerUrl:r=u(`flutter_service_worker.js?v=${i}`),timeoutMillis:e=4e3}=t,n=r;this._ttPolicy!=null&&(n=this._ttPolicy.createScriptURL(n));let a=navigator.serviceWorker.register(n).then(o=>this._getNewServiceWorker(o,i)).then(this._waitForServiceWorkerActivation);return T(a,e,"prepareServiceWorker")}async _getNewServiceWorker(t,i){if(!t.active&&(t.installing||t.waiting))return console.debug("Installing/Activating first service worker."),t.installing||t.waiting;if(t.active.scriptURL.endsWith(i))return console.debug("Loading from existing service worker."),t.active;{let r=await t.update();return console.debug("Updating service worker."),r.installing||r.waiting||r.active}}async _waitForServiceWorkerActivation(t){if(!t||t.state==="activated")if(t){console.debug("Service worker already active.");return}else throw new Error("Cannot activate a null service worker!");return new Promise((i,r)=>{t.addEventListener("statechange",()=>{t.state==="activated"&&(console.debug("Activated new service worker."),i())})})}};var y=class{constructor(t,i="flutter-js"){let r=t||[/\.js$/,/\.mjs$/];window.trustedTypes&&(this.policy=trustedTypes.createPolicy(i,{createScriptURL:function(e){if(e.startsWith("blob:"))return e;let n=new URL(e,window.location),a=n.pathname.split("/").pop();if(r.some(l=>l.test(a)))return n.toString();console.error("URL rejected by TrustedTypes policy",i,":",e,"(download prevented)")}}))}};var g=s=>{let t=WebAssembly.compileStreaming(fetch(s));return(i,r)=>((async()=>{let e=await t,n=await WebAssembly.instantiate(e,i);r(n,e)})(),{})};var I=(s,t,i,r)=>(window.flutterCanvasKitLoaded=(async()=>{if(window.flutterCanvasKit)return window.flutterCanvasKit;let e=i.hasChromiumBreakIterators&&i.hasImageCodecs;if(!e&&t.canvasKitVariant=="chromium")throw"Chromium CanvasKit variant specifically requested, but unsupported in this browser";let n=e&&t.canvasKitVariant!=="full",a=r;n&&(a=u(a,"chromium"));let o=u(a,"canvaskit.js");s.flutterTT.policy&&(o=s.flutterTT.policy.createScriptURL(o));let l=g(u(a,"canvaskit.wasm")),m=await import(o);return window.flutterCanvasKit=await m.default({instantiateWasm:l}),window.flutterCanvasKit})(),window.flutterCanvasKitLoaded);var U=async(s,t,i,r)=>{let e=u(r,"skwasm.js"),n=e;s.flutterTT.policy&&(n=s.flutterTT.policy.createScriptURL(n));let a=g(u(r,"skwasm.wasm"));return await(await import(n)).default({instantiateWasm:a,locateFile:(l,m)=>{let c=m+l;return c.endsWith(".worker.js")?URL.createObjectURL(new Blob([`importScripts('${c}');`],{type:"application/javascript"})):c},mainScriptUrlOrBlob:e})};var k=class{async loadEntrypoint(t){let{serviceWorker:i,...r}=t||{},e=new y,n=new v;n.setTrustedTypesPolicy(e.policy),await n.loadServiceWorker(i).catch(o=>{console.warn("Exception while loading service worker:",o)});let a=new h;return a.setTrustedTypesPolicy(e.policy),this.didCreateEngineInitializer=a.didCreateEngineInitializer.bind(a),a.loadEntrypoint(r)}async load({serviceWorkerSettings:t,onEntrypointLoaded:i,nonce:r,config:e}={}){e??={};let n=_flutter.buildConfig;if(!n)throw"FlutterLoader.load requires _flutter.buildConfig to be set";let a=d=>{switch(d){case"skwasm":return p.crossOriginIsolated&&p.hasChromiumBreakIterators&&p.hasImageCodecs&&p.supportsWasmGC;default:return!0}},o=(d,C)=>{switch(d.renderer){case"auto":return C=="canvaskit"||C=="html";default:return d.renderer==C}},l=d=>d.compileTarget==="dart2wasm"&&!p.supportsWasmGC||e.renderer&&!o(d,e.renderer)?!1:a(d.renderer),m=n.builds.find(l);if(!m)throw"FlutterLoader could not find a build compatible with configuration and environment.";let c={};c.flutterTT=new y,t&&(c.serviceWorkerLoader=new v,c.serviceWorkerLoader.setTrustedTypesPolicy(c.flutterTT.policy),await c.serviceWorkerLoader.loadServiceWorker(t).catch(d=>{console.warn("Exception while loading service worker:",d)}));let w=b(e,n);m.renderer==="canvaskit"?c.canvasKit=I(c,e,p,w):m.renderer==="skwasm"&&(c.skwasm=U(c,e,p,w));let f=new h;return f.setTrustedTypesPolicy(c.flutterTT.policy),this.didCreateEngineInitializer=f.didCreateEngineInitializer.bind(f),f.load(m,c,e,r,i)}};window._flutter||(window._flutter={});window._flutter.loader||(window._flutter.loader=new k);})();
//# sourceMappingURL=flutter.js.map

View File

@ -0,0 +1,16 @@
(()=>{var L=()=>navigator.vendor==="Google Inc."||navigator.agent==="Edg/",W=()=>typeof ImageDecoder>"u"?!1:L(),E=()=>typeof Intl.v8BreakIterator<"u"&&typeof Intl.Segmenter<"u",P=()=>{let s=[0,97,115,109,1,0,0,0,1,5,1,95,1,120,0];return WebAssembly.validate(new Uint8Array(s))},p={hasImageCodecs:W(),hasChromiumBreakIterators:E(),supportsWasmGC:P(),crossOriginIsolated:window.crossOriginIsolated};function u(...s){return new URL(S(...s),document.baseURI).toString()}function S(...s){return s.filter(t=>!!t).map((t,i)=>i===0?_(t):j(_(t))).filter(t=>t.length).join("/")}function j(s){let t=0;for(;t<s.length&&s.charAt(t)==="/";)t++;return s.substring(t)}function _(s){let t=s.length;for(;t>0&&s.charAt(t-1)==="/";)t--;return s.substring(0,t)}function b(s,t){return s.canvasKitBaseUrl?s.canvasKitBaseUrl:t.engineRevision&&!t.useLocalCanvasKit?S("https://www.gstatic.com/flutter-canvaskit",t.engineRevision):"canvaskit"}var h=class{constructor(){this._scriptLoaded=!1}setTrustedTypesPolicy(t){this._ttPolicy=t}async loadEntrypoint(t){let{entrypointUrl:i=u("main.dart.js"),onEntrypointLoaded:r,nonce:e}=t||{};return this._loadJSEntrypoint(i,r,e)}async load(t,i,r,e,n){n??=o=>{o.initializeEngine(r).then(l=>l.runApp())};let{entryPointBaseUrl:a}=r;if(t.compileTarget==="dart2wasm")return this._loadWasmEntrypoint(t,i,a,n);{let o=t.mainJsPath??"main.dart.js",l=u(a,o);return this._loadJSEntrypoint(l,n,e)}}didCreateEngineInitializer(t){typeof this._didCreateEngineInitializerResolve=="function"&&(this._didCreateEngineInitializerResolve(t),this._didCreateEngineInitializerResolve=null,delete _flutter.loader.didCreateEngineInitializer),typeof this._onEntrypointLoaded=="function"&&this._onEntrypointLoaded(t)}_loadJSEntrypoint(t,i,r){let e=typeof i=="function";if(!this._scriptLoaded){this._scriptLoaded=!0;let n=this._createScriptTag(t,r);if(e)console.debug("Injecting <script> tag. Using callback."),this._onEntrypointLoaded=i,document.head.append(n);else return new Promise((a,o)=>{console.debug("Injecting <script> tag. Using Promises. Use the callback approach instead!"),this._didCreateEngineInitializerResolve=a,n.addEventListener("error",o),document.head.append(n)})}}async _loadWasmEntrypoint(t,i,r,e){if(!this._scriptLoaded){this._scriptLoaded=!0,this._onEntrypointLoaded=e;let{mainWasmPath:n,jsSupportRuntimePath:a}=t,o=u(r,n),l=u(r,a);this._ttPolicy!=null&&(l=this._ttPolicy.createScriptURL(l));let m=WebAssembly.compileStreaming(fetch(o)),c=await import(l),w;t.renderer==="skwasm"?w=(async()=>{let d=await i.skwasm;return window._flutter_skwasmInstance=d,{skwasm:d.wasmExports,skwasmWrapper:d,ffi:{memory:d.wasmMemory}}})():w={};let f=await c.instantiate(m,w);await c.invoke(f)}}_createScriptTag(t,i){let r=document.createElement("script");r.type="application/javascript",i&&(r.nonce=i);let e=t;return this._ttPolicy!=null&&(e=this._ttPolicy.createScriptURL(t)),r.src=e,r}};async function T(s,t,i){if(t<0)return s;let r,e=new Promise((n,a)=>{r=setTimeout(()=>{a(new Error(`${i} took more than ${t}ms to resolve. Moving on.`,{cause:T}))},t)});return Promise.race([s,e]).finally(()=>{clearTimeout(r)})}var v=class{setTrustedTypesPolicy(t){this._ttPolicy=t}loadServiceWorker(t){if(!t)return console.debug("Null serviceWorker configuration. Skipping."),Promise.resolve();if(!("serviceWorker"in navigator)){let o="Service Worker API unavailable.";return window.isSecureContext||(o+=`
The current context is NOT secure.`,o+=`
Read more: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts`),Promise.reject(new Error(o))}let{serviceWorkerVersion:i,serviceWorkerUrl:r=u(`flutter_service_worker.js?v=${i}`),timeoutMillis:e=4e3}=t,n=r;this._ttPolicy!=null&&(n=this._ttPolicy.createScriptURL(n));let a=navigator.serviceWorker.register(n).then(o=>this._getNewServiceWorker(o,i)).then(this._waitForServiceWorkerActivation);return T(a,e,"prepareServiceWorker")}async _getNewServiceWorker(t,i){if(!t.active&&(t.installing||t.waiting))return console.debug("Installing/Activating first service worker."),t.installing||t.waiting;if(t.active.scriptURL.endsWith(i))return console.debug("Loading from existing service worker."),t.active;{let r=await t.update();return console.debug("Updating service worker."),r.installing||r.waiting||r.active}}async _waitForServiceWorkerActivation(t){if(!t||t.state==="activated")if(t){console.debug("Service worker already active.");return}else throw new Error("Cannot activate a null service worker!");return new Promise((i,r)=>{t.addEventListener("statechange",()=>{t.state==="activated"&&(console.debug("Activated new service worker."),i())})})}};var y=class{constructor(t,i="flutter-js"){let r=t||[/\.js$/,/\.mjs$/];window.trustedTypes&&(this.policy=trustedTypes.createPolicy(i,{createScriptURL:function(e){if(e.startsWith("blob:"))return e;let n=new URL(e,window.location),a=n.pathname.split("/").pop();if(r.some(l=>l.test(a)))return n.toString();console.error("URL rejected by TrustedTypes policy",i,":",e,"(download prevented)")}}))}};var g=s=>{let t=WebAssembly.compileStreaming(fetch(s));return(i,r)=>((async()=>{let e=await t,n=await WebAssembly.instantiate(e,i);r(n,e)})(),{})};var I=(s,t,i,r)=>(window.flutterCanvasKitLoaded=(async()=>{if(window.flutterCanvasKit)return window.flutterCanvasKit;let e=i.hasChromiumBreakIterators&&i.hasImageCodecs;if(!e&&t.canvasKitVariant=="chromium")throw"Chromium CanvasKit variant specifically requested, but unsupported in this browser";let n=e&&t.canvasKitVariant!=="full",a=r;n&&(a=u(a,"chromium"));let o=u(a,"canvaskit.js");s.flutterTT.policy&&(o=s.flutterTT.policy.createScriptURL(o));let l=g(u(a,"canvaskit.wasm")),m=await import(o);return window.flutterCanvasKit=await m.default({instantiateWasm:l}),window.flutterCanvasKit})(),window.flutterCanvasKitLoaded);var U=async(s,t,i,r)=>{let e=u(r,"skwasm.js"),n=e;s.flutterTT.policy&&(n=s.flutterTT.policy.createScriptURL(n));let a=g(u(r,"skwasm.wasm"));return await(await import(n)).default({instantiateWasm:a,locateFile:(l,m)=>{let c=m+l;return c.endsWith(".worker.js")?URL.createObjectURL(new Blob([`importScripts('${c}');`],{type:"application/javascript"})):c},mainScriptUrlOrBlob:e})};var k=class{async loadEntrypoint(t){let{serviceWorker:i,...r}=t||{},e=new y,n=new v;n.setTrustedTypesPolicy(e.policy),await n.loadServiceWorker(i).catch(o=>{console.warn("Exception while loading service worker:",o)});let a=new h;return a.setTrustedTypesPolicy(e.policy),this.didCreateEngineInitializer=a.didCreateEngineInitializer.bind(a),a.loadEntrypoint(r)}async load({serviceWorkerSettings:t,onEntrypointLoaded:i,nonce:r,config:e}={}){e??={};let n=_flutter.buildConfig;if(!n)throw"FlutterLoader.load requires _flutter.buildConfig to be set";let a=d=>{switch(d){case"skwasm":return p.crossOriginIsolated&&p.hasChromiumBreakIterators&&p.hasImageCodecs&&p.supportsWasmGC;default:return!0}},o=(d,C)=>{switch(d.renderer){case"auto":return C=="canvaskit"||C=="html";default:return d.renderer==C}},l=d=>d.compileTarget==="dart2wasm"&&!p.supportsWasmGC||e.renderer&&!o(d,e.renderer)?!1:a(d.renderer),m=n.builds.find(l);if(!m)throw"FlutterLoader could not find a build compatible with configuration and environment.";let c={};c.flutterTT=new y,t&&(c.serviceWorkerLoader=new v,c.serviceWorkerLoader.setTrustedTypesPolicy(c.flutterTT.policy),await c.serviceWorkerLoader.loadServiceWorker(t).catch(d=>{console.warn("Exception while loading service worker:",d)}));let w=b(e,n);m.renderer==="canvaskit"?c.canvasKit=I(c,e,p,w):m.renderer==="skwasm"&&(c.skwasm=U(c,e,p,w));let f=new h;return f.setTrustedTypesPolicy(c.flutterTT.policy),this.didCreateEngineInitializer=f.didCreateEngineInitializer.bind(f),f.load(m,c,e,r,i)}};window._flutter||(window._flutter={});window._flutter.loader||(window._flutter.loader=new k);})();
//# sourceMappingURL=flutter.js.map
if (!window._flutter) {
window._flutter = {};
}
_flutter.buildConfig = {"engineRevision":"36335019a8eab588c3c2ea783c618d90505be233","builds":[{"compileTarget":"dart2js","renderer":"canvaskit","mainJsPath":"main.dart.js"}]};
_flutter.loader.load({
serviceWorkerSettings: {
serviceWorkerVersion: "2634980571"
}
});

View File

@ -0,0 +1,206 @@
'use strict';
const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {"assets/AssetManifest.bin": "0af364fdc3f132f14a1373e8e30875fb",
"assets/AssetManifest.bin.json": "8bb43c7e7efc64071eb550668229220f",
"assets/AssetManifest.json": "83f1824b5c8e2485a0e38b40027fade2",
"assets/FontManifest.json": "dc3d03800ccca4601324923c0b1d6d57",
"assets/fonts/MaterialIcons-Regular.otf": "c9f4534d3e5ffbc2695ca42fa3c1ae5c",
"assets/images/cover-picture.jpg": "dfdbaf7cdc4ae8ebbe2c5d4afb205b99",
"assets/NOTICES": "dead00e36ea12d67db36656a49b3785a",
"assets/packages/cupertino_icons/assets/CupertinoIcons.ttf": "94495392187d1e926a41d1bf06061cf5",
"assets/shaders/ink_sparkle.frag": "ecc85a2e95f5e9f53123dcaf8cb9b6ce",
"canvaskit/canvaskit.js": "66177750aff65a66cb07bb44b8c6422b",
"canvaskit/canvaskit.js.symbols": "48c83a2ce573d9692e8d970e288d75f7",
"canvaskit/canvaskit.wasm": "1f237a213d7370cf95f443d896176460",
"canvaskit/chromium/canvaskit.js": "671c6b4f8fcc199dcc551c7bb125f239",
"canvaskit/chromium/canvaskit.js.symbols": "a012ed99ccba193cf96bb2643003f6fc",
"canvaskit/chromium/canvaskit.wasm": "b1ac05b29c127d86df4bcfbf50dd902a",
"canvaskit/skwasm.js": "694fda5704053957c2594de355805228",
"canvaskit/skwasm.js.symbols": "262f4827a1317abb59d71d6c587a93e2",
"canvaskit/skwasm.wasm": "9f0c0c02b82a910d12ce0543ec130e60",
"canvaskit/skwasm.worker.js": "89990e8c92bcb123999aa81f7e203b1c",
"favicon.png": "5dcef449791fa27946b3d35ad8803796",
"flutter.js": "f393d3c16b631f36852323de8e583132",
"flutter_bootstrap.js": "1d926076b5bed5250502c33e2ef810e0",
"icons/Icon-192.png": "ac9a721a12bbc803b44f645561ecb1e1",
"icons/Icon-512.png": "96e752610906ba2a93c65f8abe1645f1",
"icons/Icon-maskable-192.png": "c457ef57daa1d16f64b27b786ec2ea3c",
"icons/Icon-maskable-512.png": "301a7604d45b3e739efc881eb04896ea",
"index.html": "0430f309f6f8b6bc1d108883dee3735a",
"/": "0430f309f6f8b6bc1d108883dee3735a",
"main.dart.js": "66185188c8a0f478a83113201dcb134d",
"manifest.json": "1f2788209bfc3dbfe37b39fccfbb4d48",
"version.json": "4d3d79b6d52c1bb20bacdd71f46d24ed"};
// The application shell files that are downloaded before a service worker can
// start.
const CORE = ["main.dart.js",
"index.html",
"flutter_bootstrap.js",
"assets/AssetManifest.bin.json",
"assets/FontManifest.json"];
// During install, the TEMP cache is populated with the application shell files.
self.addEventListener("install", (event) => {
self.skipWaiting();
return event.waitUntil(
caches.open(TEMP).then((cache) => {
return cache.addAll(
CORE.map((value) => new Request(value, {'cache': 'reload'})));
})
);
});
// During activate, the cache is populated with the temp files downloaded in
// install. If this service worker is upgrading from one with a saved
// MANIFEST, then use this to retain unchanged resource files.
self.addEventListener("activate", function(event) {
return event.waitUntil(async function() {
try {
var contentCache = await caches.open(CACHE_NAME);
var tempCache = await caches.open(TEMP);
var manifestCache = await caches.open(MANIFEST);
var manifest = await manifestCache.match('manifest');
// When there is no prior manifest, clear the entire cache.
if (!manifest) {
await caches.delete(CACHE_NAME);
contentCache = await caches.open(CACHE_NAME);
for (var request of await tempCache.keys()) {
var response = await tempCache.match(request);
await contentCache.put(request, response);
}
await caches.delete(TEMP);
// Save the manifest to make future upgrades efficient.
await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
// Claim client to enable caching on first launch
self.clients.claim();
return;
}
var oldManifest = await manifest.json();
var origin = self.location.origin;
for (var request of await contentCache.keys()) {
var key = request.url.substring(origin.length + 1);
if (key == "") {
key = "/";
}
// If a resource from the old manifest is not in the new cache, or if
// the MD5 sum has changed, delete it. Otherwise the resource is left
// in the cache and can be reused by the new service worker.
if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) {
await contentCache.delete(request);
}
}
// Populate the cache with the app shell TEMP files, potentially overwriting
// cache files preserved above.
for (var request of await tempCache.keys()) {
var response = await tempCache.match(request);
await contentCache.put(request, response);
}
await caches.delete(TEMP);
// Save the manifest to make future upgrades efficient.
await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
// Claim client to enable caching on first launch
self.clients.claim();
return;
} catch (err) {
// On an unhandled exception the state of the cache cannot be guaranteed.
console.error('Failed to upgrade service worker: ' + err);
await caches.delete(CACHE_NAME);
await caches.delete(TEMP);
await caches.delete(MANIFEST);
}
}());
});
// The fetch handler redirects requests for RESOURCE files to the service
// worker cache.
self.addEventListener("fetch", (event) => {
if (event.request.method !== 'GET') {
return;
}
var origin = self.location.origin;
var key = event.request.url.substring(origin.length + 1);
// Redirect URLs to the index.html
if (key.indexOf('?v=') != -1) {
key = key.split('?v=')[0];
}
if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') {
key = '/';
}
// If the URL is not the RESOURCE list then return to signal that the
// browser should take over.
if (!RESOURCES[key]) {
return;
}
// If the URL is the index.html, perform an online-first request.
if (key == '/') {
return onlineFirst(event);
}
event.respondWith(caches.open(CACHE_NAME)
.then((cache) => {
return cache.match(event.request).then((response) => {
// Either respond with the cached resource, or perform a fetch and
// lazily populate the cache only if the resource was successfully fetched.
return response || fetch(event.request).then((response) => {
if (response && Boolean(response.ok)) {
cache.put(event.request, response.clone());
}
return response;
});
})
})
);
});
self.addEventListener('message', (event) => {
// SkipWaiting can be used to immediately activate a waiting service worker.
// This will also require a page refresh triggered by the main worker.
if (event.data === 'skipWaiting') {
self.skipWaiting();
return;
}
if (event.data === 'downloadOffline') {
downloadOffline();
return;
}
});
// Download offline will check the RESOURCES for all files not in the cache
// and populate them.
async function downloadOffline() {
var resources = [];
var contentCache = await caches.open(CACHE_NAME);
var currentContent = {};
for (var request of await contentCache.keys()) {
var key = request.url.substring(origin.length + 1);
if (key == "") {
key = "/";
}
currentContent[key] = true;
}
for (var resourceKey of Object.keys(RESOURCES)) {
if (!currentContent[resourceKey]) {
resources.push(resourceKey);
}
}
return contentCache.addAll(resources);
}
// Attempt to download the resource online before falling back to
// the offline cache.
function onlineFirst(event) {
return event.respondWith(
fetch(event.request).then((response) => {
return caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, response.clone());
return response;
});
}).catch((error) => {
return caches.open(CACHE_NAME).then((cache) => {
return cache.match(event.request).then((response) => {
if (response != null) {
return response;
}
throw error;
});
});
})
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="/">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="telemednet">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>telemednet</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
{
"name": "telemednet",
"short_name": "telemednet",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}

View File

@ -0,0 +1 @@
{"app_name":"telemednet","version":"1.0.0","build_number":"1","package_name":"telemednet"}

View File

@ -0,0 +1,31 @@
manifest.json,1728898403205,0fa15403d5f7c9d67e8ec05938eeee7672245fd0861a34e8de0657f14e7716ac
flutter.js,1728899185731,d87c0089304472f9dfe62f9fc6535fc5e981c66e84fe12f475ae59e4c0de293e
favicon.png,1728898403202,19880e004e8357a51f6a64f5d1fdc8828a6432fe9c781f8acb6b730eced2cd13
icons/Icon-maskable-512.png,1728898403205,ea58e5c49bc4dcdc5db0a9fe2f25b2a3152f85ef9094f0d020de0aa318451a1d
icons/Icon-maskable-192.png,1728898403204,f7ac56197638aec92f195c5344d15395c2cbf8a5ae74e846c5b4156b64f05e38
icons/Icon-512.png,1728898403204,1de493563deb283e6ad70f0d5a89cfd61e37343df3b919c9862c5a41699ac5bc
icons/Icon-192.png,1728898403204,5fd961c51d8eb53baacac01f8e53743a76f66a43390a11f5df042e8c618ad64a
canvaskit/skwasm.worker.js,1728899185724,68c8cc5328df85cd380ca0f2bbc247c661401ecb578cd8314c3eef22117f3764
canvaskit/skwasm.wasm,1728899185723,bef8b38727b2812331e4cf0c12d66732a4ec147d3cd47d2bb9b0b127eeafedc4
canvaskit/skwasm.js.symbols,1728899185710,4f560f74181b68fc35a70ad24ad8603bf96560d98295b2aff5c4e9c09a75a579
canvaskit/skwasm.js,1728899185706,462291cf0069fc56b3fc68c929529e81538452a9d5adbb5e6a1087baf38429fd
canvaskit/canvaskit.wasm,1728899185681,56b48f4e4fdadb7ada9356a00bda110457b67ab2256cf99f035ade13a187e3a2
canvaskit/canvaskit.js.symbols,1728899185655,e090a3c6db335e27cc18b3ce59e56a1351463c53f95cdc248be197243f55c982
canvaskit/canvaskit.js,1728899185652,1688fc39eac7379aca9660dea8919978f5558879c3d37f86772e1588a9d2b982
canvaskit/chromium/canvaskit.wasm,1728899185705,0089691aaeff44eff59e7f211fcb94cee78c139a92924d965fd50670c9ad8c20
canvaskit/chromium/canvaskit.js.symbols,1728899185687,a4b49b05d24c1ea03b0451301733e88c58ffa5c9d74eb548183584bf58ac3292
canvaskit/chromium/canvaskit.js,1728899185682,8455dd254f6396530094c0f3487658ec38688610bb541b9a3897e6cee37186b4
assets/images/cover-picture.jpg,1729070093924,4752dd55b57940ddd73edb0dd289a23ac9083f1e9ed7cea531791c76481bdd59
flutter_service_worker.js,1729240900925,0481932dfa48c7803afb866aef17a076f3990d6baa11f28903ba199e9a734856
flutter_bootstrap.js,1729240900372,7551ea082df64eff60d43a30400eca6af164692213298157eea7f7f8ca698ab3
assets/FontManifest.json,1729240882142,e38b95988f5d060cf9b7ce97cb5ac9236d6f4cc04a11d69567df97b2b4cbc5e5
assets/AssetManifest.json,1729240882141,a2f124124edab1d3465aed2bab20bcd74236dd4b39629d8fa6c89877ce56ab24
assets/AssetManifest.bin.json,1729240882142,9c90f401adf0bc50bae9a23bfe8e139540ea7b699c526ecd1863c19d27caac25
assets/AssetManifest.bin,1729240882142,679f659951651982dee141afb8599f99ab25e89d1c43983e8892ecebbd84d87c
assets/shaders/ink_sparkle.frag,1729240882321,591c7517d5cb43eb91ea451e0d3f9f585cbf8298cf6c46a9144b77cb0775a406
assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1729240883868,d8ca13e0aa354d908c8d3e3c194a2d25762327ff012ef24b6dd76b9eaefd984b
assets/fonts/MaterialIcons-Regular.otf,1729240883884,4b3257fe01bb8a79a4e11c3a5636d0c5bed016e47105a7587ed1c8d0e8318c16
version.json,1729240881985,be2e9f96a53a3973a9a2c4c5bc8a911ed5f1cc2704549225f88692af80acb36c
index.html,1729240900402,57ad133ae178814c081d7af459f4066efd208fb9f9558b72657370616bd2b7d8
assets/NOTICES,1729240882143,6150f9f11e513f7695b0fd0b4c90ff0d5f8f6e3f05e03fcf0ce579c7f587b263
main.dart.js,1729240881196,554c8c25edab635731c4aad45d61926e73a76f0e11f2d2514eb4ea5805196bfa

BIN
images/FemaleDr.jpg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
images/MaleDr.jpg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

BIN
images/doctor-landing.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,106 @@
import '../data/models/consultation_center.dart';
class ConsultationCenterController {
final ConsultationCenter model;
Map<String, String> validationErrors = {};
ConsultationCenterController() : model = ConsultationCenter();
// Address validation methods
bool validatePostalCode(String postalCode) {
if (postalCode.isEmpty || postalCode.length < 5) {
validationErrors['postalCode'] = 'Invalid postal code';
return false;
}
validationErrors.remove('postalCode');
return true;
}
void updateFloorBuilding(String floorBuilding) {
model.floorBuilding = floorBuilding;
}
void updateStreet(String street) {
model.street = street;
}
void updateCity(String city) {
model.city = city;
}
void updateState(String state) {
model.state = state;
}
void updateCountry(String country) {
model.country = country;
}
void updatePostalCode(String postalCode) {
if (validatePostalCode(postalCode)) {
model.postalCode = postalCode;
}
}
void updateAddressType(String addressType) {
model.addressType = addressType;
}
// New field updates
void updateConsultationFee(String fee) {
{
model.consultationFee = fee;
}
}
void updateAverageDuration(String minutes) {
{
model.averageDurationMinutes = minutes;
}
}
void addTimeSlot(String day, TimeSlot slot) {
// Validate the time slot (you can add your own validation logic)
if (!_validateTimeSlot(slot)) {
return;
}
// Ensure weeklySchedule is initialized
model.weeklySchedule ??= [];
// Find or create the day's schedule
var daySchedule = model.weeklySchedule!.firstWhere(
(schedule) => schedule.day == day,
orElse: () {
final newSchedule = AvailabilitySchedule(day: day, timeSlots: []);
model.weeklySchedule!.add(newSchedule);
return newSchedule;
},
);
// Ensure timeSlots is initialized
daySchedule.timeSlots ??= [];
// Add the new time slot
daySchedule.timeSlots!.add(slot);
}
// Example validation method (customize as needed)
bool _validateTimeSlot(TimeSlot slot) {
// Add your validation logic here
// For example, check that start time is before end time
if (slot.startTime == null || slot.endTime == null) {
return false;
}
// You can add more complex validation if needed
return true;
}
void removeTimeSlot(String day, TimeSlot slot) {
model.weeklySchedule
?.firstWhere((schedule) => schedule.day == day)
.timeSlots
?.removeWhere((existing) =>
existing.startTime == slot.startTime &&
existing.endTime == slot.endTime);
}
}

View File

@ -1,31 +1,63 @@
import 'package:telemednet/data/models/doctor.dart';
class ValidationHelper {
// Basic regex patterns
static final RegExp nameRegex = RegExp(r'^[a-zA-Z\s]{2,50}$');
static final RegExp experienceRegex = RegExp(r'^\d{1,2}$');
static final RegExp licenseRegex = RegExp(r'^[A-Z0-9-]{5,15}$');
static final RegExp postalCodeRegex = RegExp(r'^\d{6}$');
static final RegExp buildingRegex = RegExp(r'^[a-zA-Z0-9\s\-\/]{1,50}$');
static final RegExp streetRegex = RegExp(r'^[a-zA-Z0-9\s\,\-\/]{5,100}$');
// Validation error messages
static const String nameError =
'Name should be 2-50 characters long and contain only letters';
static const String experienceError =
'Years of experience should be a valid number between 0-99';
static const String licenseError =
'License number should be 5-15 alphanumeric characters';
static const String postalCodeError =
'Postal code should be exactly 6 digits';
static const String buildingError =
'Building/Floor details should be 1-50 characters';
static const String streetError = 'Street address should be 5-100 characters';
static const String requiredFieldError = 'This field is required';
static const String qualificationError =
'At least one qualification is required';
static const String achievementError =
'Achievement should be between 5-200 characters';
}
class DoctorController {
Doctor model = Doctor(
address: Address(floorBuilding: ''),
profile: Profile(qualifications: []),
);
final Doctor model;
Map<String, String> validationErrors = {};
final ProfileController profileController = ProfileController();
final AddressController addressController = AddressController();
DoctorController() : model = Doctor();
bool validateAchievement(String achievement) {
if (achievement.length < 5 || achievement.length > 200) {
validationErrors['achievement'] = ValidationHelper.achievementError;
return false;
}
return true;
}
// Doctor Specific Updates
void updateSpeciality(String speciality) {
model.speciality = speciality;
}
void updateAchievements(List<String> achievements) {
model.achievements = achievements;
model.achievements = List<String>.from(achievements);
}
// Add single achievement
void addAchievement(String achievement) {
model.achievements.add(achievement);
if (validateAchievement(achievement)) {
model.achievements!.add(achievement);
}
}
// Remove achievement
void removeAchievement(String achievement) {
model.achievements.remove(achievement);
model.achievements!.remove(achievement);
}
void updateYearsOfExperience(String years) {
@ -44,14 +76,9 @@ class DoctorController {
model.digitalSignature = signature;
}
// Validation logic can be added here
bool validateProfile() {
return model.speciality != null && model.licenseNumber != null;
void updateProfileImage(String profileImage) {
model.profileImage = profileImage;
}
}
class ProfileController {
Profile model = Profile(qualifications: []);
void updateTitle(String title) {
model.title = title;
@ -70,21 +97,13 @@ class ProfileController {
}
void addQualification(String qualification) {
model.qualifications.add(qualification);
model.qualifications!.add(qualification);
}
void removeQualification(String qualification) {
model.qualifications.remove(qualification);
model.qualifications!.remove(qualification);
}
bool validateProfile() {
return model.qualifications.isNotEmpty;
}
}
class AddressController {
Address model = Address(floorBuilding: '');
void updateFloorBuilding(String floorBuilding) {
model.floorBuilding = floorBuilding;
}
@ -109,7 +128,7 @@ class AddressController {
model.postalCode = postalCode;
}
// bool validateAddress() {
// return model.floorBuilding.isNotEmpty;
// }
void updateAddressType(String addressType) {
model.addressType = addressType;
}
}

View File

@ -0,0 +1,101 @@
import 'package:cloud_firestore/cloud_firestore.dart';
enum PaymentStatus { pending, completed, failed, refunded }
class Booking {
final String id;
// final String doctorId;
final String doctorName;
final String patientId;
final String patientName;
final String location;
final DateTime appointmentDate;
final String appointmentTime;
final int consultationFee;
final PaymentStatus paymentStatus;
final DateTime createdAt;
final String specialization;
Booking({
required this.id,
// required this.doctorId,
required this.doctorName,
required this.patientId,
required this.patientName,
required this.location,
required this.appointmentDate,
required this.appointmentTime,
required this.consultationFee,
required this.paymentStatus,
required this.createdAt,
required this.specialization,
});
// Convert Booking object to a map for Firestore
Map<String, dynamic> toMap() {
return {
'id': id,
// 'doctorId': doctorId,
'doctorName': doctorName,
'patientId': patientId,
'patientName': patientName,
'location': location,
'appointmentDate': appointmentDate,
'appointmentTime': appointmentTime,
'consultationFee': consultationFee,
'paymentStatus': paymentStatus.toString().split('.').last,
'createdAt': createdAt,
'specialization': specialization,
};
}
factory Booking.fromMap(Map<String, dynamic> map) {
return Booking(
id: map['id'],
// doctorId: map['doctorId'],
doctorName: map['doctorName'],
patientId: map['patientId'],
patientName: map['patientName'],
location: map['location'],
appointmentDate: (map['appointmentDate'] as Timestamp).toDate(),
appointmentTime: map['appointmentTime'],
consultationFee: map['consultationFee'],
paymentStatus: PaymentStatus.values.firstWhere(
(e) => e.toString().split('.').last == map['paymentStatus'],
),
createdAt: (map['createdAt'] as Timestamp).toDate(),
specialization: map['specialization'],
);
}
// Create a copy of Booking with modified fields
Booking copyWith({
String? id,
String? doctorId,
String? doctorName,
String? patientId,
String? patientName,
String? location,
DateTime? appointmentDate,
String? appointmentTime,
int? consultationFee,
PaymentStatus? paymentStatus,
DateTime? createdAt,
String? specialization,
}) {
return Booking(
id: id ?? this.id,
// doctorId: doctorId ?? this.doctorId,
doctorName: doctorName ?? this.doctorName,
patientId: patientId ?? this.patientId,
patientName: patientName ?? this.patientName,
location: location ?? this.location,
appointmentDate: appointmentDate ?? this.appointmentDate,
appointmentTime: appointmentTime ?? this.appointmentTime,
consultationFee: consultationFee!,
paymentStatus: paymentStatus ?? this.paymentStatus,
createdAt: createdAt ?? this.createdAt,
specialization: specialization ?? this.specialization,
);
}
}

View File

@ -0,0 +1,121 @@
class DoctorsConsultation {
List<ConsultationCenter>? consultationCenter;
DoctorsConsultation({
this.consultationCenter,
});
Map<String, dynamic> toJson() => {
'consultationCenter': consultationCenter
?.map((consultationCenter) => consultationCenter.toJson())
.toList(),
};
static DoctorsConsultation fromJson(Map<String, dynamic> json) =>
DoctorsConsultation(
consultationCenter: (json['consultationCenter'] as List<dynamic>?)
?.map((schedule) => ConsultationCenter.fromJson(schedule))
.toList(),
);
}
class ConsultationCenter {
String? floorBuilding;
String? street;
String? city;
String? state;
String? country;
String? postalCode;
String? documentId;
String? addressType;
String? consultationFee;
String? averageDurationMinutes;
List<AvailabilitySchedule>? weeklySchedule;
ConsultationCenter({
this.addressType,
this.documentId,
this.floorBuilding,
this.street,
this.city,
this.state,
this.country,
this.postalCode,
this.consultationFee,
this.averageDurationMinutes,
this.weeklySchedule,
});
Map<String, dynamic> toJson() => {
'floorBuilding': floorBuilding,
'documentId': documentId,
'street': street,
'city': city,
'state': state,
'country': country,
'postalCode': postalCode,
'addressType': addressType,
'consultationFee': consultationFee,
'averageDurationMinutes': averageDurationMinutes,
'weeklySchedule':
weeklySchedule?.map((schedule) => schedule.toJson()).toList(),
};
static ConsultationCenter fromJson(Map<String, dynamic> json) =>
ConsultationCenter(
// id:json['id']
floorBuilding: json['floorBuilding'],
documentId: json['documentId'],
street: json['street'],
city: json['city'],
state: json['state'],
country: json['country'],
postalCode: json['postalCode'],
addressType: json['addressType'],
consultationFee: json['consultationFee'],
averageDurationMinutes: json['averageDurationMinutes'],
weeklySchedule: (json['weeklySchedule'] as List<dynamic>?)
?.map((schedule) => AvailabilitySchedule.fromJson(schedule))
.toList(),
);
}
class AvailabilitySchedule {
String? day;
List<TimeSlot>? timeSlots;
AvailabilitySchedule({
this.day,
this.timeSlots,
});
Map<String, dynamic> toJson() => {
'day': day,
'timeSlots': timeSlots?.map((slot) => slot.toJson()).toList(),
};
static AvailabilitySchedule fromJson(Map<String, dynamic> json) =>
AvailabilitySchedule(
day: json['day'],
timeSlots: (json['timeSlots'] as List<dynamic>?)
?.map((slot) => TimeSlot.fromJson(slot))
.toList(),
);
}
class TimeSlot {
String? startTime;
String? endTime;
TimeSlot({
this.startTime,
this.endTime,
});
Map<String, dynamic> toJson() => {
'startTime': startTime,
'endTime': endTime,
};
static TimeSlot fromJson(Map<String, dynamic> json) => TimeSlot(
startTime: json['startTime'],
endTime: json['endTime'],
);
}

View File

@ -1,116 +1,89 @@
class Doctor {
// Add achievements field
List<String> achievements;
// Add to existing fields
List<String>? achievements;
String? uid;
String? profileImage;
String? speciality;
String? yearsOfExperience;
String? licenseNumber;
String? profileDescription;
String? digitalSignature;
Address address;
Profile profile;
Doctor({
this.achievements = const [], // Initialize with empty list
this.speciality,
this.yearsOfExperience,
this.licenseNumber,
this.profileDescription,
this.digitalSignature,
required this.address,
required this.profile,
});
Map<String, dynamic> toJson() => {
'achievements': achievements,
'speciality': speciality,
'yearsOfExperience': yearsOfExperience,
'licenseNumber': licenseNumber,
'profileDescription': profileDescription,
'digitalSignature': digitalSignature,
'address': address.toJson(),
'profile': profile.toJson(),
};
static Doctor fromJson(Map<String, dynamic> json) => Doctor(
achievements: List<String>.from(json['achievements'] ?? []),
speciality: json['speciality'],
yearsOfExperience: json['yearsOfExperience'],
licenseNumber: json['licenseNumber'],
profileDescription: json['profileDescription'],
digitalSignature: json['digitalSignature'],
address: Address.fromJson(json['address']),
profile: Profile.fromJson(json['profile']),
);
}
class Profile {
String? title;
String? surName;
String? middleName;
String? lastName;
List<String> qualifications;
String? profileDescription;
Profile({
this.title,
this.surName,
this.middleName,
this.lastName,
required this.qualifications,
});
Map<String, dynamic> toJson() => {
'title': title,
'surname': surName,
'lastName': lastName,
'middleName': middleName,
'qualifications': qualifications,
};
static Profile fromJson(Map<String, dynamic> json) => Profile(
title: json['title'],
surName: json['surname'],
middleName: json['middleName'],
lastName: json['lastName'],
qualifications: List<String>.from(json['qualifications']),
);
}
class Address {
List<String>? qualifications = [];
String? floorBuilding;
String? street;
String? city;
String? state;
String? country;
String? postalCode;
String? addressType;
Address({
Doctor({
this.addressType,
this.achievements,
this.profileImage, // Initialize with empty list
this.speciality,
this.yearsOfExperience,
this.licenseNumber,
this.profileDescription,
this.digitalSignature,
this.title,
this.surName,
this.middleName,
this.lastName,
this.qualifications,
this.floorBuilding,
this.street,
this.city,
this.state,
this.country,
this.postalCode,
this.uid,
});
Map<String, dynamic> toJson() => {
'profileImage': profileImage,
'achievements': achievements,
'speciality': speciality,
'yearsOfExperience': yearsOfExperience,
'licenseNumber': licenseNumber,
'profileDescription': profileDescription,
'digitalSignature': digitalSignature,
'title': title,
'surname': surName,
'lastName': lastName,
'middleName': middleName,
'qualifications': qualifications,
'floorBuilding': floorBuilding,
'street': street,
'city': city,
'state': state,
'country': country,
'postalCode': postalCode,
'addressType': addressType
};
static Address fromJson(Map<String, dynamic> json) => Address(
floorBuilding: json['floorBuilding'],
street: json['street'],
city: json['city'],
state: json['state'],
country: json['country'],
postalCode: json['postalCode'],
);
static Doctor fromJson(Map<String, dynamic> json) => Doctor(
achievements: List<String>.from(json['achievements'] ?? []),
profileImage: json['profileImage'],
speciality: json['speciality'],
yearsOfExperience: json['yearsOfExperience'],
licenseNumber: json['licenseNumber'],
profileDescription: json['profileDescription'],
digitalSignature: json['digitalSignature'],
title: json['title'],
surName: json['surname'],
middleName: json['middleName'],
lastName: json['lastName'],
qualifications: List<String>.from(json['qualifications'] ?? []),
floorBuilding: json['floorBuilding'],
street: json['street'],
city: json['city'],
state: json['state'],
country: json['country'],
postalCode: json['postalCode'],
addressType: json['addressType'],
uid: json['uid']);
}

View File

@ -0,0 +1,37 @@
// import 'package:cloud_firestore/cloud_firestore.dart';
// class Doctors {
// final String name;
// final String location;
// final String specialization;
// final int experience;
// final String description;
// final List<String> qualification;
// final List<Map<String, dynamic>> consultation;
// final String profileImage;
// Doctors({
// required this.name,
// required this.location,
// required this.specialization,
// required this.experience,
// required this.description,
// required this.qualification,
// required this.consultation,
// required this.profileImage,
// });
// factory Doctors.fromFirestore(DocumentSnapshot doc) {
// final data = doc.data() as Map<String, dynamic>;
// return Doctors(
// name: data['name'] ?? '',
// location: data['location'] ?? '',
// specialization: data['specialization'] ?? '',
// experience: data['experience'] ?? 0,
// description: data['description'] ?? '',
// qualification: List<String>.from(data['qualification'] ?? []),
// consultation: List<Map<String, dynamic>>.from(data['consultation'] ?? []),
// profileImage: data['profile_image'] ?? '',
// );
// }
// }

View File

@ -0,0 +1,85 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:telemednet/data/models/consultation_booking.dart';
class BookingService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<String> createBooking({
required String doctorName,
required String patientId,
required String patientName,
required String location,
required DateTime appointmentDate,
required String appointmentTime,
required int consultationFee,
required String specialization,
}) async {
try {
final docRef = _firestore.collection('bookings').doc();
final booking = Booking(
id: docRef.id,
doctorName: doctorName,
patientId: patientId,
patientName: patientName,
location: location,
appointmentDate: appointmentDate,
appointmentTime: appointmentTime,
consultationFee: consultationFee,
paymentStatus: PaymentStatus.pending,
createdAt: DateTime.now(),
specialization: specialization,
);
docRef.set(booking.toMap());
return docRef.id;
} catch (e) {
throw Exception('Failed to create booking: $e');
}
}
Future<Booking> getBooking(String bookingId) async {
try {
final doc = await _firestore.collection('bookings').doc(bookingId).get();
if (!doc.exists) {
throw Exception('Booking not found');
}
return Booking.fromMap(doc.data()!);
} catch (e) {
throw Exception('Failed to get booking: $e');
}
}
Stream<List<Booking>> getPatientBookings(String patientId) {
return _firestore
.collection('bookings')
.where('patientId', isEqualTo: patientId)
.orderBy('appointmentDate', descending: true)
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => Booking.fromMap(doc.data())).toList());
}
Stream<List<Booking>> getDoctorBookings(String doctorId) {
return _firestore
.collection('bookings')
.where('doctorId', isEqualTo: doctorId)
.orderBy('appointmentDate', descending: true)
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) => Booking.fromMap(doc.data())).toList());
}
Future<void> updatePaymentStatus(
String bookingId,
PaymentStatus status,
) async {
try {
await _firestore.collection('bookings').doc(bookingId).update({
'paymentStatus': status.toString().split('.').last,
});
} catch (e) {
throw Exception('Failed to update payment status: $e');
}
}
}

View File

@ -0,0 +1,160 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import '../models/consultation_center.dart';
class ConsultationCenterService {
static final String consultationCenterCollectionName =
dotenv.env['CONSULTATION_CENTER_COLLECTION_NAME']!;
static final FirebaseFirestore db = FirebaseFirestore.instance;
// Get List of Consultation Centers for a Doctor
static Future<List<ConsultationCenter>> getDoctorConsultationCenters(
String doctorUid) async {
try {
if (doctorUid.isEmpty) {
print('Doctor UID is empty');
return [];
}
final QuerySnapshot querySnapshot = await db
.collection(consultationCenterCollectionName)
.where('uid', isEqualTo: doctorUid)
.get();
final List<ConsultationCenter> consultationCenters =
querySnapshot.docs.map((doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
data['documentId'] = doc.id;
return ConsultationCenter.fromJson(data);
}).toList();
return consultationCenters;
} catch (e) {
print('Error fetching doctor consultation centers: $e');
return [];
}
}
// Save Multiple Consultation Centers
static Future<bool> saveConsultationCenters(
List<ConsultationCenterController> controllers) async {
try {
final User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('No user logged in');
return false;
}
final String uid = user.uid;
final WriteBatch batch = db.batch();
for (var controller in controllers) {
final ConsultationCenter consultationData = controller.model;
final Map<String, dynamic> consultationJson = consultationData.toJson();
// Add timestamps and user ID
consultationJson['createdAt'] = FieldValue.serverTimestamp();
consultationJson['updatedAt'] = FieldValue.serverTimestamp();
consultationJson['uid'] = uid;
// Create a new document reference
final DocumentReference docRef = db
.collection(consultationCenterCollectionName)
.doc(); // Auto-generated ID
// Add to batch
batch.set(docRef, consultationJson);
}
// Commit the batch
await batch.commit();
print('Consultation centers saved successfully');
return true;
} catch (e) {
print('Error saving consultation centers: $e');
return false;
}
}
// Update Multiple Consultation Centers
static Future<bool> updateConsultationCenters(
List<ConsultationCenterController> controllers) async {
try {
final User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('No user logged in');
return false;
}
final WriteBatch batch = db.batch();
for (var controller in controllers) {
final ConsultationCenter consultationData = controller.model;
final Map<String, dynamic> consultationJson = consultationData.toJson();
// Add updated timestamp
consultationJson['updatedAt'] = FieldValue.serverTimestamp();
// Assuming each consultation center has a unique document ID
final DocumentReference docRef = db
.collection(consultationCenterCollectionName)
.doc(consultationData
.documentId); // You'll need to add documentId to the model
// Add to batch
batch.update(docRef, consultationJson);
}
// Commit the batch
await batch.commit();
print('Consultation centers updated successfully');
return true;
} catch (e) {
print('Error updating consultation centers: $e');
return false;
}
}
// Delete a Specific Consultation Center
static Future<bool> deleteConsultationCenter({
required String doctorUid,
required String documentId,
}) async {
try {
if (doctorUid.isEmpty || documentId.isEmpty) {
print('Doctor UID or Document ID is empty');
return false;
}
// First verify that this center belongs to the doctor
final DocumentSnapshot doc = await db
.collection(consultationCenterCollectionName)
.doc(documentId)
.get();
if (!doc.exists) {
print('Consultation center not found');
return false;
}
final data = doc.data() as Map<String, dynamic>;
if (data['doctorUid'] != doctorUid) {
print('Consultation center does not belong to this doctor');
return false;
}
await db
.collection(consultationCenterCollectionName)
.doc(documentId)
.delete();
print('Consultation center deleted successfully');
return true;
} catch (e) {
print('Error deleting consultation center: $e');
return false;
}
}
}

View File

@ -1,14 +1,38 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import 'package:telemednet/data/models/doctor.dart';
import '../../controllers/doctor_controller.dart';
class DoctorProfileService {
static final String doctorProfileCollectionName =
dotenv.env['DOCTOR_PROFILE_COLLECTION_NAME']!;
static final FirebaseFirestore _db = FirebaseFirestore.instance;
static final FirebaseFirestore db = FirebaseFirestore.instance;
static Future<Doctor?> getDoctorProfile() async {
try {
final User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('No user logged in');
return null;
}
final String uid = user.uid;
final DocumentSnapshot doc =
await db.collection(doctorProfileCollectionName).doc(uid).get();
if (!doc.exists) {
print('No patient profile found for this user');
return null;
}
final data = doc.data() as Map<String, dynamic>;
return Doctor.fromJson(data);
} catch (e) {
print('Error fetching doctor profile: $e');
return null;
}
}
static Future saveDoctorProfile(DoctorController controller) async {
try {
@ -26,10 +50,7 @@ class DoctorProfileService {
doctorJson['updatedAt'] = FieldValue.serverTimestamp();
doctorJson['uid'] = uid;
await _db
.collection(doctorProfileCollectionName)
.doc(uid)
.set(doctorJson);
await db.collection(doctorProfileCollectionName).doc(uid).set(doctorJson);
print('Doctor profile saved successfully');
return true;
} catch (e) {
@ -38,39 +59,6 @@ class DoctorProfileService {
}
}
static Future<Doctor?> getDoctorProfile() async {
try {
final User? user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('No user logged in');
return null;
}
final String uid = user.uid;
final DocumentSnapshot doc =
await _db.collection(doctorProfileCollectionName).doc(uid).get();
if (!doc.exists) {
print('No doctor profile found for this user');
return null;
}
final data = doc.data() as Map<String, dynamic>;
return Doctor(
profile: Profile.fromJson(data['profile']),
speciality: data['speciality'],
yearsOfExperience: data['yearsOfExperience'],
licenseNumber: data['licenseNumber'],
profileDescription: data['profileDescription'],
digitalSignature: data['digitalSignature'],
address: Address.fromJson(data['address']),
);
} catch (e) {
print('Error fetching doctor profile: $e');
return null;
}
}
static Future updateDoctorProfile(DoctorController controller) async {
try {
final User? user = FirebaseAuth.instance.currentUser;
@ -85,7 +73,7 @@ class DoctorProfileService {
final Map<String, dynamic> doctorJson = doctorData.toJson();
doctorJson['updatedAt'] = FieldValue.serverTimestamp();
await _db
await db
.collection(doctorProfileCollectionName)
.doc(uid)
.update(doctorJson);
@ -107,7 +95,7 @@ class DoctorProfileService {
final String uid = user.uid;
await _db.collection(doctorProfileCollectionName).doc(uid).delete();
await db.collection(doctorProfileCollectionName).doc(uid).delete();
print('Doctor profile deleted successfully');
return true;
} catch (e) {

View File

@ -0,0 +1,94 @@
import 'package:cloud_firestore/cloud_firestore.dart';
Future<void> uploadDoctorsData() async {
CollectionReference doctors =
FirebaseFirestore.instance.collection('doctors');
List<Map<String, dynamic>> doctorsList = [
{
"name": "Dr. Sarah Lee",
"location": "New York, NY",
"specialization": "Cardiologist",
"experience": 15,
"description":
"Dr. Lee is a highly experienced cardiologist specializing in heart health, preventive care, and patient education.",
"qualification": [
"MBBS, MD - Cardiology",
"FACC (Fellow of the American College of Cardiology)"
],
"consultation": [
{
"location": "City Health Clinic, New York",
"day": ["Monday", "Wednesday", "Friday"],
"time": "9:00 AM - 3:00 PM",
"averageTime": "30 minutes"
},
{
"location": "Downtown Medical Center, New York",
"day": ["Tuesday", "Thursday"],
"time": "11:00 AM - 5:00 PM",
"averageTime": "30 minutes"
}
],
"profile_image": "images/FemaleDr.jpg.png"
},
{
"name": "Dr. James Wang",
"location": "Los Angeles, CA",
"specialization": "Dermatologist",
"experience": 10,
"description":
"Dr. Wang is a board-certified dermatologist with a focus on skincare, laser treatments, and dermatologic surgery.",
"qualification": [
"MBBS, MD - Dermatology",
"Diploma in Dermatology & Venereology"
],
"consultation": [
{
"location": "LA Skin Care Clinic, Los Angeles",
"day": ["Tuesday", "Thursday"],
"time": "10:00 AM - 4:00 PM",
"averageTime": "30 minutes"
},
{
"location": "Westside Dermatology, Santa Monica",
"day": ["Monday", "Wednesday", "Saturday"],
"time": "1:00 PM - 6:00 PM",
"averageTime": "30 minutes"
}
],
"profile_image": "images/MaleDr.jpg.png"
},
{
"name": "Dr. Priya Singh",
"location": "Chicago, IL",
"specialization": "Pediatrician",
"experience": 8,
"description":
"Dr. Singh is a compassionate pediatrician dedicated to providing comprehensive healthcare for children of all ages.",
"qualification": [
"MBBS, MD - Pediatrics",
"Member of the American Academy of Pediatrics (AAP)"
],
"consultation": [
{
"location": "Children's Health Center, Chicago",
"day": ["Monday", "Tuesday", "Thursday"],
"time": "9:00 AM - 2:00 PM",
"averageTime": "30 minutes"
},
{
"location": "Family Clinic, Naperville",
"day": ["Friday", "Saturday"],
"time": "11:00 AM - 5:00 PM",
"averageTime": "30 minutes"
}
],
"profile_image": "images/FemaleDr.jpg.png"
}
];
for (var doctor in doctorsList) {
await doctors.add(doctor);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:telemednet/data/models/telemed_user.dart';
import 'package:telemednet/data/services/data_service.dart';
import 'package:telemednet/data/services/doctor_profile_service.dart';
import 'package:telemednet/data/services/patient_registration_service.dart';
import 'package:telemednet/route_names.dart';
@ -43,11 +44,16 @@ class NavigationService {
}
static Future<void> handleDoctorNavigation(BuildContext context) async {
final doctorProfile = await DoctorProfileService.getDoctorProfile();
if (context.mounted) {
Navigator.pushReplacementNamed(
context,
RouteNames.profileUpload,
);
if (doctorProfile != null) {
Navigator.pushReplacementNamed(
context,
RouteNames.doctorDashbordScreen,
);
} else {
Navigator.pushReplacementNamed(context, RouteNames.profileUpload);
}
}
}

View File

@ -1,10 +1,9 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:telemednet/controllers/patient_controller.dart';
import 'package:telemednet/data/models/patient.dart';
import '../../controller/patient_controller.dart';
class PatientProfileService {
static final String patientProfileCollectionName =
dotenv.env['PATIENT_PROFILE_COLLECTION_NAME']!;

View File

@ -6,6 +6,7 @@ class RouteNames {
static const String launch = '/launch';
static const String profileUpload = '/profile-upload';
static const String patientLandingScreen = '/patient-landing-screen';
static const String patientHomeScreen = '/patient-home-screen';
static const String patientDashboardScreen = '/patient-dahboard-screen';
static const String patientRegistrationScreen =
'/patient-registration-screen';
@ -19,5 +20,24 @@ class RouteNames {
static const String specialitiesScreeen = '/doctor-specialities';
static const String digitalSignatureScreeen = '/doctor-signature';
static const String achievementsScreen = '/doctor-achievements';
static const String qualificationsScreen = '/doctor-qualifications';
static const String patientprofileScreen = '/patient-profile-screen';
static const String specialityScreen = '/speciality-screen';
static const String doctorListScreen = '/doctor-list-screen';
static const String doctorDetailsScreen = '/doctor-details-screen';
static const String consultationCenterScreen = '/consultations-center-screen';
static const String consultationTimeScreen = '/consultation-time-screen';
static const String consultationBookingScreen =
'/consultation-booking-screen';
static const String doctorDashbordScreen = '/doctor-dashboard';
static const String scheduleConsultationScreen = '/doctor-Schedule';
static const String doctorLandingScreen = '/doctor-Landing';
static const String businessCenterScreen = '/doctor-centers';
static const String centerFeeAndDuration = '/doctor-center-fee-and-duration';
static const String doctorHomeScreen = '/doctor-home-screen';
static const String doctorPersonalProfileScreen =
'/doctor-personal-profile-screen';
static const String doctorServicesMenuScreen = '/doctor-services-menu';
static const String consultationTimeSlotScreen = '/doctor-timeslot';
static const String consultationDayScreen = '/doctor-consultation-days';
}

View File

@ -1,16 +1,43 @@
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:telemednet/screens/authentication/launch_screen.dart';
import 'package:telemednet/screens/doctor_screens/doctor_profile_screen.dart';
import 'package:telemednet/controller/patient_controller.dart';
import 'package:telemednet/screens/doctor_screens/achivements.dart';
import 'package:telemednet/screens/doctor_screens/address_screen.dart';
// import 'package:telemednet/data/telemed_user.dart';
import 'package:telemednet/controllers/patient_controller.dart';
import 'package:telemednet/route_names.dart';
import 'package:telemednet/screens/doctor_screens/digital_signature.dart';
import 'package:telemednet/screens/doctor_screens/experience_screen.dart';
import 'package:telemednet/screens/doctor_screens/profile_description_screen.dart';
import 'package:telemednet/screens/doctor_screens/specialities_selection.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/business_center_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/center_fee_and_duration_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_schedule.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_landing_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/doctor_profile_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/qualifications_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultation_booking_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultation_time_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultations_center_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/doctor_details_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/doctors_list_screen.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/achivements_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/address_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/digital_signature_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/experience_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/profile_description_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/specialities_selection_screen.dart';
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_dashboard_screen.dart';
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_home_screen.dart';
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
import 'package:telemednet/screens/patientScreens/registrationScreens/patient_adress_screen.dart';
import 'package:telemednet/screens/patientScreens/registrationScreens/patient_family_members_screen.dart';
@ -30,35 +57,62 @@ final Map<String, Widget Function(BuildContext)> routes = {
// var user = ModalRoute.of(context)!.settings.arguments as TelemedUser?;
// return UserProfileScreen(user: user);
// },
// RouteNames.userHome: (context) => const UserScreen(),
RouteNames.profileUpload: (context) => const ProfileUploadPage(),
RouteNames.patientLandingScreen: (context) => const PatientLandingScreen(),
RouteNames.patientDashboardScreen: (context) =>
const PatientDashboardScreen(),
RouteNames.patientHomeScreen: (context) => const PatientHomeScreen(),
RouteNames.doctorLandingScreen: (context) => const DoctorLandingScreen(),
RouteNames.patientRegistrationScreen: (context) =>
const PatientRegistrationScreen(),
// RouteNames.patientAdressScreen: (context) =>
// PatientAddressScreen(controller: PatientController()),
// RouteNames.patientFamilyMembersScreen: (context) =>
// PatientFamilyMembersScreen(controller: PatientController()),
// RouteNames.familyMembersEditScreen: (context) =>
// FamilyMembersEditScreen(controller: PatientController()),
RouteNames.doctorAddressScreen: (context) => DoctorAddressScreen(
controller: DoctorController(), // Provide the required controller
),
RouteNames.profileDescriptionScreen: (context) =>
ProfileDescriptionScreen(controller: DoctorController()),
RouteNames.experienceScreen: (context) => ExperienceScreen(
controller: DoctorController(),
),
RouteNames.specialitiesScreeen: (context) => SpecialitiesScreen(
controller: DoctorController(),
),
RouteNames.digitalSignatureScreeen: (context) => DigitalSignatureScreen(
controller: DoctorController(),
),
RouteNames.achievementsScreen: (context) =>
AchievementsScreen(controller: DoctorController()),
// FamilyMembersEditScreen(controller: PatientController()),
RouteNames.qualificationsScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return QualificationsScreen(
controller: controller ?? DoctorController(), // Provide fallback
);
},
RouteNames.doctorAddressScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return DoctorAddressScreen(
controller: controller ?? DoctorController(), // Provide fallback
);
},
RouteNames.profileDescriptionScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return ProfileDescriptionScreen(
controller: controller ?? DoctorController(),
);
},
RouteNames.experienceScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return ExperienceScreen(
controller: controller ?? DoctorController(),
);
},
RouteNames.specialitiesScreeen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return SpecialitiesScreen(
controller: controller ?? DoctorController(),
);
},
RouteNames.digitalSignatureScreeen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return DigitalSignatureScreen(
controller: controller ?? DoctorController(),
);
},
RouteNames.achievementsScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as DoctorController?;
return AchievementsScreen(
controller: controller ?? DoctorController(),
);
},
RouteNames.patientAdressScreen: (context) {
final controller =
ModalRoute.of(context)!.settings.arguments as PatientController;
@ -74,5 +128,84 @@ final Map<String, Widget Function(BuildContext)> routes = {
ModalRoute.of(context)!.settings.arguments as PatientController;
return FamilyMembersEditScreen(controller: controller);
},
RouteNames.patientprofileScreen: (context) => const PatientProfileScreen()
RouteNames.patientprofileScreen: (context) => const PatientProfileScreen(),
RouteNames.patientDashboardScreen: (context) =>
const PatientDashboardScreen(),
RouteNames.specialityScreen: (context) => const SpecialtyScreen(),
RouteNames.doctorListScreen: (context) {
final args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return DoctorsListScreen(
specialty: args['specialty'] as String,
);
},
RouteNames.doctorDetailsScreen: (context) {
final args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return DoctorDetailsScreen(
doctor: args['doctor'] as Doctor,
);
},
RouteNames.consultationCenterScreen: (context) {
final args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return ConsultationsCenterScreen(
doctor: args['doctor'] as Doctor,
);
},
RouteNames.consultationTimeScreen: (context) {
final args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return ConsultationTimeScreen(
doctor: args['doctor'] as Doctor,
selectedConsultation: args['selectedConsultation'] as ConsultationCenter,
);
},
RouteNames.consultationBookingScreen: (context) {
final args =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return ConsultationBookingScreen(
doctor: args['doctor'] as Doctor,
selectedConsultation: args['selectedConsultation'] as ConsultationCenter,
selectedDate: args['selectedDate'] as DateTime,
selectedTime: args['selectedTime'] as String,
);
},
RouteNames.doctorDashbordScreen: (context) => const DoctorDashboardScreen(),
RouteNames.doctorHomeScreen: (context) => const DoctorDashboardHomeScreen(),
RouteNames.doctorPersonalProfileScreen: (context) =>
const DoctorPersonalProfileScreen(),
RouteNames.doctorServicesMenuScreen: (context) =>
const DoctorServicesMenuScreen(),
RouteNames.scheduleConsultationScreen: (context) =>
const ScheduleConsultationScreen(),
RouteNames.businessCenterScreen: (context) {
final controller = ModalRoute.of(context)!.settings.arguments
as ConsultationCenterController?;
return BusinessCenterScreen(
controller: controller ?? ConsultationCenterController(),
);
},
RouteNames.centerFeeAndDuration: (context) {
final controller = ModalRoute.of(context)!.settings.arguments
as ConsultationCenterController?;
return CenterFeeAndDurationScreen(
controller: controller ?? ConsultationCenterController(),
);
},
RouteNames.consultationTimeSlotScreen: (context) {
final controller = ModalRoute.of(context)!.settings.arguments
as ConsultationCenterController?;
return ConsultationTimeSlotScreen(
controller: controller ?? ConsultationCenterController(),
selectedDay: '',
);
},
RouteNames.consultationDayScreen: (context) {
final controller = ModalRoute.of(context)!.settings.arguments
as ConsultationCenterController?;
return ConsultationDayScreen(
controller: controller ?? ConsultationCenterController(),
);
},
};

View File

@ -0,0 +1,306 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import '../../../route_names.dart';
class BusinessCenterScreen extends StatefulWidget {
final ConsultationCenterController controller;
const BusinessCenterScreen({
super.key,
required this.controller,
});
@override
State<BusinessCenterScreen> createState() => _ConsultationCenterScreenState();
}
class _ConsultationCenterScreenState extends State<BusinessCenterScreen> {
late ConsultationCenterController _controller;
late TextEditingController _floorBuildingController;
late TextEditingController _streetController;
late TextEditingController _cityController;
late TextEditingController _stateController;
late TextEditingController _countryController;
late TextEditingController _postalCodeController;
late TextEditingController _addressTypeController;
final _formKey = GlobalKey<FormState>();
String? selectedAddressType;
bool showCustomTypeField = false;
final List<String> addressTypes = ['Home', 'Office', 'Others'];
@override
void initState() {
super.initState();
_controller = widget.controller;
_loadSavedData();
}
@override
void dispose() {
_floorBuildingController.dispose();
_streetController.dispose();
_cityController.dispose();
_stateController.dispose();
_countryController.dispose();
_postalCodeController.dispose();
_addressTypeController.dispose();
super.dispose();
}
void _loadSavedData() {
final center = _controller.model;
_floorBuildingController =
TextEditingController(text: center.floorBuilding ?? '');
_streetController = TextEditingController(text: center.street ?? '');
_cityController = TextEditingController(text: center.city ?? '');
_stateController = TextEditingController(text: center.state ?? '');
_countryController = TextEditingController(text: center.country ?? '');
_postalCodeController =
TextEditingController(text: center.postalCode ?? '');
_addressTypeController =
TextEditingController(text: center.addressType ?? '');
selectedAddressType = widget.controller?.model.addressType;
if (selectedAddressType != null &&
!addressTypes.contains(selectedAddressType)) {
showCustomTypeField = true;
}
}
bool _validateAndProceed() {
if (_formKey.currentState!.validate()) {
_controller.updateFloorBuilding(_floorBuildingController.text);
_controller.updateStreet(_streetController.text);
_controller.updateCity(_cityController.text);
_controller.updateState(_stateController.text);
_controller.updateCountry(_countryController.text);
_controller.updatePostalCode(_postalCodeController.text);
_controller.updateAddressType(_addressTypeController.text);
return true;
}
return false;
}
bool _areFieldsValid() {
return _floorBuildingController.text.isNotEmpty &&
_streetController.text.isNotEmpty &&
_cityController.text.isNotEmpty &&
_stateController.text.isNotEmpty &&
_countryController.text.isNotEmpty &&
_postalCodeController.text.isNotEmpty &&
_addressTypeController.text.isNotEmpty;
}
void _handleAddressTypeSelection(String type) {
setState(() {
if (type == 'Others') {
showCustomTypeField = !showCustomTypeField;
if (!showCustomTypeField) {
_addressTypeController.clear();
selectedAddressType = null;
}
} else {
showCustomTypeField = false;
selectedAddressType = type;
widget.controller?.updateAddressType(type);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.centerFeeAndDuration,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
),
],
title: const Text('Address Details'),
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTextField(
label: 'Floor, Building',
controller: _floorBuildingController,
onChanged: (value) =>
widget.controller!.updateFloorBuilding(value),
icon: Icons.apartment,
isMandatory: true,
),
_buildTextField(
label: 'Street or Road',
controller: _streetController,
onChanged: (value) => widget.controller!.updateStreet(value),
icon: Icons.streetview,
isMandatory: true,
),
_buildTextField(
label: 'City',
controller: _cityController,
onChanged: (value) => widget.controller!.updateCity(value),
icon: Icons.location_city,
isMandatory: true,
),
_buildTextField(
label: 'State',
controller: _stateController,
onChanged: (value) => widget.controller!.updateState(value),
icon: Icons.map,
isMandatory: true,
),
_buildTextField(
label: 'Country',
controller: _countryController,
onChanged: (value) => widget.controller!.updateCountry(value),
icon: Icons.flag,
isMandatory: true,
),
_buildPostalCodeField(
label: 'Postal Code',
controller: _postalCodeController,
onChanged: (value) =>
widget.controller!.updatePostalCode(value),
icon: Icons.mail,
isMandatory: true,
),
// const SizedBox(height: 16),
// _buildAddressTypeChips(),
],
),
),
),
),
);
}
Widget _buildTextField({
required String label,
required TextEditingController controller,
required Function(String) onChanged,
required IconData icon,
bool isMandatory = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
onChanged: onChanged,
validator: (value) {
if (isMandatory && (value == null || value.isEmpty)) {
return '$label is required';
}
if (value != null &&
value.isNotEmpty &&
!RegExp(r"^[a-zA-Z0-9\s]+$").hasMatch(value)) {
return 'Please enter valid text';
}
return null;
},
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(icon, color: Colors.blue),
// filled: true,
// fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
),
),
);
}
Widget _buildPostalCodeField({
required String label,
required TextEditingController controller,
required Function(String) onChanged,
required IconData icon,
bool isMandatory = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
onChanged: onChanged,
keyboardType: TextInputType.number,
maxLength: 6,
validator: (value) {
if (isMandatory && (value == null || value.isEmpty)) {
return '$label is required';
}
if (value != null && !RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'Please enter numbers only';
}
return null;
},
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(icon, color: Colors.blue),
// filled: true,
// fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
counterText: '',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
),
),
);
}
}

View File

@ -0,0 +1,278 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import 'package:telemednet/data/services/consultation_center_service.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
import '../../../route_names.dart';
class CenterFeeAndDurationScreen extends StatefulWidget {
final ConsultationCenterController controller;
const CenterFeeAndDurationScreen({
super.key,
required this.controller,
});
@override
CenterFeeAndDurationScreenState createState() =>
CenterFeeAndDurationScreenState();
}
class CenterFeeAndDurationScreenState
extends State<CenterFeeAndDurationScreen> {
final _formKey = GlobalKey<FormState>();
late final ConsultationCenterController _controller;
late TextEditingController _averageDuration;
late TextEditingController _consultationFee;
bool _isEditing = false;
@override
void initState() {
super.initState();
_controller = widget.controller;
final center = _controller.model;
_averageDuration =
TextEditingController(text: center.averageDurationMinutes ?? '');
_consultationFee =
TextEditingController(text: center.consultationFee ?? '');
}
@override
void dispose() {
_averageDuration.dispose();
_consultationFee.dispose();
super.dispose();
}
void _onFieldChanged() {
setState(() {
_isEditing = true;
});
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAndProceed() {
if (_formKey.currentState!.validate()) {
_controller.updateConsultationFee(_consultationFee.text);
_controller.updateAverageDuration(_averageDuration.text.trim());
return true;
}
return false;
}
Future<void> _saveCenter() async {
// Validate form before proceeding
if (!_validateAndProceed()) {
return;
}
try {
// Create a list with the current controller for the new service method
final List<ConsultationCenterController> controllers = [_controller];
// Use the new saveConsultationCenters method
bool success =
await ConsultationCenterService.saveConsultationCenters(controllers);
if (success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Doctor consultation saved successfully!'),
backgroundColor: Colors.green,
),
);
Navigator.of(context)
.pushReplacementNamed(RouteNames.scheduleConsultationScreen);
} else {
_showError('Failed to save business center. Please try again.');
}
} catch (e) {
_showError('An error occurred while saving. Please try again.');
print('Error saving consultation center: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: _saveCenter,
icon: const Icon(Icons.check),
),
],
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Fee & Duration',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
TextFormField(
controller: _consultationFee,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter consultation fee';
}
int? fee = int.tryParse(value);
if (fee == null || fee <= 0) {
return 'Please enter valid consultation fee';
}
return null;
},
decoration: InputDecoration(
labelText: 'Consultation fee',
prefixIcon: const Icon(Icons.money, color: Colors.blue),
filled: true,
fillColor: Colors.grey[100],
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
),
onChanged: (value) {
_onFieldChanged();
widget.controller.updateConsultationFee(value);
},
),
const SizedBox(height: 24),
TextFormField(
controller: _averageDuration,
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter average duration minutes';
}
int? duration = int.tryParse(value);
if (duration == null || duration <= 0) {
return 'Please enter valid duration';
}
return null;
},
decoration: InputDecoration(
labelText: 'Average duration (minutes)',
prefixIcon:
const Icon(Icons.timelapse, color: Colors.blue),
filled: true,
fillColor: Colors.grey[100],
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
),
onChanged: (value) {
_onFieldChanged();
widget.controller.updateAverageDuration(value);
},
),
const SizedBox(height: 24),
// New Schedule Time link
Center(
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConsultationDayScreen(
controller: widget.controller,
),
),
);
},
style: TextButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(
horizontal: 32, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text(
'Schedule Time',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,282 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/services/consultation_center_service.dart';
import 'package:telemednet/route_names.dart';
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
class ConsultationDayScreen extends StatefulWidget {
final ConsultationCenterController controller;
const ConsultationDayScreen({
super.key,
required this.controller,
});
@override
State<ConsultationDayScreen> createState() => _ConsultationDayScreenState();
}
class _ConsultationDayScreenState extends State<ConsultationDayScreen> {
final _formKey = GlobalKey<FormState>();
final List<String> weekDays = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
Future<void> _showTimeSlotDialog(String day) async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConsultationTimeSlotScreen(
controller: widget.controller,
selectedDay: day,
),
),
);
// Force rebuild after returning from TimeSlotScreen
if (mounted) {
setState(() {});
}
}
Future<void> _saveCenter() async {
if (!_formKey.currentState!.validate()) {
return;
}
try {
final List<ConsultationCenterController> controllers = [
widget.controller
];
bool success =
await ConsultationCenterService.saveConsultationCenters(controllers);
if (success) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Doctor consultation saved successfully!'),
backgroundColor: Colors.green,
),
);
Navigator.of(context)
.pushReplacementNamed(RouteNames.scheduleConsultationScreen);
} else {
_showError('Failed to save consultation center. Please try again.');
}
} catch (e) {
_showError('An error occurred while saving. Please try again.');
print('Error saving consultation center: $e');
}
}
void _showError(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, size: 20),
color: Colors.black54,
onPressed: () => Navigator.pop(context),
),
title: const Text(
'Week Days',
style: TextStyle(
color: Colors.black87,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
centerTitle: true,
actions: [
IconButton(
onPressed: _saveCenter,
icon: const Icon(
Icons.check,
),
),
],
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.08),
spreadRadius: 5,
blurRadius: 15,
offset: const Offset(0, 3),
),
],
),
padding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
child: Column(
children: [
Expanded(
child: ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 8),
itemCount: weekDays.length,
separatorBuilder: (context, index) =>
const SizedBox(height: 12),
itemBuilder: (context, index) {
final day = weekDays[index];
final schedule = widget
.controller.model.weeklySchedule
?.firstWhere(
(schedule) => schedule.day == day,
orElse: () => AvailabilitySchedule(
day: day,
timeSlots: [],
),
);
return // In the ListView.builder, update the Container decoration:
Container(
decoration: BoxDecoration(
color: schedule?.timeSlots?.isNotEmpty == true
? const Color(0xFF4FB6D8).withOpacity(
0.1) // Light blue for days with slots
: Colors.grey[
100], // Original color for days without slots
borderRadius: BorderRadius.circular(30),
),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 8,
),
title: Text(
day,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: schedule?.timeSlots?.isNotEmpty ==
true
? const Color(
0xFF4FB6D8) // Blue text for days with slots
: Colors
.black87, // Original color for days without slots
),
),
// subtitle: schedule?.timeSlots?.isNotEmpty ==
// true
// ? Padding(
// padding: const EdgeInsets.only(top: 4),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: schedule!.timeSlots!
// .map(
// (slot) => Padding(
// padding:
// const EdgeInsets.only(
// top: 2),
// // child: Text(
// // '${slot.startTime} - ${slot.endTime}',
// // style: const TextStyle(
// // fontSize: 13,
// // color: Colors.black54,
// // ),
// // ),
// ),
// )
// .toList(),
// ),
// )
// : null,
trailing: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 3,
offset: const Offset(0, 1),
),
],
),
child: IconButton(
icon: Icon(
Icons.edit_outlined,
size: 20,
color: schedule?.timeSlots?.isNotEmpty ==
true
? const Color(
0xFF4FB6D8) // Blue icon for days with slots
: Colors
.black54, // Original color for days without slots
),
onPressed: () => _showTimeSlotDialog(day),
),
),
),
);
},
),
),
],
),
),
),
// const SizedBox(height: 24),
// SizedBox(
// width: MediaQuery.of(context).size.width * 0.5,
// height: 50,
// child: ElevatedButton(
// onPressed: _saveCenter,
// style: ElevatedButton.styleFrom(
// backgroundColor: const Color(0xFF4FB6D8),
// elevation: 0,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(25),
// ),
// ),
// child: const Text(
// 'SAVE',
// style: TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.w600,
// letterSpacing: 1,
// color: Colors.white),
// ),
// ),
// ),
const SizedBox(height: 16),
],
),
),
),
);
}
}

View File

@ -0,0 +1,381 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/services/consultation_center_service.dart';
import '../../../common/custom_style.dart';
import '../../../route_names.dart';
class ScheduleConsultationScreen extends StatefulWidget {
const ScheduleConsultationScreen({super.key});
@override
ScheduleConsultationScreenState createState() =>
ScheduleConsultationScreenState();
}
class ScheduleConsultationScreenState
extends State<ScheduleConsultationScreen> {
List<ConsultationCenter> _consultationCenters = [];
bool _isLoading = true;
bool _isOnlineConsultationSelected = false;
@override
void initState() {
super.initState();
_fetchConsultationCenters();
}
Future<void> _fetchConsultationCenters() async {
try {
final User? user = FirebaseAuth.instance.currentUser;
final String uid = user!.uid;
final consultationCenters =
await ConsultationCenterService.getDoctorConsultationCenters(uid);
setState(() {
_consultationCenters = consultationCenters;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to load consultation centers: $e')),
);
}
}
String _formatAddress(ConsultationCenter center) {
List<String> addressParts = [];
if (center.floorBuilding != null) addressParts.add(center.floorBuilding!);
if (center.city != null) addressParts.add(center.city!);
return addressParts.join(', ');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pushReplacementNamed(
context, RouteNames.doctorDashbordScreen),
),
title: Text(
'Schedule Consultation',
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
),
),
elevation: CustomStyles.defaultAppBarElevation,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(CustomStyles.pagePadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Online Consultation Button
Card(
elevation: 4,
shadowColor:
Theme.of(context).colorScheme.primary.withOpacity(0.2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(
color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
),
),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
leading: Container(
width: 36,
height: 40,
decoration: BoxDecoration(
color:
Theme.of(context).colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.video_call_rounded,
color: Colors.blue,
size: 24,
),
),
title: Text(
'Online Consultation',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface,
),
),
trailing: Container(
width: 80, // Increased width to accommodate contents
child: Row(
mainAxisSize:
MainAxisSize.min, // Added this to prevent overflow
children: [
SizedBox(
width: 24,
height: 24,
child: Checkbox(
value: _isOnlineConsultationSelected,
onChanged: (bool? value) {
setState(() {
_isOnlineConsultationSelected = value ?? false;
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
checkColor: Colors.blue,
activeColor: Colors.white,
),
),
const SizedBox(width: 8),
IconButton(
padding:
EdgeInsets.zero, // Added to reduce button padding
constraints:
const BoxConstraints(), // Removed constraints
icon: Icon(
Icons.calendar_month_rounded,
color: _isOnlineConsultationSelected
? Colors.blue
: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.4),
),
iconSize: 20,
onPressed: () {
// Navigator.pushNamed(
// context,
// RouteNames.ConsultationDayScreen,
// );
},
),
],
),
),
),
),
const SizedBox(height: 24),
// Consultation Centers Section
Text(
'Consultation Centers',
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 16),
// Consultation Centers List
_isLoading
? const Center(child: CircularProgressIndicator())
: _consultationCenters.isEmpty
? Center(
child: Text(
'No consultation centers available',
style: GoogleFonts.poppins(),
),
)
: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _consultationCenters.length,
itemBuilder: (context, index) {
final center = _consultationCenters[index];
return Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: Card(
elevation: 4,
shadowColor: Theme.of(context)
.colorScheme
.primary
.withOpacity(0.15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(
color: Theme.of(context)
.colorScheme
.outline
.withOpacity(0.1),
),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
_formatAddress(center),
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.colorScheme
.onSurface,
),
),
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
padding: EdgeInsets.zero,
icon: const Icon(
Icons.edit_rounded,
color: Colors.blue,
size: 18,
),
onPressed: () {
// Navigator.pushNamed(
// context,
// RouteNames
// .businessCenterScreen,
// );
},
),
IconButton(
constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
padding: EdgeInsets.zero,
icon: const Icon(
Icons.calendar_month_rounded,
color: Colors.blue,
size: 18,
),
onPressed: () {
// Navigator.pushNamed(
// context,
// RouteNames
// .ConsultationDayScreen,
// );
},
),
],
),
],
),
const SizedBox(height: 8),
IntrinsicHeight(
child: Row(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.payments_outlined,
size: 16,
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.6),
),
const SizedBox(width: 4),
Text(
'Fee: ${center.consultationFee ?? "N/A"}',
style: GoogleFonts.poppins(
fontSize: 13,
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.6),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8),
child: VerticalDivider(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.2),
thickness: 1,
),
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.timer_outlined,
size: 16,
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.6),
),
const SizedBox(width: 4),
Text(
'${center.averageDurationMinutes ?? "N/A"} mins',
style: GoogleFonts.poppins(
fontSize: 13,
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.6),
),
),
],
),
],
),
),
],
),
),
),
);
},
),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.pushNamed(
context,
RouteNames.businessCenterScreen,
);
},
hoverColor: Colors.blue,
backgroundColor: Colors.white,
icon: const Icon(
Icons.add,
color: Colors.blue,
),
label: Text(
'Add Center',
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500, color: Colors.blue),
),
),
);
}
}

View File

@ -0,0 +1,367 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/consultation_center_controller.dart';
import 'package:telemednet/data/models/consultation_center.dart';
class ConsultationTimeSlotScreen extends StatefulWidget {
final ConsultationCenterController controller;
final String selectedDay;
const ConsultationTimeSlotScreen({
super.key,
required this.controller,
required this.selectedDay,
});
@override
State<ConsultationTimeSlotScreen> createState() =>
_ConsultationTimeSlotScreenState();
}
class _ConsultationTimeSlotScreenState
extends State<ConsultationTimeSlotScreen> {
late AvailabilitySchedule currentSchedule;
@override
void initState() {
super.initState();
_initializeSchedule();
}
void _initializeSchedule() {
// Ensure weeklySchedule is not null and initialize it if needed
widget.controller.model.weeklySchedule ??= [];
// Find the schedule for the selected day, or create a new one
currentSchedule = widget.controller.model.weeklySchedule!.firstWhere(
(schedule) => schedule.day == widget.selectedDay,
orElse: () {
final newSchedule = AvailabilitySchedule(
day: widget.selectedDay,
timeSlots: [],
);
widget.controller.model.weeklySchedule!.add(newSchedule);
return newSchedule;
},
);
// Ensure timeSlots is not null
currentSchedule.timeSlots ??= [];
// Debug print
print(
'Initial schedule for ${widget.selectedDay}: ${currentSchedule.timeSlots}');
}
void _addTimeSlot() async {
TimeOfDay? startTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
);
if (startTime != null) {
TimeOfDay? endTime = await showTimePicker(
context: context,
initialTime: startTime,
);
if (endTime != null) {
final slot = TimeSlot(
startTime:
'${startTime.hour}:${startTime.minute.toString().padLeft(2, '0')}',
endTime:
'${endTime.hour}:${endTime.minute.toString().padLeft(2, '0')}',
);
if (mounted) {
setState(() {
widget.controller.addTimeSlot(widget.selectedDay, slot);
// Update local schedule
currentSchedule =
widget.controller.model.weeklySchedule?.firstWhere(
(schedule) => schedule.day == widget.selectedDay,
orElse: () => AvailabilitySchedule(
day: widget.selectedDay,
timeSlots: [],
),
) ??
AvailabilitySchedule(
day: widget.selectedDay,
timeSlots: [],
);
});
// Debug print
print('Added time slot: $slot');
print('Updated schedule: ${currentSchedule.timeSlots}');
}
}
}
}
void _editTimeSlot(TimeSlot currentSlot) async {
final currentStart = currentSlot.startTime!.split(':');
final currentEnd = currentSlot.endTime!.split(':');
TimeOfDay? startTime = await showTimePicker(
context: context,
initialTime: TimeOfDay(
hour: int.parse(currentStart[0]),
minute: int.parse(currentStart[1]),
),
);
if (startTime != null) {
TimeOfDay? endTime = await showTimePicker(
context: context,
initialTime: TimeOfDay(
hour: int.parse(currentEnd[0]),
minute: int.parse(currentEnd[1]),
),
);
if (endTime != null && mounted) {
setState(() {
// Remove old slot
widget.controller.removeTimeSlot(widget.selectedDay, currentSlot);
// Add new slot
final newSlot = TimeSlot(
startTime:
'${startTime.hour}:${startTime.minute.toString().padLeft(2, '0')}',
endTime:
'${endTime.hour}:${endTime.minute.toString().padLeft(2, '0')}',
);
widget.controller.addTimeSlot(widget.selectedDay, newSlot);
// Update local schedule
currentSchedule = widget.controller.model.weeklySchedule!.firstWhere(
(schedule) => schedule.day == widget.selectedDay,
orElse: () => AvailabilitySchedule(
day: widget.selectedDay,
timeSlots: [],
),
);
});
// Debug print
// print('Edited time slot from $currentSlot to $newSlot');
}
}
}
void _deleteTimeSlot(TimeSlot slot) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete Time Slot'),
content: const Text('Are you sure you want to delete this time slot?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
setState(() {
widget.controller.removeTimeSlot(widget.selectedDay, slot);
// Update local schedule
currentSchedule =
widget.controller.model.weeklySchedule!.firstWhere(
(schedule) => schedule.day == widget.selectedDay,
orElse: () => AvailabilitySchedule(
day: widget.selectedDay,
timeSlots: [],
),
);
});
Navigator.pop(context);
// Debug print
print('Deleted time slot: $slot');
print('Updated schedule: ${currentSchedule.timeSlots}');
},
child: const Text(
'Delete',
style: TextStyle(color: Colors.red),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, size: 20),
color: Colors.black54,
onPressed: () => Navigator.pop(context),
),
title: Text(
'${widget.selectedDay} Schedule',
style: const TextStyle(
color: Colors.black87,
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
centerTitle: true,
actions: [
IconButton(
onPressed: () {
Navigator.of(context)
.pop(true); // Pop with true to indicate changes
},
icon: const Icon(
Icons.check,
color: Color(0xFF4FB6D8),
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
'Time Slots',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
),
Expanded(
child: Container(
height:
MediaQuery.of(context).size.height * 0.2, // Reduced height
margin: const EdgeInsets.only(bottom: 250),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.08),
spreadRadius: 5,
blurRadius: 15,
offset: const Offset(0, 3),
),
],
),
padding: const EdgeInsets.all(16),
child: (currentSchedule.timeSlots == null ||
currentSchedule.timeSlots!.isEmpty)
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.access_time,
size: 48,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'No time slots added yet',
style: TextStyle(
fontSize: 16,
color: Colors.grey[600],
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'Tap + to add your first time slot',
style: TextStyle(
fontSize: 14,
color: Colors.grey[400],
),
),
],
),
)
: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: currentSchedule.timeSlots!.length,
separatorBuilder: (context, index) =>
const Divider(height: 1),
itemBuilder: (context, index) {
final slot = currentSchedule.timeSlots![index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.access_time,
color: Colors.blue,
size: 24,
),
),
title: Text(
'${slot.startTime} - ${slot.endTime}',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.edit_outlined,
size: 30,
color: Colors.blue,
),
onPressed: () => _editTimeSlot(slot),
),
IconButton(
icon: const Icon(
Icons.delete_outline,
size: 30,
color: Colors.red,
),
onPressed: () => _deleteTimeSlot(slot),
),
],
),
),
);
},
),
),
),
],
),
),
floatingActionButton: Container(
margin: const EdgeInsets.only(bottom: 270, right: 25),
child: FloatingActionButton(
onPressed: _addTimeSlot,
backgroundColor: const Color(0xFF4FB6D8),
elevation: 2,
child: const Icon(
Icons.add,
size: 28,
color: Colors.white,
),
),
),
);
}
}

View File

@ -0,0 +1,172 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
class DoctorDashboardHomeScreen extends StatefulWidget {
const DoctorDashboardHomeScreen({super.key});
@override
State<DoctorDashboardHomeScreen> createState() =>
_DoctorDashboardHomeScreenState();
}
class _DoctorDashboardHomeScreenState extends State<DoctorDashboardHomeScreen>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildSearchBar(),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [_buildRealTimeCard(), const SizedBox(height: 20)],
),
),
// _buildBottomNavBar(),
],
),
),
);
}
Widget _buildSearchBar() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.blue[400]!,
Colors.blue[300]!,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: TextField(
decoration: InputDecoration(
hintText: 'Search Patients',
hintStyle: GoogleFonts.poppins(
color: Colors.grey[400],
),
prefixIcon: const Icon(Icons.search, color: Colors.blue),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
),
),
),
],
),
);
}
Widget _buildRealTimeCard() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue[400]!, Colors.white],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Real-time care\nat your fingertips.',
style: GoogleFonts.poppins(
fontSize: 30,
fontWeight: FontWeight.bold,
color: const Color.fromARGB(221, 67, 67, 67),
),
),
const SizedBox(height: 12),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SpecialtyScreen()),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.blue[700],
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
elevation: 5,
),
child: Text(
'Start Consultation',
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
class DoctorDashboardScreen extends StatefulWidget {
const DoctorDashboardScreen({super.key});
@override
State<DoctorDashboardScreen> createState() => _DoctorDashboardScreenState();
}
class _DoctorDashboardScreenState extends State<DoctorDashboardScreen> {
int _selectedIndex = 0;
final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
// Add your pages here
final List<Widget> _pages = [
const DoctorDashboardHomeScreen(),
// const Center(child: Text('Chat')), // Replace with your chat screen
const DoctorServicesMenuScreen(), // Replace with your records screen
const DoctorPersonalProfileScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageTransitionSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation, secondaryAnimation) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: _pages[_selectedIndex],
),
bottomNavigationBar: CurvedNavigationBar(
key: _bottomNavigationKey,
backgroundColor: Colors.transparent,
color: Colors.blue,
buttonBackgroundColor: Colors.blue,
height: 60,
index: _selectedIndex,
items: const [
Icon(Icons.home, size: 30, color: Colors.white),
// Icon(Icons.list, size: 30, color: Colors.white),
Icon(Icons.list, size: 30, color: Colors.white),
Icon(Icons.person, size: 30, color: Colors.white),
],
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
),
);
}
}

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:telemednet/route_names.dart';
class PatientLandingScreen extends StatelessWidget {
const PatientLandingScreen({super.key});
class DoctorLandingScreen extends StatelessWidget {
const DoctorLandingScreen({super.key});
@override
Widget build(BuildContext context) {
@ -34,8 +34,8 @@ class PatientLandingScreen extends StatelessWidget {
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
Navigator.of(context).pushNamed(
RouteNames.patientDashboardScreen);
Navigator.of(context)
.pushNamed(RouteNames.doctorDashbordScreen);
},
child: Text(
'Skip',
@ -53,7 +53,7 @@ class PatientLandingScreen extends StatelessWidget {
),
const SizedBox(height: 24),
const Text(
'Set your medical profile',
'Set your service profile',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
@ -64,7 +64,7 @@ class PatientLandingScreen extends StatelessWidget {
ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed(
RouteNames.patientRegistrationScreen);
RouteNames.scheduleConsultationScreen);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,

View File

@ -0,0 +1,172 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:telemednet/route_names.dart';
class DoctorPersonalProfileScreen extends StatefulWidget {
const DoctorPersonalProfileScreen({super.key});
@override
State<DoctorPersonalProfileScreen> createState() =>
_DoctorPersonalProfileScreen();
}
class _DoctorPersonalProfileScreen extends State<DoctorPersonalProfileScreen> {
final FirebaseAuth _auth = FirebaseAuth.instance;
// final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildProfileHeader(),
_buildProfileOptions(),
const Spacer(),
// _buildBottomNavBar(),
],
),
),
);
}
Widget _buildProfileHeader() {
return Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF00BCD4),
Color(0xFF2196F3),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
child: Row(
children: [
Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: const Center(
child: Text(
'D',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
),
),
const SizedBox(width: 16),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Doctor',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'Personal Profile',
style: TextStyle(
fontSize: 14,
color: Colors.white70,
),
),
],
),
),
const Icon(
Icons.chevron_right,
color: Colors.white,
size: 30,
),
],
),
);
}
Widget _buildProfileOptions() {
return Container(
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 5,
),
],
),
child: Column(
children: [
_buildOptionTile(' Profile', Icons.medical_information_outlined,
onTap: () {}, iconColor: Colors.blue),
const Divider(height: 1),
_buildOptionTile(
'Sign Out',
Icons.logout,
onTap: () {
_signOut();
},
iconColor: Colors.blue,
),
],
),
);
}
Widget _buildOptionTile(String title, IconData icon,
{required VoidCallback onTap, Color? iconColor}) {
return ListTile(
leading: Icon(
icon,
color: iconColor ?? Colors.grey,
size: 24,
),
title: Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
trailing: const Icon(
Icons.chevron_right,
color: Colors.grey,
),
onTap: onTap,
);
}
Future<void> _signOut() async {
try {
await _auth.signOut();
if (mounted) {
Navigator.of(context).pushReplacementNamed(RouteNames.launch);
}
} catch (e) {
print("Error signing out: $e");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to log out. Please try again.')),
);
}
}
}
}

View File

@ -0,0 +1,179 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:telemednet/route_names.dart';
class DoctorServicesMenuScreen extends StatefulWidget {
const DoctorServicesMenuScreen({super.key});
@override
State<DoctorServicesMenuScreen> createState() => _DoctorServicesMenuScreen();
}
class _DoctorServicesMenuScreen extends State<DoctorServicesMenuScreen> {
final FirebaseAuth _auth = FirebaseAuth.instance;
// final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildProfileHeader(),
_buildProfileOptions(),
const Spacer(),
// _buildBottomNavBar(),
],
),
),
);
}
Widget _buildProfileHeader() {
return Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF00BCD4),
Color(0xFF2196F3),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
child: Row(
children: [
Container(
width: 60,
height: 60,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: const Center(
child: Text(
'D',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
),
),
const SizedBox(width: 16),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Doctor',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'See our services below',
style: TextStyle(
fontSize: 14,
color: Colors.white70,
),
),
],
),
),
const Icon(
Icons.chevron_right,
color: Colors.white,
size: 30,
),
],
),
);
}
Widget _buildProfileOptions() {
return Container(
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 5,
),
],
),
child: Column(
children: [
_buildOptionTile(
'Schedule consultation',
Icons.medical_information_outlined,
onTap: () {
Navigator.of(context)
.pushNamed(RouteNames.scheduleConsultationScreen);
},
iconColor: Colors.blue,
),
const Divider(height: 1),
_buildOptionTile(
'E-prescription',
Icons.logout,
onTap: () {
// Navigator.of(context).pushReplacementNamed(RouteNames.scheduleConsultationScreen);
},
iconColor: Colors.blue,
),
],
),
);
}
Widget _buildOptionTile(String title, IconData icon,
{required VoidCallback onTap, Color? iconColor}) {
return ListTile(
leading: Icon(
icon,
color: iconColor ?? Colors.grey,
size: 24,
),
title: Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
trailing: const Icon(
Icons.chevron_right,
color: Colors.grey,
),
onTap: onTap,
);
}
Future<void> _signOut() async {
try {
await _auth.signOut();
if (mounted) {
Navigator.of(context)
.pushReplacementNamed(RouteNames.scheduleConsultationScreen);
}
} catch (e) {
print("Error signing out: $e");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to log out. Please try again.')),
);
}
}
}
}

View File

@ -0,0 +1,276 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class AchievementsScreen extends StatefulWidget {
final DoctorController controller;
const AchievementsScreen({
super.key,
required this.controller,
});
@override
State<AchievementsScreen> createState() => _AchievementsScreenState();
}
class _AchievementsScreenState extends State<AchievementsScreen> {
final _formKey = GlobalKey<FormState>();
late DoctorController _controller;
late TextEditingController _achievementController;
late List<String> achievements;
bool _isEditing = false;
@override
void initState() {
super.initState();
_controller = widget.controller;
_controller.model.achievements ??= [];
_achievementController = TextEditingController();
achievements = List<String>.from(_controller.model.achievements ?? []);
// if (achievements.isNotEmpty) {
// _achievementController.text = achievements.join(', ');
// }
// _achievementController.addListener(_onFieldChanged);
}
void _onFieldChanged() {
setState(() {
_isEditing = _achievementController.text.isNotEmpty;
});
}
bool _validateAchievement(String value) {
if (value.isEmpty) {
_showError('Please enter an achievement');
return false;
}
if (achievements.any((a) => a.toLowerCase() == value.toLowerCase())) {
_showError('This achievement has already been added');
return false;
}
if (value.length < 3) {
_showError('Achievement must be at least 3 characters long');
return false;
}
return true;
}
void _addAchievement() {
if (_formKey.currentState!.validate()) {
final achievement = _achievementController.text.trim();
if (_validateAchievement(achievement)) {
setState(() {
achievements.add(achievement);
_isEditing = true;
});
_controller.updateAchievements(List<String>.from(achievements));
_achievementController.clear();
}
}
}
void _removeAchievement(int index) {
setState(() {
achievements.removeAt(index);
_isEditing = true;
});
_controller.updateAchievements(List<String>.from(achievements));
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateBeforeNextPage() {
if (achievements.isEmpty) {
_showError('Please add at least one achievement');
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_isEditing) {
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('DISCARD'),
),
],
),
);
return shouldPop ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateBeforeNextPage()) {
Navigator.pushNamed(
context, RouteNames.digitalSignatureScreeen,
arguments: _controller);
}
},
icon: const Icon(Icons.arrow_forward)),
],
title: const Text('Achievements'),
),
body: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Add Your Achievements',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 8),
Container(
margin:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: TextFormField(
controller: _achievementController,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
hintText: 'Enter your achievement',
labelText: 'Achievement',
filled: true,
fillColor: Colors.grey[100],
suffixIcon: IconButton(
icon: const Icon(Icons.add_circle_outline,
color: Colors.blue),
onPressed: _addAchievement,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
helperText: achievements.isEmpty
? 'Minimum 3 characters required'
: null,
),
validator: (value) {
if (achievements.isEmpty) {
if (value == null || value.isEmpty) {
return 'Please enter an achievement';
}
if (value.length < 3) {
return 'Achievement must be at least 3 characters long';
}
}
if (value != null &&
value.isNotEmpty &&
achievements.any((a) =>
a.toLowerCase() == value.toLowerCase())) {
return 'This achievement has already been added';
}
return null;
},
onFieldSubmitted: (_) => _addAchievement(),
),
),
),
Expanded(
child: ListView.builder(
itemCount: achievements.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
return Card(
elevation: 2,
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xFF5BC0DE),
child: Text('${index + 1}'),
),
title: Text(achievements[index]),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _removeAchievement(index),
),
),
);
},
),
),
],
),
),
));
}
@override
void dispose() {
_achievementController.removeListener(_onFieldChanged);
_achievementController.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,470 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class DoctorAddressScreen extends StatefulWidget {
final DoctorController? controller;
const DoctorAddressScreen({
super.key,
required this.controller,
});
@override
State<DoctorAddressScreen> createState() => _DoctorAddressScreenState();
}
class _DoctorAddressScreenState extends State<DoctorAddressScreen> {
late DoctorController _controller;
late TextEditingController _floorBuildingController;
late TextEditingController _streetController;
late TextEditingController _cityController;
late TextEditingController _stateController;
late TextEditingController _countryController;
late TextEditingController _postalCodeController;
late TextEditingController _addressTypeController;
final _formKey = GlobalKey<FormState>();
String? selectedAddressType;
bool showCustomTypeField = false;
final List<String> addressTypes = ['Home', 'Office', 'Others'];
@override
void initState() {
super.initState();
_controller = widget.controller ?? DoctorController();
_loadSavedData();
}
@override
void dispose() {
_floorBuildingController.dispose();
_streetController.dispose();
_cityController.dispose();
_stateController.dispose();
_countryController.dispose();
_postalCodeController.dispose();
_addressTypeController.dispose();
super.dispose();
}
void _loadSavedData() {
final doctor = _controller.model;
_floorBuildingController =
TextEditingController(text: doctor.floorBuilding ?? '');
_streetController = TextEditingController(text: doctor.street ?? '');
_cityController = TextEditingController(text: doctor.city ?? '');
_stateController = TextEditingController(text: doctor.state ?? '');
_countryController = TextEditingController(text: doctor.country ?? '');
_postalCodeController =
TextEditingController(text: doctor.postalCode ?? '');
_addressTypeController =
TextEditingController(text: doctor.addressType ?? '');
selectedAddressType = widget.controller?.model.addressType;
if (selectedAddressType != null &&
!addressTypes.contains(selectedAddressType)) {
showCustomTypeField = true;
}
}
// bool _validateAndProceed() {if (_formKey.currentState!.validate()) {
// // Update the address model
// _controller.updateFloorBuilding(_floorBuildingController.text);
// _controller.updateStreet(_streetController.text);
// _controller.updateCity(_cityController.text);
// _controller.updateState(_stateController.text);
// _controller.updateCountry(_countryController.text);
// _controller.updatePostalCode(_postalCodeController.text);
// // Validate the address fields
// if (_areFieldsValid()) {
// return true;
// }
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(content: Text('Please fill in all required fields')),
// );
// return false;
// }
bool _validateAndProceed() {
// if (!_formKey.currentState!.validate()) return false;
// if (selectedAddressType == null) {
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
// content: Text('Please select an address type'),
// backgroundColor: Colors.red,
// ));
// }
if (_formKey.currentState!.validate()) {
_controller.updateFloorBuilding(_floorBuildingController.text);
_controller.updateStreet(_streetController.text);
_controller.updateCity(_cityController.text);
_controller.updateState(_stateController.text);
_controller.updateCountry(_countryController.text);
_controller.updatePostalCode(_postalCodeController.text);
_controller.updateAddressType(_addressTypeController.text);
return true;
}
return false;
}
bool _areFieldsValid() {
return _floorBuildingController.text.isNotEmpty &&
_streetController.text.isNotEmpty &&
_cityController.text.isNotEmpty &&
_stateController.text.isNotEmpty &&
_countryController.text.isNotEmpty &&
_postalCodeController.text.isNotEmpty &&
_addressTypeController.text.isNotEmpty;
}
// bool _validateAndProceed() {
// if (!_formKey.currentState!.validate()) return false;
// if (selectedAddressType == null) {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content: Text('Please select an address type'),
// backgroundColor: Colors.red,
// ),
// );
// return false;
// }
// return true;
// }
void _handleAddressTypeSelection(String type) {
setState(() {
if (type == 'Others') {
showCustomTypeField = !showCustomTypeField;
if (!showCustomTypeField) {
_addressTypeController.clear();
selectedAddressType = null;
}
} else {
showCustomTypeField = false;
selectedAddressType = type;
widget.controller?.updateAddressType(type);
}
});
}
Widget _buildAddressTypeChips() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Address Type',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
const SizedBox(height: 8),
LayoutBuilder(
builder: (context, constraints) {
// Use the width of the layout to manage chip sizes
final chipMaxWidth = constraints.maxWidth;
return Wrap(
spacing: 6, // Adjusted spacing to help fit in a single row
runSpacing: 6,
children: addressTypes.map((type) {
final isSelected =
!showCustomTypeField && selectedAddressType == type ||
(type == 'Others' && showCustomTypeField);
IconData icon;
switch (type) {
case 'Home':
icon = Icons.home;
break;
case 'Office':
icon = Icons.work;
break;
case 'Others':
icon = Icons.more_horiz;
break;
default:
icon = Icons.location_on;
}
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _handleAddressTypeSelection(type),
borderRadius: BorderRadius.circular(20),
child: Container(
constraints: BoxConstraints(
maxWidth:
(chipMaxWidth - (addressTypes.length - 1) * 6) /
addressTypes.length,
), // Calculate width to fit all chips within row
padding: const EdgeInsets.symmetric(
horizontal: 12, // Reduced horizontal padding
vertical: 8, // Reduced vertical padding
),
decoration: BoxDecoration(
color: isSelected
? Colors.blue.withOpacity(0.2)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? Colors.blue : Colors.transparent,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon,
color: Colors.blue, size: 16), // Smaller icon
const SizedBox(
width: 4), // Spacing between icon and text
Text(
type,
style: TextStyle(
fontSize: 14, // Reduced font size
color: isSelected ? Colors.blue : Colors.black87,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
);
}).toList(),
);
},
),
if (showCustomTypeField) ...[
const SizedBox(height: 16),
TextFormField(
controller: _addressTypeController,
decoration: InputDecoration(
labelText: 'Custom Address Type',
prefixIcon:
const Icon(Icons.edit_location_alt, color: Colors.blue),
// filled: true,
// fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
),
validator: (value) {
if (showCustomTypeField && (value == null || value.isEmpty)) {
return 'Please enter address type';
}
return null;
},
onChanged: (value) {
_controller.updateAddressType(value);
}),
],
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.profileDescriptionScreen,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
),
],
title: const Text('Address Details'),
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTextField(
label: 'Floor, Building',
controller: _floorBuildingController,
onChanged: (value) =>
widget.controller!.updateFloorBuilding(value),
icon: Icons.apartment,
isMandatory: true,
),
_buildTextField(
label: 'Street or Road',
controller: _streetController,
onChanged: (value) => widget.controller!.updateStreet(value),
icon: Icons.streetview,
isMandatory: true,
),
_buildTextField(
label: 'City',
controller: _cityController,
onChanged: (value) => widget.controller!.updateCity(value),
icon: Icons.location_city,
isMandatory: true,
),
_buildTextField(
label: 'State',
controller: _stateController,
onChanged: (value) => widget.controller!.updateState(value),
icon: Icons.map,
isMandatory: true,
),
_buildTextField(
label: 'Country',
controller: _countryController,
onChanged: (value) => widget.controller!.updateCountry(value),
icon: Icons.flag,
isMandatory: true,
),
_buildPostalCodeField(
label: 'Postal Code',
controller: _postalCodeController,
onChanged: (value) =>
widget.controller!.updatePostalCode(value),
icon: Icons.mail,
isMandatory: true,
),
const SizedBox(height: 16),
_buildAddressTypeChips(),
],
),
),
),
),
);
}
Widget _buildTextField({
required String label,
required TextEditingController controller,
required Function(String) onChanged,
required IconData icon,
bool isMandatory = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
onChanged: onChanged,
validator: (value) {
if (isMandatory && (value == null || value.isEmpty)) {
return '$label is required';
}
if (value != null &&
value.isNotEmpty &&
!RegExp(r"^[a-zA-Z0-9\s]+$").hasMatch(value)) {
return 'Please enter valid text';
}
return null;
},
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(icon, color: Colors.blue),
// filled: true,
// fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
),
),
);
}
Widget _buildPostalCodeField({
required String label,
required TextEditingController controller,
required Function(String) onChanged,
required IconData icon,
bool isMandatory = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
onChanged: onChanged,
keyboardType: TextInputType.number,
maxLength: 6,
validator: (value) {
if (isMandatory && (value == null || value.isEmpty)) {
return '$label is required';
}
if (value != null && !RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'Please enter numbers only';
}
return null;
},
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(icon, color: Colors.blue),
// filled: true,
// fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
counterText: '',
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
),
),
);
}
}

View File

@ -1,17 +1,14 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import '../../controllers/doctor_controller.dart';
import '../../data/services/doctor_profile_service.dart';
import '../../route_names.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../data/services/doctor_profile_service.dart';
import '../../../route_names.dart';
class DigitalSignatureScreen extends StatefulWidget {
final DoctorController controller;
const DigitalSignatureScreen({
super.key,
required this.controller,
});
const DigitalSignatureScreen({super.key, required this.controller});
@override
State<DigitalSignatureScreen> createState() => _DigitalSignatureScreenState();
@ -35,23 +32,42 @@ class _DigitalSignatureScreenState extends State<DigitalSignatureScreen> {
}
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateSignature() {
if (_signatureFile == null) {
_showError('Please upload your digital signature');
return false;
}
return true;
}
Future<void> _saveProfile() async {
if (!_validateSignature()) {
return;
}
bool success =
await DoctorProfileService.saveDoctorProfile(widget.controller);
if (mounted) {
setState(() {
if (success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Doctor profile saved successfully!')),
);
Navigator.of(context).pushNamed(RouteNames.doctorAddressScreen);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to save profile. Please try again.')),
);
}
});
if (success) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Doctor profile saved successfully!'),
backgroundColor: Colors.green,
),
);
Navigator.of(context).pushNamed(RouteNames.doctorLandingScreen);
} else {
_showError('Failed to save profile. Please try again.');
}
}
@ -59,6 +75,10 @@ class _DigitalSignatureScreenState extends State<DigitalSignatureScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: _saveProfile, icon: const Icon(Icons.arrow_forward))
],
title: const Text(
'Digital Signature',
style: TextStyle(
@ -66,18 +86,6 @@ class _DigitalSignatureScreenState extends State<DigitalSignatureScreen> {
fontWeight: FontWeight.bold,
),
),
actions: [
TextButton(
onPressed: _saveProfile,
child: const Text(
'Save and Skip',
style: TextStyle(
color: Color(0xFF5BC0DE),
fontSize: 16,
),
),
),
],
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
@ -133,21 +141,6 @@ class _DigitalSignatureScreenState extends State<DigitalSignatureScreen> {
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: _saveProfile, // Call _saveProfile here
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF5BC0DE),
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
),
],
),
);

View File

@ -0,0 +1,455 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import 'package:telemednet/route_names.dart';
class ProfileUploadPage extends StatefulWidget {
const ProfileUploadPage({super.key});
@override
_ProfileUploadPageState createState() => _ProfileUploadPageState();
}
class _ProfileUploadPageState extends State<ProfileUploadPage> {
final DoctorController _controller = DoctorController();
final TextEditingController _titleController = TextEditingController();
final TextEditingController _surnameController = TextEditingController();
final TextEditingController _lastnameController = TextEditingController();
final TextEditingController _middlenameController = TextEditingController();
File? _image;
final ImagePicker _picker = ImagePicker();
final _formKey = GlobalKey<FormState>();
String? _selectedTitle;
final List<String> _titles = ['Mr', 'Mrs', 'Miss'];
final Map<String, String> _errors = {};
@override
void initState() {
super.initState();
_titleController.text = _controller.model.title ?? '';
_surnameController.text = _controller.model.surName ?? '';
_lastnameController.text = _controller.model.lastName ?? '';
_middlenameController.text = _controller.model.middleName ?? '';
}
@override
void dispose() {
_titleController.dispose();
_surnameController.dispose();
_lastnameController.dispose();
_middlenameController.dispose();
super.dispose();
}
bool _isEditing = false;
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAndProceed() {
if (_image == null) {
_showError('Please upload your profile picture');
return false;
}
if (_formKey.currentState!.validate()) {
_controller.updateTitle(_titleController.text);
_controller.updateSurName(_surnameController.text);
_controller.updateLastName(_lastnameController.text);
_controller.updateMiddleName(_middlenameController.text);
return true;
}
return false;
}
Future<void> _getImage(ImageSource source) async {
try {
final XFile? image = await _picker.pickImage(
source: source,
imageQuality: 80,
maxWidth: 1000,
maxHeight: 1000,
);
if (image != null) {
setState(() {
_image = File(image.path);
_isEditing = true;
});
_controller.updateProfileImage(image.path);
}
} catch (e) {
debugPrint('Error picking image: $e');
_showError('Failed to upload image. Please try again.');
}
}
void _showImageSourceActionSheet(BuildContext context) {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Text(
'Select Image Source',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(Icons.photo_library, color: Colors.blue),
),
title: const Text('Choose from Gallery'),
onTap: () {
_getImage(ImageSource.gallery);
Navigator.pop(context);
},
),
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(Icons.photo_camera, color: Colors.blue),
),
title: const Text('Take a Photo'),
onTap: () {
_getImage(ImageSource.camera);
Navigator.pop(context);
},
),
const SizedBox(height: 16),
],
),
),
);
},
);
}
void _updateCombinedName(String name) {
String fullName = '$_selectedTitle$name';
_controller.updateSurName(fullName);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.qualificationsScreen,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
)
],
title: const Text('Doctor Profile'),
),
body: SafeArea(
child: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Stack(
children: [
GestureDetector(
onTap: () => _showImageSourceActionSheet(context),
child: CircleAvatar(
radius: 75,
backgroundColor: Colors.blue.withOpacity(0.5),
backgroundImage:
_image != null ? FileImage(_image!) : null,
child: _image == null
? const Icon(Icons.person,
size: 50, color: Colors.blue)
: null,
),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
child: const Icon(Icons.camera_alt,
size: 16, color: Colors.white),
),
),
],
),
),
const SizedBox(height: 24),
Container(
margin:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.blueGrey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
_buildUniformField(
label: 'Name',
icon: Icons.person,
child:
Container(), // The child parameter is not used in this implementation
),
// _buildTextField(
// 'Title',
// _titleController,
// (value) => _controller.updateTitle(value),
// icon: Icons.title,
// isMandatory: true,
// ),
_buildTextField(
'Surname',
_surnameController,
(value) => _controller.updateSurName(value),
icon: Icons.person,
isMandatory: true,
),
// _buildTextField(
// 'Firstname',
// _lastnameController,
// (value) => _controller.updateLastName(value),
// icon: Icons.person_outline,
// isMandatory: true,
// ),
_buildTextField(
'Middle name',
_middlenameController,
(value) => _controller.updateMiddleName(value),
icon: Icons.person_outline,
),
],
),
),
const SizedBox(height: 16),
],
),
),
),
),
);
}
Widget _buildUniformField({
required String label,
required IconData icon,
required Widget child,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Container(
height: 58, // Set a fixed height
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade300, width: 1),
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child:
Icon(icon, color: Colors.blue, size: 20), // Reduced icon size
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
width: 80,
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
isDense: true, // Makes dropdown more compact
value: _selectedTitle,
hint: const Text(
'Title',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
style: const TextStyle(
fontSize: 16,
color: Colors.black87,
),
onChanged: (String? newValue) {
if (newValue != null) {
setState(() {
_selectedTitle = newValue;
_titleController.text =
newValue; // Add this line to update the controller
});
_controller.updateTitle(_titleController.text);
}
},
items: _titles.map<DropdownMenuItem<String>>(
(String code) {
return DropdownMenuItem<String>(
value: code,
child: Text(
code,
style: const TextStyle(
fontSize: 16,
color: Colors.black87,
),
),
);
},
).toList(),
),
),
),
Expanded(
child: TextFormField(
controller: _lastnameController,
onChanged: (value) {
_controller.updateLastName(value);
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'First name is required';
}
if (!RegExp(r"^[a-zA-Z\s]+$").hasMatch(value)) {
return 'Please enter valid text';
}
return null;
},
style: const TextStyle(
fontSize: 16,
color: Colors.black87,
),
decoration: InputDecoration(
labelText: label,
labelStyle: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
hintText: 'Enter name',
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 12), // Reduced vertical padding
// isDense: true, // Makes the input field more compact
),
),
),
],
),
),
);
}
Widget _buildTextField(
String label,
TextEditingController controller,
Function(String) onChanged, {
required IconData icon,
bool isMandatory = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextFormField(
controller: controller,
onChanged: onChanged,
validator: (value) {
if (isMandatory && (value == null || value.isEmpty)) {
return '$label is required';
}
if (value != null &&
value.isNotEmpty &&
!RegExp(r"^[a-zA-Z\s]+$").hasMatch(value)) {
return 'Please enter valid text';
}
return null;
},
style: const TextStyle(
fontSize: 16,
color: Colors.black87,
),
decoration: InputDecoration(
labelText: label,
labelStyle: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
prefixIcon: Icon(icon, color: Colors.blue),
filled: true,
fillColor: Colors.grey[100],
contentPadding:
const EdgeInsets.symmetric(vertical: 20, horizontal: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.red, width: 1.5),
),
),
),
);
}
}

View File

@ -0,0 +1,228 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class ExperienceScreen extends StatefulWidget {
final DoctorController controller;
const ExperienceScreen({
super.key,
required this.controller,
});
@override
_ExperienceScreenState createState() => _ExperienceScreenState();
}
class _ExperienceScreenState extends State<ExperienceScreen> {
final _formKey = GlobalKey<FormState>();
late final DoctorController _controller;
late TextEditingController _selectedExperience;
late TextEditingController _licenseController;
bool _isEditing = false;
@override
void initState() {
super.initState();
_controller = widget.controller;
final doctor = _controller.model;
_selectedExperience =
TextEditingController(text: doctor.yearsOfExperience ?? '');
_licenseController =
TextEditingController(text: doctor.licenseNumber ?? '');
_licenseController.addListener(_onFieldChanged);
}
@override
void dispose() {
_selectedExperience.dispose();
_licenseController.removeListener(_onFieldChanged);
_licenseController.dispose();
super.dispose();
}
void _onFieldChanged() {
setState(() {
_isEditing = true;
});
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAndProceed() {
if (_formKey.currentState!.validate()) {
_controller.updateYearsOfExperience(_selectedExperience.text);
_controller.updateLicenseNumber(_licenseController.text.trim());
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.specialitiesScreeen,
arguments: _controller,
);
}
},
icon: const Icon(
Icons.arrow_forward,
// color: _formKey.currentState?.validate() == true
// ? Colors.blue
// : Colors.red,
),
),
],
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Professional Experience',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
TextFormField(
controller: _selectedExperience,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter years of experience';
}
int? years = int.tryParse(value);
if (years == null || years <= 0) {
return 'Please enter valid years of experience';
}
if (years > 50) {
return 'Years of experience cannot exceed 50';
}
return null;
},
decoration: InputDecoration(
labelText: 'Years of Experience',
prefixIcon: const Icon(Icons.work, color: Colors.blue),
filled: true,
fillColor: Colors.grey[100],
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
),
onChanged: (value) {
_onFieldChanged();
widget.controller.updateYearsOfExperience(value);
},
),
const SizedBox(height: 24),
TextFormField(
controller: _licenseController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter license number';
}
if (value.length < 5) {
return 'License number must be at least 5 digits';
}
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
return 'Please enter numbers only';
}
return null;
},
decoration: InputDecoration(
labelText: 'License Number',
prefixIcon: const Icon(Icons.badge, color: Colors.blue),
filled: true,
fillColor: Colors.grey[100],
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
),
onChanged: (value) {
_onFieldChanged();
widget.controller.updateLicenseNumber(value);
},
),
],
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,203 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class ProfileDescriptionScreen extends StatefulWidget {
final DoctorController? controller;
const ProfileDescriptionScreen({
super.key,
required this.controller,
});
@override
_ProfileDescriptionScreenState createState() =>
_ProfileDescriptionScreenState();
}
class _ProfileDescriptionScreenState extends State<ProfileDescriptionScreen> {
final _formKey = GlobalKey<FormState>();
late DoctorController? _controller;
late TextEditingController _descriptionController;
bool _isEditing = false;
final int _minDescriptionLength = 5;
final int _maxDescriptionLength = 500;
@override
void initState() {
super.initState();
_controller = widget.controller ?? DoctorController();
_descriptionController = TextEditingController(
text: _controller?.model.profileDescription ?? '');
_descriptionController.addListener(_onDescriptionChanged);
}
@override
void dispose() {
_descriptionController.removeListener(_onDescriptionChanged);
_descriptionController.dispose();
super.dispose();
}
void _onDescriptionChanged() {
setState(() {
_isEditing = true;
});
}
bool _validateDescription() {
final description = _descriptionController.text.trim();
if (description.isEmpty) {
_showError('Please enter a profile description');
return false;
}
if (description.length < _minDescriptionLength) {
_showError(
'Description must be at least $_minDescriptionLength characters long');
return false;
}
if (description.length > _maxDescriptionLength) {
_showError('Description cannot exceed $_maxDescriptionLength characters');
return false;
}
return true;
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAndProceed() {
if (_formKey.currentState!.validate() && _validateDescription()) {
_controller?.updateProfileDescription(_descriptionController.text.trim());
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.experienceScreen,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
),
],
title: const Text('Profile Description'),
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Tell us about yourself',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: _descriptionController,
onChanged: (value) {
widget.controller!.updateProfileDescription(value);
_onDescriptionChanged();
},
maxLength: _maxDescriptionLength,
maxLines: 8,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Profile description is required';
}
if (value.length < _minDescriptionLength) {
return 'Description must be at least $_minDescriptionLength characters';
}
if (value.length > _maxDescriptionLength) {
return 'Description cannot exceed $_maxDescriptionLength characters';
}
return null;
},
decoration: InputDecoration(
labelText: 'Profile Description',
filled: true,
fillColor: Colors.grey[100],
alignLabelWithHint: true,
// prefixIcon:
// const Icon(Icons.description, color: Colors.blue),
contentPadding: const EdgeInsets.symmetric(
vertical: 20, horizontal: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
BorderSide(color: Colors.grey.shade300, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.blue, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide:
const BorderSide(color: Colors.red, width: 1.5),
),
helperText:
'Minimum $_minDescriptionLength characters required',
counterText:
'${_descriptionController.text.length}/$_maxDescriptionLength',
),
),
],
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,313 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class QualificationsScreen extends StatefulWidget {
final DoctorController? controller;
const QualificationsScreen({
super.key,
required this.controller,
});
@override
State<QualificationsScreen> createState() => _QualificationsScreenState();
}
class _QualificationsScreenState extends State<QualificationsScreen> {
late DoctorController _controller;
late TextEditingController _qualificationsController;
late List<String> qualifications;
bool _isEditing = false;
bool _showOthersField = false;
final _formKey = GlobalKey<FormState>();
// Predefined popular qualifications
final List<String> popularQualifications = [
'MBBS',
'MD',
'MS',
'BDS',
'DNB',
'DM',
'MCh',
'PhD',
'MPH',
'Others'
];
@override
void initState() {
super.initState();
_controller = widget.controller ?? DoctorController();
_controller.model.qualifications ??= [];
_qualificationsController = TextEditingController();
qualifications = List<String>.from(_controller.model.qualifications ?? []);
}
bool _validateBeforeNextPage() {
if (qualifications.isEmpty) {
_showError('Please add at least one qualification');
return false;
}
return true;
}
bool _validateQualification(String value) {
if (value.isEmpty) {
_showError('Please enter a qualification');
return false;
}
if (qualifications.any((q) => q.toLowerCase() == value.toLowerCase())) {
_showError('This qualification has already been added');
return false;
}
if (!RegExp(r'^[a-zA-Z0-9\s.,]+$').hasMatch(value)) {
_showError('Please enter valid qualification text');
return false;
}
if (value.length < 2) {
_showError('Qualification must be at least 2 characters long');
return false;
}
return true;
}
void _newQualification() {
final qualification = _qualificationsController.text.trim();
if (_formKey.currentState!.validate() &&
_validateQualification(qualification)) {
setState(() {
qualifications.add(qualification);
_isEditing = true;
_qualificationsController.clear();
});
_controller.addQualification(qualification);
}
}
void _toggleQualification(String qualification) {
setState(() {
if (qualification == 'Others') {
_showOthersField = !_showOthersField;
return;
}
if (qualifications.contains(qualification)) {
qualifications.remove(qualification);
_controller.removeQualification(qualification);
} else {
qualifications.add(qualification);
_controller.addQualification(qualification);
}
});
}
void _removeQualification(int index) {
setState(() {
qualifications.removeAt(index);
_isEditing = true;
});
_controller.removeQualification(_qualificationsController.text);
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateBeforeNextPage()) {
Navigator.pushNamed(
context,
RouteNames.doctorAddressScreen,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
),
],
title: const Text('Qualifications'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 5,
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 2.5,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: popularQualifications.length,
itemBuilder: (context, index) {
final qualification = popularQualifications[index];
final isSelected = qualification != 'Others' &&
qualifications.contains(qualification);
final isOthers = qualification == 'Others';
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _toggleQualification(qualification),
borderRadius: BorderRadius.circular(25),
child: Container(
decoration: BoxDecoration(
color:
isSelected || (isOthers && _showOthersField)
? Colors.blue.withOpacity(0.2)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: isSelected ||
(isOthers && _showOthersField)
? Colors.blue
: Colors.transparent,
),
),
alignment: Alignment.center,
child: Text(
qualification,
style: TextStyle(
color: isSelected ||
(isOthers && _showOthersField)
? Colors.blue
: Colors.black87,
fontWeight: FontWeight.w500,
),
),
),
),
);
},
),
),
if (_showOthersField) ...[
Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.blue.shade100),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: TextFormField(
controller: _qualificationsController,
decoration: InputDecoration(
hintText: 'Enter your qualification',
border: InputBorder.none,
suffixIcon: IconButton(
icon: const Icon(Icons.add_circle_outline,
color: Colors.blue),
onPressed: _newQualification,
),
),
onFieldSubmitted: (_) => _newQualification(),
),
),
),
const SizedBox(height: 20),
],
if (qualifications.isNotEmpty) ...[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
'Selected Qualifications',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.grey[700],
),
),
),
const SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: qualifications.length,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemBuilder: (context, index) {
return Card(
elevation: 0,
color: Colors.blue.withOpacity(0.1),
margin: const EdgeInsets.only(bottom: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
title: Text(
qualifications[index],
style: const TextStyle(
fontWeight: FontWeight.w500,
),
),
trailing: IconButton(
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 20,
),
onPressed: () => _removeQualification(index),
),
),
);
},
),
],
const SizedBox(height: 20),
],
),
),
),
),
),
);
}
@override
void dispose() {
_qualificationsController.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,219 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controllers/doctor_controller.dart';
import '../../../route_names.dart';
class SpecialitiesScreen extends StatefulWidget {
final DoctorController controller;
const SpecialitiesScreen({
super.key,
required this.controller,
});
@override
State<SpecialitiesScreen> createState() => _SpecialitiesScreenState();
}
class _SpecialitiesScreenState extends State<SpecialitiesScreen> {
String? selectedSpeciality;
late final DoctorController _controller;
late TextEditingController _speciality;
bool _isEditing = false;
final List<Map<String, dynamic>> specialities = [
{
'icon': Icons.child_care,
'label': 'Pediatric',
'value': 'pediatric',
'description': 'Specialist in child healthcare',
},
{
'icon': Icons.medical_services,
'label': 'Casual',
'value': 'casual',
'description': 'General healthcare provider',
},
{
'icon': Icons.coronavirus,
'label': 'Corona',
'value': 'corona',
'description': 'COVID-19 specialist',
},
{
'icon': Icons.pregnant_woman,
'label': 'Gynecology',
'value': 'gynecology',
'description': 'Women\'s health specialist',
},
{
'icon': Icons.medical_services_outlined,
'label': 'Orthopedic',
'value': 'orthopedic',
'description': 'Bone and joint specialist',
},
{
'icon': Icons.remove_red_eye,
'label': 'Eye',
'value': 'eye',
'description': 'Eye care specialist',
},
{
'icon': Icons.psychology,
'label': 'Psychiatrist',
'value': 'psychiatrist',
'description': 'Mental health specialist',
},
{
'icon': Icons.medical_information,
'label': 'Dentistry',
'value': 'dental',
'description': 'Dental care specialist',
},
{
'icon': Icons.person,
'label': 'General Medicine',
'value': 'general',
'description': 'General practitioner',
},
];
@override
void initState() {
super.initState();
_controller = widget.controller ?? DoctorController();
_loadSavedData();
}
void _loadSavedData() {
final doctor = _controller.model;
_speciality = TextEditingController(text: doctor.speciality ?? '');
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateSelection() {
if (selectedSpeciality == null) {
_showError('Please select a speciality to continue');
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.arrow_forward),
onPressed: () {
if (_validateSelection()) {
Navigator.pushNamed(
context,
RouteNames.achievementsScreen,
arguments: _controller,
);
}
},
)
],
title: const Text('Choose Speciality'),
),
body: Column(
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Your Specialization',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
],
),
),
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: specialities.length,
itemBuilder: (context, index) {
final specialty = specialities[index];
final isSelected = selectedSpeciality == specialty['value'];
return GestureDetector(
onTap: () {
setState(() {
// _speciality = specialty['value'];
selectedSpeciality = specialty['value'];
_isEditing = true;
widget.controller.updateSpeciality(selectedSpeciality!);
});
// _controller.updateSpeciality(specialty['value']);
},
child: Container(
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF5BC0DE)
: Colors.grey.shade200,
borderRadius: BorderRadius.circular(12),
border: isSelected
? Border.all(
color: Colors.white,
width: 2,
)
: null,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
specialty['icon'],
size: 32,
color: isSelected ? Colors.white : Colors.grey,
),
const SizedBox(height: 8),
Text(
specialty['label'],
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
if (isSelected)
const Icon(
Icons.check_circle,
color: Colors.white,
size: 20,
),
],
),
),
);
},
),
),
],
),
);
}
}

View File

@ -1,202 +0,0 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:telemednet/route_names.dart';
import 'package:telemednet/screens/doctor_screens/address_screen.dart';
import '../../controllers/doctor_controller.dart';
class ProfileUploadPage extends StatefulWidget {
const ProfileUploadPage({super.key});
@override
ProfileUploadPageState createState() => ProfileUploadPageState();
}
class ProfileUploadPageState extends State<ProfileUploadPage> {
final DoctorController _controller = DoctorController();
final _titleController = TextEditingController();
final _surnameController = TextEditingController();
final _firstnameController = TextEditingController();
final _middlenameController = TextEditingController();
final _qualificationController = TextEditingController();
File? _image;
@override
void dispose() {
_titleController.dispose();
_surnameController.dispose();
_firstnameController.dispose();
_middlenameController.dispose();
_qualificationController.dispose();
super.dispose();
}
Future<void> _pickImage() async {
final picker = ImagePicker();
final pickedFile = await picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_image = File(pickedFile.path);
});
}
}
void _addQualification() {
if (_qualificationController.text.isNotEmpty) {
setState(() {
_controller.profileController
.addQualification(_qualificationController.text);
_qualificationController.clear();
});
}
}
void _removeQualification(String qualification) {
setState(() {
_controller.profileController.removeQualification(qualification);
});
}
bool validateAndProceed() {
_controller.profileController.updateTitle(_titleController.text);
_controller.profileController.updateSurName(_surnameController.text);
_controller.profileController.updateLastName(_firstnameController.text);
_controller.profileController.updateMiddleName(_middlenameController.text);
return _controller.profileController.validateProfile();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Doctor Profile'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: GestureDetector(
onTap: _pickImage,
child: CircleAvatar(
radius: 60,
backgroundImage: _image != null ? FileImage(_image!) : null,
child:
_image == null ? const Icon(Icons.camera_alt, size: 50) : null,
),
),
),
const SizedBox(height: 24),
_buildTextField(
'Title',
'Mr, Ms..',
_titleController,
(value) => _controller.profileController.updateTitle(value),
),
_buildTextField(
'Surname',
'Enter surname',
_surnameController,
(value) => _controller.profileController.updateSurName(value),
),
_buildTextField(
'Firstname',
'Enter firstname',
_firstnameController,
(value) => _controller.profileController.updateLastName(value),
),
_buildTextField(
'Middle name',
'Enter middle name',
_middlenameController,
(value) => _controller.profileController.updateMiddleName(value),
),
const SizedBox(height: 16),
const Text(
'Qualifications',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: TextField(
controller: _qualificationController,
decoration: const InputDecoration(
hintText: 'Add Qualification',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _addQualification,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(12),
),
child: const Icon(Icons.add),
),
],
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: _controller.profileController.model.qualifications
.map((qual) => Chip(
label: Text(qual),
deleteIcon: const Icon(Icons.close),
onDeleted: () => _removeQualification(qual),
))
.toList(),
),
],
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
RouteNames.doctorAddressScreen,
arguments: DoctorAddressScreen(controller: _controller),
);
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
backgroundColor: const Color(0xFF5BC0DE)),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
),
);
}
Widget _buildTextField(
String label,
String hint,
TextEditingController controller,
Function(String) onChanged,
) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextField(
controller: controller,
decoration: InputDecoration(
labelText: label,
hintText: hint,
border: const OutlineInputBorder(),
),
onChanged: onChanged,
),
);
}
}

View File

@ -1,253 +0,0 @@
import 'package:flutter/material.dart';
import '../../controllers/doctor_controller.dart';
import '../../route_names.dart';
class AchievementsScreen extends StatefulWidget {
final DoctorController controller;
const AchievementsScreen({
super.key,
required this.controller,
});
@override
State<AchievementsScreen> createState() => _AchievementsScreenState();
}
class _AchievementsScreenState extends State<AchievementsScreen> {
final TextEditingController _achievementController = TextEditingController();
late final DoctorController _controller;
late List<String> achievements;
bool _isEditing = false;
@override
void initState() {
super.initState();
_controller = widget.controller;
_achievementController.addListener(_onFieldChanged);
// Create a new modifiable list from the controller's achievements
achievements = List<String>.from(_controller.model.achievements);
}
void _addAchievement() {
final achievement = _achievementController.text.trim();
if (achievement.isNotEmpty) {
setState(() {
achievements.add(achievement);
_isEditing = true;
});
_controller.updateAchievements(List<String>.from(achievements));
_achievementController.clear();
} else {
_showError('Please enter an achievement');
}
}
void _removeAchievement(int index) {
setState(() {
achievements.removeAt(index);
_isEditing = true;
});
_controller.updateAchievements(List<String>.from(achievements));
}
@override
void dispose() {
_achievementController.removeListener(_onFieldChanged);
_achievementController.dispose();
super.dispose();
}
void _onFieldChanged() {
setState(() {
_isEditing = true;
});
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAchievements() {
if (achievements.isEmpty) {
_showError('Please add at least one achievement');
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_isEditing) {
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('DISCARD'),
),
],
),
);
return shouldPop ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Achievements'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (_isEditing) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
child: const Text('DISCARD'),
),
],
),
);
} else {
Navigator.pop(context);
}
},
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Add Your Achievements',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'List your professional accomplishments, certifications, and awards',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: TextField(
controller: _achievementController,
decoration: InputDecoration(
hintText: 'Enter your achievement',
suffixIcon: IconButton(
icon: const Icon(Icons.add),
onPressed: _addAchievement,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
onSubmitted: (_) => _addAchievement(),
),
),
Expanded(
child: ListView.builder(
itemCount: achievements.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
return Card(
elevation: 2,
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xFF5BC0DE),
child: Text('${index + 1}'),
),
title: Text(achievements[index]),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _removeAchievement(index),
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Draft saved')),
);
},
child: const Text('SAVE DRAFT'),
),
ElevatedButton(
onPressed: () {
if (_validateAchievements()) {
Navigator.pushNamed(
context,
RouteNames.digitalSignatureScreeen,
arguments: _controller,
);
}
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
backgroundColor: const Color(0xFF5BC0DE),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
],
),
),
],
),
),
);
}
}

View File

@ -1,167 +0,0 @@
import 'package:flutter/material.dart';
import 'package:telemednet/screens/doctor_screens/profile_description_screen.dart';
import '../../common/custom_style.dart';
import '../../controllers/doctor_controller.dart';
import '../../route_names.dart';
class DoctorAddressScreen extends StatefulWidget {
final DoctorController controller;
const DoctorAddressScreen({super.key, required this.controller});
@override
State<DoctorAddressScreen> createState() => _DoctorAddressScreenState();
}
class _DoctorAddressScreenState extends State<DoctorAddressScreen> {
final _floorBuildingController = TextEditingController();
final _streetController = TextEditingController();
final _cityController = TextEditingController();
final _stateController = TextEditingController();
final _countryController = TextEditingController();
final _postalCodeController = TextEditingController();
late AddressController addressController;
@override
void initState() {
super.initState();
// Initialize the AddressController
addressController = widget.controller.addressController;
// Set the initial values from the address model
_floorBuildingController.text = addressController.model.floorBuilding ?? '';
_streetController.text = addressController.model.street ?? '';
_cityController.text = addressController.model.city ?? '';
_stateController.text = addressController.model.state ?? '';
_countryController.text = addressController.model.country ?? '';
_postalCodeController.text = addressController.model.postalCode ?? '';
}
@override
void dispose() {
_floorBuildingController.dispose();
_streetController.dispose();
_cityController.dispose();
_stateController.dispose();
_countryController.dispose();
_postalCodeController.dispose();
super.dispose();
}
bool validateAndProceed() {
// Update the address model
addressController.updateFloorBuilding(_floorBuildingController.text);
addressController.updateStreet(_streetController.text);
addressController.updateCity(_cityController.text);
addressController.updateState(_stateController.text);
addressController.updateCountry(_countryController.text);
addressController.updatePostalCode(_postalCodeController.text);
// Validate the address fields
if (_areFieldsValid()) {
return true;
}
showErrorSnackBar(context, 'Please fill in all required fields');
return false;
}
bool _areFieldsValid() {
return _floorBuildingController.text.isNotEmpty &&
_streetController.text.isNotEmpty &&
_cityController.text.isNotEmpty &&
_stateController.text.isNotEmpty &&
_countryController.text.isNotEmpty &&
_postalCodeController.text.isNotEmpty;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Address Details'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTextField(
'Floor, Building',
'Enter floor and building',
_floorBuildingController,
),
_buildTextField(
'Street or Road',
'Enter street or road',
_streetController,
),
_buildTextField(
'City',
'Enter city',
_cityController,
),
_buildTextField(
'State',
'Enter state',
_stateController,
),
_buildTextField(
'Country',
'Enter country',
_countryController,
),
_buildTextField(
'Postal Code',
'Enter postal code',
_postalCodeController,
),
],
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
RouteNames.profileDescriptionScreen,
arguments: ProfileDescriptionScreen(
controller:
widget.controller, // Pass the same controller instance
),
);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
backgroundColor: const Color(0xFF5BC0DE),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
),
);
}
Widget _buildTextField(
String label,
String hint,
TextEditingController controller,
) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextField(
controller: controller,
decoration: InputDecoration(
labelText: label,
hintText: hint,
border: const OutlineInputBorder(),
),
),
);
}
}

View File

@ -1,234 +0,0 @@
import 'package:flutter/material.dart';
import '../../controllers/doctor_controller.dart';
import '../../route_names.dart';
class ExperienceScreen extends StatefulWidget {
final DoctorController controller;
const ExperienceScreen({super.key, required this.controller});
@override
ExperienceScreenState createState() => ExperienceScreenState();
}
class ExperienceScreenState extends State<ExperienceScreen> {
String? _selectedExperience;
final _licenseController = TextEditingController();
late final DoctorController _controller;
bool _isEditing = false;
@override
void initState() {
super.initState();
_controller = widget.controller;
_selectedExperience = _controller.model.yearsOfExperience;
_licenseController.text = _controller.model.licenseNumber ?? '';
_licenseController.addListener(_onFieldChanged);
}
@override
void dispose() {
_licenseController.removeListener(_onFieldChanged);
_licenseController.dispose();
super.dispose();
}
void _onFieldChanged() {
setState(() {
_isEditing = true;
});
}
bool _validateFields() {
if (_selectedExperience == null) {
_showError('Please select years of experience');
return false;
}
if (_licenseController.text.trim().isEmpty) {
_showError('Please enter your license number');
return false;
}
// Add additional license number validation if needed
if (_licenseController.text.trim().length < 5) {
_showError('License number must be at least 5 characters long');
return false;
}
return true;
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateAndProceed() {
if (!_validateFields()) {
return false;
}
_controller.updateYearsOfExperience(_selectedExperience!);
_controller.updateLicenseNumber(_licenseController.text.trim());
return true;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_isEditing) {
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('DISCARD'),
),
],
),
);
return shouldPop ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Experience Details'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (_isEditing) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
child: const Text('DISCARD'),
),
],
),
);
} else {
Navigator.pop(context);
}
},
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Professional Experience',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Please provide your years of experience and medical license details.',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
const SizedBox(height: 24),
DropdownButtonFormField<String>(
decoration: const InputDecoration(
labelText: 'Years of Experience',
border: OutlineInputBorder(),
),
value: _selectedExperience,
items: List.generate(50, (index) => index + 1)
.map((year) => DropdownMenuItem(
value: year.toString(),
child: Text('$year years'),
))
.toList(),
onChanged: (value) {
setState(() {
_selectedExperience = value;
_isEditing = true;
});
},
),
const SizedBox(height: 16),
TextField(
controller: _licenseController,
decoration: const InputDecoration(
labelText: 'License Number',
hintText: 'Enter your medical license number',
border: OutlineInputBorder(),
),
),
],
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Draft saved')),
);
},
child: const Text('SAVE DRAFT'),
),
ElevatedButton(
onPressed: () {
if (_validateAndProceed()) {
Navigator.pushNamed(
context,
RouteNames.specialitiesScreeen,
arguments: _controller,
);
}
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
backgroundColor: const Color(0xFF5BC0DE),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
],
),
),
),
);
}
}

View File

@ -1,245 +0,0 @@
import 'package:flutter/material.dart';
import '../../controllers/doctor_controller.dart';
import '../../route_names.dart';
class ProfileDescriptionScreen extends StatefulWidget {
final DoctorController controller;
const ProfileDescriptionScreen({
super.key,
required this.controller,
});
@override
ProfileDescriptionScreenState createState() =>
ProfileDescriptionScreenState();
}
class ProfileDescriptionScreenState extends State<ProfileDescriptionScreen> {
final _descriptionController = TextEditingController();
late final DoctorController _controller;
bool _isEditing = false;
final int _minDescriptionLength = 50; // Minimum description length
final int _maxDescriptionLength = 500; // Maximum description length
@override
void initState() {
super.initState();
_controller = widget.controller;
// Initialize with existing description if any
_descriptionController.text =
_controller.profileController.model.profileDescription ?? '';
// Add listener to track editing state
_descriptionController.addListener(_onDescriptionChanged);
}
@override
void dispose() {
_descriptionController.removeListener(_onDescriptionChanged);
_descriptionController.dispose();
super.dispose();
}
void _onDescriptionChanged() {
setState(() {
_isEditing = true;
});
}
bool _validateDescription() {
final description = _descriptionController.text.trim();
if (description.isEmpty) {
_showError('Please enter a profile description');
return false;
}
if (description.length < _minDescriptionLength) {
_showError(
'Description must be at least $_minDescriptionLength characters long');
return false;
}
if (description.length > _maxDescriptionLength) {
_showError('Description cannot exceed $_maxDescriptionLength characters');
return false;
}
return true;
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool validateAndProceed() {
if (!_validateDescription()) {
return false;
}
// Update the profile description in the controller
_controller.updateProfileDescription(_descriptionController.text.trim());
return true;
}
String _getCharacterCount() {
return '${_descriptionController.text.length}/$_maxDescriptionLength';
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_isEditing) {
// Show confirmation dialog if there are unsaved changes
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('DISCARD'),
),
],
),
);
return shouldPop ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Profile Description'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (_isEditing) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
child: const Text('DISCARD'),
),
],
),
);
} else {
Navigator.pop(context);
}
},
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Tell us about yourself',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Write a brief description about your professional background, expertise, and approach to patient care.',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
const SizedBox(height: 16),
TextField(
controller: _descriptionController,
maxLines: 8,
maxLength: _maxDescriptionLength,
decoration: InputDecoration(
labelText: 'Profile Description',
hintText:
'Enter your professional background and expertise...',
border: const OutlineInputBorder(),
alignLabelWithHint: true,
counterText: _getCharacterCount(),
),
textInputAction: TextInputAction.newline,
// keyboardType: TextInputAction.multiline,
),
const SizedBox(height: 8),
Text(
'Minimum $_minDescriptionLength characters required',
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
],
),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
// Save draft functionality can be added here
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Draft saved')),
);
},
child: const Text('SAVE DRAFT'),
),
ElevatedButton(
onPressed: () {
{
Navigator.pushNamed(
context,
RouteNames.experienceScreen,
arguments: _controller,
);
}
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
backgroundColor: const Color(0xFF5BC0DE),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
],
),
),
),
);
}
}

View File

@ -1,296 +0,0 @@
import 'package:flutter/material.dart';
import '../../controllers/doctor_controller.dart';
import '../../route_names.dart';
class SpecialitiesScreen extends StatefulWidget {
final DoctorController controller;
const SpecialitiesScreen({
super.key,
required this.controller,
});
@override
State<SpecialitiesScreen> createState() => _SpecialitiesScreenState();
}
class _SpecialitiesScreenState extends State<SpecialitiesScreen> {
String? selectedSpeciality;
late final DoctorController _controller;
bool _isEditing = false;
final List<Map<String, dynamic>> specialities = [
{
'icon': Icons.child_care,
'label': 'Pediatric',
'value': 'pediatric',
'description': 'Specialist in child healthcare',
},
{
'icon': Icons.medical_services,
'label': 'Casual',
'value': 'casual',
'description': 'General healthcare provider',
},
{
'icon': Icons.coronavirus,
'label': 'Corona',
'value': 'corona',
'description': 'COVID-19 specialist',
},
{
'icon': Icons.pregnant_woman,
'label': 'Gynecology',
'value': 'gynecology',
'description': 'Women\'s health specialist',
},
{
'icon': Icons.medical_services_outlined,
'label': 'Orthopedic',
'value': 'orthopedic',
'description': 'Bone and joint specialist',
},
{
'icon': Icons.remove_red_eye,
'label': 'Eye',
'value': 'eye',
'description': 'Eye care specialist',
},
{
'icon': Icons.psychology,
'label': 'Psychiatrist',
'value': 'psychiatrist',
'description': 'Mental health specialist',
},
{
'icon': Icons.medical_information,
'label': 'Dental',
'value': 'dental',
'description': 'Dental care specialist',
},
{
'icon': Icons.person,
'label': 'General',
'value': 'general',
'description': 'General practitioner',
},
];
@override
void initState() {
super.initState();
_controller = widget.controller;
selectedSpeciality = _controller.model.speciality;
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
bool _validateSelection() {
if (selectedSpeciality == null) {
_showError('Please select a speciality to continue');
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_isEditing) {
final shouldPop = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('DISCARD'),
),
],
),
);
return shouldPop ?? false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
if (_isEditing) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Discard Changes?'),
content: const Text(
'You have unsaved changes. Are you sure you want to go back?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
child: const Text('DISCARD'),
),
],
),
);
} else {
Navigator.pop(context);
}
},
),
title: const Text('Choose Speciality'),
),
body: Column(
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Your Specialization',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'Choose the medical field that best represents your expertise',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
],
),
),
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
),
itemCount: specialities.length,
itemBuilder: (context, index) {
final specialty = specialities[index];
final isSelected = selectedSpeciality == specialty['value'];
return GestureDetector(
onTap: () {
setState(() {
selectedSpeciality = specialty['value'];
_isEditing = true;
});
_controller.updateSpeciality(specialty['value']);
},
child: Container(
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF5BC0DE)
: Colors.grey.shade200,
borderRadius: BorderRadius.circular(12),
border: isSelected
? Border.all(
color: Colors.white,
width: 2,
)
: null,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
specialty['icon'],
size: 32,
color: isSelected ? Colors.white : Colors.grey,
),
const SizedBox(height: 8),
Text(
specialty['label'],
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
if (isSelected)
const Icon(
Icons.check_circle,
color: Colors.white,
size: 20,
),
],
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Draft saved')),
);
},
child: const Text('SAVE DRAFT'),
),
ElevatedButton(
onPressed: () {
if (_validateSelection()) {
Navigator.pushNamed(
context,
RouteNames.achievementsScreen,
arguments: _controller,
);
}
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(24),
backgroundColor: const Color(0xFF5BC0DE),
),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
],
),
),
],
),
),
);
}
}

View File

@ -1,207 +0,0 @@
import 'package:flutter/material.dart';
class PatientDashboardScreen extends StatefulWidget {
const PatientDashboardScreen({super.key});
@override
State<PatientDashboardScreen> createState() => _PatientDashboardScreenState();
}
class _PatientDashboardScreenState extends State<PatientDashboardScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildSearchBar(),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildRealTimeCard(),
const SizedBox(height: 20),
_buildConsultationsSection(),
const SizedBox(height: 20),
_buildFindDoctorSection(),
],
),
),
_buildBottomNavBar(),
],
),
),
);
}
Widget _buildSearchBar() {
return Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
color: Color.fromRGBO(96, 181, 250, 1),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(50.0),
bottomRight: Radius.circular(50.0)),
),
child: TextField(
decoration: InputDecoration(
hintText: 'Search Doctor/Hospital/Symtoms',
prefixIcon: const Icon(Icons.search),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
),
),
);
}
Widget _buildRealTimeCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.lightBlue[100]!, Colors.lightBlue[50]!],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Real-time care\nat your fingertips.',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
),
child: const Text('Consultation >'),
),
],
),
);
}
Widget _buildConsultationsSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Consultations',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
_consultationCard('Dr Pom', '23/09/2024\n5:00AM-7:00AM'),
const SizedBox(width: 10),
_consultationCard('Dr I', '23/09/2024\n5:00AM-7:00AM'),
],
),
),
],
);
}
Widget _consultationCard(String name, String schedule) {
return GestureDetector(
onTap: () {
// Handle the tap event
print('Tapped on consultation card for $name');
// You can add more functionality here, like navigating to a detail page
},
child: Card(
shadowColor: Colors.grey,
child: Container(
width: 200,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(color: Colors.grey.withOpacity(0.5), blurRadius: 5),
],
),
child: Row(
children: [
CircleAvatar(
radius: 30,
backgroundColor: Colors.blue[100],
child: const Icon(Icons.person, size: 40, color: Colors.white),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name,
style: const TextStyle(fontWeight: FontWeight.bold)),
Text(schedule, style: const TextStyle(fontSize: 12)),
],
),
),
],
),
),
),
);
}
Widget _buildFindDoctorSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Find a Doctor for your\nHealth Problem',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_categoryIcon(Icons.accessibility_new, Colors.blue),
_categoryIcon(Icons.remove_red_eye, Colors.blue),
_categoryIcon(Icons.medical_services, Colors.blue),
_categoryIcon(Icons.health_and_safety, Colors.blue),
_categoryIcon(Icons.child_care, Colors.blue),
],
),
],
);
}
Widget _categoryIcon(IconData icon, Color color) {
return Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: Colors.white, size: 30),
);
}
Widget _buildBottomNavBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.chat_bubble), label: 'Chat'),
BottomNavigationBarItem(icon: Icon(Icons.assignment), label: 'Records'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: 0,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (index) {
// Handle navigation
},
);
}
}

View File

@ -1,162 +0,0 @@
import 'package:flutter/material.dart';
import 'package:telemednet/screens/patientDashboard/registrationScreens/patient_family_members_screen.dart';
class FamilyMembersEditScreen extends StatefulWidget {
final FamilyMember? familyMember;
const FamilyMembersEditScreen({super.key, this.familyMember});
@override
State<FamilyMembersEditScreen> createState() =>
_FamilyMembersEditScreenState();
}
class _FamilyMembersEditScreenState extends State<FamilyMembersEditScreen> {
late TextEditingController nameController;
late TextEditingController relationController;
late TextEditingController genderController;
late TextEditingController dobController;
@override
void initState() {
super.initState();
nameController =
TextEditingController(text: widget.familyMember?.name ?? '');
relationController =
TextEditingController(text: widget.familyMember?.relation ?? '');
genderController =
TextEditingController(text: widget.familyMember?.gender ?? '');
dobController =
TextEditingController(text: widget.familyMember?.dateOfBirth ?? '');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Family member'),
actions: [
TextButton(
onPressed: () {
FamilyMember newMember = FamilyMember(
name: nameController.text,
relation: relationController.text,
gender: genderController.text,
dateOfBirth: dobController.text,
);
Navigator.pop(context, newMember);
},
child: const Text('Done', style: TextStyle(color: Colors.blue)),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTextField(nameController, 'Name'),
_buildDropdownField('Relation', relationController.text,
(String? newValue) {
setState(() {
relationController.text = newValue ?? '';
});
}),
_buildDropdownField('Gender', genderController.text,
(String? newValue) {
setState(() {
genderController.text = newValue ?? '';
});
}),
_buildDateField(context),
const SizedBox(height: 16),
const Text('Address', style: TextStyle(fontSize: 16)),
const SizedBox(height: 8),
Card(
child: ListTile(
title: const Text('Enter address details'),
trailing: const Icon(Icons.chevron_right),
onTap: () {
// Navigate to address entry screen
},
),
),
],
),
),
);
}
Widget _buildTextField(TextEditingController controller, String label) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: TextField(
controller: controller,
decoration: InputDecoration(
labelText: label,
border: const OutlineInputBorder(),
),
),
);
}
Widget _buildDropdownField(
String label, String value, Function(String?) onChanged) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: label,
border: const OutlineInputBorder(),
),
value: value.isEmpty ? null : value,
onChanged: onChanged,
items: <String>['Father', 'Mother', 'Son', 'Daughter']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
);
}
Widget _buildDateField(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: TextField(
controller: dobController,
decoration: const InputDecoration(
labelText: 'Date of Birth',
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.calendar_today),
),
readOnly: true,
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
);
if (pickedDate != null) {
setState(() {
dobController.text =
"${pickedDate.day}/${pickedDate.month}/${pickedDate.year}";
});
}
},
),
);
}
@override
void dispose() {
nameController.dispose();
relationController.dispose();
genderController.dispose();
dobController.dispose();
super.dispose();
}
}

View File

@ -1,114 +0,0 @@
import 'package:flutter/material.dart';
import 'package:country_state_city_picker/country_state_city_picker.dart';
class PatientAddressScreen extends StatefulWidget {
const PatientAddressScreen({super.key});
@override
State<PatientAddressScreen> createState() => _PatientAddressScreenState();
}
class _PatientAddressScreenState extends State<PatientAddressScreen> {
final TextEditingController _houseNoController = TextEditingController();
final TextEditingController _lineController = TextEditingController();
final TextEditingController _townController = TextEditingController();
final TextEditingController _pincodeController = TextEditingController();
String? country;
String? state;
String? city;
String? addressType;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Address'),
actions: [
TextButton(
onPressed: () {
// Save address logic here
},
child: const Text('Done', style: TextStyle(color: Colors.blue)),
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTextField('House No', _houseNoController),
_buildTextField('Line', _lineController),
_buildTextField('Town', _townController, hintText: '(OPTIONAL)'),
_buildTextField('Pincode', _pincodeController),
const SizedBox(height: 20),
SelectState(
onCountryChanged: (value) {
setState(() {
country = value;
});
},
onStateChanged: (value) {
setState(() {
state = value;
});
},
onCityChanged: (value) {
setState(() {
city = value;
});
},
),
const SizedBox(height: 20),
const Text('Type of address',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
_buildAddressTypeChips(),
if (addressType == 'Other')
const TextField(
decoration: InputDecoration(
hintText: 'Other Label...',
border: OutlineInputBorder(),
),
),
],
),
),
);
}
Widget _buildTextField(String label, TextEditingController controller,
{String? hintText}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
TextField(
controller: controller,
decoration: InputDecoration(
hintText: hintText,
border: const UnderlineInputBorder(),
),
),
const SizedBox(height: 20),
],
);
}
Widget _buildAddressTypeChips() {
return Wrap(
spacing: 8.0,
children: ['Home', 'Office', 'Other'].map((String type) {
return ChoiceChip(
label: Text(type),
selected: addressType == type,
onSelected: (bool selected) {
setState(() {
addressType = selected ? type : addressType;
});
},
);
}).toList(),
);
}
}

View File

@ -1,153 +0,0 @@
import 'package:flutter/material.dart';
import 'package:telemednet/screens/patientDashboard/registrationScreens/family_members_edit_screen.dart';
class FamilyMember {
final String name;
final String gender;
final String dateOfBirth;
final String relation;
FamilyMember({
required this.name,
required this.gender,
required this.dateOfBirth,
required this.relation,
});
}
class PatientFamilyMembersScreen extends StatefulWidget {
const PatientFamilyMembersScreen({super.key});
@override
State<PatientFamilyMembersScreen> createState() =>
_PatientFamilyMembersScreenState();
}
class _PatientFamilyMembersScreenState
extends State<PatientFamilyMembersScreen> {
List<FamilyMember> familyMembers = [
FamilyMember(
name: "Dhansh A S",
gender: "Male",
dateOfBirth: "18/12/2001",
relation: "Father",
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Family members'),
actions: [
TextButton(
onPressed: () {
// Handle 'Done' action
},
child: const Text('Done', style: TextStyle(color: Colors.blue)),
),
],
),
body: ListView.builder(
itemCount: familyMembers.length,
itemBuilder: (context, index) {
return FamilyMemberCard(
familyMember: familyMembers[index],
onEdit: () => _editFamilyMember(index),
onDelete: () => _deleteFamilyMember(index),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addFamilyMember,
backgroundColor: Colors.blue,
child: const Icon(Icons.add),
),
);
}
void _addFamilyMember() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FamilyMembersEditScreen()),
).then((newMember) {
if (newMember != null) {
setState(() {
familyMembers.add(newMember);
});
}
});
}
void _editFamilyMember(int index) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
FamilyMembersEditScreen(familyMember: familyMembers[index]),
),
).then((editedMember) {
if (editedMember != null) {
setState(() {
familyMembers[index] = editedMember;
});
}
});
}
void _deleteFamilyMember(int index) {
setState(() {
familyMembers.removeAt(index);
});
}
}
class FamilyMemberCard extends StatelessWidget {
final FamilyMember familyMember;
final VoidCallback onEdit;
final VoidCallback onDelete;
const FamilyMemberCard({
super.key,
required this.familyMember,
required this.onEdit,
required this.onDelete,
});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Name: ${familyMember.name}',
style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text('Gender: ${familyMember.gender}'),
const SizedBox(height: 4),
Text('Date of Birth: ${familyMember.dateOfBirth}'),
const SizedBox(height: 4),
Text('Relation: ${familyMember.relation}'),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: const Icon(Icons.edit, color: Colors.blue),
onPressed: onEdit,
),
IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: onDelete,
),
],
),
],
),
),
);
}
}

View File

@ -1,226 +0,0 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:telemednet/route_names.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
class PatientRegistrationScreen extends StatefulWidget {
const PatientRegistrationScreen({super.key});
@override
State<PatientRegistrationScreen> createState() =>
_PatientRegistrationScreenState();
}
class _PatientRegistrationScreenState extends State<PatientRegistrationScreen> {
final TextEditingController _nameController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
String? _gender;
DateTime? _dateOfBirth;
File? _image;
final ImagePicker _picker = ImagePicker();
Future<void> _getImage(ImageSource source) async {
final XFile? pickedFile = await _picker.pickImage(source: source);
if (pickedFile != null) {
setState(() {
_image = File(pickedFile.path);
});
}
}
void _showImageSourceActionSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Wrap(
children: <Widget>[
ListTile(
leading: const Icon(Icons.photo_library),
title: const Text('Choose from Gallery'),
onTap: () {
_getImage(ImageSource.gallery);
Navigator.pop(context);
},
),
ListTile(
leading: const Icon(Icons.photo_camera),
title: const Text('Take a Photo'),
onTap: () {
_getImage(ImageSource.camera);
Navigator.pop(context);
},
),
],
),
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Profile'),
actions: [
IconButton(
icon: const Icon(Icons.check, color: Colors.blue),
onPressed: () {
// Save profile logic here
},
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Column(
children: [
GestureDetector(
onTap: () => _showImageSourceActionSheet(context),
child: CircleAvatar(
radius: 50,
backgroundImage:
_image != null ? FileImage(_image!) : null,
child: _image == null
? const Icon(Icons.person, size: 50)
: null,
),
),
TextButton(
onPressed: () => _showImageSourceActionSheet(context),
child: const Text('Upload picture',
style: TextStyle(color: Colors.blue)),
),
],
),
),
const SizedBox(height: 20),
_buildTextField('Name', _nameController),
_buildTextField('Phone number', _phoneController),
_buildDropdownField('Gender', _gender, ['Male', 'Female', 'Other'],
(value) {
setState(() => _gender = value);
}),
_buildDateField('Date of Birth', _dateOfBirth),
_buildNavigationField('Address'),
_buildNavigationField('Family members'),
],
),
),
);
}
Widget _buildTextField(String label, TextEditingController controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
TextField(
controller: controller,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
),
),
const SizedBox(height: 20),
],
);
}
Widget _buildDropdownField(String label, String? value, List<String> items,
Function(String?) onChanged) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
DropdownButton<String>(
value: value,
isExpanded: true,
hint: Text('Select $label'),
onChanged: onChanged,
items: items.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
const SizedBox(height: 20),
],
);
}
Widget _buildDateField(String label, DateTime? date) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(date != null
? DateFormat('dd/MM/yyyy').format(date)
: 'Select date'),
IconButton(
icon: const Icon(Icons.calendar_today, color: Colors.blue),
onPressed: () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: date ?? DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
);
if (picked != null && picked != date) {
setState(() {
_dateOfBirth = picked;
});
}
},
),
],
),
const Divider(),
const SizedBox(height: 20),
],
);
}
Widget _buildNavigationField(String label) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label,
style:
const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
IconButton(
icon: const Icon(Icons.chevron_right, color: Colors.blue),
onPressed: () {
if (label == 'Address') {
Navigator.of(context)
.pushNamed(RouteNames.patientAdressScreen);
} else {
Navigator.of(context)
.pushNamed(RouteNames.patientFamilyMembersScreen);
}
},
),
],
),
const Divider(),
const SizedBox(height: 20),
],
);
}
}

View File

@ -0,0 +1,394 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:telemednet/data/services/consultation_booking_service.dart';
import 'package:telemednet/data/services/patient_registration_service.dart';
import 'package:telemednet/widgets/alert_screen.dart';
class ConsultationBookingScreen extends StatelessWidget {
final Doctor doctor;
final ConsultationCenter selectedConsultation;
final DateTime selectedDate;
final String selectedTime;
const ConsultationBookingScreen({
super.key,
required this.doctor,
required this.selectedConsultation,
required this.selectedDate,
required this.selectedTime,
});
String get formattedAddress {
final parts = [
selectedConsultation.floorBuilding,
selectedConsultation.street,
selectedConsultation.city,
selectedConsultation.state,
selectedConsultation.postalCode
].where((part) => part != null && part.isNotEmpty).toList();
return parts.join(', ');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
appBar: _buildAppBar(context),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildAppointmentCard(),
const SizedBox(height: 24),
_buildDoctorDetails(),
const SizedBox(height: 24),
_buildLocationDetails(),
const SizedBox(height: 24),
_buildPaymentDetails(),
const SizedBox(height: 24),
_buildConfirmButton(context),
],
),
),
),
);
}
PreferredSizeWidget _buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Booking Overview',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
);
}
Widget _buildAppointmentCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
Row(
children: [
const Icon(Icons.calendar_today, color: Colors.white),
const SizedBox(width: 12),
Text(
DateFormat('EEEE, MMMM d').format(selectedDate),
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.access_time, color: Colors.white),
const SizedBox(width: 12),
Text(
selectedTime,
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
],
),
);
}
Widget _buildDoctorDetails() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
doctor.profileImage!,
width: 80,
height: 80,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 80,
height: 80,
color: Colors.grey[300],
child: Icon(Icons.person, size: 40, color: Colors.grey[600]),
);
},
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
doctor.lastName!,
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
Text(
doctor.speciality!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
Text(
'${doctor.yearsOfExperience} years experience',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
],
),
);
}
Widget _buildLocationDetails() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Location',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
Text(
formattedAddress,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 8),
Text(
'Average consultation time: ${selectedConsultation.averageDurationMinutes} minutes',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
);
}
Widget _buildPaymentDetails() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Payment Details',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Consultation Fee',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
Text(
'${selectedConsultation.consultationFee ?? "500"}',
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
],
),
],
),
);
}
Widget _buildConfirmButton(BuildContext context) {
return SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
// Handle payment and booking confirmation
_showConfirmationDialog(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text(
'Confirm & Pay',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
);
}
void _showConfirmationDialog(BuildContext context) async {
final bookingService = BookingService();
final currentUser = FirebaseAuth.instance.currentUser;
final patientProfile = await PatientProfileService.getPatientProfile();
if (patientProfile == null) {
return;
}
try {
if (context.mounted) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const Center(
child: CircularProgressIndicator(),
),
);
}
final bookingId = await bookingService.createBooking(
doctorName: doctor.lastName!,
patientId: currentUser!.uid,
patientName: patientProfile.name ?? 'Patient',
location: formattedAddress,
appointmentDate: selectedDate,
appointmentTime: selectedTime,
consultationFee:
int.parse(selectedConsultation.consultationFee ?? "500"),
specialization: doctor.speciality!,
);
if (context.mounted) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AlertScreen(
arguments: AlertArguments(
title: 'Booking Confirmed',
message:
'Your appointment has been successfully booked. Booking ID: ${bookingId.substring(0, 8)}\n\nPlease complete the payment to confirm your appointment.',
actionTitle: 'View Appointments',
type: AlertType.success,
onActionPressed: () {
Navigator.of(context).popUntil((route) => route.isFirst);
},
),
),
),
);
}
} catch (e) {
if (context.mounted) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AlertScreen(
arguments: AlertArguments(
title: 'Booking Failed',
message: 'Unable to create booking. ${e.toString()}',
actionTitle: 'Try Again',
type: AlertType.error,
onActionPressed: () {
Navigator.of(context).pop();
},
),
),
),
);
}
}
}
}

View File

@ -0,0 +1,553 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:intl/intl.dart';
import 'package:telemednet/route_names.dart';
class ConsultationTimeScreen extends StatefulWidget {
final Doctor doctor;
final ConsultationCenter selectedConsultation;
const ConsultationTimeScreen({
super.key,
required this.doctor,
required this.selectedConsultation,
});
@override
State<ConsultationTimeScreen> createState() => _ConsultationTimeScreenState();
}
class _ConsultationTimeScreenState extends State<ConsultationTimeScreen> {
DateTime? selectedDate;
String? selectedTime;
List<TimeSlot> getTimeSlotsForDay(String dayName) {
try {
final schedule = widget.selectedConsultation.weeklySchedule?.firstWhere(
(schedule) => schedule.day == dayName,
orElse: () => AvailabilitySchedule(
day: dayName,
timeSlots: [],
),
);
return schedule?.timeSlots ?? [];
} catch (e) {
debugPrint('Error getting time slots: $e');
return [];
}
}
DateTime? parseTimeString(String? timeStr) {
if (timeStr == null) return null;
try {
// Try parsing 12-hour format first
return DateFormat('h:mm a').parse(timeStr);
} catch (e) {
try {
// Try parsing 24-hour format
return DateFormat('HH:mm').parse(timeStr);
} catch (e) {
debugPrint('Error parsing time: $timeStr');
return null;
}
}
}
String get formattedAddress {
final parts = [
widget.selectedConsultation.floorBuilding,
widget.selectedConsultation.street,
widget.selectedConsultation.city,
widget.selectedConsultation.state,
widget.selectedConsultation.postalCode
].where((part) => part != null && part.isNotEmpty).toList();
return parts.join(', ');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
appBar: _buildAppBar(),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildLocationInfo(),
const SizedBox(height: 24),
_buildDateSelection(),
const SizedBox(height: 24),
_buildTimeSlots(),
],
),
),
),
);
}
PreferredSizeWidget _buildAppBar() {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Select Date & Time',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
);
}
Widget _buildLocationInfo() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.doctor.lastName!,
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
Text(
widget.doctor.speciality!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
widget.doctor.profileImage!,
width: 60,
height: 60,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 60,
height: 60,
color: Colors.grey[300],
child:
Icon(Icons.person, size: 30, color: Colors.grey[600]),
);
},
),
),
],
),
const Divider(height: 24),
Text(
'Selected Location',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
Text(
widget.selectedConsultation.city ?? '',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 4),
Text(
'Average consultation time: ${widget.selectedConsultation.averageDurationMinutes}',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
);
}
Widget _buildDateSelection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Date',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 20, // Show next 20 days
itemBuilder: (context, index) {
final date = DateTime.now().add(Duration(days: index));
final isSelected = selectedDate?.day == date.day &&
selectedDate?.month == date.month &&
selectedDate?.year == date.year;
final isAvailable = _isDateAvailable(date);
return GestureDetector(
onTap: isAvailable
? () {
setState(() {
selectedDate = date;
selectedTime = null; // Reset time when date changes
});
}
: null,
child: Container(
width: 70,
margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isSelected
? Colors.blue
: isAvailable
? Colors.white
: Colors.grey[200],
borderRadius: BorderRadius.circular(16),
boxShadow: isAvailable
? [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
]
: null,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
DateFormat('EEE').format(date).toUpperCase(),
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: isSelected
? Colors.white
: isAvailable
? Colors.grey[600]
: Colors.grey[400],
),
),
const SizedBox(height: 8),
Text(
date.day.toString(),
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
color: isSelected
? Colors.white
: isAvailable
? Colors.black87
: Colors.grey[400],
),
),
],
),
),
);
},
),
),
],
);
}
Widget _buildTimeSlots() {
if (selectedDate == null) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.5),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.grey.withOpacity(0.2)),
),
child: Center(
child: Text(
'Please select a date to view available time slots',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
),
);
}
final dayName = DateFormat('EEEE').format(selectedDate!);
final timeSlots = getTimeSlotsForDay(dayName);
final allTimeSlots = _generateTimeSlots(timeSlots);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Time',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Wrap(
spacing: 12,
runSpacing: 12,
children: allTimeSlots.map((time) {
final isSelected = selectedTime == time;
final isAvailable = _isTimeSlotAvailable(time);
return GestureDetector(
onTap: isAvailable
? () {
Navigator.pushNamed(
context,
RouteNames.consultationBookingScreen,
arguments: {
'doctor': widget.doctor,
'selectedConsultation': widget.selectedConsultation,
'selectedDate': selectedDate,
'selectedTime': time
},
);
}
: null,
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
decoration: BoxDecoration(
color: isSelected
? Colors.blue
: isAvailable
? Colors.white
: Colors.grey[200],
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected
? Colors.blue
: isAvailable
? Colors.grey.withOpacity(0.2)
: Colors.grey.withOpacity(0.1),
),
),
child: Text(
time,
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: isSelected
? Colors.white
: isAvailable
? Colors.black87
: Colors.grey[400],
),
),
),
);
}).toList(),
),
),
],
);
}
bool _isDateAvailable(DateTime date) {
final dayName = DateFormat('EEEE').format(date);
return widget.selectedConsultation.weeklySchedule
?.any((schedule) => schedule.day == dayName) ??
false;
}
List<String> _generateTimeSlots(List<TimeSlot> timeSlots) {
final slots = <String>[];
final timeFormat = DateFormat('h:mm a');
for (var slot in timeSlots) {
final startTime = parseTimeString(slot.startTime);
final endTime = parseTimeString(slot.endTime);
if (startTime == null || endTime == null) continue;
var currentTime = startTime;
while (currentTime.isBefore(endTime)) {
slots.add(timeFormat.format(currentTime));
currentTime = currentTime.add(const Duration(minutes: 30));
}
}
return slots;
}
bool _isTimeSlotAvailable(String time) {
final now = DateTime.now();
if (selectedDate == null) return false;
// Parse the time slot
final timeSlot = parseTimeString(time);
if (timeSlot == null) return false;
// Create a DateTime combining selected date and time
final slotDateTime = DateTime(
selectedDate!.year,
selectedDate!.month,
selectedDate!.day,
timeSlot.hour,
timeSlot.minute,
);
// Check if the slot is in the past
if (slotDateTime.isBefore(now)) return false;
// Here you would typically check against your booking database
// For now, returning true for future slots
return true;
}
void _handleBooking() {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
title: Text(
'Confirm Booking',
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildConfirmationDetail(
'Doctor',
widget.doctor.lastName!,
),
const SizedBox(height: 8),
_buildConfirmationDetail(
'Location',
widget.selectedConsultation.city!,
),
const SizedBox(height: 8),
_buildConfirmationDetail(
'Date',
DateFormat('EEEE, MMMM d').format(selectedDate!),
),
const SizedBox(height: 8),
_buildConfirmationDetail(
'Time',
selectedTime!,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
'Cancel',
style: GoogleFonts.poppins(
color: Colors.grey[600],
),
),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text(
'Confirm',
style: GoogleFonts.poppins(
color: Colors.white,
),
),
),
],
),
);
}
Widget _buildConfirmationDetail(String label, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 80,
child: Text(
'$label:',
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
color: Colors.grey[600],
),
),
),
Expanded(
child: Text(
value,
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
),
),
),
],
);
}
}

View File

@ -0,0 +1,312 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:telemednet/data/models/consultation_center.dart';
import 'package:telemednet/data/services/consultation_center_service.dart';
import 'package:telemednet/route_names.dart';
class ConsultationsCenterScreen extends StatefulWidget {
final Doctor doctor;
const ConsultationsCenterScreen({
super.key,
required this.doctor,
});
@override
State<ConsultationsCenterScreen> createState() =>
_ConsultationsCenterScreenState();
}
class _ConsultationsCenterScreenState extends State<ConsultationsCenterScreen> {
List<ConsultationCenter> _consultationCenters = [];
bool _isLoading = true;
String? _error;
@override
void initState() {
super.initState();
_fetchDoctorConsultationCenters();
}
Future<void> _fetchDoctorConsultationCenters() async {
try {
setState(() {
_isLoading = true;
_error = null;
});
if (widget.doctor.uid == null) {
throw Exception('Doctor UID is missing');
}
final centers =
await ConsultationCenterService.getDoctorConsultationCenters(
widget.doctor.uid!,
);
if (mounted) {
setState(() {
_consultationCenters = centers;
_isLoading = false;
});
}
} catch (e) {
if (mounted) {
setState(() {
_error = e.toString();
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to load consultation centers: $e')),
);
}
}
}
String _formatAddress(ConsultationCenter center) {
List<String> addressParts = [];
if (center.floorBuilding != null && center.floorBuilding!.isNotEmpty) {
addressParts.add(center.floorBuilding!);
}
if (center.street != null && center.street!.isNotEmpty) {
addressParts.add(center.street!);
}
if (center.city != null && center.city!.isNotEmpty) {
addressParts.add(center.city!);
}
return addressParts.join(', ');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
appBar: _buildAppBar(),
body: RefreshIndicator(
onRefresh: _fetchDoctorConsultationCenters,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDoctorInfo(),
const SizedBox(height: 24),
_buildConsultationLocations(),
],
),
),
),
),
);
}
PreferredSizeWidget _buildAppBar() {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Select Location',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
);
}
Widget _buildDoctorInfo() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
widget.doctor.profileImage!,
width: 80,
height: 80,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 80,
height: 80,
color: Colors.grey[300],
child: Icon(Icons.person, size: 40, color: Colors.grey[600]),
);
},
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.doctor.lastName!,
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
Text(
widget.doctor.speciality!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
Text(
'${widget.doctor.yearsOfExperience} years experience',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
],
),
);
}
Widget _buildConsultationLocations() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Select Location',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
if (_isLoading)
const Center(child: CircularProgressIndicator())
else if (_error != null)
Center(
child: Column(
children: [
Text(
'Error loading centers',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.red,
),
),
TextButton(
onPressed: _fetchDoctorConsultationCenters,
child: const Text('Retry'),
),
],
),
)
else if (_consultationCenters.isEmpty)
Center(
child: Text(
'No consultation centers available',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
)
else
SizedBox(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _consultationCenters.length,
itemBuilder: (context, index) {
final center = _consultationCenters[index];
return GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
RouteNames.consultationTimeScreen,
arguments: {
'doctor': widget.doctor,
'selectedConsultation': center,
},
);
},
child: Container(
width: 200,
margin: const EdgeInsets.only(right: 16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_formatAddress(center),
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const Spacer(),
if (center.averageDurationMinutes != null)
Text(
'Average time: ${center.averageDurationMinutes} mins',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey[600],
),
),
if (center.consultationFee != null)
Text(
'Fee: ${center.consultationFee}',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
);
},
),
),
],
);
}
}

View File

@ -0,0 +1,297 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:telemednet/route_names.dart';
class DoctorDetailsScreen extends StatelessWidget {
final Doctor doctor;
const DoctorDetailsScreen({
super.key,
required this.doctor,
});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
body: Column(
children: [
_buildAppBar(context),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDoctorCard(),
const SizedBox(height: 24),
_buildDescription(),
const SizedBox(height: 24),
_buildQualifications(),
],
),
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context, RouteNames.consultationCenterScreen,
arguments: {
'doctor': doctor,
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
disabledBackgroundColor: Colors.grey[300],
),
child: Text(
'Confirm Booking',
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
),
],
),
);
}
Widget _buildAppBar(BuildContext context) {
return Container(
color: Colors.white,
child: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Doctor',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
),
);
}
Widget _buildDoctorCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
doctor.profileImage!,
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 100,
height: 100,
color: Colors.grey[300],
child:
Icon(Icons.person, size: 50, color: Colors.grey[600]),
);
},
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
doctor.lastName!,
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
Text(
doctor.speciality!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 8),
Row(
children: [
Icon(Icons.medical_services,
size: 16, color: Colors.blue[400]),
const SizedBox(width: 4),
Expanded(
child: Text(
doctor.speciality!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
),
],
),
Row(
children: [
Icon(Icons.location_on,
size: 16, color: Colors.blue[400]),
const SizedBox(width: 4),
Expanded(
child: Text(
doctor.city!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
),
],
),
Row(
children: [
Icon(Icons.star, size: 16, color: Colors.blue[400]),
const SizedBox(width: 4),
Text(
'${doctor.yearsOfExperience} Years',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
],
),
),
],
),
],
),
);
}
Widget _buildDescription() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Description',
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
Text(
doctor.profileDescription!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
TextButton(
onPressed: () {},
child: Text(
'Read more',
style: GoogleFonts.poppins(
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
],
),
);
}
Widget _buildQualifications() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Qualifications',
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 8),
...doctor.qualifications!.map((qual) => Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Text(
qual.toString(),
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
)),
],
),
);
}
}

View File

@ -0,0 +1,299 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:telemednet/data/models/doctor.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/route_names.dart';
class DoctorsListScreen extends StatefulWidget {
final String specialty;
const DoctorsListScreen({
super.key,
required this.specialty,
});
@override
State<DoctorsListScreen> createState() => _DoctorsListScreenState();
}
class _DoctorsListScreenState extends State<DoctorsListScreen> {
late final Query doctorsQuery;
final TextEditingController _searchController = TextEditingController();
bool _isSearching = false;
@override
void initState() {
super.initState();
doctorsQuery = FirebaseFirestore.instance
.collection('doctorprofiles')
.where('speciality', isEqualTo: widget.specialty.toLowerCase());
_searchController.addListener(_onSearchChanged);
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
void _onSearchChanged() {
setState(() {
_isSearching = _searchController.text.isNotEmpty;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
body: CustomScrollView(
slivers: [
_buildSliverAppBar(),
SliverToBoxAdapter(
child: _buildSearchBar(),
),
_buildDoctorsList(),
],
),
);
}
Widget _buildSliverAppBar() {
return SliverAppBar(
expandedHeight: 55,
floating: true,
pinned: true,
stretch: true,
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
flexibleSpace: FlexibleSpaceBar(
title: Text(
'${widget.specialty} Specialists',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
),
);
}
Widget _buildSearchBar() {
return Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search doctors...',
hintStyle: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 14,
),
prefixIcon: const Icon(Icons.search, color: Colors.grey),
suffixIcon: _isSearching
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
_searchController.clear();
FocusScope.of(context).unfocus();
},
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
filled: true,
fillColor: Colors.white,
),
),
),
);
}
Widget _buildDoctorsList() {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: StreamBuilder<QuerySnapshot>(
stream: doctorsQuery.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const SliverFillRemaining(
child: Center(child: CircularProgressIndicator()),
);
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return SliverFillRemaining(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.medical_services_outlined,
size: 64,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'No doctors available in this specialty',
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.grey[600],
),
),
],
),
),
);
}
final doctors = snapshot.data!.docs
.map((doc) => Doctor.fromJson(doc.data() as Map<String, dynamic>))
.where((doctor) {
if (_searchController.text.isEmpty) return true;
final searchQuery = _searchController.text.toLowerCase();
return doctor.surName!.toLowerCase().contains(searchQuery) ||
doctor.city!.toLowerCase().contains(searchQuery);
}).toList();
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final doctor = doctors[index];
return _buildDoctorCard(doctor);
},
childCount: doctors.length,
),
);
},
),
);
}
Widget _buildDoctorCard(Doctor doctor) {
return Container(
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 5),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.pushNamed(
context,
RouteNames.doctorDetailsScreen,
arguments: {
'doctor': doctor,
},
);
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: DecorationImage(
image: doctor.profileImage!.startsWith('http')
? NetworkImage(doctor.profileImage!)
: FileImage(File(doctor.profileImage!))
as ImageProvider,
fit: BoxFit.cover,
),
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
doctor.surName!,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
'${doctor.yearsOfExperience!} years experience',
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 4),
Row(
children: [
Icon(
Icons.location_on,
size: 16,
color: Colors.grey[600],
),
const SizedBox(width: 4),
Expanded(
child: Text(
doctor.city!,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.grey[600],
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Colors.grey[400],
),
],
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,426 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:animate_do/animate_do.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:telemednet/route_names.dart';
class Specialty {
final String name;
final IconData icon;
final Color color;
final String description;
Specialty({
required this.name,
required this.icon,
required this.color,
required this.description,
});
}
class SpecialtyScreen extends StatefulWidget {
const SpecialtyScreen({super.key});
@override
State<SpecialtyScreen> createState() => _SpecialtyScreenState();
}
class _SpecialtyScreenState extends State<SpecialtyScreen> {
final List<Specialty> _allSpecialties = [
Specialty(
name: 'Pediatric',
icon: Icons.child_care,
color: Colors.blue,
description: 'Medical care for infants, children, and adolescents',
),
Specialty(
name: 'General Medicine',
icon: Icons.medical_services,
color: Colors.green,
description:
'Primary healthcare for adults and general medical conditions',
),
Specialty(
name: 'Family Medicine',
icon: Icons.family_restroom,
color: Colors.teal,
description: 'Comprehensive healthcare for families and individuals',
),
Specialty(
name: 'Cardiologist',
icon: Icons.favorite,
color: Colors.red,
description: 'Diagnosis and treatment of heart conditions',
),
Specialty(
name: 'Neurology',
icon: Icons.psychology,
color: Colors.purple,
description: 'Treatment of nervous system disorders',
),
Specialty(
name: 'Gastroenterology',
icon: Icons.local_hospital,
color: Colors.orange,
description: 'Digestive system disorders and treatment',
),
Specialty(
name: 'Dermatologist',
icon: Icons.face,
color: Colors.pink,
description: 'Skin, hair, and nail conditions',
),
Specialty(
name: 'Orthopedic',
icon: Icons.wheelchair_pickup,
color: Colors.indigo,
description: 'Musculoskeletal system and injury treatment',
),
Specialty(
name: 'Ophthalmology',
icon: Icons.remove_red_eye,
color: Colors.brown,
description: 'Eye care and vision treatment',
),
Specialty(
name: 'ENT',
icon: Icons.hearing,
color: Colors.cyan,
description: 'Ear, nose, and throat specialist',
),
Specialty(
name: 'Psychiatry',
icon: Icons.psychology_outlined,
color: Colors.deepPurple,
description: 'Mental health and behavioral disorders',
),
Specialty(
name: 'Gynecology',
icon: Icons.pregnant_woman,
color: Colors.pinkAccent,
description: "Women's health and reproductive care",
),
Specialty(
name: 'Urology',
icon: Icons.water_drop,
color: Colors.lightBlue,
description: 'Urinary tract and male reproductive health',
),
Specialty(
name: 'Endocrinology',
icon: Icons.biotech,
color: Colors.amber,
description: 'Hormone and metabolic disorders',
),
Specialty(
name: 'Oncology',
icon: Icons.bloodtype,
color: Colors.redAccent,
description: 'Cancer diagnosis and treatment',
),
Specialty(
name: 'Rheumatology',
icon: Icons.accessibility,
color: Colors.deepOrange,
description: 'Arthritis and autoimmune conditions',
),
Specialty(
name: 'Pulmonology',
icon: Icons.air,
color: Colors.lightGreen,
description: 'Respiratory system disorders',
),
Specialty(
name: 'Nephrology',
icon: Icons.water,
color: Colors.blueGrey,
description: 'Kidney diseases and disorders',
),
Specialty(
name: 'Dentistry',
icon: Icons.cleaning_services,
color: Colors.cyan,
description: 'Oral health and dental care',
),
Specialty(
name: 'Physical Therapy',
icon: Icons.accessibility_new,
color: Colors.deepPurple,
description: 'Rehabilitation and physical medicine',
),
Specialty(
name: 'Sports Medicine',
icon: Icons.sports,
color: Colors.green,
description: 'Athletic injuries and performance',
),
Specialty(
name: 'Allergy & Immunology',
icon: Icons.sick,
color: Colors.orange,
description: 'Allergies and immune system disorders',
),
Specialty(
name: 'Pain Management',
icon: Icons.healing,
color: Colors.red,
description: 'Chronic pain treatment',
),
Specialty(
name: 'Sleep Medicine',
icon: Icons.bedtime,
color: Colors.indigo,
description: 'Sleep disorders and treatment',
),
Specialty(
name: 'Geriatrics',
icon: Icons.elderly,
color: Colors.brown,
description: 'Healthcare for elderly patients',
),
];
late List<Specialty> _filteredSpecialties;
final TextEditingController _searchController = TextEditingController();
bool _isSearching = false;
@override
void initState() {
super.initState();
_filteredSpecialties = _allSpecialties;
_searchController.addListener(_onSearchChanged);
}
@override
void dispose() {
_searchController.dispose();
super.dispose();
}
void _onSearchChanged() {
final searchQuery = _searchController.text.toLowerCase();
setState(() {
_isSearching = searchQuery.isNotEmpty;
_filteredSpecialties = _allSpecialties
.where((specialty) =>
specialty.name.toLowerCase().contains(searchQuery) ||
specialty.description.toLowerCase().contains(searchQuery))
.toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FF),
body: CustomScrollView(
slivers: [
_buildSliverAppBar(),
SliverToBoxAdapter(
child: _buildSearchBar(),
),
SliverPadding(
padding: const EdgeInsets.all(16),
sliver: _buildSpecialtiesGrid(),
),
],
),
);
}
Widget _buildSliverAppBar() {
return SliverAppBar(
expandedHeight: 55,
floating: true,
pinned: true,
stretch: true,
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.pop(context),
),
flexibleSpace: FlexibleSpaceBar(
title: Text(
'Find a Specialist',
style: GoogleFonts.poppins(
color: Colors.black87,
fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
),
);
}
Widget _buildSearchBar() {
return FadeIn(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search specialties...',
hintStyle: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 14,
),
prefixIcon: const Icon(Icons.search, color: Colors.grey),
suffixIcon: _isSearching
? IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
_searchController.clear();
FocusScope.of(context).unfocus();
},
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
filled: true,
fillColor: Colors.white,
),
),
),
),
);
}
Widget _buildSpecialtiesGrid() {
return SliverAnimationBuilder(
child: MasonryGridView.count(
crossAxisCount: 2,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _filteredSpecialties.length,
itemBuilder: (context, index) {
final specialty = _filteredSpecialties[index];
return FadeInUp(
delay: Duration(milliseconds: 100 * index),
child: _buildSpecialtyCard(specialty),
);
},
),
);
}
Widget _buildSpecialtyCard(Specialty specialty) {
return GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
RouteNames.doctorListScreen,
arguments: {
'specialty': specialty.name,
},
);
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: specialty.color.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 5),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: CircleAvatar(
radius: 40,
backgroundColor: specialty.color.withOpacity(0.1),
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: specialty.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
specialty.icon,
color: specialty.color,
size: 28,
),
),
const SizedBox(height: 16),
Text(
specialty.name,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
const SizedBox(height: 8),
Text(
specialty.description,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.grey[600],
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
),
);
}
}
class SliverAnimationBuilder extends StatelessWidget {
final Widget child;
const SliverAnimationBuilder({
super.key,
required this.child,
});
@override
Widget build(BuildContext context) {
return SliverAnimatedList(
initialItemCount: 1,
itemBuilder: (context, index, animation) {
return SlideInUp(
from: 50,
child: child,
);
},
);
}
}

View File

@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
import 'package:telemednet/route_names.dart';
import 'package:animations/animations.dart';
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_home_screen.dart';
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
class PatientDashboardScreen extends StatefulWidget {
const PatientDashboardScreen({super.key});
@ -9,200 +12,50 @@ class PatientDashboardScreen extends StatefulWidget {
}
class _PatientDashboardScreenState extends State<PatientDashboardScreen> {
int _selectedIndex = 0;
final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
// Add your pages here
final List<Widget> _pages = [
const PatientHomeScreen(),
const Center(child: Text('Chat')), // Replace with your chat screen
const Center(child: Text('Records')), // Replace with your records screen
const PatientProfileScreen(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildSearchBar(),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildRealTimeCard(),
const SizedBox(height: 20),
_buildConsultationsSection(),
const SizedBox(height: 20),
_buildFindDoctorSection(),
],
),
),
_buildBottomNavBar(),
],
),
body: PageTransitionSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder: (child, animation, secondaryAnimation) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: _pages[_selectedIndex],
),
);
}
Widget _buildSearchBar() {
return Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
color: Color.fromRGBO(96, 181, 250, 1),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(50.0),
bottomRight: Radius.circular(50.0)),
),
child: TextField(
decoration: InputDecoration(
hintText: 'Search Doctor/Hospital/Symtoms',
prefixIcon: const Icon(Icons.search),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
),
),
);
}
Widget _buildRealTimeCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.lightBlue[100]!, Colors.lightBlue[50]!],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Real-time care\nat your fingertips.',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
),
child: const Text('Consultation >'),
),
bottomNavigationBar: CurvedNavigationBar(
key: _bottomNavigationKey,
backgroundColor: Colors.transparent,
color: Colors.blue,
buttonBackgroundColor: Colors.blue,
height: 60,
index: _selectedIndex,
items: const [
Icon(Icons.home, size: 30, color: Colors.white),
// Icon(Icons.chat_bubble, size: 30, color: Colors.white),
Icon(Icons.list, size: 30, color: Colors.white),
Icon(Icons.person, size: 30, color: Colors.white),
],
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
),
);
}
Widget _buildConsultationsSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Consultations',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
_consultationCard('Dr Pom', '23/09/2024\n5:00AM-7:00AM'),
const SizedBox(width: 10),
_consultationCard('Dr I', '23/09/2024\n5:00AM-7:00AM'),
],
),
),
],
);
}
Widget _consultationCard(String name, String schedule) {
return GestureDetector(
onTap: () {
print('Tapped on consultation card for $name');
},
child: Card(
shadowColor: Colors.grey,
child: Container(
width: 200,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(color: Colors.grey.withOpacity(0.5), blurRadius: 5),
],
),
child: Row(
children: [
CircleAvatar(
radius: 30,
backgroundColor: Colors.blue[100],
child: const Icon(Icons.person, size: 40, color: Colors.white),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name,
style: const TextStyle(fontWeight: FontWeight.bold)),
Text(schedule, style: const TextStyle(fontSize: 12)),
],
),
),
],
),
),
),
);
}
Widget _buildFindDoctorSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Find a Doctor for your\nHealth Problem',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_categoryIcon(Icons.accessibility_new, Colors.blue),
_categoryIcon(Icons.remove_red_eye, Colors.blue),
_categoryIcon(Icons.medical_services, Colors.blue),
_categoryIcon(Icons.health_and_safety, Colors.blue),
_categoryIcon(Icons.child_care, Colors.blue),
],
),
],
);
}
Widget _categoryIcon(IconData icon, Color color) {
return Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: Colors.white, size: 30),
);
}
Widget _buildBottomNavBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.chat_bubble), label: 'Chat'),
BottomNavigationBarItem(icon: Icon(Icons.assignment), label: 'Records'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
currentIndex: 0,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (index) {
if (index == 3) {
Navigator.pushNamed(context, RouteNames.patientprofileScreen);
}
},
);
}
}

View File

@ -0,0 +1,447 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
class PatientHomeScreen extends StatefulWidget {
const PatientHomeScreen({super.key});
@override
State<PatientHomeScreen> createState() => _PatientHomeScreenState();
}
class _PatientHomeScreenState extends State<PatientHomeScreen>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_animationController.forward();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
_buildSearchBar(),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildRealTimeCard(),
const SizedBox(height: 20),
_buildConsultationsSection(),
const SizedBox(height: 20),
_buildFindDoctorSection(),
],
),
),
// _buildBottomNavBar(),
],
),
),
);
}
Widget _buildSearchBar() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.blue[400]!,
Colors.blue[300]!,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: TextField(
decoration: InputDecoration(
hintText: 'Search Doctor/Hospital/Symptoms',
hintStyle: GoogleFonts.poppins(
color: Colors.grey[400],
),
prefixIcon: const Icon(Icons.search, color: Colors.blue),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide.none,
),
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
),
),
),
],
),
);
}
Widget _buildRealTimeCard() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue[400]!, Colors.white],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Real-time care\nat your fingertips.',
style: GoogleFonts.poppins(
fontSize: 30,
fontWeight: FontWeight.bold,
color: const Color.fromARGB(221, 67, 67, 67),
),
),
const SizedBox(height: 12),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SpecialtyScreen()),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.blue[700],
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
elevation: 5,
),
child: Text(
'Start Consultation',
style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
Widget _buildConsultationsSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Upcoming Consultations',
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
SizedBox(
height: 160,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
_consultationCard(
'Dr. Smith', '23/09/2024\n5:00 PM - 6:00 PM', 'Cardiologist'),
const SizedBox(width: 16),
_consultationCard('Dr. Johnson', '24/09/2024\n3:30 PM - 4:30 PM',
'Pediatrician'),
],
),
),
],
);
}
Widget _consultationCard(String name, String schedule, String speciality) {
return Container(
width: 280,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.white, Colors.grey[50]!],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.blue[100],
shape: BoxShape.circle,
),
child: const Icon(
Icons.person,
size: 40,
color: Colors.white,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
speciality,
style: GoogleFonts.poppins(
color: Colors.grey[600],
),
),
],
),
),
],
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(10),
),
child: Text(
schedule,
style: GoogleFonts.poppins(
color: Colors.blue[700],
fontSize: 12,
),
),
),
],
),
);
}
Widget _buildFindDoctorSection() {
final specialistData = [
{
'icon': Icons.local_hospital,
'label': 'General',
'color': Colors.blue,
'description': 'Primary Healthcare'
},
{
'icon': Icons.remove_red_eye,
'label': 'Eye',
'color': Colors.indigo,
'description': 'Vision Care'
},
{
'icon': Icons.medical_services,
'label': 'Dental',
'color': Colors.amber,
'description': 'Oral Health'
},
{
'icon': Icons.favorite,
'label': 'Cardio',
'color': Colors.red,
'description': 'Heart Specialist'
},
{
'icon': Icons.psychology,
'label': 'Mental',
'color': Colors.green,
'description': 'Mental Health'
},
{
'icon': Icons.child_care,
'label': 'Pediatric',
'color': Colors.purple,
'description': 'Child Care'
},
{
'icon': Icons.elderly,
'label': 'Geriatric',
'color': Colors.teal,
'description': 'Senior Care'
},
{
'icon': Icons.fitness_center,
'label': 'Physio',
'color': Colors.orange,
'description': 'Physical Therapy'
},
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text(
'Find Specialists',
style: GoogleFonts.poppins(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (final data in specialistData)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: _specialistCard(
icon: data['icon'] as IconData,
label: data['label'] as String,
color: data['color'] as Color,
description: data['description'] as String,
),
),
const SizedBox(width: 8),
],
),
),
),
IconButton(
icon: const Icon(Icons.arrow_forward, color: Colors.blue),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SpecialtyScreen()),
);
},
),
],
),
],
);
}
Widget _specialistCard({
required IconData icon,
required String label,
required Color color,
required String description,
}) {
return GestureDetector(
onTap: () {
// Replace with your desired navigation action
},
child: Container(
width: 140,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: color.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: color, size: 24),
),
const SizedBox(height: 8),
Text(
label,
style: GoogleFonts.poppins(
color: Colors.black87,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
description,
style: GoogleFonts.poppins(
color: Colors.grey[600],
fontSize: 12,
),
),
],
),
),
);
}
}

View File

@ -11,6 +11,7 @@ class PatientProfileScreen extends StatefulWidget {
class _PatientProfileScreenState extends State<PatientProfileScreen> {
final FirebaseAuth _auth = FirebaseAuth.instance;
// final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
@ -20,7 +21,7 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> {
_buildProfileHeader(),
_buildProfileOptions(),
const Spacer(),
_buildBottomNavBar(),
// _buildBottomNavBar(),
],
),
),
@ -155,38 +156,6 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> {
);
}
Widget _buildBottomNavBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.people_outline),
label: 'Consult',
),
BottomNavigationBarItem(
icon: Icon(Icons.description_outlined),
label: 'Records',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
currentIndex: 3,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.grey,
onTap: (index) {
if (index != 3) {
Navigator.of(context).pop();
}
},
);
}
Future<void> _signOut() async {
try {
await _auth.signOut();

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:telemednet/controller/patient_controller.dart';
import 'package:telemednet/controllers/patient_controller.dart';
import 'package:telemednet/data/models/patient.dart';
class FamilyMembersEditScreen extends StatefulWidget {

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:country_state_city_picker/country_state_city_picker.dart';
import 'package:telemednet/controller/patient_controller.dart';
import 'package:telemednet/controllers/patient_controller.dart';
class PatientAddressScreen extends StatefulWidget {
final PatientController? controller;

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:telemednet/screens/patientScreens/registrationScreens/family_members_edit_screen.dart';
import 'package:telemednet/data/models/patient.dart';
import '../../../controller/patient_controller.dart';
import '../../../controllers/patient_controller.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class PatientFamilyMembersScreen extends StatefulWidget {

View File

@ -1,12 +1,10 @@
// ignore_for_file: dead_code
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:telemednet/route_names.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import '../../../controller/patient_controller.dart';
import '../../../controllers/patient_controller.dart';
import '../../../widgets/alert_screen.dart';
class PatientRegistrationScreen extends StatefulWidget {
@ -553,14 +551,12 @@ class _PatientRegistrationScreenState extends State<PatientRegistrationScreen> {
_hasErrors = true;
}
// Validate required address fields
final address = _controller.model.address;
if (address.houseNo?.isEmpty ?? true) {
_errors['address'] = 'Please complete all required address fields';
_hasErrors = true;
}
// Validate address type and other label
if (address.addressType == 'Other' &&
(address.otherLabel?.isEmpty ?? true)) {
_errors['address'] = 'Please specify other address label';

View File

@ -56,7 +56,7 @@ class AlertScreen extends StatelessWidget {
fontWeight: FontWeight.bold,
color: Colors.black,
),
textAlign: TextAlign.center,
textAlign: TextAlign.start,
),
],
Text(
@ -65,7 +65,7 @@ class AlertScreen extends StatelessWidget {
fontSize: 16,
color: Colors.grey,
),
textAlign: TextAlign.center,
textAlign: TextAlign.start,
),
const SizedBox(height: 20),
TextButton(

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.2.1+4
version: 1.3.0+5
environment:
sdk: ^3.5.3
@ -49,6 +49,14 @@ dependencies:
intl_phone_field: ^3.2.0
flutter_slidable: ^3.1.1
gap: ^3.0.1
curved_navigation_bar: ^1.0.6
google_fonts: ^6.2.1
shimmer: ^3.0.0
animations: ^2.0.11
animate_do: ^3.3.4
flutter_staggered_animations: ^1.1.1
flutter_staggered_grid_view: ^0.7.0
carousel_slider: ^5.0.0
dev_dependencies:
flutter_test:
@ -80,6 +88,8 @@ flutter:
- .env
- images/cover-picture.jpg
- images/patient-avathar.png
- images/MaleDr.jpg.png
- images/FemaleDr.jpg.png
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images