From cbefa35256590180dcf3e9d3e99c2d1155ce5088 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 19:28:38 +0300 Subject: [PATCH 1/9] fix: restore modern Flutter web compatibility and hosting --- .gitignore | 1 - deploy/nginx.conf | 34 +++ docker-compose.hosting.yml | 10 + lib/app/ui/global_widgets/appbar.dart | 2 +- .../global_widgets/projects_grid_widget.dart | 3 - lib/app/ui/main_page/main_page.dart | 2 +- .../widgets/social_network_button.dart | 4 +- .../top_section/widgets/left_text_column.dart | 24 +- .../project_page/widgets/project_images.dart | 2 +- .../top_section/widgets/projects_title.dart | 6 +- pubspec.lock | 239 ++++++++++++------ pubspec.yaml | 8 +- test/widget_test.dart | 28 +- 13 files changed, 237 insertions(+), 126 deletions(-) create mode 100644 deploy/nginx.conf create mode 100644 docker-compose.hosting.yml diff --git a/.gitignore b/.gitignore index 0fa6b67..a1345d0 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ /build/ # Web related -lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols diff --git a/deploy/nginx.conf b/deploy/nginx.conf new file mode 100644 index 0000000..3ad4058 --- /dev/null +++ b/deploy/nginx.conf @@ -0,0 +1,34 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location = /index.html { + add_header Cache-Control "no-cache"; + } + + location = /flutter_service_worker.js { + add_header Cache-Control "no-cache"; + } + + location = /version.json { + add_header Cache-Control "no-cache"; + } + + location / { + try_files $uri $uri/ /index.html; + } + + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types + application/javascript + application/json + application/wasm + image/svg+xml + text/css + text/plain; +} diff --git a/docker-compose.hosting.yml b/docker-compose.hosting.yml new file mode 100644 index 0000000..80f23ec --- /dev/null +++ b/docker-compose.hosting.yml @@ -0,0 +1,10 @@ +services: + web7: + image: nginx:latest + container_name: nginx7 + restart: unless-stopped + ports: + - "4077:80" + volumes: + - ./build/web:/usr/share/nginx/html:ro + - ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro diff --git a/lib/app/ui/global_widgets/appbar.dart b/lib/app/ui/global_widgets/appbar.dart index 0f0b78c..df176be 100644 --- a/lib/app/ui/global_widgets/appbar.dart +++ b/lib/app/ui/global_widgets/appbar.dart @@ -7,7 +7,7 @@ import 'package:url_launcher/link.dart'; import '../theme/app_addition_colors.dart'; import '../theme/app_fonts.dart'; -class AppBarWidget extends StatelessWidget with PreferredSizeWidget { +class AppBarWidget extends StatelessWidget implements PreferredSizeWidget { const AppBarWidget( {Key? key, this.needBack = true, diff --git a/lib/app/ui/global_widgets/projects_grid_widget.dart b/lib/app/ui/global_widgets/projects_grid_widget.dart index 8017d3a..b692bf6 100644 --- a/lib/app/ui/global_widgets/projects_grid_widget.dart +++ b/lib/app/ui/global_widgets/projects_grid_widget.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:url_launcher/link.dart'; - import '../../data/models/project.dart'; -import '../../routes/app_pages.dart'; import '../theme/app_constants.dart'; import 'project_card.dart'; diff --git a/lib/app/ui/main_page/main_page.dart b/lib/app/ui/main_page/main_page.dart index cb68b1b..9e2dc9e 100644 --- a/lib/app/ui/main_page/main_page.dart +++ b/lib/app/ui/main_page/main_page.dart @@ -22,7 +22,7 @@ class MainPage extends StatelessWidget { ]; } final _controller = ScrollController(); - List sections = []; + late final List sections; @override Widget build(BuildContext context) { diff --git a/lib/app/ui/main_page/sections/contact_me/widgets/social_network_button.dart b/lib/app/ui/main_page/sections/contact_me/widgets/social_network_button.dart index a0ce88b..ffea13c 100644 --- a/lib/app/ui/main_page/sections/contact_me/widgets/social_network_button.dart +++ b/lib/app/ui/main_page/sections/contact_me/widgets/social_network_button.dart @@ -21,8 +21,8 @@ class SocialNetworkButton extends StatelessWidget { Widget build(BuildContext context) { return ElevatedButton( style: ElevatedButton.styleFrom( - primary: backgroundColor.withOpacity(0.1), - onPrimary: Colors.white, + backgroundColor: backgroundColor.withOpacity(0.1), + foregroundColor: Colors.white, elevation: 0, shadowColor: Colors.white.withOpacity(0), shape: diff --git a/lib/app/ui/main_page/sections/top_section/widgets/left_text_column.dart b/lib/app/ui/main_page/sections/top_section/widgets/left_text_column.dart index ebd2f1a..53d815d 100644 --- a/lib/app/ui/main_page/sections/top_section/widgets/left_text_column.dart +++ b/lib/app/ui/main_page/sections/top_section/widgets/left_text_column.dart @@ -32,12 +32,12 @@ class LeftTextColumn extends StatelessWidget { direction: Axis.vertical, spacing: defaultPadding, children: [ - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), @@ -53,12 +53,12 @@ class LeftTextColumn extends StatelessWidget { ); }, ), - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), @@ -84,14 +84,14 @@ class LeftTextColumn extends StatelessWidget { ])), ); }), - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, delay: Duration(milliseconds: (animationTime * 0.2 * 1000).round()), duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), @@ -105,14 +105,14 @@ class LeftTextColumn extends StatelessWidget { ), ); }), - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, delay: Duration(milliseconds: (animationTime * 0.4 * 1000).round()), duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), @@ -125,14 +125,14 @@ class LeftTextColumn extends StatelessWidget { fontSize: usualText.fontSize! * 1.5), ))); }), - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, delay: Duration(milliseconds: (animationTime * 0.6 * 1000).round()), duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), @@ -163,14 +163,14 @@ class LeftTextColumn extends StatelessWidget { )), ))); }), - PlayAnimation( + PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, delay: Duration(milliseconds: (animationTime * 0.8 * 1000).round()), duration: Duration(seconds: animationTime), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), diff --git a/lib/app/ui/project_page/widgets/project_images.dart b/lib/app/ui/project_page/widgets/project_images.dart index 82a2ec7..13f12ae 100644 --- a/lib/app/ui/project_page/widgets/project_images.dart +++ b/lib/app/ui/project_page/widgets/project_images.dart @@ -16,7 +16,7 @@ class ProjectImages extends StatefulWidget { final Project project; final Size size; - final CarouselController _controller = CarouselController(); + final CarouselSliderController _controller = CarouselSliderController(); @override State createState() => _ProjectImagesState(); } diff --git a/lib/app/ui/projects_page/sections/top_section/widgets/projects_title.dart b/lib/app/ui/projects_page/sections/top_section/widgets/projects_title.dart index 6176da1..533db98 100644 --- a/lib/app/ui/projects_page/sections/top_section/widgets/projects_title.dart +++ b/lib/app/ui/projects_page/sections/top_section/widgets/projects_title.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:simple_animations/stateless_animation/play_animation.dart'; +import 'package:simple_animations/simple_animations.dart'; import '../../../../theme/app_constants.dart'; import '../../../../theme/app_fonts.dart'; @@ -11,12 +11,12 @@ class ProjectsTitle extends StatelessWidget { @override Widget build(BuildContext context) { - return PlayAnimation( + return PlayAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), curve: Curves.ease, fps: 300, duration: const Duration(seconds: 2), - builder: (context, child, value) { + builder: (context, value, child) { return Padding( padding: EdgeInsets.only( left: defaultPadding * 4 - value * defaultPadding * 4), diff --git a/pubspec.lock b/pubspec.lock index ce5e251..b43958c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,93 +5,106 @@ packages: dependency: "direct main" description: name: animated_text_kit - url: "https://pub.dartlang.org" + sha256: "37392a5376c9a1a503b02463c38bc0342ef814ddbb8f9977bc90f2a84b22fa92" + url: "https://pub.dev" source: hosted version: "4.2.2" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: "793964beb8e297995714326628881437d4211f10fc8843534bab54129cd896ee" + url: "https://pub.dev" source: hosted version: "3.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.13.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" + url: "https://pub.dev" source: hosted version: "2.1.0" card_swiper: dependency: "direct main" description: name: card_swiper - url: "https://pub.dartlang.org" + sha256: "0c94c538f47be1dab52d018d4900a7046b4cb0700dc7f95b8628da89d1212b35" + url: "https://pub.dev" source: hosted version: "2.0.4" carousel_slider: dependency: "direct main" description: name: carousel_slider - url: "https://pub.dartlang.org" + sha256: febf4b0163e0242adc13d7a863b04965351f59e7dfea56675c7c2caa7bcd7476 + url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "5.1.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.3" flutter: dependency: transitive description: flutter @@ -101,14 +114,16 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_svg: dependency: "direct main" description: name: flutter_svg - url: "https://pub.dartlang.org" + sha256: "0382db7886d4d0e23dd4e1261406bdf65ffdf7ecbdcb25c1f5ad09a80ecfab96" + url: "https://pub.dev" source: hosted version: "1.1.3" flutter_test: @@ -125,245 +140,311 @@ packages: dependency: "direct main" description: name: image - url: "https://pub.dartlang.org" + sha256: "9d2c5f73435a70a936d317769ee8e7ef480e37674b9f2bce95ea98969a307855" + url: "https://pub.dev" source: hosted version: "3.2.0" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + url: "https://pub.dev" source: hosted version: "0.17.0" - js: + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: dependency: transitive description: - name: js - url: "https://pub.dartlang.org" + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.13.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.18.0" mouse_parallax: dependency: "direct main" description: name: mouse_parallax - url: "https://pub.dartlang.org" + sha256: a40423bef0462de641c3638dc0976139e74d1ed3a0894d489076d701db155db0 + url: "https://pub.dev" source: hosted version: "1.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.1" path_drawing: dependency: transitive description: name: path_drawing - url: "https://pub.dartlang.org" + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" source: hosted version: "1.0.1" path_parsing: dependency: transitive description: name: path_parsing - url: "https://pub.dartlang.org" + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" source: hosted version: "1.0.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71" + url: "https://pub.dev" source: hosted version: "5.0.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.8" sa3_liquid: dependency: "direct main" description: name: sa3_liquid - url: "https://pub.dartlang.org" + sha256: "609742dd35e6fd97812eda55262c50468521eb2ffc47e50e625b4ba418648bc8" + url: "https://pub.dev" source: hosted version: "1.0.1" simple_animations: dependency: "direct main" description: name: simple_animations - url: "https://pub.dartlang.org" + sha256: "0e90dc63183212b2c47c7969bd77cf7648be9f62c9461837ae4cbe8a62ff3369" + url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "5.3.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: d77dbb9d0b7469d91e42d352334b2b4bbd5cec4379542f1bdb630db368c4d9f6 + url: "https://pub.dev" source: hosted version: "1.8.2" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: dd11571b8a03f7cadcf91ec26a77e02bfbd6bbba2a512924d3116646b4198fc4 + url: "https://pub.dev" source: hosted version: "1.1.0" supercharged: dependency: transitive description: name: supercharged - url: "https://pub.dartlang.org" + sha256: ab49c848b33e28243f5ce82b976736de17d0852b71d0dfbde53fbb5e2ecca7cb + url: "https://pub.dev" source: hosted version: "2.1.1" supercharged_dart: dependency: transitive description: name: supercharged_dart - url: "https://pub.dartlang.org" + sha256: cb95edda32eacd27664089700a750120be41daa84aa6cd2aeded46227c16b867 + url: "https://pub.dev" source: hosted version: "2.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a88162591b02c1f3a3db3af8ce1ea2b374bd75a7bb8d5e353bcfbdc79d719830 + url: "https://pub.dev" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.7.11" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" source: hosted - version: "6.1.5" + version: "6.3.2" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 + url: "https://pub.dev" source: hosted - version: "6.0.17" + version: "6.3.32" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + url: "https://pub.dev" source: hosted - version: "6.0.17" + version: "6.4.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.2.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.2.5" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" + url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.4.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.5" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.dev" + source: hosted + version: "15.2.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "1.1.1" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb + url: "https://pub.dev" source: hosted version: "6.1.0" sdks: - dart: ">=2.17.0 <3.0.0" - flutter: ">=2.11.0-0.1.pre" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5d05818..8622502 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.15.0 <3.0.4" + sdk: ">=3.0.0 <4.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -36,13 +36,13 @@ dependencies: flutter_svg: ^1.1.1+1 card_swiper: ^2.0.4 image: ^3.2.0 - simple_animations: ^4.2.0 + simple_animations: ^5.3.0 sa3_liquid: ^1.0.1 mouse_parallax: ^1.1.0 - url_launcher: ^6.1.5 + url_launcher: ^6.3.2 animated_text_kit: ^4.2.2 intl: ^0.17.0 - carousel_slider: ^4.1.1 + carousel_slider: ^5.1.2 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart index e3d04ff..7bf6171 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,30 +1,20 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:portfolio_flutter_web/main.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); + testWidgets('portfolio home page renders', (WidgetTester tester) async { + tester.view.physicalSize = const Size(1440, 900); + tester.view.devicePixelRatio = 1.0; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); + await tester.pumpWidget(const MyApp()); await tester.pump(); - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); + expect(find.text('Mentoster'), findsOneWidget); + expect(find.text('Главная'), findsOneWidget); + expect(find.text('Все Проекты'), findsOneWidget); }); } From 9fea76521e8079fa0ccaebdbe35dff9cb9fa9828 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 19:33:28 +0300 Subject: [PATCH 2/9] fix(web): load instrument icons from modern asset manifest --- .../widgets/small_icons_wrap_widget.dart | 34 ++++++------- test/small_icons_wrap_widget_test.dart | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 test/small_icons_wrap_widget_test.dart diff --git a/lib/app/ui/main_page/sections/work_instruments/widgets/small_icons_wrap_widget.dart b/lib/app/ui/main_page/sections/work_instruments/widgets/small_icons_wrap_widget.dart index 931e2ba..8a533fe 100644 --- a/lib/app/ui/main_page/sections/work_instruments/widgets/small_icons_wrap_widget.dart +++ b/lib/app/ui/main_page/sections/work_instruments/widgets/small_icons_wrap_widget.dart @@ -1,6 +1,3 @@ -import 'dart:convert'; -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -10,25 +7,29 @@ import 'small_circle_icon.dart'; class SmallIconsWrapWidget extends StatefulWidget { const SmallIconsWrapWidget({ Key? key, + this.assetBundle, }) : super(key: key); + final AssetBundle? assetBundle; + @override State createState() => _SmallIconsWrapWidgetState(); } class _SmallIconsWrapWidgetState extends State { + static const _iconsPath = 'assets/icons/instruments/others/'; Future> _initImages() async { - final manifestContent = await rootBundle.loadString('AssetManifest.json'); - - final Map manifestMap = json.decode(manifestContent); - - final imagePaths = manifestMap.keys - .where((String key) => key.contains('assets/icons/instruments/others/')) - .where((String key) => key.contains('.svg')) - .toList(); + final manifest = await AssetManifest.loadFromAssetBundle( + widget.assetBundle ?? rootBundle, + ); - return imagePaths; + return manifest + .listAssets() + .where((String key) => key.startsWith(_iconsPath)) + .where((String key) => key.endsWith('.svg')) + .toList() + ..sort(); } @override @@ -44,12 +45,11 @@ class _SmallIconsWrapWidgetState extends State { for (var path in snapshot.data!) SmallCircleIcon( iconPath: path, - title: File(path) - .uri - .pathSegments + title: path + .split('/') .last - .replaceAll(".svg", "") - .replaceAll("_", " "), + .replaceAll('.svg', '') + .replaceAll('_', ' '), ) ], ); diff --git a/test/small_icons_wrap_widget_test.dart b/test/small_icons_wrap_widget_test.dart new file mode 100644 index 0000000..cbd202d --- /dev/null +++ b/test/small_icons_wrap_widget_test.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:portfolio_flutter_web/app/ui/main_page/sections/work_instruments/widgets/small_icons_wrap_widget.dart'; + +class _ThrowingAssetBundle extends CachingAssetBundle { + @override + Future load(String key) { + throw FlutterError('manifest unavailable'); + } +} + +void main() { + testWidgets('loads instrument icons from the current Flutter asset manifest', + (WidgetTester tester) async { + tester.view.physicalSize = const Size(1440, 1200); + tester.view.devicePixelRatio = 1.0; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: SingleChildScrollView( + child: SmallIconsWrapWidget(), + ), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('Bash'), findsOneWidget); + expect(find.textContaining('cant load icons'), findsNothing); + }); + + testWidgets('shows a readable error when the manifest cannot load', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SmallIconsWrapWidget(assetBundle: _ThrowingAssetBundle()), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.textContaining('cant load icons'), findsOneWidget); + expect(find.byIcon(Icons.error_outline), findsOneWidget); + }); +} From 3e5a0653aab3d11b5a6fa3c1993d1e652931b7e1 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 19:46:25 +0300 Subject: [PATCH 3/9] perf(web): reduce continuous rendering and image payload --- .../data/information_data/info_projects.dart | 2 +- .../global_widgets/animated_background.dart | 101 ++++++++---------- .../widgets/certificate_widget.dart | 1 + .../widgets/diploma_diploma_widget.dart | 1 + pubspec.lock | 56 ---------- pubspec.yaml | 15 ++- 6 files changed, 58 insertions(+), 118 deletions(-) diff --git a/lib/app/data/information_data/info_projects.dart b/lib/app/data/information_data/info_projects.dart index 18fecca..bfed2d2 100644 --- a/lib/app/data/information_data/info_projects.dart +++ b/lib/app/data/information_data/info_projects.dart @@ -12,7 +12,7 @@ final projects = [ description: """ Приложение дает пользователям возможность осуществлять процесс сборки предоставленной модели в формате виртуальной реальности. Люди могут собирать ракетный двигатель как самостоятельно, так и в многопользовательской комнате, объединившись с напарниками. Процесс сопровождают различные подсказки и тексты с описаниями деталей. Все это, вкупе с глубоким погружением, способствует быстрому усвоению материала. При окончании сборки модель становится анимированной и демонстрирует свой принцип работы.""", - backgroundImagePath: "assets/images/projects/Revolit/background.png", + backgroundImagePath: "assets/images/projects/Revolit/preview.png", images: [ "assets/images/projects/Revolit/preview.png", "assets/images/projects/Revolit/preview.png", diff --git a/lib/app/ui/global_widgets/animated_background.dart b/lib/app/ui/global_widgets/animated_background.dart index d3740e8..7a8f46a 100644 --- a/lib/app/ui/global_widgets/animated_background.dart +++ b/lib/app/ui/global_widgets/animated_background.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:sa3_liquid/sa3_liquid.dart'; class AnimatedBackground extends StatelessWidget { const AnimatedBackground({ @@ -11,63 +10,53 @@ class AnimatedBackground extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack(children: [ - SizedBox( - width: size.width, - height: size.height, - child: const PlasmaRenderer( - type: PlasmaType.infinity, - particles: 2, - color: Color.fromARGB(49, 247, 0, 255), - blur: 0.7, - size: 0.7, - speed: 2, - offset: 0, - blendMode: BlendMode.srcOver, - particleType: ParticleType.atlas, - variation1: 0.31, - variation2: 0.3, - variation3: 0.0, - rotation: -0.7, - )), - SizedBox( - width: size.width, - height: size.height, - child: const PlasmaRenderer( - type: PlasmaType.infinity, - particles: 2, - color: Color.fromARGB(50, 0, 0, 255), - blur: 0.7, - size: 0.7, - speed: 2, - offset: 0, - blendMode: BlendMode.srcOver, - particleType: ParticleType.atlas, - variation1: 0.31, - variation2: 0.3, - variation3: 0.0, - rotation: 1.2, + return SizedBox( + width: size.width, + height: size.height, + child: const DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0x300000FF), + Color(0x22030003), + Color(0x2EF700FF), + Color(0x22030003), + Color(0x26FFFF00), + ], + stops: [0.0, 0.24, 0.5, 0.76, 1.0], + ), ), - ), - SizedBox( - width: size.width, - height: size.height, - child: const PlasmaRenderer( - type: PlasmaType.infinity, - particles: 2, - color: Color.fromARGB(50, 255, 255, 0), - blur: 0.7, - size: 0.7, - speed: 2, - offset: 0, - blendMode: BlendMode.srcOver, - particleType: ParticleType.atlas, - variation1: 0.31, - variation2: 0.3, - variation3: 0.0, - rotation: 0, + child: DecoratedBox( + decoration: BoxDecoration( + gradient: RadialGradient( + center: Alignment(-0.72, -0.55), + radius: 1.25, + colors: [ + Color(0x2BF700FF), + Color(0x160000FF), + Colors.transparent, + ], + stops: [0.0, 0.48, 1.0], + ), + ), + child: DecoratedBox( + decoration: BoxDecoration( + gradient: RadialGradient( + center: Alignment(0.78, 0.65), + radius: 1.1, + colors: [ + Color(0x24FFFF00), + Color(0x140000FF), + Colors.transparent, + ], + stops: [0.0, 0.52, 1.0], + ), + ), + ), ), ), - ]); + ); } } diff --git a/lib/app/ui/main_page/sections/certificates/widgets/certificate_widget.dart b/lib/app/ui/main_page/sections/certificates/widgets/certificate_widget.dart index d6f5305..76b5ce7 100644 --- a/lib/app/ui/main_page/sections/certificates/widgets/certificate_widget.dart +++ b/lib/app/ui/main_page/sections/certificates/widgets/certificate_widget.dart @@ -35,6 +35,7 @@ class CertificatePct extends StatelessWidget { child: Image.asset( certificate.image, fit: BoxFit.fill, + cacheWidth: 1500, ), ), ), diff --git a/lib/app/ui/main_page/sections/diplomas/widgets/diploma_diploma_widget.dart b/lib/app/ui/main_page/sections/diplomas/widgets/diploma_diploma_widget.dart index 83fc7ea..d8965d2 100644 --- a/lib/app/ui/main_page/sections/diplomas/widgets/diploma_diploma_widget.dart +++ b/lib/app/ui/main_page/sections/diplomas/widgets/diploma_diploma_widget.dart @@ -40,6 +40,7 @@ class DiplomaPct extends StatelessWidget { child: Image.asset( diploma.image, fit: BoxFit.cover, + cacheWidth: 1200, ), ), ), diff --git a/pubspec.lock b/pubspec.lock index b43958c..1c15a47 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,14 +9,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.2" - archive: - dependency: transitive - description: - name: archive - sha256: "793964beb8e297995714326628881437d4211f10fc8843534bab54129cd896ee" - url: "https://pub.dev" - source: hosted - version: "3.3.1" async: dependency: transitive description: @@ -81,14 +73,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" cupertino_icons: dependency: "direct main" description: @@ -136,14 +120,6 @@ packages: description: flutter source: sdk version: "0.0.0" - image: - dependency: "direct main" - description: - name: image - sha256: "9d2c5f73435a70a936d317769ee8e7ef480e37674b9f2bce95ea98969a307855" - url: "https://pub.dev" - source: hosted - version: "3.2.0" intl: dependency: "direct main" description: @@ -256,14 +232,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - sa3_liquid: - dependency: "direct main" - description: - name: sa3_liquid - sha256: "609742dd35e6fd97812eda55262c50468521eb2ffc47e50e625b4ba418648bc8" - url: "https://pub.dev" - source: hosted - version: "1.0.1" simple_animations: dependency: "direct main" description: @@ -309,22 +277,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - supercharged: - dependency: transitive - description: - name: supercharged - sha256: ab49c848b33e28243f5ce82b976736de17d0852b71d0dfbde53fbb5e2ecca7cb - url: "https://pub.dev" - source: hosted - version: "2.1.1" - supercharged_dart: - dependency: transitive - description: - name: supercharged_dart - sha256: cb95edda32eacd27664089700a750120be41daa84aa6cd2aeded46227c16b867 - url: "https://pub.dev" - source: hosted - version: "2.1.1" term_glyph: dependency: transitive description: @@ -341,14 +293,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.11" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" url_launcher: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 8622502..4ac7f31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,9 +35,7 @@ dependencies: cupertino_icons: ^1.0.2 flutter_svg: ^1.1.1+1 card_swiper: ^2.0.4 - image: ^3.2.0 simple_animations: ^5.3.0 - sa3_liquid: ^1.0.1 mouse_parallax: ^1.1.0 url_launcher: ^6.3.2 animated_text_kit: ^4.2.2 @@ -73,9 +71,16 @@ flutter: - assets/icons/own_icons/ - assets/icons/instruments/top_5/ - assets/icons/instruments/others/ - - assets/images/papers/diplomas/ - - assets/images/papers/certificates/ - - assets/images/projects/Revolit/ + - assets/images/papers/diplomas/цифровой_прорыв_прорыв_2021.png + - assets/images/papers/diplomas/теле2_game_2019.png + - assets/images/papers/diplomas/junction_skysea_game-1.png + - assets/images/papers/diplomas/цифровой_прорыв_2021-финал.png + - assets/images/papers/diplomas/volvo_page-0001.jpg + - assets/images/papers/diplomas/diploma_mai_2021.png + - assets/images/papers/certificates/_OST_1_MIREA_IKBO_certificate_page-0001.jpg + - assets/images/papers/certificates/Математика и Python для анализа данных_page-0001.jpg + - assets/images/papers/certificates/Макаров Дмитрий 2_page-0001.jpg + - assets/images/projects/Revolit/preview.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. From 23f4edaafdb1fddb06567fe6ec8177861bdb7668 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 19:46:31 +0300 Subject: [PATCH 4/9] perf(web): modernize bootstrap and nginx static delivery --- deploy/nginx.conf | 23 +++++++++++++++++++++++ web/flutter_bootstrap.js | 26 ++++++++++++++++++++++++++ web/index.html | 34 +--------------------------------- 3 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 web/flutter_bootstrap.js diff --git a/deploy/nginx.conf b/deploy/nginx.conf index 3ad4058..763e2eb 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -5,6 +5,13 @@ server { root /usr/share/nginx/html; index index.html; + error_page 404 = @not_found; + + location @not_found { + default_type text/plain; + return 404 "Not found\n"; + } + location = /index.html { add_header Cache-Control "no-cache"; } @@ -17,6 +24,22 @@ server { add_header Cache-Control "no-cache"; } + location ^~ /assets/ { + try_files $uri =404; + } + + location ^~ /canvaskit/ { + try_files $uri =404; + } + + location ^~ /icons/ { + try_files $uri =404; + } + + location ~* \.(?:js|mjs|wasm|json|png|svg|ico|webp|jpg|jpeg|css|map|symbols)$ { + try_files $uri =404; + } + location / { try_files $uri $uri/ /index.html; } diff --git a/web/flutter_bootstrap.js b/web/flutter_bootstrap.js new file mode 100644 index 0000000..860e99b --- /dev/null +++ b/web/flutter_bootstrap.js @@ -0,0 +1,26 @@ +{{flutter_js}} +{{flutter_build_config}} + +_flutter.loader.load({ + serviceWorkerSettings: { + serviceWorkerVersion: {{flutter_service_worker_version}}, + }, + onEntrypointLoaded: async function (engineInitializer) { + const loading = document.querySelector('#loading'); + if (loading) { + loading.classList.add('main_done'); + } + + const appRunner = await engineInitializer.initializeEngine(); + + if (loading) { + loading.classList.add('init_done'); + } + + await appRunner.runApp(); + + if (loading) { + window.setTimeout(() => loading.remove(), 200); + } + }, +}); diff --git a/web/index.html b/web/index.html index cae0339..d11bc1b 100644 --- a/web/index.html +++ b/web/index.html @@ -25,17 +25,6 @@ } --> - - @@ -97,28 +86,7 @@ Loading indicator... - + From 82fa7bebd446fa1d22a958937f473e52a744b8f4 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 19:46:39 +0300 Subject: [PATCH 5/9] ci: modernize Flutter web verification and deploy workflows --- .github/workflows/dart_analyze.yml | 28 ++++++++++++------- .github/workflows/dart_score.yml | 2 +- .github/workflows/firebase-hosting-merge.yml | 14 ++++++++-- .../workflows/fluttter_to_github_pages.yml | 17 +++++++---- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/.github/workflows/dart_analyze.yml b/.github/workflows/dart_analyze.yml index 5237994..5b341c3 100644 --- a/.github/workflows/dart_analyze.yml +++ b/.github/workflows/dart_analyze.yml @@ -1,18 +1,26 @@ -name: DartAnalyze +name: Flutter CI -on: pull_request +on: + pull_request: jobs: - linter: + verify: runs-on: ubuntu-latest - name: Lint flutter code + name: Analyze, test and build web steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v6 - name: Set up Flutter - uses: subosito/flutter-action@v1 - - run: flutter pub get - - name: Analyze Flutter - uses: ValentinVignal/action-dart-analyze@v0.11 + uses: subosito/flutter-action@v2 with: - fail-on: "warning" + channel: stable + flutter-version: '3.44.6' + cache: true + - name: Install dependencies + run: flutter pub get + - name: Analyze Flutter + run: flutter analyze + - name: Run tests + run: flutter test + - name: Build web + run: flutter build web --release diff --git a/.github/workflows/dart_score.yml b/.github/workflows/dart_score.yml index 042dd54..d149e7f 100644 --- a/.github/workflows/dart_score.yml +++ b/.github/workflows/dart_score.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - uses: axel-op/dart-package-analyzer@v3 # set an id for the current step id: analysis diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml index ac8ccb8..2ba0148 100644 --- a/.github/workflows/firebase-hosting-merge.yml +++ b/.github/workflows/firebase-hosting-merge.yml @@ -6,12 +6,22 @@ name: Deploy to Firebase Hosting on merge push: branches: - master + jobs: build_and_deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - run: sudo snap install flutter --classic && flutter channel stable && flutter config --enable-web && flutter build web --release --web-renderer canvaskit + - uses: actions/checkout@v6 + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: '3.44.6' + cache: true + - name: Install dependencies + run: flutter pub get + - name: Build web + run: flutter build web --release - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: '${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/fluttter_to_github_pages.yml b/.github/workflows/fluttter_to_github_pages.yml index 3644a2b..7a355f5 100644 --- a/.github/workflows/fluttter_to_github_pages.yml +++ b/.github/workflows/fluttter_to_github_pages.yml @@ -4,13 +4,20 @@ on: push: branches: [master] +permissions: + contents: write + jobs: build: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 - - uses: erickzanardo/flutter-gh-pages@v3 + - uses: actions/checkout@v6 + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: '3.44.6' + cache: true + - uses: bluefireteam/flutter-gh-pages@v9 with: - webRenderer: canvaskit + baseHref: /portfolio_flutter_web/ From 224c861698897c752c5c756ff882ead365ce6fc7 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 20:06:14 +0300 Subject: [PATCH 6/9] fix(ci): support analyzer and package score toolchains --- .github/workflows/dart_analyze.yml | 2 +- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dart_analyze.yml b/.github/workflows/dart_analyze.yml index 5b341c3..1955e60 100644 --- a/.github/workflows/dart_analyze.yml +++ b/.github/workflows/dart_analyze.yml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies run: flutter pub get - name: Analyze Flutter - run: flutter analyze + run: flutter analyze --no-fatal-infos - name: Run tests run: flutter test - name: Build web diff --git a/pubspec.lock b/pubspec.lock index 1c15a47..48bdf7c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -236,10 +236,10 @@ packages: dependency: "direct main" description: name: simple_animations - sha256: "0e90dc63183212b2c47c7969bd77cf7648be9f62c9461837ae4cbe8a62ff3369" + sha256: "2f4817d7e56a8ae34f1666ba9906aed394a48c7e1568d0fcd63efefb95142dd5" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.2.0" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 4ac7f31..c9ae55a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: cupertino_icons: ^1.0.2 flutter_svg: ^1.1.1+1 card_swiper: ^2.0.4 - simple_animations: ^5.3.0 + simple_animations: 5.2.0 mouse_parallax: ^1.1.0 url_launcher: ^6.3.2 animated_text_kit: ^4.2.2 From e7fca9977fa7770472b9ecc12ce7b65ef25f75b3 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 20:09:52 +0300 Subject: [PATCH 7/9] fix(ci): repair DartScore threshold script --- .github/workflows/dart_score.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dart_score.yml b/.github/workflows/dart_score.yml index d149e7f..3ba27f1 100644 --- a/.github/workflows/dart_score.yml +++ b/.github/workflows/dart_score.yml @@ -22,7 +22,8 @@ jobs: TOTAL_MAX: ${{ steps.analysis.outputs.total_max }} run: | PERCENTAGE=$(( $TOTAL * 100 / $TOTAL_MAX )) - if (( $PERCENTAGE < 50 )) - then - echo Score too low! + if (( PERCENTAGE < 50 )); then + echo "Score too low: ${PERCENTAGE}%" exit 1 + fi + echo "Dart package score: ${PERCENTAGE}%" From 9bf678b89e9f7c223dccb15cc62fd9db1fd89992 Mon Sep 17 00:00:00 2001 From: mentoster Date: Fri, 24 Jul 2026 20:26:29 +0300 Subject: [PATCH 8/9] fix(web): retire legacy service workers without reload loops --- web/flutter_bootstrap.js | 70 +++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/web/flutter_bootstrap.js b/web/flutter_bootstrap.js index 860e99b..d031b3b 100644 --- a/web/flutter_bootstrap.js +++ b/web/flutter_bootstrap.js @@ -1,26 +1,60 @@ {{flutter_js}} {{flutter_build_config}} -_flutter.loader.load({ - serviceWorkerSettings: { - serviceWorkerVersion: {{flutter_service_worker_version}}, - }, - onEntrypointLoaded: async function (engineInitializer) { - const loading = document.querySelector('#loading'); - if (loading) { - loading.classList.add('main_done'); - } +async function retireLegacyServiceWorker() { + if (!('serviceWorker' in navigator)) { + return true; + } + + const cleanupKey = 'portfolio_flutter_web_service_worker_cleanup'; + if (sessionStorage.getItem(cleanupKey) === 'done') { + return true; + } - const appRunner = await engineInitializer.initializeEngine(); + const registrations = await navigator.serviceWorker.getRegistrations(); + const currentUrl = window.location.href; + let removedController = false; - if (loading) { - loading.classList.add('init_done'); + for (const registration of registrations) { + if (currentUrl.startsWith(registration.scope)) { + const removed = await registration.unregister(); + removedController = removedController || removed; } + } - await appRunner.runApp(); + sessionStorage.setItem(cleanupKey, 'done'); - if (loading) { - window.setTimeout(() => loading.remove(), 200); - } - }, -}); + if (removedController && navigator.serviceWorker.controller) { + window.location.reload(); + return false; + } + + return true; +} + +(async function startFlutter() { + if (!await retireLegacyServiceWorker()) { + return; + } + + _flutter.loader.load({ + onEntrypointLoaded: async function (engineInitializer) { + const loading = document.querySelector('#loading'); + if (loading) { + loading.classList.add('main_done'); + } + + const appRunner = await engineInitializer.initializeEngine(); + + if (loading) { + loading.classList.add('init_done'); + } + + await appRunner.runApp(); + + if (loading) { + window.setTimeout(() => loading.remove(), 200); + } + }, + }); +})(); From 8672ac0905ee246a3e3b9a032ae6ca6de1ba37eb Mon Sep 17 00:00:00 2001 From: mentoster Date: Sat, 25 Jul 2026 09:15:42 +0300 Subject: [PATCH 9/9] chore: remove CI/CD workflows --- .github/workflows/dart_analyze.yml | 26 ---------------- .github/workflows/dart_score.yml | 29 ------------------ .github/workflows/firebase-hosting-merge.yml | 30 ------------------- .../workflows/fluttter_to_github_pages.yml | 23 -------------- 4 files changed, 108 deletions(-) delete mode 100644 .github/workflows/dart_analyze.yml delete mode 100644 .github/workflows/dart_score.yml delete mode 100644 .github/workflows/firebase-hosting-merge.yml delete mode 100644 .github/workflows/fluttter_to_github_pages.yml diff --git a/.github/workflows/dart_analyze.yml b/.github/workflows/dart_analyze.yml deleted file mode 100644 index 1955e60..0000000 --- a/.github/workflows/dart_analyze.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Flutter CI - -on: - pull_request: - -jobs: - verify: - runs-on: ubuntu-latest - name: Analyze, test and build web - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: '3.44.6' - cache: true - - name: Install dependencies - run: flutter pub get - - name: Analyze Flutter - run: flutter analyze --no-fatal-infos - - name: Run tests - run: flutter test - - name: Build web - run: flutter build web --release diff --git a/.github/workflows/dart_score.yml b/.github/workflows/dart_score.yml deleted file mode 100644 index 3ba27f1..0000000 --- a/.github/workflows/dart_score.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: DartScore -on: pull_request - -jobs: - package-analysis: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6 - - uses: axel-op/dart-package-analyzer@v3 - # set an id for the current step - id: analysis - with: - githubToken: ${{ secrets.GITHUB_TOKEN }} - - # You can then use this id to retrieve the outputs in the next steps. - # The following step shows how to exit the workflow with an error if the total score in percentage is below 50: - - name: Check scores - env: - # NB: "analysis" is the id set above. Replace it with the one you used if different. - TOTAL: ${{ steps.analysis.outputs.total }} - TOTAL_MAX: ${{ steps.analysis.outputs.total_max }} - run: | - PERCENTAGE=$(( $TOTAL * 100 / $TOTAL_MAX )) - if (( PERCENTAGE < 50 )); then - echo "Score too low: ${PERCENTAGE}%" - exit 1 - fi - echo "Dart package score: ${PERCENTAGE}%" diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml deleted file mode 100644 index 2ba0148..0000000 --- a/.github/workflows/firebase-hosting-merge.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This file was auto-generated by the Firebase CLI -# https://github.com/firebase/firebase-tools - -name: Deploy to Firebase Hosting on merge -'on': - push: - branches: - - master - -jobs: - build_and_deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: '3.44.6' - cache: true - - name: Install dependencies - run: flutter pub get - - name: Build web - run: flutter build web --release - - uses: FirebaseExtended/action-hosting-deploy@v0 - with: - repoToken: '${{ secrets.GITHUB_TOKEN }}' - firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_DMITRIY_MAKAROV }}' - channelId: live - projectId: dmitriy-makarov diff --git a/.github/workflows/fluttter_to_github_pages.yml b/.github/workflows/fluttter_to_github_pages.yml deleted file mode 100644 index 7a355f5..0000000 --- a/.github/workflows/fluttter_to_github_pages.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Gh-Pages - -on: - push: - branches: [master] - -permissions: - contents: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: '3.44.6' - cache: true - - uses: bluefireteam/flutter-gh-pages@v9 - with: - baseHref: /portfolio_flutter_web/