[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"technologies":3,"\u002Fopen-source\u002Fflutter-progress-dialog":167},[4,10,15,21,26,32,38,43,48,53,58,63,68,73,77,82,87,92,97,103,108,113,118,123,128,133,138,143,147,152,157,162],{"title":5,"description":6,"slug":7,"category":8,"icon":9},"Android","Каждое наше приложение выходит и на Android — платформенные API, фоновое выполнение, разрешения и требования магазина вместе с ними.","android","framework","logos:android-icon",{"title":11,"description":12,"slug":13,"category":8,"icon":14},"Angular","Фронтенд-фреймворк, в котором мы работаем, когда продукт уже на Angular, — строгая структура, подходящая большим долгоживущим приложениям.","angular","logos:angular-icon",{"title":16,"description":17,"slug":18,"category":19,"icon":20},"Dart","Язык, на котором написано каждое наше Flutter-приложение, — строгая null safety, полноценный pattern matching и компиляция в нативный код и веб.","dart","language","logos:dart",{"title":22,"description":23,"slug":24,"category":8,"icon":25},"Django","Python-фреймворк, который мы берём, когда продукту нужны админка, аутентификация и модель данных в первый же день, а не самописный сервис.","django","logos:django-icon",{"title":27,"description":28,"slug":29,"category":30,"icon":31},"Docker","Каждый наш сервис поставляется в виде контейнера, поэтому на ноутбуке, в CI и в продакшене работает один и тот же артефакт, а не три разных.","docker","infrastructure","logos:docker-icon",{"title":33,"description":34,"slug":35,"category":36,"icon":37},"Fastlane","Автоматизация релизов в нашей мобильной разработке — подпись, сборки и загрузка в сторы идут из CI, а не с ноутбука одного инженера в день релиза.","fastlane","tools","logos:fastlane",{"title":39,"description":40,"slug":41,"category":8,"icon":42},"Flutter","Наш основной мобильный стек с 2018 года — одна кодовая база на Dart для iOS, Android, веба и десктопа без отдельной команды под каждую платформу.","flutter","logos:flutter",{"title":44,"description":45,"slug":46,"category":36,"icon":47},"Git","Все проекты, к которым мы прикасаемся, живут в Git — ревью пул-реквестов, CI на каждой ветке и история, понятная и спустя месяцы.","git","logos:git-icon",{"title":49,"description":50,"slug":51,"category":19,"icon":52},"Go","Наш бэкенд-язык для real-time API и сервисов под нагрузкой — маленькие бинарники, быстрая сборка и конкурентность, которая остаётся читаемой.","go","logos:gopher",{"title":54,"description":55,"slug":56,"category":30,"icon":57},"Google Cloud","Облако, в котором работают наши продакшен-нагрузки, — управляемый Kubernetes, хранилище и сеть без серверов, которые надо обслуживать руками.","gcp","logos:google-cloud",{"title":59,"description":60,"slug":61,"category":36,"icon":62},"Gradle","Система сборки, через которую проходит каждый Android-релиз, — флейворы, конфигурации подписи и вся обвязка зависимостей под Flutter-приложением.","gradle","logos:gradle",{"title":64,"description":65,"slug":66,"category":30,"icon":67},"Helm","Так мы упаковываем деплой в Kubernetes — сервис, конфигурация, секреты и ingress как одна версионируемая единица, которую можно выкатить и откатить.","helm","logos:helm",{"title":69,"description":70,"slug":71,"category":19,"icon":72},"Kotlin","То, что мы берём, когда Flutter-приложению нужен настоящий Android под ним, — platform channels, фоновые задачи и интеграции с нативными SDK.","kotlin","logos:kotlin-icon",{"title":74,"description":75,"slug":76,"category":8,"icon":72},"Kotlin Multiplatform","Общая бизнес-логика для iOS и Android, а нативный интерфейс у каждой платформы свой, — альтернатива, когда Flutter не подходит.","kmp",{"title":78,"description":79,"slug":80,"category":30,"icon":81},"Kubernetes","Так мы запускаем сервисы в продакшене — деплой в Helm-чартах, откатываемые выкатки и масштабирование, для которого не нужен человек в три ночи.","kubernetes","logos:kubernetes",{"title":83,"description":84,"slug":85,"category":30,"icon":86},"NATS","Лёгкий обмен сообщениями между сервисами — publish\u002Fsubscribe и request\u002Freply без эксплуатационного веса полноценного кластера брокера.","nats","logos:nats-icon",{"title":88,"description":89,"slug":90,"category":8,"icon":91},"Nuxt","Vue с серверным рендерингом, роутингом и SEO из коробки — так мы делаем сайты и веб-приложения, которые должны быстро грузиться и индексироваться.","nuxt","logos:nuxt-icon",{"title":93,"description":94,"slug":95,"category":19,"icon":96},"PHP","Там, где PHP-бэкенд уже есть: дорабатываем его, интегрируемся с ним и делаем мобильные и веб-клиенты, которые он обслуживает.","php","logos:php",{"title":98,"description":99,"slug":100,"category":101,"icon":102},"PostgreSQL","Наша база данных по умолчанию — от проектирования схемы до настройки индексов мы берём её, если у продукта нет конкретной причины взять другую.","postgres","database","logos:postgresql",{"title":104,"description":105,"slug":106,"category":19,"icon":107},"Python","Наш язык для бэкендов, работы с данными и AI-интеграций — включая Python-биндинги, которые мы выпускаем к собственным инструментам на Rust.","python","logos:python",{"title":109,"description":110,"slug":111,"category":8,"icon":112},"React","Фронтенд-библиотека, в которой мы работаем, когда продукт уже на React, — компоненты, хуки и выросшая вокруг них экосистема.","react","logos:react",{"title":114,"description":115,"slug":116,"category":101,"icon":117},"Redis","Место для данных, которые должны быть быстрыми и которые не жалко пересчитать, — кэши, сессии, лимиты и очереди фоновых задач.","redis","logos:redis",{"title":119,"description":120,"slug":121,"category":19,"icon":122},"Ruby","Язык, на котором написана автоматизация наших мобильных релизов, — лейны Fastlane, кастомные действия и связка с CI, доставляющая сборки в сторы.","ruby","logos:ruby",{"title":124,"description":125,"slug":126,"category":19,"icon":127},"Rust","Куда мы идём, когда важны и скорость, и корректность, — рендеринг документов, CLI-инструменты и сервисы, которые обязаны оставаться быстрыми и предсказуемыми.","rust","simple-icons:rust",{"title":129,"description":130,"slug":131,"category":101,"icon":132},"SQLite","База данных, которая поставляется внутри приложения, — локальные кэши, offline-first хранилище и всё, что должно работать без сети.","sqlite","logos:sqlite",{"title":134,"description":135,"slug":136,"category":8,"icon":137},"Strapi","Headless CMS, к которой мы обращаемся, когда контент должны вести сами редакторы, — готовая админка и чистый API вместо самописных.","strapi","logos:strapi-icon",{"title":139,"description":140,"slug":141,"category":19,"icon":142},"Swift","То, что мы берём, когда Flutter-приложению нужен настоящий iOS под ним, — platform channels, интеграции нативных SDK, виджеты и App Clips.","swift","logos:swift",{"title":144,"description":145,"slug":146,"category":8,"icon":142},"SwiftUI","UI-фреймворк Apple, на котором мы делаем нативные поверхности, недоступные Flutter-приложению, — виджеты, App Clips и расширения.","swiftui",{"title":148,"description":149,"slug":150,"category":8,"icon":151},"Tailwind CSS","Так мы стилизуем весь фронтенд — утилитарные классы и дизайн-токены вместо таблицы стилей, которая только растёт и никогда не чистится.","tailwind","logos:tailwindcss-icon",{"title":153,"description":154,"slug":155,"category":19,"icon":156},"TypeScript","Стандарт для всего, что мы пишем для браузера и для Node-сервисов, — типы ловят ошибки интеграции раньше, чем код доходит до ревью.","typescript","logos:typescript-icon",{"title":158,"description":159,"slug":160,"category":8,"icon":161},"Vue","Наш фронтенд-фреймворк для админок, дашбордов мерчантов и веб-приложений, которые должны оставаться поддерживаемыми годами, а не спринтами.","vue","logos:vue",{"title":163,"description":164,"slug":165,"category":36,"icon":166},"Whisper","Открытая модель распознавания речи от OpenAI — движок транскрипции для голосового ввода, который работает и как бэкенд-сервис, и прямо на устройстве в приложении.","whisper","simple-icons:openai",{"id":168,"title":169,"body":170,"description":594,"extension":595,"links":596,"meta":600,"metaDescription":601,"metaTitle":602,"navigation":476,"ogDescription":603,"path":604,"repository":605,"seo":609,"slug":608,"stem":610,"technologies":611,"updated":612,"__hash__":613,"stats":614},"open_source_ru\u002Fopen-source\u002Fflutter-progress-dialog.md","Flutter Future Progress Dialog",{"type":171,"value":172,"toc":582},"minimark",[173,178,182,185,188,204,208,223,231,234,238,308,312,317,323,327,333,337,346,350,353,357,360,387,393,548,563,574,578],[174,175,177],"h2",{"id":176},"проблема","Проблема",[179,180,181],"p",{},"Большинству Flutter-приложений приходится выполнять задачи, занимающие несколько секунд — загрузка данных из API, отправка файла или обработка платежа. В это время пользователь видит застывший экран без каких-либо признаков того, что что-то происходит. Он нажимает кнопку повторно, вызывает дублирующие запросы или решает, что приложение зависло.",[179,183,184],{},"Стандартное решение — вручную управлять состоянием загрузки: переключить флаг, показать спиннер, дождаться завершения future, скрыть спиннер, а затем обработать результат или ошибку. Эта логика дублируется на десятках экранов с мелкими различиями каждый раз.",[179,186,187],{},"Типичные проблемы:",[189,190,191,195,198,201],"ul",{},[192,193,194],"li",{},"Повторяющийся шаблонный код управления состоянием загрузки на каждом экране",[192,196,197],{},"Повторные нажатия пользователей из-за отсутствия визуальной обратной связи",[192,199,200],{},"Закрытые диалоги, которые оставляют «осиротевшие» future, продолжающие работу в фоне",[192,202,203],{},"Непоследовательная обработка ошибок — одни экраны перехватывают исключения, другие падают молча",[174,205,207],{"id":206},"как-flutter_future_progress_dialog-решает-эту-задачу","Как flutter_future_progress_dialog решает эту задачу",[179,209,210,214,215,218,219,222],{},[211,212,213],"code",{},"flutter_future_progress_dialog"," заменяет весь этот шаблонный код одним вызовом функции. Передайте асинхронную задачу — пакет покажет незакрываемый диалог прогресса, дождётся результата, закроет диалог и вернёт типобезопасный результат: ",[211,216,217],{},"Success"," со значением или ",[211,220,221],{},"Failure"," с ошибкой.",[179,224,225],{},[226,227],"img",{"alt":228,"src":229,"style":230},"Демо Flutter progress dialog на iPhone","\u002Fopen-source\u002Fflutter-progress-dialog\u002Fflutter_progress_dialog.gif","max-height: 600px; height: auto; width: auto;",[179,232,233],{},"Обработка ошибок встроена в тип результата, поэтому вы никогда не забудете перехватить исключение.",[174,235,237],{"id":236},"возможности","Возможности",[189,239,240,251,260,269,279,300],{},[192,241,242,246,247,250],{},[243,244,245],"strong",{},"Material-диалог"," — ",[211,248,249],{},"showProgressDialog"," отображает стандартный круговой индикатор прогресса в стиле Material",[192,252,253,246,256,259],{},[243,254,255],{},"Cupertino-диалог",[211,257,258],{},"showCupertinoProgressDialog"," показывает индикатор активности в стиле iOS",[192,261,262,246,265,268],{},[243,263,264],{},"Адаптивный диалог",[211,266,267],{},"showAdaptiveProgressDialog"," автоматически выбирает стиль, соответствующий текущей платформе",[192,270,271,274,275,278],{},[243,272,273],{},"Свой интерфейс диалога"," — передайте ",[211,276,277],{},"builder",", чтобы заменить стандартный индикатор любым виджетом",[192,280,281,246,284,287,288,290,291,293,294,290,297],{},[243,282,283],{},"Типобезопасные результаты",[211,285,286],{},"ProgressDialogResult\u003CT>"," — sealed-класс с вариантами ",[211,289,217],{}," и ",[211,292,221],{},", поддерживающий pattern matching и удобные методы ",[211,295,296],{},"unwrap()",[211,298,299],{},"map()",[192,301,302,246,305,307],{},[243,303,304],{},"Перехват ошибок",[211,306,221],{}," содержит объект ошибки и трассировку стека",[174,309,311],{"id":310},"сценарии-использования","Сценарии использования",[313,314,316],"h3",{"id":315},"обработка-платежей","Обработка платежей",[179,318,319,320,322],{},"Экран оформления заказа вызывает API платёжного шлюза. Без диалога прогресса пользователи нажимают «Оплатить» повторно, когда ничего не происходит, вызывая двойные списания. С ",[211,321,249],{}," диалог остаётся на экране и блокирует взаимодействие до ответа шлюза, а затем pattern matching результата позволяет перейти на экран подтверждения или ошибки.",[313,324,326],{"id":325},"загрузка-файлов","Загрузка файлов",[179,328,329,330,332],{},"Сканер документов отправляет изображения на сервер. Загрузка может занять несколько секунд на медленном соединении. Если обернуть загрузку в ",[211,331,267],{},", пользователь сразу получает визуальную обратную связь, а диалог соответствует стилю платформы — Material на Android, Cupertino на iOS.",[313,334,336],{"id":335},"отправка-форм","Отправка форм",[179,338,339,340,342,343,345],{},"Многошаговая форма отправляет данные на сервер на финальном этапе. Диалог прогресса предотвращает повторную отправку и даёт понятный результат ",[211,341,217],{},"\u002F",[211,344,221],{},", по которому легко решить, что показывать — экран успеха или сообщение об ошибке прямо в форме.",[313,347,349],{"id":348},"фоновая-синхронизация-данных","Фоновая синхронизация данных",[179,351,352],{},"CRM-приложение синхронизирует локальные изменения с удалённым сервером. Собственный builder может показать брендированную анимацию загрузки вместо стандартного спиннера, сохраняя единый стиль приложения.",[174,354,356],{"id":355},"начало-работы","Начало работы",[179,358,359],{},"Установите пакет:",[361,362,367],"pre",{"className":363,"code":364,"language":365,"meta":366,"style":366},"language-shell shiki shiki-themes material-theme-lighter github-light github-dark","flutter pub add flutter_future_progress_dialog\n","shell","",[211,368,369],{"__ignoreMap":366},[370,371,374,377,381,384],"span",{"class":372,"line":373},"line",1,[370,375,41],{"class":376},"sbgvK",[370,378,380],{"class":379},"s_sjI"," pub",[370,382,383],{"class":379}," add",[370,385,386],{"class":379}," flutter_future_progress_dialog\n",[179,388,389,390,392],{},"Затем вызовите ",[211,391,249],{}," с вашей асинхронной задачей:",[361,394,397],{"className":395,"code":396,"language":18,"meta":366,"style":366},"language-dart shiki shiki-themes material-theme-lighter github-light github-dark","final result = await showProgressDialog(\n  context: context,\n  future: () => fetchData(),\n);\n\nswitch (result) {\n  case Success(:final value):\n    \u002F\u002F Используйте значение\n  case Failure(:final error):\n    \u002F\u002F Обработайте ошибку\n}\n",[211,398,399,424,440,462,471,478,487,510,517,536,542],{"__ignoreMap":366},[370,400,401,405,409,413,417,421],{"class":372,"line":373},[370,402,404],{"class":403},"sbsja","final",[370,406,408],{"class":407},"su5hD"," result ",[370,410,412],{"class":411},"smGrS","=",[370,414,416],{"class":415},"sVHd0"," await",[370,418,420],{"class":419},"sGLFI"," showProgressDialog",[370,422,423],{"class":407},"(\n",[370,425,427,430,433,436],{"class":372,"line":426},2,[370,428,429],{"class":407},"  context",[370,431,432],{"class":411},":",[370,434,435],{"class":407}," context",[370,437,439],{"class":438},"sP7_E",",\n",[370,441,443,446,448,451,454,457,460],{"class":372,"line":442},3,[370,444,445],{"class":407},"  future",[370,447,432],{"class":411},[370,449,450],{"class":407}," () ",[370,452,453],{"class":411},"=>",[370,455,456],{"class":419}," fetchData",[370,458,459],{"class":407},"()",[370,461,439],{"class":438},[370,463,465,468],{"class":372,"line":464},4,[370,466,467],{"class":407},")",[370,469,470],{"class":438},";\n",[370,472,474],{"class":372,"line":473},5,[370,475,477],{"emptyLinePlaceholder":476},true,"\n",[370,479,481,484],{"class":372,"line":480},6,[370,482,483],{"class":415},"switch",[370,485,486],{"class":407}," (result) {\n",[370,488,490,493,497,500,502,504,507],{"class":372,"line":489},7,[370,491,492],{"class":415},"  case",[370,494,496],{"class":495},"sZMiF"," Success",[370,498,499],{"class":407},"(",[370,501,432],{"class":411},[370,503,404],{"class":403},[370,505,506],{"class":407}," value)",[370,508,509],{"class":411},":\n",[370,511,513],{"class":372,"line":512},8,[370,514,516],{"class":515},"sutJx","    \u002F\u002F Используйте значение\n",[370,518,520,522,525,527,529,531,534],{"class":372,"line":519},9,[370,521,492],{"class":415},[370,523,524],{"class":495}," Failure",[370,526,499],{"class":407},[370,528,432],{"class":411},[370,530,404],{"class":403},[370,532,533],{"class":407}," error)",[370,535,509],{"class":411},[370,537,539],{"class":372,"line":538},10,[370,540,541],{"class":515},"    \u002F\u002F Обработайте ошибку\n",[370,543,545],{"class":372,"line":544},11,[370,546,547],{"class":407},"}\n",[179,549,550,551,553,554,556,557,559,560,562],{},"Доступны три функции диалога: ",[211,552,249],{}," (Material), ",[211,555,258],{}," (Cupertino) и ",[211,558,267],{}," (автоматический выбор платформы). Все принимают необязательный параметр ",[211,561,277],{}," для своего интерфейса.",[179,564,565,566,573],{},"Полный рабочий пример доступен в ",[567,568,572],"a",{"href":569,"rel":570},"https:\u002F\u002Fgithub.com\u002Fnerdy-pro\u002Fflutter-progress-dialog\u002Ftree\u002Fmain\u002Fexample",[571],"nofollow","директории example",".",[575,576],"questions",{":items":577},"[{\"title\":\"Может ли пользователь закрыть диалог вручную?\",\"text\":\"Нет. Диалог по умолчанию незакрываемый, что предотвращает осиротевшие future и повторные отправки. Диалог закрывается автоматически после завершения асинхронной задачи.\"},{\"title\":\"Что произойдёт, если future выбросит исключение?\",\"text\":\"Диалог закроется, а результат вернётся как Failure, содержащий ошибку и трассировку стека. Ваш код может использовать pattern matching для обработки ошибок без блоков try-catch.\"},{\"title\":\"Работает ли это и на Android, и на iOS?\",\"text\":\"Да. Используйте showProgressDialog для стиля Material, showCupertinoProgressDialog для стиля iOS или showAdaptiveProgressDialog для автоматического соответствия платформе.\"},{\"title\":\"Можно ли кастомизировать индикатор загрузки?\",\"text\":\"Да. Передайте параметр builder в любую из трёх функций диалога, чтобы заменить стандартный индикатор прогресса на свой виджет — брендированную анимацию, текстовое сообщение или любой другой Flutter-виджет.\"},{\"title\":\"Как работает тип результата?\",\"text\":\"ProgressDialogResult\u003CT> — это sealed-класс с двумя вариантами: Success\u003CT>, содержащий возвращённое значение, и Failure\u003CT>, содержащий ошибку и трассировку стека. Можно использовать pattern matching в Dart или удобные методы isSuccess, isError, unwrap() и map().\"}]",[579,580,581],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}",{"title":366,"searchDepth":426,"depth":426,"links":583},[584,585,586,587,593],{"id":176,"depth":426,"text":177},{"id":206,"depth":426,"text":207},{"id":236,"depth":426,"text":237},{"id":310,"depth":426,"text":311,"children":588},[589,590,591,592],{"id":315,"depth":442,"text":316},{"id":325,"depth":442,"text":326},{"id":335,"depth":442,"text":336},{"id":348,"depth":442,"text":349},{"id":355,"depth":426,"text":356},"Flutter-пакет для отображения диалога прогресса во время асинхронных операций с автоматическим возвратом результата — в стилях Material, Cupertino и адаптивном.","md",[597],{"type":598,"url":599},"pub_dev","https:\u002F\u002Fpub.dev\u002Fpackages\u002Fflutter_future_progress_dialog",{},"Лёгкий Flutter-пакет: показывает диалог прогресса во время асинхронной работы и возвращает результат. Material, Cupertino и адаптивный стиль.","Flutter-диалог прогресса для асинхронных задач","Дождаться операции, показать диалог, получить результат. Маленький Flutter-пакет для индикатора, который вы каждый раз пишете заново.","\u002Fopen-source\u002Fflutter-progress-dialog",{"type":606,"company":607,"name":608},"github","nerdy-pro","flutter-progress-dialog",{"title":169,"description":594},"open-source\u002Fflutter-progress-dialog",[41,18],"2026-03-17","jNmnnyn-PIwO9P3pep4OTk6vwUucGaVBEzgeOtiq5Ug",{"forks":615,"stars":426,"contributors":616,"last_release":627,"issues":615,"has_contribution_guide":628,"license":629,"last_updated":630,"watchers":426},0,[617,622],{"login":618,"profile_url":619,"avatar_url":620,"contributions":621},"thenixan","https:\u002F\u002Fgithub.com\u002Fthenixan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F3602098?v=4",100,{"login":623,"profile_url":624,"avatar_url":625,"contributions":626},"OleksandrFedyay","https:\u002F\u002Fgithub.com\u002FOleksandrFedyay","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F17413471?v=4",33,"v2.0.0",false,"MIT","2026-08-19T17:15:57Z"]