Skip to content

Changelog

Release history for the Chorki mobile app, newest first.

Entries before iOS 3.0.68 / Android 2.0.91 are not covered — this file starts at commit 9b72fc8b (2026-05-14) and was reconstructed from git history, since there were no release tags past v0.0.3 and no changelog before this one.

The two platforms carry different version numbers and never match:

Platform Source of truth Range covered here
Android pubspec.yaml version: → flutter.versionName / flutter.versionCode (android/app/build.gradle:42-43) 2.0.91 (291) → 2.2.4 (305)
iOS FLUTTER_BUILD_NAME + MARKETING_VERSION hardcoded in ios/Runner.xcodeproj/project.pbxproj, which overrides pubspec (ios/Runner/Info.plist:32 reads $(FLUTTER_BUILD_NAME)) 3.0.67 → 3.1.77

Known quirks:

  • iOS CFBundleVersion is static. ios/Runner/Info.plist:73 hardcodes it to 3 (unchanged since 2024-03-31) and FLUTTER_BUILD_NUMBER = 1 in the pbxproj, so the Android build number (+291…) never reaches iOS builds. TestFlight build numbers are set outside the repo.
  • Force-update is two independent ladders. Because the version schemes diverged, min_app_version_android and min_app_version_ios in the settings API have to be maintained separately (see checkUpdate in lib/presentation/bloc/splash_screen/splash_screen_bloc.dart).
  • 3.0.67 never shipped. The BillDesk branch was cut from cdb1b944, the parent of the commit that set 3.0.67, so it carried 3.0.66 forward and jumped straight to 3.0.68 on merge.
  • Versions skipped entirely: iOS 3.0.71, 3.0.74, 3.1.74; Android 2.0.92, 2.0.94–96, 2.0.98, 2.1.2–2.2.1 (302).

Add a new section at the top when bumping versions. Bump both sources — version: in pubspec.yaml (Android) and the three FLUTTER_BUILD_NAME + MARKETING_VERSION pairs in the pbxproj (iOS) — and title the section with both numbers. Put native-only changes under the Android / iOS subsections and everything else under Shared. Reference the short commit SHA for anything non-obvious.


iOS 3.1.77 · Android 2.2.4 (305) — 2026-07-30

Section titled “iOS 3.1.77 · Android 2.2.4 (305) — 2026-07-30”

Targeted subscription-offer deeplinks. (3466d13c, 16069a25, a1f854d5)

  • Added — /subscribe?id=<a>+<b> shows only the named packages. id is a client-side filter (the API has no such parameter), so it is stripped from the query before the request and applied to the response, preserving the order the ids were listed in and de-duplicating. Because Uri decodes + in a query to a space, the parser accepts +, commas and whitespace as separators. subscription_screen_bloc.dart.
  • Changed — targeted links bypass the conditional_visible gate. Naming a package by id is how a hidden campaign plan is revealed; the gate still applies to the normal catalog view.
  • Added — SubscriptionOfferUnavailable state for when a deeplinked id matches nothing (deleted, expired, geo-blocked). The screen shows “This offer is no longer available” plus a View all plans button, which re-dispatches GetPackages with the new bypassIdFilter: true flag. The bottom Subscribe bar is hidden in that state — its handler indexes into the (now empty) list.
  • Fixed — package list stopped at page one. SubscriptionDataSource.getPackages now follows links.next (capped at 10 pages), since a deeplinked package can sit beyond the API’s 50-per-page first page. subscription_data_source.dart.
  • Fixed — subscribe deeplink query leaked into later visits. DeeplinkServices no longer stashes the subscribe query string in the global deeplink_url; it is passed straight to the route. Otherwise an id= filter stuck to every later plain /subscription_screen visit for the rest of the session. (deeplink_services.dart)
  • Fixed — stale selection index on a shorter list. subscriptionIndex resets to 0 when the loaded list is shorter than the previous one.
  • Added — TVOD package rendering. Subscription / SubscriptionModel gained type and contents (new PackageContent entity + PackageContentModel). For type == 'tvod' — a ticket for a single title, which comes back with an empty description — the row shows the interval in the description slot and the unlocked title’s 16:9 thumbnail below it. The row’s fixed height: 100.v became a minHeight constraint with an IntrinsicHeight wrapper so only TVOD rows grow.
  • Added — AppDecoration.outlinedMenuCard (transparent fill, 1px divider border), now used by the profile, account, download-settings, my-library and preferences screens in place of the filled card. (16069a25)
  • Profile settings: Spacer above the app-version row dropped, 24.v → 14.v spacing.
  • i18n: subscription_offer_unavailable, view_all_plans (en + bn).
  • Tests added: subscription_data_source_test.dart (pagination), subscription_screen_bloc_test.dart (id parsing, filtering, unavailable state).

