Developing Text Post Publishing in a Mobile App
A text post is the most basic content in social apps. But "just TextField + Send button" works poorly: a user writes a long text, minimizes the app, returns — the draft is lost. Or types text with poor internet, hits "Publish," gets an error — and the same empty screen again. These details separate proper implementation from a quick one.
Text Editor and Formatting
Simple Variant
UITextView (iOS) or BasicTextField/OutlinedTextField (Compose) — if formatting is not needed. Must have: autocorrectionType, spellCheckingType, minimum height with auto-expansion up to maximum (5-6 lines). On iOS auto-expansion of UITextView — through NSLayoutConstraint on height with update in textViewDidChange.
With Formatting (bold, italic, lists)
UITextView + NSAttributedString — minimal variant for iOS. For a full-featured editor — RichTextKit (open source, Swift) or custom implementation on NSTextStorage. On Android — Spannable/SpannableStringBuilder with EditText, or Markwon if you need Markdown preview.
In Flutter, flutter_quill is popular — Delta format, supports image insertion, lists, headers. But adds ~2 MB to binary and requires Delta → backend-format serialization.
Store text on server in neutral format — HTML or Markdown — not in Delta and not in NSAttributedString-blob. Client converts when loading.
Drafts
Drafts are mandatory. Implementation: on every text change save to UserDefaults (iOS) or DataStore (Android) with 1-2 second debounce. Key — draft_post or draft_post_{channel_id} if draft is tied to specific context.
When opening post creation screen: check for draft → if exists, show UIAlertController "Continue draft?" or restore text immediately. After publishing or manual reset — clear.
On Flutter — SharedPreferences or Hive, update through debounceTime(Duration(seconds: 1)) in stream.
Publishing with Poor Internet
Optimistic update + retry queue — standard for social apps. When hitting "Publish":
- Generate local
client_post_id(UUID). - Immediately add post to feed with
pendingstatus (gray/semi-transparent indicator). - Send request to server. On success — replace
client_post_idwith serverid, remove pending indicator. - On error — show "Not sent" status with "Retry" button.
On Android for retry on network recovery use WorkManager with NetworkConstraint. On iOS — BGTaskScheduler for background retry or retry on NWPathMonitor event.
Limits and Validation
Character limit — display counter, don't block input until limit (Twitter approach: show -20 in red). Validate on server anyway — client validation is not protection.
Block empty publication: button active only when text.trimmingCharacters(in: .whitespacesAndNewlines).count > 0. On Compose — enabled = text.isNotBlank().
Mentions and hashtags in text — separate task (parsing @username and #tag with highlighting). If needed — implement through NSAttributedString/AnnotatedString with regex patterns and separate tap handlers.
Workflow Stages
Design post structure and API → UI editor with draft → publish logic with optimistic update → error handling and retry → offline scenario testing.
Timeline
Simple text editor with draft and retry — 2-3 days. With formatting, mentions, hashtags — 5-7 days. Cost calculated individually.







