<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>@easy_dev991</title><generator>teletype.in</generator><description><![CDATA[Делюсь интересными находками/лайфхаками в процессе разработки под iOS, и возможно ты найдешь что-то полезное для себя!]]></description><image><url>https://img1.teletype.in/files/0b/1a/0b1a0809-912b-4a06-801a-ac4f5e10a1bf.png</url><title>@easy_dev991</title><link>https://teletype.in/@easy_dev991</link></image><link>https://teletype.in/@easy_dev991?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/easy_dev991?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/easy_dev991?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Thu, 23 Jul 2026 08:28:15 GMT</pubDate><lastBuildDate>Thu, 23 Jul 2026 08:28:15 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/nQFonqU59Zp</guid><link>https://teletype.in/@easy_dev991/nQFonqU59Zp?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/nQFonqU59Zp?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Переход с iOS на Android</title><pubDate>Tue, 21 Jul 2026 18:19:17 GMT</pubDate><category>Android</category><description><![CDATA[Месяц назад я сменил основной смартфон на андроид, и сейчас расскажу почему и как все прошло.]]></description><content:encoded><![CDATA[
  <p id="QEFI">Месяц назад я сменил основной смартфон на андроид, и сейчас расскажу почему и как все прошло.</p>
  <h2 id="sZcb">Без паники!</h2>
  <p id="MNFw">Для начала успокою своих самых преданных подписчиков: айфон у меня все еще есть - использую его для рабочих задач:</p>
  <ul id="Z2Qp">
    <li id="Q2sg">проверить фичу на сборке из testflight (ручное тестирование)</li>
    <li id="WTKh">задебажить хитрый сценарий, который возникает на девайсе, но не на симуляторе (по проводу в Xcode)</li>
  </ul>
  <h2 id="zK98">Причины для перехода</h2>
  <h3 id="AFn7">Процесс публикации своих приложений</h3>
  <p id="FbOP">Я хотел делать приложения, которыми будет приятно пользоваться, и делиться ими с другими людьми, но недавно закрыли последнюю официальную &quot;лавочку&quot; для оплаты подписки разработчика apple, а без этого невозможно опубликовать приложения для iOS во всеми любимом AppStore.</p>
  <p id="5hs0">Теперь нельзя оплатить аккаунт со счета оператора связи, а искать новые обходные пути (менять регион аккаунта и т.д.) мне не хочется - я ведь не огромная компания с кучей платных подписчиков или постоянным притоком денег.</p>
  <p id="xQ6d">Мне нравилось пользоваться своими приложениями на айфоне - это правда, но мне совершенно не нравилось публиковать свои приложения в аппсторе, потому что это та еще цирковая передача.</p>
  <p id="OTnT">Тем, кто не публиковал приложения сам, или кто публиковал только несколько сборок, наверное сложно будет представить как это происходит.</p>
  <p id="a8dE"><strong>Вкратце процесс выглядит так</strong>:</p>
  <ul id="AaFd">
    <li id="BaQ8">регистрируешься в качестве разработчика apple</li>
    <li id="gi8R">(делаешь само приложение, что обычно не очень сложно и довольно интересно)</li>
    <li id="4PRU">находишь способ оплатить подписку (8990 р/год) - да, не у всех и не с первого раза получалось ее оплатить, и если вы физ.лицо, то никаких встроенных покупок у вас в приложении не будет</li>
    <li id="1exN">заполняешь тонну полей в анкете для создания каждого приложения</li>
    <li id="42YQ">загружаешь приложение в кабинет разработчика</li>
    <li id="ORM0">отправляешь на модерацию</li>
    <li id="vwrt">надеешься, что попадется не стремный модератор</li>
    <li id="SBms">попадается стремный модератор с идиотскими вопросами, ответы на которые есть буквально в той же самой анкете, которую ты уже заполнял ранее</li>
    <li id="e6v4">отвечаешь на все вопросы и ждешь, пока модератор соизволит одобрить приложение или задаст еще какие-нибудь идиотские вопросы</li>
    <li id="AKgm">в случае успешной проверки приложение через некоторое время появляется в магазине ... или не появляется несколько часов без объяснения причин, или через пару дней появится, ну как повезет</li>
  </ul>
  <p id="bHbJ">И в целом даже с таким стремным процессом (оформление приложения в кабинете apple, модерация) я готов был мириться, пока схема работала хотя бы в таком виде.</p>
  <h3 id="0P3k">Санкции</h3>
  <p id="kKYQ">Бац - удалили банковские приложения. Бац - удалили еще пачку приложений.</p>
  <p id="uqj8">Просто потому что политика, отлично.</p>
  <p id="UzJH">Я конечно поразвлекался, пока загружал приложения от крупных компаний через их обходные пути, в том числе приложение <strong>РЖД</strong>, которое они распространяют через <strong>Testflight</strong> для обычных пользователей (ни в какие ворота, ну камон), но надоело.</p>
  <p id="r0UU">Еще просидел около 40 минут в зеленом банке, пока сотрудник банка с тупым взглядом пытался установить мне приложение, и нифига не получилось. </p>
  <p id="q5qQ">Справедливости ради, за неделю до перехода на андроид мне все же удалось в другом офисе этого банка установить приложение, считаю это невероятным везением.</p>
  <h3 id="b2Ud">Операционная система</h3>
  <p id="RTsu">iOS уже не тот. Даже если эта фраза выглядит избитой, то сейчас я для себя это ощутил сполна, когда перешел на iOS 26.</p>
  <p id="xhBO">Да, стекло не каждому нравится, ну и фиг с ним, но зависания на домашнем экране, глюки анимации и прочие проблемы, которые раньше у меня ассоциировались с дешевыми смартфонами на андроиде - это неприемлемо.</p>
  <p id="MZDk">Мои требования к айфону стали слишком высокими, потому что я отлично помню iPhone 5s, который классно работал, и не лагал как iPhone 13 Pro.</p>
  <p id="JL4y">Причем ошибки и тормоза каждый год добавляются поверх старых, как будто так и должно быть, как будто пользователи (в том числе я) должны просто это терпеть - ну нафиг. Забегая вперед - если так и дальше продлится, и если даже андроидом будет невозможно пользоваться, куплю кнопочный телефон. Скриньте.</p>
  <p id="qz5q">Представьте себе, перенести данные с айфона на айфон мне удалось не с первого раза, когда недавно менял айфон.</p>
  <p id="mve1">Руки кривые? Да, но не у меня, а у тех умников, которые пропустили iOS 26 в продакшен и забили на ручное тестирование (по всей видимости, уже очень давно).</p>
  <h2 id="r9vk">Месяц на андроиде</h2>
  <p id="32ME">Процесс переноса данных с айфона на андроид оказался ничем не хуже, чем перенос данных со старого айфона на новый - удалось все перенести со второй попытки (для такой же процедуры с двумя айфонами на iOS 26 пришлось потратить 3 попытки).</p>
  <h3 id="gm7H">Что не понравилось</h3>
  <p id="ViJo"><strong>Сканер отпечатка пальцев</strong></p>
  <p id="Vyqy">В моем смартфоне ультразвуковой сканер пальца, и это полный отстой по сравнению с face id в айфоне (а ведь еще бывают и оптические сканеры пальца, жуть). Нужно попасть в конкретную зону экрана пальцем, при этом регулярно палец не распознается даже с трех раз. В этом плане пока что андроиды сильно проигрывают айфонам (хотя есть новости о предстоящем добавлении аналога face id, но это где-то в будущем).</p>
  <p id="WMYD"><strong>Системные приложения и баги</strong></p>
  <p id="9r2Y">Скорее всего привычка к iOS все еще сказывается - просто не хватает некоторых мелочей, которые были удобны в iOS.</p>
  <p id="XYIg">Например, галерея не индексирует фотографии без особых настроек девайса. Через 2 недели после покупки я загуглил как это поправить и за 2 ночи все фото/видео проиндексировались, но некоторые отметили людей с ошибками, а исправить эти ошибки буквально нельзя в стандартном приложении галереи (гугл фото не использую).</p>
  <p id="7ERF">Темная тема не включается/выключается по расписанию при смене режима на &quot;сон&quot; и обратно, что является частой проблемой в купленном мной андроиде, и прочие мелкие проблемы.</p>
  <h3 id="PcIR">Что понравилось</h3>
  <p id="jnhG"><strong>Публикация своих приложений</strong></p>
  <p id="uJyG">Помните ту дикую инструкцию в самом начале статьи для публикации в аппсторе на iOS?</p>
  <p id="n9k7">Тут шагов всего 2: </p>
  <ul id="Q9oK">
    <li id="qVmi">сделать приложение (спасибо агентам за удобство и скорость в этом деле)</li>
    <li id="aFse">установить себе на девайс (и при желании поделиться со всем интернетом)</li>
  </ul>
  <p id="jyj3">Шок-контент!</p>
  <p id="Yb8U">Я и раньше знал об этом, но пока лично не попробовал, не думал, что это настолько удобно.</p>
  <p id="slFr">Да, система не дает устанавливать приложения не из магазина по умолчанию, но это можно обойти за пару секунд, с помощью системных настроек в разделе &quot;Безопасность&quot;.</p>
  <p id="E4XM">Еще удобно публиковать свои приложения в rustore, хотя сам я его не скачал, но мои приложения там есть, и одно из них регулярно скачивают.</p>
  <p id="gg46"><strong>Сторонние магазины приложений</strong></p>
  <p id="wyIv">Я использую f-droid и repostore, и мне очень нравится! </p>
  <p id="c5tH">Например, стандартный ютуб мне не нравится ни в iOS, ни в Android, поэтому я установил другое приложение из гитхаба через repostore, которое мне нравится намного больше, чем официальное от гугла.</p>
  <p id="aWgV">Да, я знаю про риски, и да, я несу ответственность за установку таких приложений сам. Но как будто в гугл-магазине и аппсторе никогда не было мошеннических приложений?</p>
  <h3 id="SJX3">Автоматизация</h3>
  <p id="S6tD">У меня в айфоне были 2 &quot;быстрые команды&quot;, которые активировались либо голосом (как и любая быстрая команда) через Siri, либо нажатием на ярлык на рабочем столе:</p>
  <ul id="VMaP">
    <li id="RhcZ">выхожу из дома (для включения блютус + lte, и выключения wifi)</li>
    <li id="XM5m">вернулся домой (обратный процесс)</li>
  </ul>
  <p id="AKMR">В андроиде эти две команды включаются автоматически без необходимости нажимать на ярлык или выполнять голосовую команду, и это БЕЗ использования геолокации, чудеса!</p>
  <p id="UTWs">Самое классное то, что настроить это можно было без хитровыпендренных завихрений приложения &quot;Команды&quot; (iOS), в котором черт ногу сломит (ну серьезно, никогда не любил процесс создания команд, но полезные команды там все же можно сделать) - просто в системных настройках есть раздел &quot;Режимы и сценарии&quot;, где можно добавлять любые сценарии и делать это с намного более удобным UX.</p>
  <h2 id="sOfg">А что с карьерой?</h2>
  <p id="DLfw">Делать приложения для себя - одно, а работать iOS-разработчиком - совсем другое дело. Я все еще считаю, что было отличным (и удачным) решением научиться этому делу и зайти в эту профессию до активного развития нейросетей.</p>
  <h2 id="coBG">Заключение</h2>
  <p id="SeZc">Да, я знаю про предстоящие изменения в политике гугла и надвигающихся осложнениях в установке приложений не из магазина гугла, но что поделать - будем адаптироваться. В любом случае есть еще PWA, так что не пропадем 😅</p>
  <p id="90nC">Если статья соберет больше 5 лайков, расскажу про критерии, по которым я выбирал себе смартфон на андроиде, и что в итоге выбрал ✅</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/G6cggxnKUec</guid><link>https://teletype.in/@easy_dev991/G6cggxnKUec?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/G6cggxnKUec?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Краткий обзор ponytail</title><pubDate>Sun, 12 Jul 2026 13:00:08 GMT</pubDate><category>agent</category><description><![CDATA[<img src="https://img1.teletype.in/files/47/38/47386765-bc56-4397-b3fc-07fcb32800bf.png"></img>Уже больше недели использую ponytail на постоянной основе в opencode, и мне нравятся результаты.]]></description><content:encoded><![CDATA[
  <p id="crRe">Уже больше недели использую <a href="https://github.com/DietrichGebert/ponytail" target="_blank">ponytail</a> на постоянной основе в <code>opencode</code>, и мне нравятся результаты.</p>
  <h2 id="NNa6">Как это работает</h2>
  <p id="RvDQ">Предлагаю прочитать <a href="https://github.com/DietrichGebert/ponytail/blob/main/README.md" target="_blank">ридми</a> - там есть достаточное количество примеров и описание этого инструмента, а сюда просто скопирую оттуда кусочек:</p>
  <figure id="cX1T" class="m_column">
    <img src="https://img1.teletype.in/files/47/38/47386765-bc56-4397-b3fc-07fcb32800bf.png" width="962" />
    <figcaption>Перед тем как написать код, агент проводит такой анализ (скриншот из ридми)</figcaption>
  </figure>
  <h2 id="mCFQ">Как я это использую</h2>
  <h3 id="gQ7F">Сценарий 1</h3>
  <p id="QDyM">В пет-проектах, над которыми давно не работал, использую основную команду <code>/ponytail-audit</code> - эта команда проверяет весь репозиторий, например, проверим <a href="https://github.com/easydev991/SwiftUI-Days" target="_blank">SwiftUI-Days</a>:</p>
  <pre id="MV4N">Now I have a complete picture of the entire codebase. Here&#x27;s the audit:
yagni ItemSchema.swift + ItemMigrationPlan.swift (157 lines). Three versioned schemas duplicating the model + two custom migration stages that only set optional fields to nil. SwiftData lightweight migration handles this automatically when you just add optional properties. SwiftUI-Days/Models/ItemSchema.swift, SwiftUI-Days/Models/ItemMigrationPlan.swift
shrink BackupFileDocument.swift (217 lines). RawBackupItem duplicates BackupItem with different encode/decode strategy — same 5 fields, two Codable impls. BackupWrapper envelope format + legacy flat array = two parsing paths for one export format. Merge into a single type, drop the legacy path. SwiftUI-Days/Models/BackupFileDocument.swift
yagni Analytics — 4 files (AnalyticsProvider protocol + FirebaseAnalyticsProvider + NoopAnalyticsProvider + AnalyticsService) for one real provider. The protocol has one method and one implementation in production. A single AnalyticsService with a Firebase-only init (or a log closure parameter) replaces 4 files. SwiftUI-Days/Services/Analytics/
yagni SectionTitleView.swift (35 lines). A .bold().foregroundStyle(isEnabled ? .primary : .secondary).frame(maxWidth: .infinity, alignment: .leading) modifier on Text. That&#x27;s a one-line View extension, not a file. SwiftUI-Days/Screens/CommonViews/SectionTitleView.swift
yagni EditSectionView.swift (30 lines). Used in one screen (EditItemScreen). Inline the SectionTitleView + TextField pair. SwiftUI-Days/Screens/Detail/EditSectionView.swift
yagni ReadSectionView.swift (33 lines). Used in one screen (ItemScreen). Inline the SectionTitleView + Text pair. SwiftUI-Days/Screens/Detail/ReadSectionView.swift
yagni DaysEditButton.swift (13 lines). Button { action } Label(.edit, systemImage: &quot;pencil&quot;). Used in two places; inline Button directly is less code than the file overhead. SwiftUI-Days/Screens/Main/DaysEditButton.swift
yagni DaysDeleteButton.swift (19 lines). Same as DaysEditButton. SwiftUI-Days/Screens/Main/DaysDeleteButton.swift
yagni ItemDatePicker.swift (14 lines). A DatePicker with .bold(). Inline. SwiftUI-Days/Screens/Detail/ItemDatePicker.swift
yagni ItemDisplayOptionPicker.swift (24 lines). A Picker with SectionTitleView. Used in two screens; inline both calls. SwiftUI-Days/Screens/Detail/ItemDisplayOptionPicker.swift
yagni ColorTagFilterSheetState.swift (36 lines). Compute-only struct used by one sheet. The three computed properties + two methods can live in the sheet body. SwiftUI-Days/Screens/Main/ColorTagFilterSheetState.swift
yagni Binding+mappedToBool.swift (21 lines). Single-use extension. Inline init(bindingOptional:) at the call site in AppDataScreen. SwiftUI-Days/Extensions/Binding+mappedToBool.swift
yagni ThemeIconScreen+IconViewModel.swift IconError (10 lines). Single-case error enum. Use a descriptive string instead. SwiftUI-Days/Screens/More/ThemeIcon/ThemeIconScreen+IconViewModel.swift
delete BackupFormat.android case. iOS-only app. SwiftUI-Days/Models/BackupFormat.swift
delete AppDataError.swift (5 lines). Single-case enum used once. Use a string literal. SwiftUI-Days/Models/AppDataError.swift
delete ColorTagFilterSheet+Preview.swift (31 lines). 10 static let constants configuring hue/saturation/brightness/count for previews. The previews call static constants that equal literal numbers — use the numbers directly. SwiftUI-Days/Preview Content/ColorTagFilterSheet+Preview.swift
stdlib Color+Hex.swift body (51 lines discounting preview). Hand-rolled hex-to-UInt64 scanner. Scanner already does scanHexInt64. The bit-shifting color extraction is just CGFloat math that UIColor component accessor already provides. Could halve the line count. SwiftUI-Days/Extensions/Color+Hex.swift
shrink DisplayOption.unitsStyle (20 lines). Switch-picking .full/.short/.abbreviated based on which components are nonzero. This is polish: DateComponentsFormatter auto-selects a reasonable style. SwiftUI-Days/Models/DisplayOption.swift
shrink Item.makeDaysCount creates a new DateComponentsFormatter per call. A static let formatter saves the allocation. SwiftUI-Days/Models/Item.swift
shrink FeedbackSender.platformName — nested function inside a computed var body. Extract or inline. SwiftUI-Days/Services/FeedbackSender.swift
yagni ThemeIconScreen+IconVariant.variantNumber — manual switch self returning 1...7. A @frozen enum with Int raw value gives this for free. SwiftUI-Days/Screens/More/ThemeIcon/ThemeIconScreen+IconVariant.swift
net: -~660 lines, -1 dependency (Firebase could go closure-based but kept), -1 file (BackupFormat.android dead path)</pre>
  <p id="VcVR">Дальше закидываю этот анализ в другую модель и прошу составить план безопасного рефактора, чтобы ничего не сломать.</p>
  <h3 id="ZAhs">Сценарий 2</h3>
  <p id="4lxk">В процессе работы проверяю конкретный коммит с помощью команды <code>/ponytail-review</code>, например:</p>
  <p id="oWhI"><code>/ponytail-review коммит 8e82b6cad16c12c1dcca1574b6908304ef15ccc8</code></p>
  <p id="UbDx">В результате получаю похожий отчет, с которым потом можно работать дальше:</p>
  <pre id="hJVs">Ponytail review — коммит 8e82b6ca