iOS 3.1.76 · Android 2.2.3 (304) — 2026-07-23

Section titled “iOS 3.1.76 · Android 2.2.3 (304) — 2026-07-23”
  • Fixed — popup notifications could never match a location. lib/data/models/popup_notification_model.dart read location_classname / location_route_uri / location_template out of the already-nested location object, where the keys are classname / route_uri / template, so every location field parsed empty. (0229aefd)
  • Changed — popups are now location-aware and queued. The full list is cached in popup_notifications_global instead of only firing popup_list[0] on home load. _checkPopupForLocation matches the current tab’s route URI (trailing slash normalized) on load and on every tab switch, queues matches, and shows them one at a time through appRouter.navigatorKey.currentContext. The old SharedPreferences show_popup once-per-install suppression was replaced by an in-session _scheduledPopupIds set. home_screen_bloc.dart, popup_notification_widget.dart.
  • Added — geo context notifiers current_city, current_continent, current_timezone in core/constant/const.dart, populated from the ipinfo response in settings_data_source.dart.
  • Added — getDynamicApiV2() on DioApiProvider for the v2 dynamic API base.
  • Marktag context / play / purchase payload refinements; the subscription screen’s inline purchase logging (~44 lines) folded into the shared helper.
  • i18n: “Have a Redeem code?” → “Redeem Code”.

iOS 3.1.75 · Android 2.2.2 (303) — 2026-07-13

Section titled “iOS 3.1.75 · Android 2.2.2 (303) — 2026-07-13”

Domain cutover release. (4600c37d)

  • Changed — chorki.com → chorki.net across api_static, api_dynamic, ip_info_api, awardsCarnivalUrl, the Marktag tag (mtag-cayk.chorki.net), and the VPN screen’s platform domain.
  • Refactor: auth_bottomsheet.dart (~124 lines).
  • autoVerify="true" intent-filters added for chorki.net and www.chorki.net alongside the existing chorki.com pair.
  • applinks:chorki.net + applinks:www.chorki.net added to Runner.entitlements (which was also missing bare applinks:chorki.com) and to Info.plist.

iOS 3.0.73 (unchanged) · Android 2.1.1 (301) — 2026-07-09

Section titled “iOS 3.0.73 (unchanged) · Android 2.1.1 (301) — 2026-07-09”

Android-only bump — 08f0d018 did not touch the pbxproj, so iOS stayed on 3.0.73.

  • Added — ChorkiCaptchaWebView (lib/presentation/widgets/auth/chorki_captcha_webview.dart): loads the real Cloudflare-served /captcha page in flutter_inappwebview and forwards the Turnstile token via JS injection. The cloudflare_turnstile package injects inline HTML with a synthetic origin (loadDataWithBaseURL), which defeats HTTP/2 connection coalescing — Turnstile’s randomized *.challenges.cloudflare.com sub-hosts have no public DNS record and then fail with ERR_NAME_NOT_RESOLVED, making the widget loop.
  • Chore — dependency pinning to keep a beta out. cloudflare_turnstile pinned exact at 3.7.2 and flutter_inappwebview / flutter_inappwebview_android pinned at 6.1.5 / 1.1.3, because the caret floated onto the 6.2.0-beta line and broke the Android method-channel bridge.
  • Chore: FVM 3.38.5 → 3.41.8; marktag ^2.0.2 → ^2.0.3.
  • Docs: docs/api/ — Postman collection, environment file, and README.

iOS 3.0.73 · Android 2.1.0 (300) — 2026-06-25

Section titled “iOS 3.0.73 · Android 2.1.0 (300) — 2026-06-25”

