اپ iOS و اندروید
تیک — اپ کارهای روزانه برای iOS و اندروید
یک اپ ساده برای کارهای هر روز: کار را اضافه میکنی، تیک میزنی، تمام. ظاهرش شیشهای و مینیمال است، مثل خود iOS 27. فارسی و انگلیسی دارد، تقویمش شمسی است، و ویجتش از روی صفحهی اصلی گوشی تیک میخورد. هم برای آیفون و آیپد هست، هم برای گوشی و تبلت اندروید.
مشکل چه بود؟
اپهای کار روزانه معمولاً یکی از این دو مشکل را دارند: یا آنقدر سادهاند که به درد برنامهریزی نمیخورند، یا آنقدر شلوغاند که اضافه کردن یک کار ساده، خودش یک کار حساب میشود.
من یک چیز میخواستم: صبح کارهای امروز را سریع بنویسم و در طول روز تیکشان بزنم. و چون فارسیزبانم، تقویم شمسی و راستبهچپ درست برایم مهم بود — نه یک ترجمهی نصفهنیمه.
چی ساختم؟
«تیک»، اول یک اپ بومی iOS برای آیفون و آیپد، و بعد همین اپ برای اندروید. صفحهی اولش «امروز» است: کارهای امروز، کارهای عقبافتاده، و یک نوار پیشرفت. هر کار میتواند یادداشت، زیرکار، تاریخ و ساعت، اولویت، عکس و تکرار داشته باشد — ولی هر کدام را که لازم نداری، از تنظیمات خاموش میکنی و از فرم حذف میشود.
- لیستهای شخصی با رنگ و آیکون، و چهار لیست هوشمند: امروز، برنامهریزیشده، همه، انجامشدهها
- یادآور با دو دکمه روی خود اعلان: «انجام شد» و «۱۰ دقیقهی دیگر یادم بنداز»
- ویجت صفحهی اصلی در سه اندازه، و سه ویجت برای صفحهی قفل
- تم روشن و تیره، ۱۱ رنگ اصلی و ۶ آیکون برای خود اپ
- و وقتی آخرین کار روز تیک بخورد، کمی کاغذ رنگی روی صفحه میریزد
یک دکمه که به فیلد تبدیل میشود
سریعترین راه اضافه کردن کار، نوشتنش است — نه باز کردن یک فرم. دکمهی شیشهای «+» پایین صفحه با یک لمس، با افکت Liquid Glass «ذوب» میشود و به یک فیلد متن تبدیل میشود.
نکتهی اصلی این است که بعد از زدن اینتر، فیلد بسته نمیشود. صبح میشود پنج کار را پشتسرهم تایپ کرد، بدون یک لمس اضافه. برای جزئیات بیشتر هم دکمهای کنار فیلد هست که فرم کامل را با همان عنوان باز میکند.
فارسی واقعی، نه فقط ترجمه
زبان اپ از داخل خود اپ عوض میشود، مستقل از زبان گوشی. با یک لمس، کل رابط راستبهچپ میشود و فونت وزیرمتن جای فونت سیستم را میگیرد.
تقویم پیشفرض شمسی است و هفته از شنبه شروع میشود. تکرار «هر ماه» هم با ماههای شمسی حساب میشود: کاری که اول مهر است، دفعهی بعد اول آبان میآید. و به انتخاب خودم، عددها همهجا لاتین میمانند — در ساعت، در تاریخ، و حتی در درصد پیشرفت.
ویجتی که تیک میخورد
ویجت و اپ دو برنامهی جدا هستند، ولی باید یک داده را ببینند. پایگاه داده (SwiftData) در یک App Group مشترک ذخیره میشود تا هر دو به آن دسترسی داشته باشند، و تیک زدن از روی ویجت با App Intents انجام میشود — بدون اینکه اپ باز شود.
بخش سختش این بود که اپ بعدش بفهمد داده عوض شده. ویجت در یک فرایند جدا کار میکند، پس اپ هنوز نسخهی قدیمی را در حافظه دارد. راهحل: ویجت بعد از هر تغییر یک «مهر زمان» در تنظیمات مشترک میگذارد، و اپ وقتی دوباره باز میشود آن را میبیند و داده را از نو میخواند.
کارهای تکراری
وقتی یک کار تکراری را تیک میزنی، نسخهی بعدیاش خودکار ساخته میشود — و اگر تیک را برداری، همان نسخه هم پاک میشود. کاری که دیر تیک بخورد هم دوباره در گذشته ساخته نمیشود؛ نسخهی بعدی همیشه از فردا به بعد است.
نسخهی اول، «هر ماه» را فقط از تاریخ آخرین کار حساب میکرد. تست نشان داد کاری که ۳۱ ژانویه بود، بعد از فوریه ۲۸ام میشد — و برای همیشه ۲۸ام میماند.
حالا روز اصلی ماه کنار قانون تکرار نگه داشته میشود و هر وقت ماه اجازه بدهد، کار به همان روز برمیگردد. در تقویم شمسی هم همین است: کار ۳۱ شهریور در ماههای ۳۰روزه روز ۳۰ میآید، و در فروردین بعد دوباره ۳۱ام.
روی آیپد
نسخهی اندروید
بعد از iOS، همین اپ را برای اندروید هم ساختم: با همان امکانات، برای گوشی و تبلت. این بار با Kotlin و Jetpack Compose، و بدون یک خط کد مشترک با نسخهی iOS. منطق اپ، از تقویم شمسی تا قانونهای تکرار، از نو نوشته شد و تست شد تا دقیقاً مثل نسخهی iOS رفتار کند.
شیشه، به سبک تلگرام
اندروید Liquid Glass ندارد. ظاهر شیشهای را از طراحی تازهی تلگرام برای اندروید الهام گرفتم: نوار تبها، دکمهها و نوار بالای صفحه شیشهی ماتاند، و از اندروید ۱۲ به بالا هر چه پشتشان رد شود، محو دیده میشود.
روی اندروید ۱۳ به بالا یک قدم جلوتر رفتم: وقتی انگشت روی نوار تبها میلغزد، یک «قطرهی آب» شفاف زیر انگشت حرکت میکند و آیکونهای زیرش را کمی خم میکند؛ شکستِ نور روی کارت گرافیک حساب میشود. روی گوشیهای قدیمیتر، همان شکلها با یک رنگ نیمهشفاف ساده کشیده میشوند.
ویجتی که باید برعکس میشد
ویجت اندروید با Jetpack Glance ساخته شده و مثل iOS از روی صفحهی اصلی تیک میخورد. ولی لانچر اندروید، ویجت را به زبانِ گوشی میچیند، نه به زبانِ اپ. پس اگر اپ فارسی باشد و گوشی انگلیسی، ردیفها باید دستی برعکس شوند.
نسخهی اول درست برعکس نمیشد. معلوم شد از اندروید ۱۳ به بعد، زبانی که برای خودِ اپ انتخاب میشود، روی چیزی هم که اپ «زبان گوشی» میبیند اثر میگذارد؛ پس ویجت فکر میکرد گوشی هم فارسی است. راهحل این بود که زبان واقعی گوشی را مستقیم از سیستم بپرسم. حالا ویجت در هر ترکیبی درست است، و در حالت فارسی حتی نوار پیشرفتش هم از راست پر میشود.
در نسخهی آزمایشی همهچیز درست بود، ولی در فایل نهایی (APK) ویجت روی دایرهی «در حال بارگذاری» میماند. ابزاری که کد نهایی را کوچک و فشرده میکند (R8)، سازندهی یکی از کلاسهای WorkManager را حذف کرده بود؛ کلاسی که فقط از روی اسمش ساخته میشود. برای همین ویجت هیچوقت کشیده نمیشد.
یک قانون کوچک برای نگه داشتن آن کلاس، مشکل را حل کرد. درسش این بود که فایل نهایی را هم خودم امتحان کنم، نه فقط نسخهی آزمایشی و تستها را.
روی تبلت اندروید
تستها
منطق نسخهی iOS با ۳۵ تست واحد پوشش داده شده: تاریخ شمسی و میلادی با عدد لاتین، همهی قانونهای تکرار، اینکه کدام کار در «امروز» بیاید و به چه ترتیبی، و تیک زدن از روی ویجت. ۱۷ تست رابط کاربری هم مسیرهای اصلی را مثل یک کاربر واقعی امتحان میکنند — و عکسهای آیفونِ همین صفحه را هم همان تستها گرفتهاند.
نسخهی اندروید ۴۸ تست واحد و ۱۰ تست روی گوشی دارد. تقویم شمسیاش هم برای تکتک روزهای سال ۱۹۰۰ تا ۲۱۰۰ میلادی با کتابخانهی ICU مقایسه شده؛ همان چیزی که iOS برای تقویم از آن استفاده میکند.
با چه ابزارهایی
| iOS | اندروید | |
|---|---|---|
| رابط کاربری | SwiftUI برای iOS 27، با Liquid Glass | Jetpack Compose و Material 3، با شیشهی Haze |
| داده | SwiftData، مشترک با ویجت از طریق App Group | Room برای کارها و DataStore برای تنظیمات |
| ویجت | WidgetKit و App Intents | Jetpack Glance |
| یادآور | UserNotifications، با دکمه روی خود اعلان | آلارم دقیق و اعلان با دکمه |
| زبانها | String Catalog با انگلیسی و فارسی | زبانِ جدا برای خود اپ، با انگلیسی و فارسی |
| تست | ۳۵ تست واحد با Swift Testing و ۱۷ تست رابط کاربری | ۴۸ تست واحد و ۱۰ تست روی گوشی |
| جزئیات | آیکونها با کد کشیده شدهاند و صداها از فرمول ریاضی ساخته شدهاند | |
نتیجه
اپی برای کارهای هر روز: سریع برای نوشتن، راحت برای تیک زدن، و فارسیِ درست. برای استفادهی شخصی ساخته شده، پس در اپاستور و گوگلپلی نیست. نسخهی iOS با یک Apple ID رایگان، مستقیم از Xcode روی آیفون نصب میشود. نسخهی اندروید را هم میشود بهصورت یک فایل APK از گیتهاب دانلود کرد و مستقیم روی گوشی نصب کرد. راهنمای نصب هر دو در گیتهاب هست.
حالا تیک سایت خودش را هم دارد، با دموی زنده و دانلود مستقیم: tik.mahyarmozafar.ir. داستان ساختش را در صفحهی سایت تیک نوشتهام.