Ниже только over-engineering, не correctness.
- ColorTagFilterSheetState.swift:1 yagni Целая структура + enum для двух if-else (applyEnabled/resetEnabled/toggledColorHex/resetResult). Всё в 4 строчки в теле view. Удалить файл.
- MainScreenFilterState.swift:11 shrink itemsCountForFilterButton — синоним visibleItems.count. Убрать, заменить на visibleItems.count в isFilterButtonVisible.
- ColorTagFilterSheet+Preview.swift:9 yagni colors1 = 1, colors3 = 3, colors8 = 8, colors30 = 30 — константы, равные числу. Лишние имена. Вставить числа в вызовы.
- docs/doc-main-screen-color-tag-filter.md:1 yagni 78 строк внутренней документации, которая устареет при следующем рефакторинге. Удалить, пока не появился внешний контрибьютор, которому она нужна.
Net removable: ~40 строк</pre>
  <h2 id="3n8o">Что с рабочим проектом</h2>
  <p id="IELI">Если запустить аудит всего рабочего проекта, то агент предлагает поудалять много нужного кода и зависимостей, поэтому не рекомендую запускать аудит большого проекта целиком. Во всяком случае недорогие модели с такой задачей справляются плохо.</p>
  <p id="1cqH">При этом польза ощутима при выполнении конкретных задач, когда срабатывает проверка на YAGNI из раздела &quot;Как это работает&quot;, и получается меньше кода, чем могло бы быть без этих проверок.</p>
  <h2 id="kyri">Заключение</h2>
  <p id="wP8J">Это уже <strong>пятый</strong> инструмент для агентов, который я использую на постоянной основе внутри <code>opencode</code>, а полный список вот: <code>serena</code>, <code>codegraph</code>, <code>rtk</code>, <code>openspec</code>, <code>ponytail</code>, и все складывается очень даже удобно для работы с агентом 👍</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/2BqBJC8Wrkh</guid><link>https://teletype.in/@easy_dev991/2BqBJC8Wrkh?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/2BqBJC8Wrkh?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Экспорт напоминаний Apple</title><pubDate>Sun, 05 Jul 2026 10:10:11 GMT</pubDate><description><![CDATA[<img src="https://img3.teletype.in/files/a3/8a/a38a06a6-ddf0-489b-97e4-2677937971cf.png"></img>Недавно перешел с ios на андроид и захотел перенести все напоминания из стандартного приложения &quot;Напоминания&quot; на маке/айфоне, но не нашел простого способа как это сделать, поэтому сделал инструмент для экспорта напоминаний.]]></description><content:encoded><![CDATA[
  <p id="8g2t">Недавно перешел с ios на андроид и захотел перенести все напоминания из стандартного приложения &quot;Напоминания&quot; на маке/айфоне, но не нашел простого способа как это сделать, поэтому сделал <a href="https://github.com/easydev991/export-reminders-from-mac" target="_blank">инструмент для экспорта напоминаний</a>.</p>
  <h2 id="mdZD">Проблема</h2>
  <p id="mP4l">Есть несколько приложений в аппсторе, которые достают напоминания из стандартного приложения и что-то дальше с ними делают (чаще всего просто копируют их в себя).</p>
  <p id="83yD">Однако эти приложения не позволяют бесплатно экспортировать список напоминаний, чтобы делать потом с ними что-то еще.</p>
  <p id="56P2">Синхронизация между платформами тоже нетривиальная задача, и популярные приложения не дают бесплатно синхронизировать напоминания между платформами.</p>
  <p id="nb53">Я даже поробовал microsoft todo, но мне совсем не понравилось их приложение.</p>
  <h2 id="RpRE">Решение</h2>
  <p id="jJPW">Нашел бесплатное и неплохое приложение для андроид <a href="https://github.com/tasks/tasks" target="_blank">Tasks.org</a>, и сделал небольшой инструмент на свифте для экспорта из приложения &quot;Напоминания&quot; на макбуке в формат <strong>Tasks.org</strong>.</p>
  <p id="8rdp">Разработку вел целиком с использованием <code>opencode</code> + <code>openspec</code> - рассказывал об этом подходе в <a href="https://teletype.in/@easy_dev991/TQsjWIzfHde" target="_blank">предыдущей статье</a>.</p>
  <figure id="igQ9" class="m_column">
    <img src="https://img3.teletype.in/files/a3/8a/a38a06a6-ddf0-489b-97e4-2677937971cf.png" width="1424" />
    <figcaption>Доступные команды в Makefile на момент первого релиза</figcaption>
  </figure>
  <h3 id="rRmV">Как пользоваться</h3>
  <ol id="MbFh">
    <li id="uio8">Клонировать репозиторий</li>
    <li id="kBkn">Открыть терминал в папке проекта</li>
    <li id="g3cQ">Выполнить команду <code>make export-tasks-org</code></li>
    <li id="3GTF">Взять получившийся файл <code>reminders_export_tasks_org.json</code> из папки с проектом и импортировать в андроид-приложение <strong>Tasks.org</strong></li>
    <li id="pAsn">Профит</li>
  </ol>
  <h2 id="DZQN">Выводы</h2>
  <p id="7qM9">Является ли это решение лучшим? Вряд ли. Единственным? Нет. При этом я сделал его довольно быстро, и было очень легко тестировать прямо на симуляторе в андроид-студии.</p>
  <p id="Anpp">Нужны ли знания языка программирования для создания подобных инструментов? Точно нет.</p>
  <p id="0Uxk">Удобно ли мне пользоваться приложением Tasks.org на андроиде? Вполне ✅</p>
  <p id="6peF">Было ли удобнее в стандартном приложении &quot;Напоминания&quot; от apple? 💯 Да    </p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/TQsjWIzfHde</guid><link>https://teletype.in/@easy_dev991/TQsjWIzfHde?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/TQsjWIzfHde?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>openspec в работе</title><pubDate>Sat, 27 Jun 2026 12:09:21 GMT</pubDate><category>agent</category><description><![CDATA[<img src="https://img4.teletype.in/files/f1/5d/f15d7427-e310-4ff3-9992-d20d928d0596.png"></img>Примерно два месяца назад я узнал про openspec, и решил попробовать. Пет-проекты на тот момент были на паузе, поэтому пробовать начал сразу в рабочем проекте. В этой статье покажу как выглядит рабочий процесс с использованием openspec внутри opencode.]]></description><content:encoded><![CDATA[
  <p id="vI0G">Примерно два месяца назад я узнал про <a href="https://github.com/Fission-AI/openspec" target="_blank">openspec</a>, и решил попробовать. Пет-проекты на тот момент были на паузе, поэтому пробовать начал сразу в рабочем проекте. В этой статье покажу как выглядит рабочий процесс с использованием <strong>openspec</strong> внутри <strong>opencode</strong>.</p>
  <p id="7W5G">Дублировать документацию из гитхаба не буду - ее можно прочитать по ссылке в первом абзаце, а расскажу именно про мой опыт использования <em>openspec</em>.</p>
  <h2 id="ybcG">Установка в проекте</h2>
  <p id="4mQl">В терминале в папке с проектом выполнил команду <code>openspec init</code> и отметил нужные инструменты (<em>opencode</em> и т.д.)</p>
  <figure id="rfYQ" class="m_column">
    <img src="https://img4.teletype.in/files/f1/5d/f15d7427-e310-4ff3-9992-d20d928d0596.png" width="1028" />
    <figcaption>Выбрал opencode</figcaption>
  </figure>
  <figure id="mjs4" class="m_column">
    <img src="https://img4.teletype.in/files/36/6c/366c67f5-8518-4fd7-ac25-2da29805269c.png" width="1026" />
    <figcaption>После нажатия enter нужно перезагрузить IDE, в моем случае - просто завершить сеанс opencode в терминале и запустить его заново</figcaption>
  </figure>
  <figure id="TJmR" class="m_column">
    <img src="https://img2.teletype.in/files/12/2b/122b0da8-e227-4526-b7d5-b10dde024185.png" width="996" />
    <figcaption>Теперь нужно закоммитить добавленные в проект навыки и команды, чтобы ими можно было пользоваться</figcaption>
  </figure>
  <h2 id="06kT">Использование в работе</h2>
  <p id="cab8">Запускаем <em>opencode</em> и начинаем вводить команду <code>/o</code></p>
  <figure id="7Dkp" class="m_column">
    <img src="https://img3.teletype.in/files/af/d9/afd95472-f7bc-4d89-a477-aa1adf90dcf0.png" width="2042" />
    <figcaption>Первые несколько секунд идет загрузка всех команд, а потом в списке появляются новые команды openspec</figcaption>
  </figure>
  <h3 id="y2NE">Новая мелкая фича</h3>
  <p id="xgTV">Если есть <strong>полное понимание, что нужно делать</strong>, то можно сразу использовать <code>/opsx-ff</code> - я так делал два раза для мелких задач, где все максимально очевидно и обсуждать нечего, например:</p>
  <pre id="hkWL">/opsx-ff task1234-toggle</pre>
  <p id="9tC6">Тут <strong>task1234-toggle</strong> является кратким названием задачи - это важное название и лучше делать его уникальным, чтобы потом было проще ориентироваться в задачах. Потом для продолжения работы над задачей может потребоваться явно передать в промпте это самое название задачи, чтобы агент знал, над которой задачей вы сейчас работаете.</p>
  <p id="Kw3Z">Отправляем промпт в работу, и получаем ответ типа такого: </p>
  <blockquote id="3xDA">I found existing toggle-related code in the project (reminder settings toggle, filter dialog toggle), but &quot;task-1234-toggle&quot; doesn&#x27;t tell me what you want to build or fix.<br />What do you want this change to do? For example:<br />- Add a new toggle for some feature<br />- Fix a bug with an existing toggle<br />- Refactor toggle logic<br />Describe the feature/fix and I&#x27;ll create all the OpenSpec artifacts.</blockquote>
  <p id="0UWn">Дальше отправляю промпт с кратким описанием фичи (ведь она мелкая):</p>
  <blockquote id="XKrp">нужно сделать фичефлаг для настройки возможности включения или отключения экрана с логами для разработчика на экране</blockquote>
  <p id="EqEq">Агент какое-то время думает и создает все необходимые документы (артефакты) по задаче:</p>
  <figure id="lrtu" class="m_column">
    <img src="https://img3.teletype.in/files/28/e7/28e70851-53e2-4d00-bf16-689adb0b306a.png" width="1474" />
    <figcaption>Окончание работы по созданию документов к задаче</figcaption>
  </figure>
  <p id="5Pa5">Теперь нужно проверить получившиеся документы самостоятельно (т.к. там действительно немного текста) и при обнаружении нестыковок/ошибок нужно внести правки в документы (вручную или опять же через агента).</p>
  <p id="uMFm">После проверки/исправления всех документов можно сразу переходить к <code>/opsx-apply</code> или сохранить прогресс (делаем коммит) и переключиться на что-то еще.</p>
  <h3 id="crQZ">Новая стандартная фича</h3>
  <p id="eMVp">Если хочется больше контроля над процессом создания документации, или еще не до конца известны все требования для задачи, то есть смысл начинать с команды <code>/opsx-new</code>, например:</p>
  <pre id="iJJ6">/opsx-new task1234-medium-feature</pre>
  <p id="U2kO">Отправляем этот промпт и получаем ответ: </p>
  <blockquote id="rZbF">Here&#x27;s the summary:<br />Change: task1234-medium-feature<br />Location: openspec/changes/task1234-medium-feature/<br />Schema: spec-driven (4 artifacts)<br />Progress: 0/4 complete<br />[ ] proposal          ← ready now<br />[-] design             (blocked by: proposal)<br />[-] specs              (blocked by: proposal)<br />[-] tasks               (blocked by: design, specs)<br />First artifact: proposal.md — establish why this change is needed.<br />Template:<br />## Why<br />&lt;!-- Problem/opportunity, 1-2 sentences --&gt;</blockquote>
  <blockquote id="Jk78">## What Changes<br />&lt;!-- Bullet list: new capabilities, modifications, removals --&gt;</blockquote>
  <blockquote id="jhkE">## Capabilities<br />### New Capabilities<br />- &#x60;&lt;name&gt;&#x60;: &lt;description&gt;</blockquote>
  <blockquote id="IzeZ">### Modified Capabilities<br />&lt;!-- List only if spec-level behavior changes --&gt;</blockquote>
  <blockquote id="nLhC">## Impact<br />&lt;!— Affected code, APIs, dependencies --&gt;<br />Ready to create the first artifact? Run /opsx-continue or describe what this change is about and I&#x27;ll draft it.</blockquote>
  <p id="RYdh">В таком сценарии можно делать все документы по порядку, начиная с <em>proposal</em>, который является кратким описанием задачи для последующей детализации в других документах, напишем промпт с использованием команды <code>/opsx-continue</code>:</p>
  <blockquote id="5Hrr">/opsx-continue task1234-medium-feature нужно сделать фичефлаг для настройки возможности включения или отключения экрана с логами для разработчика на экране</blockquote>
  <p id="o1So">Отправляем этот промпт и получаем ответ: </p>
  <blockquote id="rvTT">Created: proposal.md<br />Schema: spec-driven | Progress: 1/4<br />[x] proposal       ✓<br />[ ] design          ← unlocked<br />[ ] specs           ← unlocked<br />[-] tasks           (blocked by: design, specs)<br />What&#x27;s in the proposal:<br />- Why: Нет способа просмотреть логи внутри приложения, нужна фиче-флаг для скрытия от обычных пользователей<br />- Capabilities: dev-log-screen (экран логов) + dev-log-feature-flag (флаг управления)<br />- Impact: AppSettingsDataStore, Screen, MoreScreen, новый DevLogScreen + ViewModel<br />Ready to create the next artifact? Run /opsx-continue — I&#x27;ll draft either design.md or the spec files next.</blockquote>
  <p id="5jqU">Теперь читаем <em>proposal</em>, вносим правки при необходимости, и либо продолжаем дальше работу в том же формате с командой <code>/opsx-continue</code>, либо ставим на паузу и переключаемся на что-то другое - главное сделать коммит, чтобы сохранить прогресс.</p>
  <p id="BIad">В нашем случае для примера я &quot;промотаю&quot; создание документов командой <code>/opsx-ff</code>, чтобы показать как работает <code>/opsx-apply</code>:</p>
  <figure id="F9tI" class="m_column">
    <img src="https://img1.teletype.in/files/82/a9/82a96c7a-a47a-4f30-a635-574989f86196.png" width="956" />
    <figcaption>Агент начал работу</figcaption>
  </figure>
  <figure id="1yVU" class="m_column">
    <img src="https://img4.teletype.in/files/73/64/7364e7c0-773d-41dd-8cb8-e62bfb4e49bd.png" width="1658" />
    <figcaption>После окончания работы агент предлагает добавить фичу в архив как выполненную</figcaption>
  </figure>
  <figure id="oEUp" class="m_column">
    <img src="https://img3.teletype.in/files/26/2b/262b15ba-3959-4f58-ae83-28809846a83c.png" width="1260" />
    <figcaption>Результат работы - тоггл &quot;Developer logs&quot;</figcaption>
  </figure>
  <figure id="LMey" class="m_column">
    <img src="https://img1.teletype.in/files/c4/dd/c4ddd3fe-cddd-41ef-bace-31c43027b5ca.png" width="1260" />
    <figcaption>Если тоггл включить, появится новая кнопка Dev Log</figcaption>
  </figure>
  <figure id="CviC" class="m_column">
    <img src="https://img2.teletype.in/files/92/4a/924ac31c-de1a-4556-a221-ae31446b59c2.png" width="1260" />
    <figcaption>А вот и сам экран логов</figcaption>
  </figure>
  <p id="mHIn">Представим, что положение тоггла было таким и задумано изначально.</p>
  <p id="4Afv">И вот пришло новое требование (ну ничего себе) - нужно тоггл переместить в нижнюю часть экрана. Правим артефакты либо вручную, либо новым промптом (без использования команд <code>/opsx</code>) и снова вызываем <code>/opsx-apply</code> для применения правок в коде:</p>
  <figure id="FXjg" class="m_column">
    <img src="https://img4.teletype.in/files/b7/37/b73750e2-8a67-4fb3-bad2-63c57fc55742.png" width="1260" />
    <figcaption>Успех! Положение тоггла исправлено</figcaption>
  </figure>
  <h3 id="ZL9p">Верификация статуса</h3>
  <p id="RnoL">Бывает, что задача откладывается на неопределенный срок, пока ее тестируют, обсуждают и т.д., и все это время код по задаче не пишется, но возможно меняются документы (вручную или нет, не важно).</p>
  <p id="ZqfY">Когда к задаче нужно вернуться, то можно проверить статус с помощью команды <code>/opsx-verify</code>, это я и сделал в нашем случае, вот итоги проверки:</p>
  <blockquote id="AM6H">No critical issues found. <br />3 warnings to consider — all minor. The implementation correctly follows all design decisions, covers all requirements and scenarios, and maintains code pattern consistency.<br />Ready for archive. ✓</blockquote>
  <p id="d5Hl">Там сначала идет отчет по шаблону, и в нем перечислены все детали проверок, в нашем случае их нет смысла смотреть, но в реальной задаче следует прочитать и убедиться, что все корректно.</p>
  <p id="4sHl">Когда задачу &quot;приняли&quot; окончательно, ее нужно архивировать командой <code>/opsx-archive</code>:</p>
  <blockquote id="XZmm">Archive Complete<br />Change: task1234-medium-feature<br />Schema: spec-driven<br />Archived to: openspec/changes/archive/2026-06-27-task1234-medium-feature/<br />Specs: Delta specs preserved (new capabilities — no main specs to sync to)<br />All 4 artifacts complete. All 20 tasks complete.</blockquote>
  <p id="10QY">Вот и все! Работа над задачей завершена, теперь любые доработки нужно делать через отдельные задачи (<code>/opsx-new</code> или <code>/opsx-ff</code>).</p>
  <h2 id="oMdM">Мой отзыв</h2>
  <p id="j5oY">Мне нравится использовать <em>openspec</em>, потому что:</p>
  <ol id="td2B">
    <li id="q6RM">Стандартизируется рабочий процесс - сначала документация, потом реализация по четкому плану</li>
    <li id="2kwI">Появляется документация в удобном формате прямо в папке с проектом, а не где-то далеко в отдельной системе</li>
    <li id="Dzqq">Удобно отслеживать работу и возвращаться к задаче после длительного перерыва</li>
  </ol>
  <p id="g4Iy">Не нравится, что агент часто генерирует документацию на английском. Да что уж там, иногда иероглифы до сих пор вставляет то тут, то там 😅, но даже с учетом этого недостатка штука очень удобная.</p>
  <h3 id="gfRB">Нюансы</h3>
  <ul id="Rj3x">
    <li id="C9Ld">Многое зависит от используемой модели и настроек проекта (в том числе <code>AGENTS.md</code>) - не нужно ожидать классную реализацию плана с нужным стилем/подходом, если агент не знает ничего этого</li>
    <li id="TsXh">Даже если проект настроен правильно, нейросеть может ошибиться в составлении документации (например), и потом сделать работу по неправильному плану, поэтому нужно перепроверять документацию и реализацию (как это делать - другой вопрос, кто-то будет сам читать, а у кого-то будут автоматизированные проверки)</li>
  </ul>
  <p id="F6RT">Еще раз ссылка на репозиторий <a href="https://github.com/Fission-AI/openspec" target="_blank">openspec</a>, рекомендую попробовать самостоятельно 😉</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/Greg5st017e</guid><link>https://teletype.in/@easy_dev991/Greg5st017e?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/Greg5st017e?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Краткий обзор RTK</title><pubDate>Mon, 08 Jun 2026 16:46:02 GMT</pubDate><description><![CDATA[Недавно нашёл ещё один полезный инструмент для использования в opencode — RTK (Rust Token Killer).]]></description><content:encoded><![CDATA[
  <p id="w7ME">Недавно нашёл ещё один полезный инструмент для использования в <code>opencode</code> — <a href="https://github.com/rtk-ai/rtk" target="_blank">RTK</a> (Rust Token Killer). </p>
  <p id="0Fj6">Устанавливается одной командой, встраивается через <code>hook</code> и автоматом сжимает вывод команд перед тем, как он попадёт в контекст нейросети.</p>
  <h2 id="md-heading-1">Как это работает</h2>
  <p id="WxZl">RTK перехватывает команды и применяет к ним четыре стратегии:</p>
  <ol id="s7Ip">
    <li id="vnBU">фильтрацию шума</li>
    <li id="yzP2">группировку похожих элементов</li>
    <li id="vIF7">обрезку лишнего</li>
    <li id="OidT">дедупликацию повторяющихся строк.</li>
  </ol>
  <p id="GNyd">В результате модель получает ровно ту же информацию, но в 3–10 раз меньше токенов.</p>
  <h2 id="n0jx">Примеры</h2>
  <h3 id="NRgE">git status</h3>
  <p id="QtR5"><strong>Без RTK (~67 токенов):</strong></p>
  <pre id="RKpk">On branch main