Pure analytics-instrumentation release. (f45f53aa)

  • Added — three shared Marktag modules, centralizing payloads that were duplicated across firing sites:
    • core/utils/marktag_context.dart — buildMarktagUserContext() assembling chorkiId, country / IP, a compact device descriptor (returns {} on failure so an event is never blocked), and a coarse subscriptionStatus() of none / expired / active.
    • core/utils/marktag_play.dart — logMarktagPlay() with content-type mapping, resume position, and genre/cast/age falling back to the parent series for episodes lacking their own metadata.
    • core/utils/marktag_purchase.dart — logMarktagPurchase() unified across SVOD web, SVOD IAP and TVOD web, and across success / failed / canceled, adding purchase_status, sub_type, payment_gateway, package_id while keeping the existing value / currency / plan_name / plan_duration / method fields.
  • Refactor: the firing sites in user_auth_bloc, in_app_purchase_bloc, subscription_screen, web_view, single_content_screen, video_player_screen all switched to those helpers.

iOS 3.0.72 · Android 2.0.99 (299) — 2026-06-22

Section titled “iOS 3.0.72 · Android 2.0.99 (299) — 2026-06-22”
  • Fixed — Marktag Signup events were both duplicated and lost. (5930e31f)
    • The email signup flag moved from an in-memory bool to SharedPreferences (marktag_email_signup_pending) so it survives an app kill between OTP and SetPassword. Forgot-password shares the same PasswordSet path, so this flag is the only way to tell a signup from a reset.
    • Phone/social signups are detected by a missing profile, which recurs on repeat logins before profile setup; now guarded by a persisted per-account key (marktag_signup_logged_$userId) via a new _logSignupOnce().
    • AppInstall is no longer burned on an offline first launch — it checks InternetConnectionChecker first and retries next launch, since the SDK is fire-and-forget and swallows delivery failures.
  • Added — Marktag Purchase event on IAP verify success, with plan details. VerifyPurchase now carries the Subscription; subscription_screen.dart captures the plan at Subscribe-tap time because the verify response contains no plan data. (0055dd5a)
  • Added — Tools section: toolsUrl / toolsDeeplinkPath, a /tools deep-link branch in deeplink_services.dart, a Tools card in the preferences screen, and “Tools” strings in both locales. (0055dd5a)
  • Added — notification badge count in profile settings, with its own bloc. (0055dd5a)
  • Fixed — hidden subscription packages were shown to everyone. A visibility field was added to SubscriptionModel / Subscription and the subscription screen now filters on it unless a query param opts in (hiddenSubscriptionPackageId const). (0055dd5a, 34a09c6d)
  • Added — logMarktagEvent() (core/utils/marktag_logger.dart): debugPrints every event’s full payload as one grep-able [MARKTAG] line before forwarding to the SDK. Uses debugPrint rather than dart:developer’s log, which drops/truncates long lines in the flutter run console. (34a09c6d)
  • Refactor: web_view.dart restructured (~313 lines). (5930e31f)
  • Chore: device_info_plus, share_plus, package_info_plus upgraded; SDK constraints moved to Dart 3.10.0 / Flutter 3.38.1; FVM pin updated. (0055dd5a)
  • i18n: “My Account” → “Account Settings”, “Account” → “My Account”, “App Version” → “V.”

iOS 3.0.70 · Android 2.0.97 (297) — 2026-06-14

Section titled “iOS 3.0.70 · Android 2.0.97 (297) — 2026-06-14”

The largest release in this range — the offline-download subsystem was rewritten.

  • Added — HLS download pipeline, replacing the old downloader. (da4c2510) New lib/data/services/hls/: download_orchestrator.dart, download_task_factory.dart, hls_manifest_parser.dart, local_playlist_writer.dart, asset_progress_tracker.dart, plus download_manager_impl.dart, content_entity_serde.dart, new DownloadRecord / DownloadStatusV2 entities, a DownloadManager interface, and a DownloadRowWatcher widget. Removed download_services.dart (983 lines), download_local_data_source.dart, download_repository_impl.dart, get_downloads.dart. CacheContentEntity reshaped (Hive adapter regenerated).
  • Added — download progress notifications. (7ad15874) download_progress_notifier.dart, flutter_local_notifications + permission_handler, and running / paused / error / complete / interrupted / multi-item strings in intl_en.arb + intl_bn.arb.
  • Added — download protection tip (download_protection_tip.dart): one-time dialog for aggressive-OEM battery managers, with a deep link into device settings.
  • Added — range-request support in the local playback server so seeking works on offline HLS. lib/domain/services/local_server.dart gained Range handling, extra media MIME types, and guaranteed response closure on exceptions; new LocalPlaybackServerController. (1d2f0af4)
  • Added — settings restructure. profile_settings.dart split into my_library_screen.dart, account_screen.dart, preferences_screen.dart; the old preference_screen.dart deleted. New strings: My Library, Account, Preferences, Support & About, Contact Us, Share App, App Version. (1d2f0af4)
  • Added — profile settings redesign. (7ad15874) Profile avatar list with add-profile, menu cards, bottom action row (share / rate / help / call support), version display and logout.
  • Added — Awards / Carnival entry point, gated on a new awards_enabled Remote Config flag, with an /awards deep link that shows the auth sheet first and drops the pending link if the user closes it without logging in. deeplink_services.dart, remote_config_service.dart, Award_Icon.svg. (7ad15874)
  • Fixed — Hive downloads migration could brick startup or corrupt progress. (9768c216)
    • A failed box wipe no longer persists the schema version, so the migration retries next launch instead of being skipped forever (the old CacheContentEntity shares typeId 1 with an incompatible field map, which throws on read).
    • Legacy download dirs are now detected via bare .ts / .m4s segments as well as master.m3u8, so partial old downloads get cleaned — stale segments were inflating the new tracker’s disk count and finalizing re-downloads prematurely.
    • _initHive deletes and recreates an unreadable downloads box instead of wedging every app start.
  • Fixed — account screen device card now routes to the purchase screen instead of the devices URL; unused purchase card removed from My Library. (7ad15874)
  • DownloadForegroundService.kt (new, 165 lines) + MainActivity.kt method-channel plumbing (+123), FOREGROUND_SERVICE_DATA_SYNC and notification permissions, service registration, values/ + values-bn/strings.xml. (7ad15874)
  • Removed the unused FOREGROUND_SERVICE_MEDIA_PLAYBACK permission. (9768c216)
  • AppDelegate.swift + Info.plist entries for the notification/download path; one stale Info.plist key removed in da4c2510.

iOS 3.0.69 · Android 2.0.93 (293) — 2026-05-24

Section titled “iOS 3.0.69 · Android 2.0.93 (293) — 2026-05-24”
  • Added — geo-targeted subscription bottomsheet, driven by a JSON Firebase Remote Config key subscription_geo_bottomsheet. New SubscriptionGeoBottomsheetConfig entity + RemoteConfigService.getSubscriptionGeoBottomsheetConfig() (falls back to .disabled() when RC is unavailable), new subscription_geo_bottomsheet.dart widget, wired into subscription_screen.dart and single_content_screen.dart. (ca790e3c, UI polish in 421133b8, spacing in c4ee8cea)
  • Fixed — trailer controls lifecycle. The player status listener was never removed when the controller instance swapped, and setState could run after dispose. lib/presentation/widgets/player/trailer_controls.dart reworked (~283 lines), added dispose() and mounted guards. (ca790e3c)
  • Fixed — UPI links opened via target=_blank were still lost. Added an onCreateWindow handler plus javaScriptCanOpenWindowsAutomatically: true, widened the regex from (upi) to (upi|intent), and added diagnostic logging when canLaunchUrl returns false. (c4ee8cea)
  • New assets announcement.png, danger_triangle.svg + image_constant.dart entries.
  • Tooling: .vscode/launch.json run configurations added. (421133b8)

iOS 3.0.68 · Android 2.0.91 (291) — 2026-05-19

Section titled “iOS 3.0.68 · Android 2.0.91 (291) — 2026-05-19”

Merge 458bac61 of feature/billdesk-upi-intent-webview.

  • Fixed — BillDesk UPI handoff was silently failing. Non-http URL interception in InAppWebView never launched upi:// / intent:// links, so UPI payments dead-ended. shouldOverrideUrlLoading in lib/presentation/pages/in_app_view/web_view.dart now hands off to launchUrl(externalApplication) (41631f3a), gated on a doc-verbatim (upi) regex so other non-http schemes fall through to ALLOW (f4342f86).
  • Added — Sentry. Initialized only when !kDebugMode and SENTRY_DSN is non-empty; Sentry Dio interceptor added to every DioApiProvider client. DSN / environment / release / sample-rate are String.fromEnvironment so CI can override per build. lib/main.dart, lib/core/network/dio_api_provider.dart. (27d04aa3)
  • Fixed — force-update prompt used the wrong minimum version on iOS. checkUpdate in splash_screen_bloc.dart parsed min_app_version_android on both platforms; now selects min_app_version_ios on iOS. (ab987523)
  • <queries> entries in AndroidManifest.xml so canLaunchUrl can resolve UPI apps under Android 11+ package visibility.
  • LSApplicationQueriesSchemes entries in Info.plist for the same reason.