Your branch is up to date with &#x27;origin/main&#x27;.</pre>
  <pre id="F0jd">Untracked files:
  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)
	.serena/
	docs/</pre>
  <pre id="nzIL">nothing added to commit but untracked files present</pre>
  <p id="jgZs"><strong>С RTK (~12 токенов):</strong></p>
  <pre id="q1dT">* main...origin/main
?? .serena/
?? docs/</pre>
  <p id="qrOY">Шесть строк превратились в три — при этом полезная информация не потерялась.</p>
  <h3 id="md-heading-3">git diff</h3>
  <p id="ZSau"><strong>Без RTK (~200 токенов):</strong></p>
  <pre id="1jgr">diff --git a/Shared SwiftUI Content/100_ScenePhaseExample.swift b/Shared SwiftUI Content/100_ScenePhaseExample.swift
index 3a4b5c6d..7e8f9a0b 100644
--- a/Shared SwiftUI Content/100_ScenePhaseExample.swift
+++ b/Shared SwiftUI Content/100_ScenePhaseExample.swift
@@ -10,6 +10,7 @@ struct ScenePhaseExample: View {
     @State private var isActive = false</pre>
  <pre id="Mvwc">     var body: some View {
+        // MARK: - Main Content
         VStack(spacing: 20) {
             Text(isActive ? &quot;Active&quot; : &quot;Inactive&quot;)
                 .font(.largeTitle)
</pre>
  <p id="tc4y"><strong>С RTK (~40 токенов):</strong></p>
  <pre id="Ycrx">100_ScenePhaseExample.swift: +1
  + // MARK: - Main Content</pre>
  <p id="ojbe">RTK показывает только имя файла, количество изменённых строк и сами добавленные/удалённые строки — без служебной информации <code>diff</code> (индексы, заголовки патчей, контекстные строки).</p>
  <h2 id="md-heading-4">Установка и настройка</h2>
  <p id="5H4A">С помощью <code>homebrew</code>:</p>
  <pre id="lXBE">brew install rtk</pre>
  <p id="E2E9">После установки нужно инициализировать <code>hook</code> для вашего рабочего инструмента:</p>
  <pre id="5JrW">rtk init -g                     # Claude Code / Copilot (по умолчанию)
rtk init -g --gemini            # Gemini CLI
rtk init -g --codex             # Codex (OpenAI)
rtk init -g --agent cursor      # Cursor
rtk init -g --agent windsurf    # Windsurf
rtk init -g --opencode          # opencode</pre>
  <p id="gMNc">После настройки для <code>opencode</code> в <code>~/.config/opencode/plugins/</code> появится файл <code>rtk.ts</code>, который автоматически будет перехватывать вызовы Bash-инструмента и переписывать команды через RTK.</p>
  <h2 id="6309">Заключение</h2>
  <p id="mO1P">RTK — это один из тех инструментов, которые ставишь один раз и сразу получаешь профит. Буквально за пару минут получаем экономию токенов, которая особенно заметна на длинных сессиях при работе с агентом 👍</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/orJ5fF-h3jo</guid><link>https://teletype.in/@easy_dev991/orJ5fF-h3jo?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/orJ5fF-h3jo?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Подключаем нейросеть к Xcode</title><pubDate>Fri, 05 Jun 2026 09:13:54 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/41/b0/41b08270-305a-4266-9621-30807738876d.png"></media:content><category>iOS</category><description><![CDATA[<img src="https://img1.teletype.in/files/00/39/003964b1-9383-45db-95d7-d066878e3662.png"></img>В прошлом году презентовали Xcode 26 с возможностью добавления других провайдеров нейросетей кроме chatgpt/claude, но вот незадача - это не так и просто сделать, если не погуглить дополнительно.]]></description><content:encoded><![CDATA[
  <figure id="litW" class="m_column">
    <img src="https://img1.teletype.in/files/00/39/003964b1-9383-45db-95d7-d066878e3662.png" width="1644" />
    <figcaption>Xcode выдает ошибку при попытке подключить kimi</figcaption>
  </figure>
  <p id="8cJO">В прошлом году презентовали <code>Xcode 26</code> с возможностью добавления других провайдеров нейросетей кроме <code>chatgpt</code>/<code>claude</code>, но вот незадача - это не так и просто сделать, если не погуглить дополнительно.</p>
  <p id="zeAm">Для сравнения вот как выглядит настройка в <code>Android Studio</code>:</p>
  <figure id="xXMO" class="m_column">
    <img src="https://img2.teletype.in/files/55/92/55928ade-57ee-4450-9b14-900c6ccb68cd.png" width="2188" />
    <figcaption>Подключается с первого раза без ошибок, чудеса</figcaption>
  </figure>
  <p id="9JLP">Если просто ввести в настройках <code>Xcode</code> те же данные, что в <code>Android Studio</code>, то ничего не выйдет.</p>
  <p id="8Tpz">Причина проблемы в поле URL: <code>Xcode</code> автоматически добавляет <code>/v1/models</code> или <code>/models</code> к URL провайдера для валидации подключения.</p>
  <p id="A0QU">Поэтому нужно удалить часть URL с версией... чтобы <code>Xcode</code> сам подставил ее. </p>
  <p id="t0Tx">Гениально, не так ли?</p>
  <figure id="3xPJ" class="m_column">
    <img src="https://img2.teletype.in/files/56/14/56140c5d-9238-46f0-8dac-38a9c5c0f47c.png" width="1644" />
    <figcaption>Пример корректной настройки для kimi в Xcode</figcaption>
  </figure>
  <figure id="h6Ms" class="m_column">
    <img src="https://img1.teletype.in/files/c2/6d/c26de0e7-40a0-470f-be71-6a91757bd641.png" width="1644" />
    <figcaption>Успешно подключили kimi</figcaption>
  </figure>
  <figure id="LJKL" class="m_column">
    <img src="https://img2.teletype.in/files/d0/eb/d0ebadfc-fd5c-44f4-8601-b76bc07ecd4e.png" width="1644" />
    <figcaption>Детальный экран подключенного kimi</figcaption>
  </figure>
  <p id="T3Zs">И чтобы не было подозрений, что я рекламирую kimi для <code>Xcode</code>:</p>
  <figure id="NdSr" class="m_original">
    <img src="https://img4.teletype.in/files/ba/2b/ba2b11f6-2724-415a-8023-7c81b2bde693.png" width="780" />
    <figcaption>kimi нифига не работает в Xcode</figcaption>
  </figure>
  <p id="4JiK">Всем удачных подключений!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/P3qUJL1LTfs</guid><link>https://teletype.in/@easy_dev991/P3qUJL1LTfs?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/P3qUJL1LTfs?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Отказ от Icon Composer</title><pubDate>Sun, 19 Apr 2026 14:01:16 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/58/bc/58bc94a6-a0ca-4458-a234-7251c37302f2.png"></media:content><category>iOS</category><description><![CDATA[Если у вас в приложение несколько альтернативных иконок, и все они сделаны с использованием Icon Composer, эта статья для вас.]]></description><content:encoded><![CDATA[
  <p id="YYRP">Если у вас в приложение несколько альтернативных иконок, и все они сделаны с использованием <code>Icon Composer</code>, эта статья для вас.</p>
  <p id="vTFC">Или если у вас простая иконка, которая почему-то получает тень или стекло при установке приложения на девайс, эта статья для вас.</p>
  <h2 id="HgRL">Предыстория</h2>
  <p id="g4ku">В <code>Xcode 26.1</code> добавили баг при создании сборки приложения - ассеты иконок, сделанных в <code>Icon Composer</code> добавляются в итоговый архив несколько раз, что приводит к заметному увеличению веса приложения. Ссылки на форум: <a href="https://developer.apple.com/forums/thread/804739" target="_blank">первая</a>, <a href="https://developer.apple.com/forums/thread/821826" target="_blank">вторая</a>.</p>
  <p id="PvjP">Если иконку создать в композере, то она будет выглядеть как и задумано, вот только в итоговой сборке эта иконка будет весить в несколько раз больше, чем нужно. И если в приложении есть альтернативные иконки, то общий вес легко может вырасти в 2 раза для легкого приложения (например, <a href="https://github.com/easydev991/SwiftUI-Days" target="_blank">этого</a>).</p>
  <p id="nJmG">Обходное решение есть - не использовать композер, и добавлять иконки в приложение старым способом (через ассеты).</p>
  <p id="Ctmr">Однако для простых иконок это приводит к некрасивому результату:</p>
  <figure id="OF4i" class="m_original">
    <img src="https://img4.teletype.in/files/b8/ee/b8ee6a3f-71f4-42ab-a3a8-39d359cc5c86.jpeg" width="136" />
    <figcaption>Иконка приложения с дефолтным градиентом</figcaption>
  </figure>
  <blockquote id="8LLt">Простой я называю иконку, которая состоит из двух цветов без градиентов или прозрачности.</blockquote>
  <p id="EoRK">Получается, что либо мы снижаем вес приложения и миримся с некрасивой тенью (или стеклом, в зависимости от иконки), либо соглашаемся с повышением веса приложения, и целиком управляем тенями и стеклом (привет, композер)?</p>
  <p id="HFqF"><u>Так не пойдет.</u></p>
  <h2 id="xSmz">Решение</h2>
  <figure id="vRDD" class="m_original">
    <img src="https://img4.teletype.in/files/ff/fe/fffe123e-29d3-46c1-baaa-56474e25c881.png" width="472" />
    <figcaption>Настройка градиента в фигме - добавляем градиент для иконки, чтобы система не считала картинку такой уж простой для накладывания своих лишних эффектов</figcaption>
  </figure>
  <figure id="E9Du" class="m_column">
    <img src="https://img1.teletype.in/files/c0/cd/c0cd6390-2008-4cf8-bd99-0541f6e61f57.png" width="1850" />
    <figcaption>Слева старая иконка без градиентов, справа - новая с градиентом. Глазом разницу почти не видно, зато избавляемся от некрасивой тени на экране девайса</figcaption>
  </figure>
  <figure id="1PqV" class="m_original">
    <img src="https://img1.teletype.in/files/00/7b/007b9eb9-19a1-424a-86bb-be3b37aa06ec.png" width="154" />
    <figcaption>Так выглядит новая иконка с незаметным градиентом на экране девайса - без тени и стекла</figcaption>
  </figure>
  <h2 id="AGCC">Результат в мегабайтах</h2>
  <figure id="PFrQ" class="m_column">
    <img src="https://img4.teletype.in/files/3b/55/3b55d6bf-f705-4c92-967b-7611f85b0508.png" width="1408" />
    <figcaption>Размер приложения с иконками, сделанными в Icon Composer</figcaption>
  </figure>
  <figure id="TVbJ" class="m_column">
    <img src="https://img4.teletype.in/files/f9/72/f972833b-1bed-46c8-8b46-2d40580ca6f2.png" width="1410" />
    <figcaption>Размер приложения после обновления основной иконки и альтернативных</figcaption>
  </figure>
  <p id="DLAY">Вес приложения снизился почти на 4 мегабайта!</p>
  <p id="FF7Z">И при этом новые градиентные иконки весят в 5-7 раз больше, чем простые однотонные. Но простые, как мы уже знаем, система покрывает своим стеклом или тенью, а выглядит это некрасиво.</p>
  <p id="nbJQ">Интересный момент: в темной теме ни стекло, ни дополнительная тень на иконки не накладывается - по крайней мере в <a href="https://github.com/easydev991/SwiftUI-Days" target="_blank">счётчике дней</a> так.</p>
  <h2 id="JHCS">Заключение</h2>
  <p id="ZbjO">Если у вас в приложении много альтернативных иконок, или вы используете <code>Icon Composer</code> для создания ваших иконок, то будет здорово вернуться к ассетам и подождать, пока композер починят (а починить его не могут уже больше 5 месяцев).</p>
  <p id="QSpa">Зачем заставлять пользователя скачивать лишние мегабайты мусора вместе с нормальным приложением?</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/h91zeBj4yyW</guid><link>https://teletype.in/@easy_dev991/h91zeBj4yyW?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/h91zeBj4yyW?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Чиним синхронизацию Swift Data</title><pubDate>Fri, 17 Apr 2026 19:28:53 GMT</pubDate><category>iOS</category><description><![CDATA[В моем iOS-приложении для подсчета дней используется Swift Data и в проекте все настроено для автоматической синхронизации данных между всеми девайсами пользователя в iCloud. Сегодня я починил эту синхронизацию (она давно не работала).]]></description><content:encoded><![CDATA[
  <p id="4xrH">В моем <a href="https://github.com/easydev991/SwiftUI-Days" target="_blank">iOS-приложении для подсчета дней</a> используется <code>Swift Data</code> и в проекте все настроено для автоматической синхронизации данных между всеми девайсами пользователя в <code>iCloud</code>. Сегодня я починил эту синхронизацию (она давно не работала).</p>
  <h2 id="1IlA">Проблемный сценарий</h2>
  <p id="TAct">На одном девайсе создаю запись в приложении, жду, сворачиваю/разворачиваю приложение, проверяю на другом девайсе через минуту - там эта запись не появляется.</p>
  <h2 id="cC8P">Решение</h2>
  <p id="M3Vp">Открываем <a href="https://icloud.developer.apple.com/" target="_blank">https://icloud.developer.apple.com/</a></p>
  <figure id="rBMx" class="m_column">
    <img src="https://img2.teletype.in/files/19/e7/19e78701-e72f-48f0-9809-a07c98bf2ece.png" width="1864" />
    <figcaption>Жмем CloudKit Database</figcaption>
  </figure>
  <figure id="oUtH" class="m_column">
    <img src="https://img3.teletype.in/files/ae/3a/ae3af325-ccc8-4790-bbd5-aab8c031ea7f.png" width="848" />
    <figcaption>Выбираем справа сверху настроенный для приложения контейнер и вариант Production</figcaption>
  </figure>
  <figure id="3Vy9" class="m_column">
    <img src="https://img3.teletype.in/files/af/61/af617173-007e-4dbd-83f7-a7c911f67040.png" width="908" />
    <figcaption>Открываем логи</figcaption>
  </figure>
  <p id="MLqd">Находим запись с ошибкой, например так:</p>
  <figure id="U2v2" class="m_column">
    <img src="https://img2.teletype.in/files/d8/f9/d8f993b1-a68d-485d-b47d-df89835d91dd.png" width="3168" />
    <figcaption>Фильтруем по OverallStatus = USER_ERROR и жмем справа синюю кнопку Query</figcaption>
  </figure>
  <p id="DEY9">Проверяем схему (типы записей) в development и production</p>
  <figure id="cPuV" class="m_original">
    <img src="https://img2.teletype.in/files/93/5c/935cd717-10d2-4571-ba26-5ccf72210d31.png" width="446" />
    <figcaption>Жмем сюда для development и production по очереди, чтобы убедиться в наличии нестыковок</figcaption>
  </figure>
  <p id="x0Vg">Нестыковки найти очень легко: в моем случае в production-схеме буквально не было нужного типа записи с полями из iOS-приложения.</p>
  <figure id="OlPK" class="m_column">
    <img src="https://img3.teletype.in/files/e5/78/e57896b4-472b-42a4-bd7f-c6b958543fa2.png" width="3210" />
    <figcaption>Вот как у меня было в прод-схеме - только один тип записи &quot;Users&quot;</figcaption>
  </figure>
  <p id="Q3Nl">Если найдены нестыковки, и development-схема содержит более актуальные данные, нужно ... опубликовать эти изменения в прод.</p>
  <figure id="Incq" class="m_column">
    <img src="https://img1.teletype.in/files/06/ce/06cee1f4-1fc5-4c55-8ce9-18c079d8aa12.png" width="3202" />
    <figcaption>Вот как у меня было в дев-схеме (есть нужный мне тип записи &quot;CD_Item&quot;), и тут же выделил слева внизу кнопку для публикации изменений</figcaption>
  </figure>
  <figure id="C4MW" class="m_column">
    <img src="https://img4.teletype.in/files/33/4a/334ae115-28fd-4fc0-8f26-d6ef91b1f1a8.png" width="1292" />
    <figcaption>Перед деплоем можно посмотреть изменения - тут в общем все поля моей модели данных, которая используется в &quot;Счётчике дней&quot; на iOS</figcaption>
  </figure>
  <p id="Qit4">После нажатия &quot;Deploy&quot; можно подождать пару минут и повторить тест на проблемном сценарии. У меня проблема была решена через 2 минуты после деплоя актуальной схемы в прод.</p>
  <h2 id="6EhW">Заключение</h2>
  <p id="l4tE">Когда я в первый раз настраивал <code>Swift Data</code>, то вообще не заглядывал в консоль <code>icloud.developer</code>, не проверял ничего связанного со схемами, и даже статей на эту тему не искал и не читал. Оказалось, настроить синхронизацию с облаком несложно, нужно только знать как это делается 😅</p>
  <p id="bws5">Спасибо интернету! И нейросетям 😉</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/hlx_HA24Cgy</guid><link>https://teletype.in/@easy_dev991/hlx_HA24Cgy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/hlx_HA24Cgy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Какой макбук выбрать в 2026 году</title><pubDate>Sat, 28 Mar 2026 10:19:10 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/7c/ca/7cca7d4a-d86e-4dce-acee-14c2ddc59bca.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/16/2f/162f3954-4a8e-41c5-9496-7cad859f3172.png"></img>Предыдущая статья про 2025 год доступна по ссылке - большинство рекомендаций из нее все еще актуальны, кроме цен и версии Xcode, конечно.]]></description><content:encoded><![CDATA[
  <p id="GWNq">Предыдущая статья про 2025 год доступна по <a href="https://telegra.ph/115-Kakoj-makbuk-vybrat-v-2025-godu-04-16" target="_blank">ссылке</a> - большинство рекомендаций из нее все еще актуальны, кроме цен и версии <code>Xcode</code>, конечно.</p>
  <p id="ZOyD">За год изменилось немного: появился чип <strong>m5 </strong>и вышел <strong>Xcode 26...</strong></p>
  <h2 id="Макбук-для-работы">Макбук для работы</h2>
  <p id="RFz4">Рекомендации по поводу рабочего макбука двигаем на <strong>1</strong> цифру вперед, то есть на работе заказываем <strong>MacBook Pro m5 pro </strong>- как обычно, даже в базовой конфигурации это будет отличный вариант на несколько лет вперед.</p>
  <p id="Ulxm">Если компания не выдает технику, то есть смысл взять то, на что хватает денег из линейки <strong>m3</strong>-<strong>m5</strong>. <strong>m1</strong>-<strong>m2</strong> не рассматриваем, потому что они уже прилично состарились, а <strong>m2</strong> и вовсе проиграл в некоторых тестах предшественнику.</p>
  <h2 id="Макбук-не-для-работы">Макбук не для работы</h2>
  <p id="tB2h">В 2020 году я купил себе <strong>MacBook Pro 13&#x27;&#x27; m1 </strong>за<strong> 150к </strong>(на официальном сайте с доставкой на дом, чудеса вообще), и он отлично прослужил мне до второй половины 2025 года, когда я его продал за <strong>64к</strong> - это была отличная продажа и я очень доволен таким успехом, и покупатель будет еще долго доволен, т.к. ему макбук нужен был не для программирования, а для повседневного использования.</p>
  <p id="wQLY">В 2026 не могу рекомендовать макбуки из линейки <strong>m1-m2</strong>, так что находим выгодные варианты <strong>m3</strong>-<strong>m5</strong> (как и для работы) на маркетплейсах и радуемся запасу производительности на ближайшие 3-5 лет.</p>
  <p id="rAkm">Очевидно, <strong>m5</strong> прослужит лучше в течение 5 лет, чем <strong>m3</strong>, но для рядового пользователя, полагаю, разницы не будет вообще - не всем же нужно запускать <code>Xcode</code>/<code>Android Studio</code> каждый день по несколько раз и ждать выполнение unit/ui-тестов 😁</p>
  <h2 id="yaz9">Macbook Neo</h2>
  <p id="Lriu">Сделал отдельный раздел специально для этой модели, потому что в личку мне уже написали гениальную идею купить этот макбук для ios-разработки.</p>
  <p id="nfIW">Этот раздел статьи не для слабонервных!</p>
  <p id="I6kO">.</p>
  <p id="xc0g">.</p>
  <p id="rM6S">.</p>
  <p id="Dc1f">.</p>
  <p id="ljUM">.</p>
  <p id="ILCT">.</p>
  <p id="uSq4">Я серьезно, если вы фанат Apple или просто ярый поклонник всех макбуков, то лучше не читать дальше!</p>
  <p id="VjEX">.</p>
  <p id="G5Hd">.</p>
  <p id="AHif">.</p>
  <p id="I9uX">.</p>
  <p id="Xx1J">.</p>
  <p id="ulIb">.</p>
  <p id="7gTg">Вы еще тут? Окей, поехали)</p>
  <p id="hWNE">Специально для этой модели я покажу скриншоты цен (актуально на конец марта - начало апреля 2026) без рекламы конкретного маркетплейса, и потом мы вместе сравним с ценами на другие модели на том же маркетплейсе, опять же не реклама:</p>
  <figure id="pnBQ" class="m_column">
    <img src="https://img2.teletype.in/files/16/2f/162f3954-4a8e-41c5-9496-7cad859f3172.png" width="2268" />
    <figcaption>Цены на безымянном (популярном) маркетплейсе на Macbook Neo - от 66к руб с учетом пошлины</figcaption>
  </figure>
  <figure id="E9Xj" class="m_column">
    <img src="https://img4.teletype.in/files/b8/32/b832a1ec-d3a0-420d-a268-01144b1c17ea.png" width="2318" />
    <figcaption>Цены на том же маркетплейсе на Macbook Air M4 - от 89к руб с учетом пошлины</figcaption>
  </figure>
  <p id="Ajp4"><strong>Важная деталь</strong>: это сравнение цен на новые ноутбуки, т.е. не б/у, не паленые, а прямо новые.</p>
  <p id="CFKc"><strong>Air m4</strong> дороже на <strong>23к</strong> руб (на этом маркетплейсе), но и по большинству параметров он намного лучше.</p>
  <p id="9vhE">У мелких перекупщиков на других популярных сайтах можно найти тот же <strong>air m4</strong> за <strong>69к</strong>.</p>
  <p id="hHov"><u>Внимательный</u> читатель может спросить: &quot;<em>Зачем покупать дорогой air m4, если можно купить новый модный и молодежный neo дешевле?</em>&quot;.</p>
  <p id="jsVf">На это я <em>отвечу</em> внимательному читателю: &quot;<em>Если не получается найти разницу при беглом сравнении параметров обеих моделей под свои потребности, то не нужно платить больше</em>&quot;.</p>
  <p id="n66a">Потом <u>сообразительный</u> читатель может спросить: &quot;<em>Зачем вообще покупать макбук в 2026 году за такие деньги не для ios-разработки, когда можно купить ноутбук на виндовс под любые потребности и по любой цене, в том числе от 15к и до 60к?</em>&quot;</p>
  <p id="GInl">На что я отвечу сообразительному читателю: &quot;<em>Отличный вопрос, мой дорогой читатель! Нет никакого смысла тратить деньги на макбук, если нет конкретных задач, для которых нужен именно макбук, и с которыми не справятся другие ноутбуки</em>&quot;.</p>
  <p id="eLf5">И пока другие блогеры и СМИ активно пиарят новый <strong>macbook neo</strong> как убийцу доступных ноутбуков на винде, мы с вами как самые сообразительные понимаем, что это пустой трёп, который нацелен только на отработку рекламного ТЗ, или на сбор хайпа (или и то, и другое разом).</p>
  <figure id="fIlM" class="m_column">
    <img src="https://img2.teletype.in/files/92/09/920960e0-5641-4551-bb55-18da1fbb2857.png" width="2266" />
    <figcaption>Вот пример реальных убийц macbook neo на том же маркетплейсе дешевле 25к руб. В карточках товара кринж, но это не так важно.</figcaption>
  </figure>
  <p id="gY7l">И прежде чем набегут желающие защитить божественный бренд Apple от сравнения с безымянными ноутбуками, сначала вспомним, что этот раздел был не для слабонервных и не для фанатов Apple!</p>
  <p id="srx3">А теперь можно вместе подумать, что еще можно купить на оставшиеся 45к руб после покупки ноутбука на винде:</p>
  <ul id="0rEu">
    <li id="xx5Z">Отличный новый андроид-смартфон</li>
    <li id="2qoL">Два хороших новых андроид-смартфона</li>
    <li id="oxUm">Хороший андроид-смартфон и еще один ноутбук на винде</li>
    <li id="nnbN">Два дополнительных ноутбука на винде</li>
    <li id="1ABD">45 пицц по 1000 рублей каждая</li>
  </ul>
  <p id="z2uI">Ну вы поняли, надеюсь 😉</p>
  <h2 id="oBfa">Заключение</h2>
  <p id="AYFS">Итоговый выбор как всегда зависит от ваших конкретных задач (но не покупайте, пожалуйста, <strong>macbook neo</strong>), для которых выбирается макбук, и в большинстве случаев для разработки подойдет любая модель с чипом <strong>m4</strong>-<strong>m5</strong>.</p>
  <p id="gfix">Удачных покупок!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@easy_dev991/baZfVYrGA5H</guid><link>https://teletype.in/@easy_dev991/baZfVYrGA5H?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991</link><comments>https://teletype.in/@easy_dev991/baZfVYrGA5H?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=easy_dev991#comments</comments><dc:creator>easy_dev991</dc:creator><title>Загружаем фото в андроид-эмулятор</title><pubDate>Fri, 20 Mar 2026 19:18:24 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/1e/19/1e199205-20aa-4772-9b17-0e91fcd114fa.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/51/55/5155b125-26a8-44dc-8192-92da8d2af2a6.png"></img>В процессе разработки андроид-приложения бывает нужно протестировать функционал добавления фотографий из галереи в приложение.]]></description><content:encoded><![CDATA[
  <p id="DZbY">В процессе разработки андроид-приложения бывает нужно протестировать функционал добавления фотографий из галереи в приложение.</p>
  <p id="uvnt">Есть разные способы загрузки фоток в эмулятор, например:</p>
  <ul id="qJML">
    <li id="iMIh">перетащить файлы с фотками на экран эмулятора</li>
    <li id="mVuf">перетащить файлы с фотками в открытое приложение &quot;файлы&quot; на экране эмулятора</li>
    <li id="xIBT">открыть Device Explorer и добавить фотки в папку sdcard/DCIM</li>
  </ul>
  <p id="LOpN">Но что бы вы ни сделали, все эти способы могут не привести к желаемому результату...</p>
  <p id="SB53">А вот кстати и желаемый результат:</p>
  <figure id="1xXu" class="m_column">
    <img src="https://img2.teletype.in/files/51/55/5155b125-26a8-44dc-8192-92da8d2af2a6.png" width="1080" />
    <figcaption>В приложении можно открыть галерею фотографий</figcaption>
  </figure>
  <figure id="ddko" class="m_column">
    <img src="https://img1.teletype.in/files/0e/a8/0ea83121-a09d-4551-ad5c-df2c3961292e.png" width="1080" />
    <figcaption>Фото из галереи можно выгрузить в приложение</figcaption>
  </figure>
  <h2 id="KUrD">Проблема</h2>
  <p id="8TnF">Все перечисленные ранее способы не сработали:</p>
  <figure id="pslV" class="m_column">
    <img src="https://img1.teletype.in/files/0f/95/0f9536df-c57a-4c4c-bac2-35b650a96af1.png" width="1080" />
    <figcaption>Фотографии добавлены в эмулятор каждым из перечисленных ранее способов, но приложение их не видит (как и сам эмулятор)</figcaption>
  </figure>
  <h2 id="9Tk4">Решение</h2>
  <p id="cRx5">После копирования фотографий на эмулятор любым из ранее перечисленных способов выключаем эмулятор и жмем <code>Cold Boot</code>:</p>
  <figure id="qK93" class="m_column">
    <img src="https://img4.teletype.in/files/fb/e3/fbe3b5a9-9508-4f3a-bb0e-e78475f5c01c.png" width="1080" />
    <figcaption>Чудо-кнопка, решающая проблему с обнаружением фотографий в эмуляторе</figcaption>
  </figure>
  <h2 id="AMrX">Заключение</h2>
  <p id="lQAa">Перед написанием этой статьи я пробовал добавить фотографии в эмулятор всеми перечисленными способами, даже стирал данные эмулятора и перезагружал его - ничего не помогало.</p>
  <p id="VheN">И только чудо-кнопка <code>Cold Boot</code> помогла.</p>
  <p id="Ox3a">Будет здорово, если кому-то эта статья поможет сэкономить время в подобной ситуации </p>

]]></content:encoded></item></channel></rss>