Commit Graph

178 Commits

Author SHA1 Message Date
Evgeny df5ea3d460 android, desktop: new settings section design (#6777)
* android, desktop: new settings section design

* Section facelift: LIGHT canvas swap, equal padding, 2dp item dividers

- LIGHT canvas (themedBackground) now paints the off-white formula
  (bg.mixWith(onBackground, 0.95f)) so white cards read as raised.
  DARK/BLACK keep palette bg (cards already raised via founder's
  formula in Section.kt). SIMPLEX keeps its gradient.
- Section cards in LIGHT switch from formula to pure white via
  Color.White. DARK/BLACK keep the formula, unchanged.
- Section card horizontal padding equalized to 16dp on outer + inner
  for clean canvas-edge alignment. extraPadding (icon-indented rows)
  keeps DEFAULT_PADDING * 1.7f.
- 2dp dividers between rows inside section cards, color matches the
  per-theme canvas (SIMPLEX uses gradient bottom stop). Implemented via
  Modifier.drawBehind on each SectionItemView, gated by a private
  LocalInSectionCard CompositionLocal set true only by SectionView's
  inner Column — standalone SectionItemView usage (alerts, pickers)
  stays unaffected. Single canvas helper canvasColorForCurrentTheme()
  in Theme.kt is the source of truth for both canvas paint and divider
  color.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: paint item divider on top of clickable's hover indication

Previously sectionItemDivider() was inside the modifier val before
clickable, so the hover background drew over it inconsistently — on
hover the row's content area got a tinted overlay while the 2dp
divider area stayed at canvas color, creating visible contrast that
read as a "dark line below hovered row".

Moving the modifier to the end of the chain (after clickable+padding)
makes drawBehind paint after the hover indication, so the divider
color is consistently #F2F2F2-ish regardless of hover state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: trim section item horizontal padding to 15dp

CARD_PADDING (16dp) still drives outer card margin from screen edge.
Item content inside the card now uses CARD_ITEM_PADDING = CARD_PADDING - 1.dp,
giving the row text a slightly tighter horizontal inset that reads
better at the current card width.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Appearance: drop redundant 10dp spacer between Apply-to row and wallpaper preview

Before section facelift the spacer separated the Apply-to row from the
wallpaper preview block visually. With the new 2dp item divider drawing
under the Apply-to row that separation is already provided, and the spacer
leaves an awkward white gap between the divider and the preview.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: repurpose SectionDivider() as explicit 2dp canvas-color line; use in Appearance themes card

SectionDivider() composable had 0 callsites and used Material Divider
with horizontal inset (unused legacy). Repurposed to draw a 2dp
canvas-color Box matching the auto-divider style used by
SectionItemView, gated by LocalInSectionCard so it no-ops outside a
section card.

Use it in Appearance themes card between WallpaperPresetSelector
(custom composable, not a SectionItemView, so no auto-divider) and the
following content (Remove image / Color mode / Dark mode), providing
the visual separator the user expects between the theme grid and the
rows below it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Appearance: symmetric vertical padding around profile avatar row

ProfileImageSection's Row had Modifier.padding(top = 10.dp), giving 10dp
above the avatar and 0dp below — visibly asymmetric inside the card.
Changed to vertical = 10.dp so top and bottom padding match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* NetworkAndServers: move messages card footer/spacer out of SectionView

Before PR #6777 SectionView had no card chrome, so SectionTextFooter and
SectionDividerSpaced placed inside its content lambda rendered as plain
inline content. After the card chrome was added, the same code rendered
the footer caption and the spacer INSIDE the white card area, producing
an unwanted gap (and visible auto-divider tail) under Advanced network
settings.

Move both out of the SectionView lambda so the footer reads as a caption
below the card (iOS-style) and the spacer separates this card from the
next one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* DeveloperView: move card footer/bottom-spacer out of SectionView lambdas

Same pre-card-chrome pattern as NetworkAndServers: SectionTextFooter
("Show: Database IDs and Transport isolation...") and SectionBottomSpacer
were inside SectionView lambdas, so after PR #6777 added card chrome they
rendered inside the white card area — the footer caption sat inside the
first card and the 48dp bottom spacer appeared as an empty row at the
end of the deprecated-options card (after SimpleX links).

Move both out of the SectionView lambda so the footer reads as a caption
below the first card and the bottom spacer adds safe-area room after the
deprecated-options card (not inside it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ChatInfoView: move chat-ttl footer caption out of SectionView lambda

Same pre-card-chrome pattern: SectionTextFooter("Delete chat messages
from your device.") was inside the ChatTTLOption SectionView lambda, so
after PR #6777 added card chrome it rendered inside the card. Move it
out so the caption sits below the card iOS-style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ChatWallpaperEditor: wrap loose params in SectionView cards

In ChatInfo > Chat theme screen the wallpaper preset selector, the
wallpaper setup controls, the reset/set-default buttons and the
"Apply to" mode dropdown were rendered as loose composables on a gray
canvas — no card chrome, inconsistent with the rest of Appearance.

Wrap them in SectionView so they read as raised iOS-style cards:
- wallpaper preset selector + setup view → one card
- reset-to-global + set-default buttons → one card
- (advanced mode) Apply-to dropdown → one card
- (collapsed mode) Advanced-settings button → one card

CustomizeThemeColorsSection and ImportExportThemeSection were already
SectionView-wrapped and remain unchanged. UserWallpaperEditor (sister
function with similar layout, lines 28-220) is intentionally left
alone — user reported only the chat-theme entry point.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* GroupChatInfoView: render group members inside the same SectionView card as owner

Previously the members card showed only the current user (owner) and the
add-members button — the actual group members were rendered as separate
LazyColumn items() OUTSIDE the SectionView, so they sat on the gray
canvas without card chrome. Visually inconsistent: owner in a card,
everyone else floating.

Move filteredMembers.value.forEach { ... } INSIDE the SectionView lambda
so every member row is part of the same card as the owner. Drop the
explicit Divider() call (auto-divider handles it now). Move remember
key to member.groupMemberId so per-member state survives reorders.

Trade-off: lazy rendering of member rows is replaced with eager
composition inside a Column. For typical groups (<100 members) this is
imperceptible; very large groups may compose slower on open. Watching
for reports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ChatInfoView: move E2E encryption card spacer out of SectionView lambda

Same pre-card-chrome pattern: SectionDividerSpaced was inside the
single-row SectionView around the InfoRow, so after PR #6777 added
card chrome it rendered as a white gap inside the card (under the
auto-divider on the InfoRow), producing the "extra divider + gap"
the user reported.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ServersSummaryView: wrap Message reception sections in SectionView card

SubscriptionsSectionView and SMPSubscriptionsSection both rendered their
InfoRows + control item in a plain Column without card chrome — so on
the Servers info screen the "Message reception" section title sat above
loose rows on the gray canvas (no card), inconsistent with the rest of
the screen. Wrap the inner Column in SectionView so the rows get the
raised iOS-style card look. The custom header Row (title + subscription
status indicator) stays outside the card so the icon stays inline with
the title text.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Appearance: add missing SectionDivider import

f922d8fc introduced SectionDivider() call in the themes card but forgot
to add the per-symbol import. SectionView/SectionDividerSpaced etc. in
this codebase are imported individually (Section.kt declares them at
top level, not inside a package), so SectionDivider needs its own
import line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: fix item divider position — paint via drawWithContent at full row bottom

8050676b moved sectionItemDivider() AFTER clickable.padding() in the
modifier chain to make the line paint on top of clickable's hover
indication. Side effect: drawBehind then saw the size of the
padding-reduced content area, not the full row, so dividers rendered
15dp ABOVE the actual row bottom (in the middle of the row's bottom
padding zone) instead of at the row edge between adjacent items.

Fix: keep sectionItemDivider() in the modifier val BEFORE clickable/
padding (so size = full row outer bounds) AND switch from drawBehind
to drawWithContent { drawContent(); drawLine(...) } so the line is
painted AFTER the chain's content + hover indication draw. Both
goals satisfied: divider sits at the true row bottom AND paints on
top of hover overlay.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: bump hover ripple alpha to 0.08 on LIGHT theme for visibility against canvas

Default Compose Material 1 RippleTheme uses hoveredAlpha=0.04 for LIGHT,
producing a Black·0.04 overlay (~#F5F5F5) on white cards — visually 3
units per channel away from the off-white canvas (~#F2F2F2), so the
hover state blends into the canvas and the row looks unfocused.

Add a section-local SectionRippleTheme that mirrors Material's defaults
for everything except hoveredAlpha on LIGHT (raised to 0.08 → ~#EBEBEB
overlay, ~7 units delta from canvas — visibly distinct). Dark themes
keep Material defaults since their hover contrast is already adequate.

Provided via CompositionLocalProvider in all three SectionView variants
alongside LocalInSectionCard, so it scopes only to section card items.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ProtocolServerView: pad CustomServer address field inside its card

The TextEditor (144dp tall input) sat flush against the top and bottom
edges of its containing SectionView card on the New server screen.
Pass padding = PaddingValues(vertical = DEFAULT_PADDING_HALF) to the
SectionView so the field gets 10dp of breathing room top and bottom
inside the card.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* NetworkAndServers: move ConditionsButton into operators card; wrap Save servers in its own card

- "Review conditions" (ConditionsButton — a bare SectionItemView) was
  rendered between the operators card and the messages card on the
  canvas without card chrome. Move it inside the operators SectionView
  lambda after the operator rows, so it shares the card and gets a
  2dp auto-divider above it separating it from the operator list.
- "Save servers" (a bare SectionItemView further down) is now wrapped
  in its own SectionView so it reads as a single-item card matching
  the iOS-style facelift of the rest of the screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Appearance: fix Transparency truncation and SettingsActionItem horizontal padding

Two layout regressions from earlier facelift commits where slider/item
math assumed DEFAULT_PADDING (20dp) for inner card padding, but the
facelift uses CARD_PADDING (16dp outer) + CARD_ITEM_PADDING (15dp inner)
= 31dp per side instead of 20dp.

- Slider widthIn calc in AppToolbarsSection and MessageShapeSection
  used (maxWidth - DEFAULT_PADDING * 2) so the slider was ~22dp wider
  than it should be, shrinking the label Box (weight 1f) and clipping
  "Transparency" to "Transparenc". Switched to
  (CARD_PADDING + CARD_ITEM_PADDING) * 2.
- SettingsActionItemWithContent explicitly passed
  PaddingValues(horizontal = DEFAULT_PADDING) to its SectionItemView,
  overriding the new CARD_ITEM_PADDING default. That made any row using
  SettingsPreferenceItem/SettingsActionItem sit 5dp further inset than
  rows using plain SectionItemViewWithoutMinPadding — visible as a left
  indent on "Tail" relative to "Corner". Replaced with CARD_ITEM_PADDING
  so it matches.

Removed `private` from CARD_PADDING and CARD_ITEM_PADDING in Section.kt
to allow imports from other files (used the same way as SectionView etc.
are imported individually).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Appearance + Customize theme: bring loose items into cards, drop spurious spacer

Four small fixes on the same theme-related screens:

- Move "Customize theme" SectionItemView INSIDE the THEMES SectionView
  in AppearanceView so it sits in the same card as Color mode / Dark
  mode colors with an auto-divider above it.
- Wrap WallpaperPresetSelector (theme slots + chat preview) and the
  conditional Remove-image button in CustomizeThemeView with a
  SectionView so they read as a card, matching the Appearance themes
  card pattern. Add a SectionDividerSpaced after.
- Drop SectionSpacer() that sat between the Wallpaper tint row and the
  Sent message row inside WallpaperSetupView — auto-divider on the
  Wallpaper tint SectionItemView already provides separation; the
  30dp spacer rendered as extra empty padding inside the card.
- Wrap the Reset colors action in a single-item SectionView so it
  reads as its own card, matching the export/import card below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ServersSummaryView: wrap "Showing info for" dropdown in SectionView card

The user-selection ExposedDropDownSettingRow at the top of the
servers info screen was rendered loose on the canvas with no card
chrome. Wrap in SectionView so it reads as a card matching the rest
of the screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* GroupChatInfoView: move chat-ttl footer caption out of SectionView lambda

Same pre-card-chrome pattern as ChatInfoView (fixed in b1a1dad8):
SectionTextFooter("Delete chat messages from your device.") sat inside
the SectionView around ChatTTLOption, so it rendered inside the white
card after PR #6777 added card chrome. Move it out so the caption sits
below the card iOS-style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* NewChatSheet: render filtered contact list inside SectionView card

The "Contacts" header was a SectionView with empty content lambda, and
the actual contact rows were rendered as separate LazyColumn items
OUTSIDE the SectionView — so they sat on canvas without card chrome.

Move filteredContactChats.forEachIndexed { ContactListNavLinkView }
INSIDE the SectionView lambda in both OneHandLazyColumn and
NonOneHandLazyColumn so the contacts read as a single card matching
the iOS-style facelift.

Same trade-off as GroupChatInfoView members fix (fa29bb7a): lazy
rendering of contact rows replaced with eager composition inside a
Column. For typical contact lists (<100) imperceptible; very long
lists may compose slower on open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* AddGroupView/AddChannelView: wrap action buttons + toggles in SectionView card

In Create group and Create public channel screens the action buttons
(Create / Configure relays) and incognito toggle were rendered as loose
SectionItemViews on the gray canvas with no card chrome. Wrap them in
SectionView so they read as a single card matching the iOS-style facelift.
The display-name input above and the descriptive footer below stay
outside the card (text input keeps its own padding, footer reads as
caption).

Added missing `import SectionView` in AddGroupView.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* TagListView: wrap Add/Save list button in SectionView card

The "Add to list" / "Save list" action button in TagListEditor (opened
from chatlist "+" Add list) was a loose SectionItemView on the canvas
with no card chrome. Wrap in SectionView so it reads as a single-item
card. ChatTagInput stays as a form field above.

Added missing `import SectionView`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* UserAddressView: move "contacts remain connected" footer out; pad welcome message field; wrap Save in card

Three SimpleX address fixes:
- "Your contacts will remain connected" SectionTextFooter moved out of
  the DeleteAddressButton SectionView (was rendering inside the card).
- Address settings > welcome message field gets 10dp vertical
  contentPadding on its SectionView so the TextEditor doesn't sit flush
  against the card top/bottom.
- Address settings > Save action wrapped in its own SectionView so it
  reads as a single-item card.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* WelcomeView: wrap Create profile action button in SectionView card

The Create profile action SettingsActionItem at the bottom of the
Create profile screen was loose on canvas. Wrap in SectionView so it
reads as a single-item card matching the iOS-style facelift. The two
SectionTextFooter captions below stay outside the card.

Added missing `import SectionView`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ConnectMobileView: move footer + spacer out of "this device name" SectionView lambda

Same pre-card-chrome pattern: SectionTextFooter and SectionDividerSpaced
were inside the SectionView around DeviceNameField + multicast toggle,
so they rendered inside the white card after PR #6777 — visible as an
extra empty padding below the "Discoverable via local network" toggle
(the SectionDividerSpaced 10dp Spacer inside the card).

Move both outside the SectionView so the footer reads as caption below
the card and the spacer separates this card from the next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: suppress RippleTheme deprecation warnings (build was treating warnings as errors)

`androidx.compose.material.ripple.RippleTheme` and `LocalRippleTheme`
were deprecated in newer Compose Material in favor of the modern
Indication APIs. Our SectionRippleTheme override (a5b199660) hit those
deprecations and the project's Kotlin compiler flags treat warnings as
errors, breaking the build.

Add `@file:Suppress("DEPRECATION")` to Section.kt — narrow file-level
scope. Modern Indication-based ripple migration is a separate, larger
concern; suppress for now so the section hover-alpha override keeps
working.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: also suppress DEPRECATION_ERROR — RippleTheme is @Deprecated(level=ERROR)

Previous attempt (4bf981a6b) suppressed DEPRECATION but the Compose
library deprecated RippleTheme with level=DeprecationLevel.ERROR, which
requires the DEPRECATION_ERROR suppression key instead. Add both so
either severity is covered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: replace deprecated RippleTheme override with modern Modifier.hoverable + background

Drop SectionRippleTheme/RippleAlpha/LocalRippleTheme machinery (deprecated
in newer Compose Material, would not compile with the project's warnings-
as-errors policy without DEPRECATION_ERROR suppress, which is a code
smell). Replace with a Modifier.hoverable + Modifier.background pattern —
the modern Compose-native way to apply a hover overlay:

- New private @Composable Modifier.sectionItemHover() that:
  - returns Modifier as-is outside SectionView card (LocalInSectionCard = false)
  - inside a card, attaches its own MutableInteractionSource via .hoverable()
    and paints a transparent or onBackground@0.08-alpha background based on
    collectIsHoveredAsState

- Applied alongside .sectionItemDivider() in each SectionItemView modifier
  chain. Click ripple keeps coming from Modifier.clickable's own indication
  (default ripple, no changes there).

- Drop @file:Suppress deprecation lines; drop SectionRippleTheme object;
  drop ripple imports; drop LocalRippleTheme from CompositionLocalProvider
  calls in three SectionView variants.

Visual result identical to the previous attempt (hovered row gets a visible
gray overlay on LIGHT canvas), no deprecated APIs, no warnings-as-errors
fight. Click ripple unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: suppress sectionItemHover on disabled SectionItemView

sectionItemHover was applied unconditionally inside section cards, so a
disabled row would still show the hover overlay on mouseover —
misleading: the visible interactive feedback contradicts the disabled
state (no click reaction).

Add `enabled: Boolean = true` parameter; the helper now returns `this`
unchanged when `enabled = false`. The 3 SectionItemView family
functions that own a modifier chain pass `enabled = !disabled`.
SectionItemViewWithoutMinPadding inherits through SectionItemView delegation.

Non-clickable info rows (click == null but disabled = false) still get
the hover overlay — that's intentional cursor feedback matching iOS
Settings behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: lighten section item hover overlay from 0.08 to 0.05 alpha

0.08 read as too dark on white cards. Original Compose default 0.04
blended with the off-white canvas (#F2F2F2 vs ~#F5F5F5). 0.05 is the
midpoint — still visibly distinct from canvas (~#F2F2F2 canvas vs
~#F3F3F3 hover on white card) but no longer reads as a heavy box.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* RTCServers: wrap Configure ICE servers toggle in SectionView card

Your ICE servers screen had its Configure-ICE toggle and the description
text / editor / read-only display all directly in a raw Column with no
card chrome. Wrap the toggle row in SectionView so it reads as a card
matching the iOS-style facelift. The description text and the
TextEditor / read-only Surface stay in the same loose Column below
(they're a form/display block, not a settings row).

Removed the explicit `padding = PaddingValues()` on the
SectionItemViewSpaceBetween — inside SectionView it inherits
CARD_ITEM_PADDING by default which is what we want now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* NetworkAndServers: rewrite UseSocksProxySwitch via SettingsActionItemWithContent

UseSocksProxySwitch was a custom Row with hard-coded horizontal padding
of DEFAULT_PADDING (20dp) — but its neighbours on the messages card are
SettingsActionItem rows that go through SectionItemView with the new
CARD_ITEM_PADDING (15dp). 5dp icon misalignment between the SOCKS
toggle row and the rest, plus no auto-divider underneath since it
wasn't a SectionItemView.

Replace the custom Row with SettingsActionItemWithContent — same
icon + label + DefaultSwitch shape, now wrapped in SectionItemView so
it shares padding and auto-divider with siblings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* SocksProxySettings: move section text footers out of SectionView lambdas

Same pre-card-chrome pattern as elsewhere: two SectionTextFooter calls
("Disable onion hosts when not supported" and the proxy-auth footer)
were inside their SectionView lambdas in SocksProxySettings, so after
the card chrome was added they rendered inside the white cards as
inline content. Move both out so they read as captions below the
corresponding cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* SocksProxySettings: split UseOnionHosts so the dynamic description footer renders outside the card

UseOnionHosts wrapped its ExposedDropDownSettingRow and a dynamic
SectionTextFooter ("Onion hosts will be used when available." / similar)
in a Column, so when UseOnionHosts was called inside a SectionView
lambda the footer rendered inside the white card.

Split into two composables:
- UseOnionHosts — only the dropdown row (no longer wraps in Column)
- UseOnionHostsDescription — only the dynamic SectionTextFooter,
  called separately by the caller

Shared `onionHostsValues` is now a private @Composable val accessible
to both. In SocksProxySettings, UseOnionHostsDescription is now placed
AFTER the SectionView block (alongside the existing
"Disable onion hosts when not supported" caption) so the dynamic
description reads as a caption below the card.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: suppress hover on rows whose action is an inline control (switch/dropdown)

sectionItemHover used to show on every row inside a section card. But
rows where the action is an inline control (switch via PreferenceToggle,
dropdown via ExposedDropDownSettingRow) are not "interactive as a row"
— the user has to hit the actual control, not the whole row. Showing
hover on the whole row was misleading.

Add `clickable: Boolean = true` param to sectionItemHover; suppress when
false. SectionItemView and SectionItemViewSpaceBetween pass
`clickable = click != null`. SectionItemViewLongClickable keeps the
default (its click is non-nullable, always interactive).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section + Theme: lighten LIGHT canvas to 0.97; revert custom hover overlay

User feedback: the off-white canvas at 0.95 (#F2F2F2) read as too
dark. Two coordinated changes:

- canvasColorForCurrentTheme LIGHT branch: 0.95f → 0.97f. Canvas now
  #F7F7F7 (3% darker than white, was 5%). Still distinct from pure
  white card but lighter.

- Drop the custom sectionItemHover Modifier helper (and its hoverable
  + InteractionSource + background machinery). The reason for the
  custom hover was that the default Material 0.04-alpha ripple hover
  (#F5F5F5 on white card) blended with the old #F2F2F2 canvas. With
  the lighter canvas at #F7F7F7 the default hover #F5F5F5 is now
  visibly darker than canvas (2 units delta) — visible enough at
  Material default without our custom override.

Removed unused MutableInteractionSource and collectIsHoveredAsState
imports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: bump section item minHeight by 6dp (50 → 56)

User asked for taller settings rows. Bump the default minHeight in
all four SectionItemView family functions from DEFAULT_MIN_SECTION_ITEM_HEIGHT
(50dp) to DEFAULT_MIN_SECTION_ITEM_HEIGHT + 6.dp (56dp).

Scoped to SectionItemView callers only — does not touch the global
DEFAULT_MIN_SECTION_ITEM_HEIGHT constant, so non-section callers
(ChatItemInfoView, ComposeContextProfilePicker, TagListView,
UserPicker) keep the 50dp baseline.

Callers that pass explicit minHeight (e.g. 54dp in GroupChatInfoView
members) are unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Move SectionTextFooter / Spacer out of cards in 5 screens

Fixes from the user's verified list of misplaced footers/spacers:

- ChatInfoView: SimpleX address footer ("You can share this address
  with your contacts to let them connect with you.") moved out of the
  address SectionView lambda.
- GroupMemberInfoView: same string for member address.
- Appearance: SectionSpacer in the Image-wallpaper branch (after
  "Remove image" button) removed — it created 30dp empty padding
  inside the THEMES card only when a custom image was selected.
- NotificationsSettingsView: Xiaomi battery-optimization footer
  ("Xiaomi devices: please enable Autostart...") moved out of the
  notifications SectionView lambda (visible only on Xiaomi devices
  in Periodic/Service notification mode).
- ConnectMobileView: dropped the 20dp Spacer that sat inside the QR
  SectionView after the developer-tools "Share link" row — visible
  as extra padding below Share link inside the card.

Same pre-card-chrome pattern as other moves: helpers placed inside
SectionView lambdas before PR #6777 rendered fine when SectionView was
a plain Column; after card chrome they render inside the white card.
Moved them outside so footers read as captions and spacers actually
separate cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate views: move all SectionTextFooter / SectionSpacer out of SectionView lambdas

Same pre-card-chrome pattern as elsewhere. MigrateToDevice (4 footers)
and MigrateFromDevice (9 footers + 1 SectionSpacer in error view)
historically wrote captions and inter-card spacers inside their
SectionView content lambdas. After PR #6777 added card chrome these
rendered inside the white cards.

MigrateToDevice fixes (4 footers, one per sub-view):
- Confirm network settings footer
- Database init failed retry footer
- Archive import failed retry footer
- Passphrase entering dynamic footer

MigrateFromDevice fixes (9 footers + 1 SectionSpacer):
- ChatStopFailed view footer
- Passphrase confirmation footer
- Upload confirmation footer
- Upload failed retry footer
- Link shown view: archive-will-be-deleted + choose-migrate footers
- Finished view: 2 warning footers (must-not-use-two-devices,
  using-on-two-devices-breaks-encryption)
- Implicit SectionSpacer at ChatStopFailed view also moved out

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section + ChatListNavLink.android: align in-card chat row divider with desktop; canvas to 0.94

Two changes:

1) Theme.kt LIGHT canvas: 0.97f → 0.94f (#F0F0F0). User wants more
   contrast against cards. With Material's default 0.04-alpha hover
   (#F5F5F5) this puts hover LIGHTER than canvas by 5 units — unusual
   direction but it's the user's call; they'll evaluate visually.

2) ChatListNavLinkView.android: when rendered inside a SectionView card
   (e.g. contact list inside NewChatSheet after the forEach-into-card
   refactor), use SectionDivider() — same 2dp full-width canvas-color
   divider as desktop. Outside a card (main chat list), fall back to
   the original Material `Divider(Modifier.padding(horizontal = 8.dp))`
   so unchanged for that context.

3) LocalInSectionCard made `internal` so the android-specific file can
   read it. Same pattern as LocalAppColors etc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Section: bump section item minHeight by 2dp more (56 → 58)

* GroupWelcomeView: wrap message editor/preview and buttons in SectionView cards

* GroupLinkView: wrap action items below QR in SectionView card

* Section: align InfoRow / IndentedInfoRow horizontal padding with CARD_ITEM_PADDING

InfoRow defaulted to DEFAULT_PADDING (20dp), but card chrome adopted CARD_ITEM_PADDING (15dp) for SectionItemView and InfoRowTwoValues. Inside a card, rows of different kinds visibly jumped left/right. Bring InfoRow and its IndentedInfoRow variant onto the same baseline.

* ServersSummaryView: align Message reception header indent with other section headers

* ServersSummaryView: split SMP/XFTP server summary into separate top-level cards

The summary layouts wrapped Stats / Subscriptions / Sessions inside the outer Server address SectionView, which produced nested cards and pushed the Statistics 'Starting from...' footer inside a card. Unnest them so each section is its own card with proper spacing and the footer renders outside.

* CreateProfile: add vertical gap between profile fields and Create profile action card

* UserPicker: wrap menu options in SectionView cards (SecondSection + GlobalSettingsSection)

* UserPicker: gate SectionView card wrap on Android only

Desktop UserPicker doesn't have a canvas background, so white cards on the white surface were invisible and the existing desktop divider above inactive users looked stray next to the SectionItemView mini-dividers.

* Revert "UserPicker: gate SectionView card wrap on Android only"

This reverts commit be365e55ae.

* UserPicker: use canvas color on desktop and split SecondSection around inactive-users grid

Desktop background was MaterialTheme.colors.surface (white) so the SectionView cards introduced earlier were invisible. Switch to canvasColorForCurrentTheme() to match Android.

Drop the explicit Divider above the inactive-users grid: split SecondSection into two SectionView cards with the avatar grid between them so the section dividers come from the cards themselves.

* ChatListNavLinkView.android: fix LocalInSectionCard import path

LocalInSectionCard is declared in Section.kt which has no package (root package), so it must be imported as 'import LocalInSectionCard', not as 'chat.simplex.common.views.helpers.LocalInSectionCard'.

* UserPicker: merge SecondSection + GlobalSettings into one card on portrait

Both Android and desktop portrait now show address, preferences, (desktop: inactive-users grid), profiles, link mobile / use from desktop, and settings inside a single SectionView card. Desktop landscape keeps the side-by-side two-card layout.

* ChatInfoImage: default placeholder icon color to secondary

secondaryVariant is near-white (#F1F2F6) and disappears against the gray canvas. Use the visible secondary tone instead so default avatars without a photo are legible on both card and canvas backgrounds.

* UserPicker: align item padding with Settings, add divider after inactive-users grid

UserPickerOptionRow no longer applies extraPadding on desktop, and the Settings row uses default SectionItemView padding instead of its own. Both now match the CARD_ITEM_PADDING used in Settings screens. After the inactive-users avatar grid in the unified card, paint a SectionDivider so it visually separates from Your chat profiles.

* ChatInfoImage: place default avatar one canvas-shade darker than the canvas

secondary (#8B8786) was too dark. Use background mixed with onBackground at 0.88 — same darkening recipe as canvasColorForCurrentTheme uses with 0.94, applied a step further. On LIGHT this lands near #E1E1E1: 15 units darker than the canvas, matching how the canvas sits 15 darker than white.

* Appearance: symmetric vertical padding around Font size and Zoom preview tiles

Both rows used Modifier.padding(top = 10.dp) so the tile hugged the bottom of the SectionView card. Switch to padding(vertical = 10.dp) to match the symmetric padding used by ProfileImageSection.

* ChatInfoImage: dark themes use secondaryVariant for default avatar to match UserPicker

The mixWith canvas-darkening formula only lands well in LIGHT. For DARK / BLACK / SIMPLEX, fall back to secondaryVariant, which UserPicker already uses for the active profile avatar — keeps placeholder avatars consistent across the app on dark themes.

* Section: tighten icon-to-text spacing in TextIconSpaced by 2dp

* ChatInfoImage: lighten LIGHT default avatar to halfway between white and canvas

* ChatInfoView: hide Servers section header when there is no server content

When both chatSubStatus and cStats are null, the SectionView body rendered as empty (zero-height card) but the SERVERS title still appeared, leaving an orphan header between E2E encryption and Clear chat. Gate the whole section on having at least one of the two.

* GroupLink / WelcomeMessage: use SectionDividerSpaced between adjacent cards

Three places had adjacent SectionView cards with no spacer (GroupLinkView QR + actions, WelcomeMessageView non-owner preview + copy), or used a one-off Spacer(8.dp) instead of the conventional helper (owner mode-button card). Replace with SectionDividerSpaced() so all between-card gaps live behind one helper.

* Chat info / Group info: use full spacing between two title-less cards

ChatInfoView (Contact prefs/Send receipts/Chat theme → Delete messages) and GroupChatInfoView (Member reports → Edit group profile) both used SectionDividerSpaced(maxBottomPadding = false) = 10dp between two cards that have neither header nor footer touching the gap, so the tight variant wasn't justified. Switch to the default 20dp.

* remove diff noise

* Sections: drop .uppercase() from all section / header titles

Source string resources are already in sentence case (e.g. "Profile images", "Message reception"). The .uppercase() calls forced them to ALL CAPS, which is the Android settings convention but conflicts with the iOS-style facelift. Remove the call everywhere so headers render as in the source.

* Section: shrink icon-to-text spacing to 5dp (-3dp from previous 8dp)

* Appearance: shrink ColorModeSwitcher tap target to keep UserPicker Settings row at standard 58dp height

* UserPicker.android: align profile boxes with menu card left edge (CARD_PADDING)

* ChatListNavLinkView.desktop: restore chat list dividers outside SectionView

Commit 633e0f414 made SectionDivider() a no-op outside SectionView card, which removed the desktop chat list dividers (the list is not wrapped in a SectionView). Mirror the Android conditional: SectionDivider in-card, padded Divider otherwise.

* UserPicker: restore SectionView wrap around desktop active-profile row

Commit 3a7118235 extracted the profile out of its original SectionView when wrapping the menu in its own card. Without the card chrome the profile shifted to the screen edge instead of sitting at CARD_PADDING like the menu below. Wrap it back in SectionView and add SectionDividerSpaced before the menu card.

* Strings: convert section-title resources from ALL CAPS to sentence case

26 section header strings used as SectionView titles (SETTINGS, CHAT DATABASE, HELP, SERVERS, etc.) were stored ALL CAPS in source. The .uppercase() removal commit did nothing for them. Convert the source values to sentence case with proper-noun preservation (SimpleX, SOCKS). LIVE and OK stay all-caps (status badge and button).

* UserPicker: add top spacer above active profile card and tighten its left padding

Card was flush against the sheet's top edge; add DEFAULT_PADDING spacer above. Left padding inside the card was 16dp while the avatar (60dp) sat in an 80dp minHeight row so visual top/bottom were ~10dp — bring start down to 10dp so the photo sits equidistant from card top, bottom and left.

* Section: bump card-title font size from 12sp to 14sp across all 3 SectionView variants

* ServersSummaryView: bump Message reception custom header to 14sp to match other card titles

* Sections: add SemiBold weight to card titles across all 4 places

* Sections: drop card-title weight from SemiBold to Medium (W500)

* ServersSummaryView: Message reception header bottom padding 5dp -> 8dp to match SectionView default

* Strings: convert group_info_section_title_num_members to sentence case

* Strings: convert settings_section_title_interface to sentence case (Interface)

* Revert UserPicker to pre-card-wraps state per founder's request

Restore UserPicker.kt and UserPicker.android.kt to their state at 43855ae07
(before commit 3a7118235 introduced SectionView wraps). The founder asked in
chat to keep UserPicker out of the cards facelift — undo all of our changes
to it, including the followup tweaks (avatar padding, divider above grid,
active-profile wrap, etc.) and the founder's own followup cleanup 23b0e41d8
which only existed to refactor our wraps.

* Section / Theme: extract sectionCardColor() helper

Three SectionView overloads were each computing the same cardColor inline:
if (CurrentColors.value.base == DefaultTheme.LIGHT) Color.White
else MaterialTheme.colors.background.mixWith(...). DRY violation paired with
the canvasColorForCurrentTheme() helper that already covers the canvas side
of the same theme split. Add a sectionCardColor() function in Theme.kt and
collapse the 3 inline formulas to one call.

* Theme: document why canvasColorForCurrentTheme reads CurrentColors.value directly

Reviewer asked why this helper uses CurrentColors.value.base instead of the
Compose MaterialTheme/CompositionLocal route. Reason is that the helper is
intentionally callable from both @Composable bodies and DrawScope (inside
sectionItemDivider's drawWithContent), and DrawScope can't invoke @Composable
getters. Add a paragraph to the doc-comment so future readers don't try to
'fix' it back to MaterialTheme.colors and break the divider draw path.

* ConnectMobileView: collapse double blank line left over from move-footer edit

* Sections: normalize redundant SectionDividerSpaced flag combinations

After founder simplified SectionDividerSpaced to one Spacer height (any flag
true -> DEFAULT_PADDING; both false -> DEFAULT_PADDING_HALF), many call sites
still pass combinations like (maxTopPadding = true) or
(maxTopPadding = true, maxBottomPadding = false) that all produce the same
20dp gap as the default. The flag names no longer match what they do —
reviewer flagged this as misleading.

Collapse all call sites to two canonical forms: SectionDividerSpaced() for
the 20dp gap, SectionDividerSpaced(maxBottomPadding = false) for the 10dp
tight gap. Behavior identical. Function signature kept (founder's API).

* NewChatSheet: render filtered contacts in search mode (regression fix)

Commit 3a9ece8d1 moved contacts forEach inside the if-branch and made the
else-branch fall back to NoFilteredContactsItem. That broke search: when
the user typed text and the filter returned non-empty results, the
if-condition (filtered.isNotEmpty() && searchText.isEmpty()) was false,
the else ran NoFilteredContactsItem, NoFilteredContactsItem's internal
guard saw a non-empty filter and rendered nothing — search results disappeared.

Restore three-way branching with when{}: header + contacts in card when
no search; contacts in plain card when search has matches; NoFilteredContactsItem
when filter is empty. Applied at both OneHandLazyColumn and the regular layout.

* GroupChatInfoView: keep Invite + owner in card, render members as lazy items

fa29bb7a7 put filteredMembers.value.forEach inside the same SectionView as
the Invite button and the owner row to get a unified card visual. That
sacrificed lazy rendering — all members composed at once, hurting big-group
scroll perf. Founder asked to bring lazy back.

Compromise: keep Invite + (search row) + owner row inside the SectionView
card (the 'hero' rows). Move the rest of the members out to a sibling
items(filteredMembers.value, key = { it.groupMemberId }) call in the
parent LazyColumn — bare SectionItemViewLongClickable rows below the card,
lazy-composed by LazyColumn.

* ChatInfoImage: LIGHT default avatar at midpoint of white card and gray canvas

Was at 0.91 mix (~#E8) — designed to sit 'below' the white card, but on the
~#F0 canvas it nearly blended (delta ~8). Switch to 0.97 mix (~#F7), which
is the geometric midpoint between #FF (white card) and ~#F0 (canvas) and so
sits at equal absolute contrast against either background.

* MemberProfileImage: use defaultProfileIconColor instead of secondaryVariant

MemberProfileImage hard-coded color = MaterialTheme.colors.secondaryVariant
as default, which is LightGray (#F1F2F6) on LIGHT — slightly bluish and
nearly invisible against the ~#F0F0F0 canvas. Reuse the defaultProfileIconColor()
helper so the LIGHT default matches the rest of the app (midpoint between
canvas and white card), and DARK themes keep their palette secondaryVariant.

defaultProfileIconColor() in ChatInfoImage.kt promoted from private to file-
level visibility so it can be referenced from GroupMemberInfoView.

* ProfileImage colors: split into card vs canvas variants

Revert defaultProfileIconColor back to 0.91 mix (~#E8) — that's the right
amount of contrast against a white SectionView card. Add a sibling helper
defaultProfileIconColorOnCanvas() at 0.85 mix (~#D9), which sits 23 units
below the ~#F0 canvas — same absolute contrast as the card variant achieves
on white.

Switch MemberProfileImage default from defaultProfileIconColor to the canvas
variant. Member avatars almost always render on canvas (chat list rows,
chat-bubble author avatar, group members list outside the card, channel
members, channel relays). Callers that need the card variant pass an
explicit color.

* GroupChatInfoView: move owner row out of the members card into the lazy list

Per review #1: card holds only Invite + (optional) search; the user-as-owner
row joins the same lazy column as the rest of the members, picking up the
canvas-variant avatar color through MemberProfileImage's updated default.

* Revert "ProfileImage colors: split into card vs canvas variants"

This reverts commit 379f84a4ae.

* Revert "MemberProfileImage: use defaultProfileIconColor instead of secondaryVariant"

This reverts commit bea3f24664.

* Revert "ChatInfoImage: LIGHT default avatar at midpoint of white card and gray canvas"

This reverts commit 05fbd6e0b1.

* Theme: darken LightColorPalette.secondaryVariant from #F1F2F6 (LightGray) to #E0E0E0

Old value (LightGray = #F1F2F6) was nearly invisible against the ~#F0F0F0
canvas — slightly bluish hue, ~1-2 units of contrast. The new #E0E0E0 sits
~16 units below canvas and ~31 below white card, visible on both. Affects
all LIGHT-theme avatar placeholders, UserPicker icons, DevicePill borders
and a handful of subtle UI surfaces using secondaryVariant.

* Card-less screens: paint background with Material surface

Form-only and link/QR screens have no card sections — the off-white canvas
under them just adds an extra visual layer with nothing to lift. Switch
their background to MaterialTheme.colors.surface (white on LIGHT, palette
surface on DARK/BLACK/SIMPLEX) so the screen reads as a single sheet.

Two patterns by container:
- 11 ModalView callsites get background = MaterialTheme.colors.surface.
- 4 screens rendered inside someone else's ModalView (GroupLinkView,
  HiddenProfileView, TagListView, UserProfilesView) wrap their root
  ColumnWithScrollBar in Box(Modifier.fillMaxSize().background(...))
  so they own their background regardless of caller.
- 1 BottomSheet root (CreateProfile in WelcomeView) gets background on
  the fillMaxSize Box.

Touched screens: Create profile, Create first profile (mobile/desktop),
Create group, Create channel (3 wizard steps), Edit group profile,
Group link, Add welcome message / Welcome message, Edit own profile,
Hide profile, Tag list editor, Your chat profiles, Add server,
Add chat relay (new variant only — Edit relay stays settings-style).

* NewServerView: add missing MaterialTheme import after previous commit

* Revert "GroupLink / WelcomeMessage: use SectionDividerSpaced between adjacent cards"

This reverts commit 29be15404f.

* Revert "CreateProfile: add vertical gap between profile fields and Create profile action card"

This reverts commit 43855ae07d.

* Revert "WelcomeView: wrap Create profile action button in SectionView card"

This reverts commit c61ea01092.

* Revert "AddGroupView/AddChannelView: wrap action buttons + toggles in SectionView card"

This reverts commit 4d9319d12a.

* Revert "GroupLinkView: wrap action items below QR in SectionView card"

This reverts commit f2ef38092a.

* Revert "GroupWelcomeView: wrap message editor/preview and buttons in SectionView cards"

This reverts commit edb3495a8f.

* Revert "TagListView: wrap Add/Save list button in SectionView card"

This reverts commit c25f36a900.

* UserProfilesView: drop SectionView wraps to remove card chrome

The Your-chat-profiles screen is now on white surface bg; the SectionView
cards (founder's original from PR #6777) painted white-on-white and only
contributed padding. Unwrap the two SectionViews (hidden-profile reveal
button + main profiles list) so the rows render directly inside the
ColumnWithScrollBar without card chrome.

* NewChatSheet: use standard 20dp gap between cards instead of tight 10dp

* WelcomeMessageView/GroupChatInfoView: unify owner button row, restore member dividers

WelcomeMessageView: drop SectionView wrap on SaveButton so all three
owner-mode action rows (Edit/Preview, Copy, Save) render uniformly as
loose rows on canvas, matching the post-revert direction of the
card-chrome cleanup.

GroupChatInfoView: restore per-item Divider() in the members lazy list
(lost during card-chrome experimentation). Owner row stays attached
to the "N members" card by design; divider appears between owner and
first lazy member, and between each subsequent member.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Strings: sentence case for 29 section-title keys across all locales

Base file was converted in 8292a815f / de36f1f40 / 314384b69 but other
locales still rendered titles like SETTINGS, НАСТРОЙКИ, EINSTELLUNGEN,
PARAMÈTRES, USTAWIENIA, ÎMPOSTAZIONI in ALL CAPS. Bring every locale to
sentence case with a single sweep.

Implementation: Python script (/tmp/fix_uppercase_locales.py) walks every
non-base locale dir, finds the 29 key strings, and rewrites them when the
value is entirely uppercase (no lowercase letter). Placeholders like %1$s
are preserved as-is; SimpleX and SOCKS are kept as proper nouns after the
lowercase pass. Values already in sentence case, empty, or in scripts with
no case distinction are left alone.

540 string changes across 33 locales (ar, bg, ca, cs, da, de, el, es, fa,
fi, fr, hr, hu, in, it, iw, ja, ko, ku, lt, nb-rNO, nl, pl, pt, pt-rBR,
ro, ru, th, tr, uk, vi, zh-rCN, zh-rTW). Locales bn, hi, ml, sv, lv had
nothing to change.

* UserProfilesView: use Divider() between rows (SectionDivider no-op outside SectionView)

* ShareListView: use MaterialTheme.colors.surface background (Forward picker)

* ChatItemInfoView: white surface background + drop SectionView card wraps

Message info screen (right-click → Info on desktop) had off-white themedBackground
canvas with white SectionView cards inside. Switch to MaterialTheme.colors.surface
background and replace 7 SectionView wraps with plain Column (preserving the
contentPadding the SectionViews had) — content reads as a single sheet, no
ghost card edges on white-on-white.

* Card-less screens batch 2: surface bg for conditions + how-to-use + about + version

Six more screens get white surface background to match the form-screen visual:

- UsageConditionsView (Network & servers → Review conditions): root
  ColumnWithScrollBar gets .background(surface).
- SingleOperatorUsageConditionsView (operator-conditions modal opened from
  enabling an operator): same.
- HowItWorks (Settings → How to use it): root Column gets .background(surface).
- WhatsNewView (Settings → What's new): ModalView gets background = surface.
- SimpleXInfoLayout (Settings → About SimpleX Chat): conditional on
  onboardingStage == null so the onboarding entry keeps its themedBackground
  while the settings entry switches to surface.
- VersionInfoView (Settings → App version): root ColumnWithScrollBar gets
  .background(surface).

* fix language strings

* fix contact list to be lazy

* more language fixes

* fix greek

* fix indentation

* refactor and simplify

* remove dividers

* background for settings pages with cards

* fix section titles

* remove footers outside of section cards

* move footers out of cards

* fix appearance etc

* fix members lists, add background

* appearance

* reduce paddings inside cards

* paddings

* more paddings

* card item paddings

* fix paddings

* toolbar color

* more toolbar color

* fix toolbar

* add padding

* refactor modals hierarchy

* more cards

* more cards

* fix theme

* split walpaper settings to two sections

* better grid

* grid

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: another-simple-pixel <anton.m.egorov@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:45:02 +01:00
sh c165663555 desktop: prevent duplicate launches (#6979)
* desktop: prevent duplicate launches

Acquires a file lock and listens on a loopback ServerSocket in dataDir.
A second launch signals the running instance to restore its window and
exits silently. See plans/2026-05-13-desktop-single-instance.md.

* desktop: un-minimize window in showWindow

toFront() does not un-minimize a JFrame on any AWT platform. Clear the
ICONIFIED bit so a minimized window restores; preserves MAXIMIZED_BOTH.
Also fixes the same case when restoring from the tray icon.

* desktop: move showWindow from DesktopTray to DesktopApp

It has callers outside the tray (single-instance signal) and belongs
next to simplexWindowState, which it operates on.

* simplify

* refactor

* desktop: start show-file watcher when choosing minimize from first-close dialog

The handleCloseRequest path already starts the watcher when minimizing to
tray; the Ask-dialog path did not, so the first-time user who picks
"Minimize to tray" got a hidden window with no signal handling — a
duplicate launch would not restore it.

* desktop: always watch for duplicate-launch signal, drop hung-instance alert

The watcher now runs for the JVM lifetime once the lock is acquired,
not only when minimized to tray. Duplicate launches always restore the
primary's window (un-minimize, un-tray-hide, toFront) instead of being
silently dropped when the primary is not minimized.

Drops the "may be hung, start anyway?" popup and the two strings — that
fallback was needed only because the watcher could miss signals. With
the always-on watcher there is no scenario where the primary fails to
consume simplex.show, so the escape hatch becomes dead code.

* desktop: alert when primary's watcher doesn't consume the show file

Restores the "another instance may be running" alert. Every duplicate
launch waits up to 1s for the primary's watcher to delete the show file
it just created. If the file is consumed within the window, the
duplicate exits silently. If still there after 1s the primary is hung
and the alert fires.

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-05-18 09:15:20 +01:00
sh 334a50dda5 desktop: add tray support (#6970)
* plans: design and implementation plan for desktop tray icon

Adds a system tray icon to the SimpleX desktop app with first-close
dialog and an Appearance toggle. Covered: minimize-to-tray on Linux,
Windows, and macOS via ComposeNativeTray; tri-state CloseBehavior
preference; unread-dot icon swap; show/quit menu.

The design plan covers the user-facing behavior, library choice
rationale (AWT/Compose Tray is broken on stock GNOME per JDK-8322750;
ComposeNativeTray uses platform-native APIs and is maintained), and
out-of-scope items. The implementation plan splits the work into 8
incremental commits, each leaving the build green.

* desktop: add CloseBehavior preference

* plans: switch tray to built-in Compose Tray with GNOME probe

* desktop: branch close handler on CloseBehavior preference

* desktop: first-close dialog for tray choice

* desktop: tray icon assets and menu strings

* desktop: system tray icon with show/quit menu

* desktop: unread indicator on tray icon

* desktop: Appearance toggle for minimize-to-tray

* desktop: tray feature fixes from audit

- Scope closedByError per application iteration; set before dispatchEvent.
- Short-circuit Ask to Quit when tray is unavailable.
- Sum users.unreadCount (pre-aggregated) instead of iterating chats.
- Replace dialog's captured lambdas with a top-level flag and
  ApplicationScope extension; wrap in SimpleXTheme.
- Probe SystemTray with real add/remove off the EDT.
- Drop duplicate ic_simplex_tray.svg; nudge unread dot to cy=34 to
  stop the r=6 circle clipping at the viewBox bottom.
- Use mkSafeEnumPreference, PreferenceToggle, SectionTextFooter.

* plans: sync desktop tray plans with implementation

* desktop: render close-behavior popup via AlertManager

Replaces the bespoke DialogWindow with AlertManager.shared.showAlertDialogButtonsColumn —
same in-app surface as e.g. the link-previews opt-in alert. Drops isAskingCloseBehavior,
the CloseBehaviorDialog Composable, the resetAskCloseBehavior helper, and the per-iteration
reset call: the alert's lifecycle is now bounded by AlertManager's single slot, so a crash
mid-dialog gets cleanly overwritten by the crash report.

* desktop: reset closeBehavior with 'Reset all hints'

Generalises AppPreferences.hintPreferences to a heterogeneous List<HintPref>
so non-Boolean prefs can participate. Adds closeBehavior to the list, so
'Reset all hints' brings the first-close dialog back.

* desktop: skip muted profiles in tray unread sum

Active profile still counts so the user can see their own unread; non-active
muted profiles contribute zero.

* desktop: dark-theme tray icons

Adds ic_simplex_tray_light and ic_simplex_tray_dot_light — copies of the
existing tray SVGs with the navy back-X swapped to white. Picks the variant
via isInDarkTheme() so the icon stays visible against dark tray backgrounds.
2026-05-13 08:58:42 +01:00
Narasimha-sc 5d597faf7e desktop: pick a free port for the call server if 50395 is in use (#6963)
* desktop: pick a free port for the call server if 50395 is in use

startServer() bound a hard-coded port (50395); when it was already in use,
NanoWSD threw "BindException: Address already in use: bind" and the call
failed. It now falls back to an OS-assigned free port, and WebRTCController
opens the browser at the actually-bound port (server.listeningPort) -- still
50395 in the normal case, so browser camera/mic permission stays put.

* plans: justify call server port-bind fix
2026-05-12 10:12:39 +01:00
Narasimha-sc 8c9c6471a7 desktop: fix RTL text rendering under the send button (#6906)
* desktop: fix RTL text rendering under the send button (#4137)

The chat composer's text field reserved 50dp on the wrong horizontal side
when an RTL message was typed under an LTR system locale: BiDi auto-detection
right-aligned the text onto the BottomEnd edge where the send button sits,
hiding the first characters as they were typed.

The padding was originally written inside the CompositionLocalProvider(
LocalLayoutDirection provides Rtl) scope (#4675), where start resolved to
the right edge for RTL paragraphs. The "edge to edge design" refactor
(#5051) lifted the modifier out of that scope onto the outer BasicTextField,
so start began resolving against the global LTR direction and the
reservation drifted to the left.

Always reserve on the global end - the same side Alignment.BottomEnd in
SendMsgView resolves to - so the reservation tracks the send button
regardless of locale or typed-text direction. Behavior is byte-identical
for LTR text and for any RTL-locale combination; only the buggy
"RTL text + LTR system locale" pair changes.

* desktop: minimise diff of RTL fix to 2 lines (#4137)

The previous commit (bfc111cc6) renamed/removed several helper locals
and rewrote the comment block alongside the behaviour change. The
behaviour-changing part is just two lines: making startPadding always
0.dp and endPadding equal to startEndPadding.

Restore the surrounding code (startEndPadding name, startPadding decl,
PaddingValues argument, .padding modifier, and the original two-line
comment) to its master form so the PR's only effect on master is the
two-line fix.

Behaviour: cases 1, 3, 4 of the locale x text matrix are byte-identical
to master. Only case 2 (LTR locale + RTL text) flips the reservation
from the wrong side to the correct side.

* plans: desktop RTL composer fix (#4137)

* plans: align with surgical 2-line fix in PR (#4137)
2026-05-08 11:10:14 +01:00
Evgeny ab2d036301 android, desktop: reduce timeout and do not use hardward acceleration for video preview generation (#6924)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-04-30 08:37:54 +01:00
Narasimha-sc d49ab88e66 desktop: fix Windows per-app volume reset on video playback (#6852)
VideoPlayer's mediaPlayerReady listener called mediaPlayer.audio().setVolume(100)
on every freshly created VLC player. On Windows, VLCJ routes setVolume through
WASAPI's ISimpleAudioVolume, which is the per-app entry in the Windows Volume
Mixer — so every video playback snapped SimpleX Chat's mixer volume back to 100%,
overriding the user's own setting.

The call was also redundant: VLCJ's default volume for a new MediaPlayer is
already 100, and the only path that previously used setVolume (enableSound) has
been disabled since VLCJ issue #985 ("Impossible to change volume for only one
player. It changes for every player.").

Dropping the setVolume(100) line fixes the Windows regression without changing
playback loudness on any platform. AudioPlayer / SoundPlayer / CallSoundsPlayer
use a singleton VLC player and never called setVolume, so voice messages and
ringtones are unaffected.

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-04-21 20:10:50 +01:00
Evgeny 035a2f954c ui: new UX for making connections after / as part of onboarding (#6753)
* ui: additional images, views for making connections and creating groups (#6750)

* ios: setup for additional assets

* ios build config

* header

* fix

* update layout

* more views with images

* layout

* layout

* android images and view

* fix path

* fix desktop

* fix desktop build

* smaller image

* layout

* more layout

* more kotlin views

* group layout

* padding

* create group layout

* more create group layout

* layout

* tweak layout

* more tweak

* config

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

* ios: connecting as part of onboarding (#6754)

* ios: implementation of "connecting" cards

* ios: revision

* fix flip

* fixes

* fix frame

* replace nav stack with tab view

* rename

* update gradient and card label material

* fix gradient

* debug

* remove debug code

* update card labels

* card label layout

* landscape cards

* layout

* safe area

* less bold

* debug landscape

* refactor titles, back inline with title in landscape

* remove ignoreSafeArea

* remove extra padding

* refactor

* clean

* layout spec added to plan

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

* android, desktop: connecting during onboarding - new cards (#6757)

* android, desktop: connecting during onboarding - new cards

* fix

* change layout

* fixes

* fix

* fix

* layout

* fix layout

* animation

* import

* paddings

* 350ms

* font

* fonts

* layout

* box

* more layout

* layout

* simpler

* hide toolbar heading in onboarding mode

* simpler desktop layout

* better desktop

* revert desktop toolbar

* bigger font, landscape

* fix desktop

* cap width

* refactor, simplify

* qr code scanner icon

* use icon without assets

* cleaner

* fix

* fix

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

* android, desktop: connect banner after onboarding (#6761)

* android, desktop: connect banner after onboarding

* improve

* smaller button

* bigger icon, same string

* fallback gradients

* improve build

* simpler connect screens during onboarding

* left-align

* update strings

* improve state machine

* text, padding

* strings

* primary color for tap to paste link

* fix race condition

* fix loading race

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

* ios: banner and connect screens (#6767)

* ios: banner and connect screens

* fix

* return nav

* remove padding

* refactor

* refactor

* refactor 2

* refactor 3

* refactor 4

* header

* xcode files

* improve

* fix toolbar

* toolbar 2

* no assets

* no assets 2

* padding

* android padding

* simplify

* layout

* fix

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

* fix refreshable

* text

* fix toolbar color

* rework address share logic

* padding

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2026-04-21 17:41:52 +01:00
Evgeny 4545fdd0a9 desktop: support sending voice messages, use shared VLC media-player factory (#6739)
* desktop: support sending voice messages

* alert for unsupported platforms

* dont record on error

* better initialization

* desktop: use shared VLC media-player factory (#6741)

* desktop: use shared VLC media-player factory

* fix factory

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-04-03 21:24:08 +01:00
Evgeny Poberezkin 4db9319c40 Merge branch 'stable' 2026-03-30 18:14:17 +01:00
Evgeny c3663ae285 android, desktop: constrain image sizes for previews (#6726)
* android, desktop: constrain image sizes for previews

* use correct JSON parser

* more JSON fixes

* constrain ratio in image decoder

* constrain max height in layout

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-03-30 12:24:16 +01:00
sh 024df7099d multiplatform: fix image loading performance and layout stability (#6631)
- Replace runBlocking { imageAndFilePath(file) } with LaunchedEffect +
  withContext(Dispatchers.IO) to unblock main thread on all platforms
- Set fixed container size (width + aspectRatio) from preview bitmap to
  eliminate layout shifts during async image loading
- Cache base64ToBitmap() with remember() in CIImageView and FramedItemView
- Desktop: replace imageBitmap.toAwtImage().toPainter() with BitmapPainter
  to eliminate unnecessary round-trip conversion
- Desktop: add LRU cache for base64ToBitmap (200 entries) and
  getLoadedImage (30 entries) to survive LazyColumn item disposal
- Clear loaded image cache on app file deletion via expect/actual

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-03-04 09:11:55 +00:00
spaced4ndy a09acda329 multiplatform: product specification (#6655) 2026-02-26 17:54:44 +00:00
Evgeny 2fc72861e2 multiplatform/common: catch every exception at base64ToBitmap (#6576)
Co-authored-by: shum <github.shum@liber.li>
2026-01-15 14:47:50 +00:00
Evgeny d1d2e4bc18 android: hold wakelock for 30 seconds after received event was processed, to prevent race condition with incoming call activity. (#6224)
* android: hold wakelock for 45 seconds after event is received

* create new lock instances, delay release by 30 seconds

* comment
2025-08-27 19:54:53 +01:00
Evgeny 83923b9740 android: reduce battery usage by not using permanent wakelock (#6176)
* android, desktop: core API event timeout setting

* chat_recv_msg_wait with STM timeout

* Revert "chat_recv_msg_wait with STM timeout"

This reverts commit fdfa2964c5.

* do not use permanent wake lock

* wakelock option, get wakelock on network information change

* remove option
2025-08-19 21:02:50 +01:00
Stanislav Dmitrenko e8d0425b38 android, desktop: compose 1.8.2 + Kotlin 2.1.20 + compileSdk 35 (#5774)
* android, desktop: compose 1.8.0-beta01 + Kotlin 2.1.20 + compileSdk 35

* more fixes

* remove non-total methods

* fix script path

* switch to stable compose.ui, import icons separately

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-08-11 13:24:21 +01:00
Evgeny d3a5936d17 android, desktop: gaurd crashes when item is absent in the list (#6140) 2025-08-01 16:18:55 +01:00
Evgeny a6a5afb58e ui: use conventional save icon for all files (#6077) 2025-07-15 13:23:30 +01:00
Evgeny b848f735ce ui: smaller QR code for short links (#5946)
* ui: smaller QR code for short links

* more small

* size

* translations
2025-05-25 11:56:00 +01:00
spaced4ndy b0547cf6f7 Merge branch 'stable' 2025-05-19 20:02:49 +04:00
Evgeny 7b362ff655 ui: label in compose when user cannot send messages (#5922)
* ui: label in compose when user cannot send messages

* gray buttons when user cannot send messages

* improve

* kotlin

* fix order

* fix alert

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2025-05-19 14:50:33 +00:00
spaced4ndy a92c74d3e5 android, desktop: better Chat with admins indications for members; unread badges (#5917) 2025-05-16 08:26:28 +00:00
spaced4ndy b97e1e0f11 ui: show new messages from support scope in main chat preview when invitee is pending (#5909) 2025-05-14 15:14:34 +00:00
spaced4ndy 805a69da94 android, desktop: group knocking (#5816) 2025-04-21 15:17:21 +00:00
spaced4ndy 0f3e546e36 kotlin: refactor chat contexts 2 (null secondary context, pass context instead of content tag, straighten chat state code) (#5830) 2025-04-15 13:50:06 +00:00
spaced4ndy 38c2529d8b kotlin: refactor chat contexts 1 (remove functions creating indirection) (#5827)
* kotlin: refactor chat contexts 1

* remove withChats

* comment

* remove withReportChatsIfOpen

* remove comment

* fix desktop
2025-04-14 17:01:22 +01:00
Diogo 760ea17fb9 android, desktop: group member mentions (#5574)
* initial wip

* initial parser

* limit mentions

* wip types and ohter changes

* small animation

* better limit

* show mentioned member when mention is in selectable area

* better space handling

* animation working

* changes

* auto tagging

* centralize state

* focus in desktop fix

* close picker on click outside

* use profile display name, avoid local

* show box with max number of mentions

* scrollbar in group mentions desktop

* sending and displaying mentions in views based on latest core code

* latest types and updates new api

* desktop selection area fix

* show mentions correctly

* new notifications UI changes

* local alias support

* mention notifications working

* mentions markdown changes

* fix notifications

* Revert "fix notifications"

This reverts commit 59643c24725d3caee3c629df6732f4b5bc294f8f.

* simple cleanup

* mentions in info view

* refactor/renames

* show member name to replies of my messages as primary

* show local alias and display name for mentions

* show 4 rows and almost all of 5th as picker max height

* only call list members api on new @ and searchn in all names

* fix

* correction

* fixes

* unread mentions chat stats

* unread indication in chat

* filtering of unread

* show @ in chat previews

* @ style

* alone @

* forgotten change

* deleted

* remove whitespace

* fix to make clear chat mark tags red

* comments changes

* @ as icon to avoid issues

* change

* simplify like ios

* renames

* wip using haskell parser

* show mention name containing @ in quotes

* cleanup and position of cursor after replace

* move

* show selected tick and edits working

* cimention in map

* eol

* text selection

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2025-02-03 18:05:40 +00:00
Stanislav Dmitrenko 94815bf644 android, desktop: reports dashboard (#5471)
* android, desktop: reports dashboard

* changes

* changes

* unneeded updates and fixes

* changes

* api change

* item moderated/deleted

* a lot of changes

* changes

* reports tag and icon in ChatList

* archived by

* increasing counter when new report arrives

* refactor

* groupInfo button and closing when needed

* fix archived by

* reorder

* simplify

* rename

* filled flag

* Revert "filled flag"

This reverts commit 8b5da85101.

* removed support of archived page and counter

* fix closing modal

* show search button in bar without menu

* removed content filter

* no icon

* Revert "no icon"

This reverts commit 86c725b53e.

* fix tags

* unlogs

* unlogs

* chat item statuses

* background color

* refactor

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-01-10 19:41:33 +00:00
Stanislav Dmitrenko 05a5d161fb desktop: saving settings in a safer way to handle process death (#4687)
* desktop: saving settings in a safer way to handle process death

* enhancements

* unused

* changes

* rename
2025-01-07 09:52:01 +00:00
Diogo ab0c320fcb android, desktop: chat tags UX improvements (#5455)
* show "all" in meny when any active filter or text enabled, reset search when all selected

* show active preset filter as blue

* label changes

* edit, delete and change order via context menu

* simplify filter logic to match and make sure active chat always present

* notes preset

* remove no longer needed code

* reorder mode boolean, rememberSaveable

* avoid glitch in dropdown menu animation

* move dropdown menu to tagListview

* tagsRow via actual/expect

* current chat id always on top

* avoid recompose

* fix android

* selected preset should be blue

* show change list in context menu if chat already had tag

* swap icons

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2025-01-01 22:18:15 +00:00
Stanislav Dmitrenko 0dfcd60490 android, desktop: moving chats changing in main thread (#5461)
* android, desktop: moving chats changing in main thread

* modifying chat items in main thread only

* comment
2025-01-01 21:31:06 +00:00
Evgeny 086e375bac ui: chat tag fixes (#5427)
* ui: chat tag fixes

* fix switching tags

* change

* android: fix switching profile

* change

* sp

* change

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-12-25 22:09:18 +00:00
Diogo 84a45cedbe android, desktop: chat tags (#5396)
* types and api

* remaining api

* icons for tags (named label due to name conflict)

* icon fix

* wup

* desktop handlers to open list

* updates

* filtering

* progress

* wip dump

* icons

* preset updates

* unread

* + button in tags view

* drag n drop helpers

* chats reorder

* tag chat after list creation (when chat provided)

* updates on unread tags

* initial emoji picker

* fixes and tweaks

* reoder color

* clickable shapes

* paddings

* reachable form

* one hand for tags

* ui tweaks

* input for emojis desktop

* wrap chat tags in desktop

* handling longer texts

* fixed a couple of issues in updates of unread tags

* reset search text on active filter change

* fix multi row alignment

* fix modal paddings

* fix single emoji picker for skin colors

* dependency corrected

* icon, refactor, back action to exit edit mode

* different icon params to make it larger

* refactor

* refactor

* rename

* rename

* refactor

* refactor

* padding

* unread counter size

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-12-25 11:35:48 +00:00
Stanislav Dmitrenko d80d2fa156 android: open file in default app (#5413)
* android: open file in default app

* icon

* changes

* changes

* fix

* allow files without extension
2024-12-24 19:33:47 +00:00
Stanislav Dmitrenko 0fdd2e04cc android, desktop: hide debug logs by default (#5362)
* android, desktop: hide debug logs by default

* string

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-12-12 16:14:55 +00:00
Stanislav Dmitrenko 4f8a70a6c1 android, desktop: allow to scan QR multiple times after fail (#5323) 2024-12-05 15:52:45 +00:00
Stanislav Dmitrenko ee146cdc7b android, desktop, core: option to show toolbar in chat at the top in reachable UI (#5316)
* android, desktop: ability to show toolbar in chat at the top in reachable UI

* rename

* core AppSettings

* ios AppSettings

* rename

* strings, enable reachable chat toolbar when enabled reachable app toolbars

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-12-04 16:49:45 +00:00
Diogo c04e952620 desktop: onboarding improvements (#5294)
* consistent space to bottom on future of messaging

* consistent button suze on server operators

* updated setup database passphrase screen

* ability to cancel random passphrase

* reduce conditions padding to header

* show scrollbar in desktop

* EOLs

* EOL

* fix random passphrase param when deleting database and recreating new one

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-12-02 21:00:55 +00:00
Diogo 94377d0b7a android, desktop: bottom bar and update texts in onboarding (#5279)
* android, desktop: remove one hand ui bar from onboarding and design matching latest ios

* padding before text

* stop reserving space in conditions view

* notifications view

* revert unwanted

* update heading

* translations for new how it works

* how it works redone

* show create profile in how it works

* revert

* conditions of use same padding bottom

* unused str

* swapped instant and off notifications order

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-11-30 18:21:48 +00:00
Stanislav Dmitrenko 4738286f4e android, desktop: start/stop chat toggle refactoring (#5261)
* android, desktop: start/stop chat toggle refactoring

* changes

* translations

* better

* better

* do not start chat after export, always show run toggle (#5283)

* update heading

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-11-30 16:33:38 +00:00
spaced4ndy 9c6e0a7051 desktop: fix avatar crop (#5271)
* desktop: fix avatar crop wip

* fix
2024-11-28 13:37:52 +00:00
Diogo 396fa7f988 desktop, android: server operators (#5212)
* api and types

* whats new view

* new package and movements

* move network and servers to new package

* network and servers view

* wip

* api update

* build

* conditions modal in settings

* network and servers fns

* save server fixes

* more servers

* move protocol servers view

* message servers with validation

* added message servers

* use for files

* fix error by server type

* list xftp servers

* android: add server view (#5221)

* android add server wip

* test servers button

* fix save of custom servers

* remove unused code

* edit and view servers

* fix

* allow to enable untested

* show all test errors in the end

* android: custom servers view (#5224)

* cleanup

* validation footers

* operator enabled validation

* var -> val

* reuse onboarding button

* AppBarTitle without alpha

* remove non scrollable title

* change in AppBarTitle

* changes in AppBar

* bold strings + bordered text view

* ChooseServerOperators

* fix

* new server view wip

* fix

* scan

* rename

* fix roles toggle texts

* UsageConditionsView

* aligned texts

* more texts

* replace hard coded logos with object ref

* use snapshot state to recalculate errors

* align views; fix accept

* remove extra snapshots

* fix ts

* fix whatsnew

* stage

* animation on onboarding

* refactor and fix

* remember

* fix start chat alert

* show notice in chat list

* refactor

* fix validation

* open conditions

* whats new view updates

* icon for navigation improvements

* remove debug

* simplify

* fix

* handle click when have unsaved changes

* fix

* Revert "fix"

This reverts commit d49c373641.

* Revert "handle click when have unsaved changes"

This reverts commit 39ca03f9c0.

* fixed close of modals in whats new view

* grouping

* android: conditions view paddings (#5228)

* revert padding

* refresh operators on save

* fixed modals in different views for desktop

* ios: fix enabling operator model update

* fix modals

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
2024-11-22 18:42:07 +04:00
Stanislav Dmitrenko 2b155db57d android, desktop: open chat on first unread, "scroll" to quoted items that were not loaded (#5140)
* android, desktop: infinity scroll rework

* group corrections

* scroll to quote/unread/top/bottom

* changes

* changes

* changes

* changes

* better

* changes

* fix chat closing on desktop

* fix reading items counter, scrolling to newly appeared message, removed unneeded items loading, only partially visible items marked read

* workaround of showing buttom with arrow down on new messages receiving

* rename param

* fix tests

* comments and removed unused code

* performance optimization

* optimization for loading more items in small chat

* fix loading prev items in loop

* workaround to blinking button with counter

* terminal scroll fix

* different click events for floating buttons

* refactor

* change

* WIP

* refactor

* refactor

* renames

* refactor

* refactor

* change

* mark read problem fix

* fix tests

* fix auto scroll in some situations

* fix scroll to quote when it's near the top loaded area

* refactor

* refactor

* rename

* rename

* fix

* alert when quoted message doesn't exist

* refactor

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-11-20 19:23:55 +00:00
Stanislav Dmitrenko 4162bccc46 multiplatform: edge to edge design (#5051)
* multiplatform: insets

* more features and better performance

* calls and removed unused code

* changes

* removed logs

* status and nav bar colors

* chatList and newChatSheet search fields

* overhaul

* search fields, devtools, chatlist, newchatsheet, onehand on desktop, scrollbars

* android, desktop: update to Compose 1.7.0

- support image drag-and-drop from other applications right to a chat
(with and without transparent pixels - will be png or jpg)

* stable

* workaround

* changes

* ideal adapting height layout

* dropdownmenu, userpicker, onehandui, call layout, columns

* rename bars properties and strings

* faster update and better layout

* gallery in landscape with cutout

* better cutout

* 1% step on slider

* app bar moves to bottom in one hand ui

* default alpha

* changes

* userpicker colors

* changes

* blur

* fix wrong drawing area in chatview

* fix

* fixed differently

* changes

* changes

* android fix

* Revert "android fix"

This reverts commit 7d417afd9b.

* changes

* changes

* blur

* swap

* no logs

* fix build

* old Android support

* fix position of menu

* disable blur on Android 12

* call button padding

* useless code

* fix padding in group info view

* rename

* rename

* newline

* one more fix

* changes

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-10-31 17:26:17 +00:00
Stanislav Dmitrenko 24090fe350 android, desktop: update to Compose 1.7.0 (#5038)
* docs: correction

* android, desktop: update to Compose 1.7.0

- support image drag-and-drop from other applications right to a chat
(with and without transparent pixels - will be png or jpg)

* stable

* workaround

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-10-31 17:11:26 +00:00
Stanislav Dmitrenko 54b40a5838 android, desktop: checking for camera in calls and handle uninitialized call (#4997)
* android, desktop: checking for camera in calls and handle uninitialized call

* explanation for situation without permission

* reorder

* reorder

* strings

* font

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-10-08 17:16:34 +01:00
Stanislav Dmitrenko 193e17f7af android, desktop: thread-safe terminal items and floating terminal improvements (#4992)
* android, desktop: thread-safe terminal items and floating terminal improvements

* optimization
2024-10-08 08:08:22 +01:00
Diogo bb2a6ec65d android, desktop: add chat message tail and roundness settings (#4958)
* android, desktop: add roundness setting to chat items

* add tail setting

* use shape for clip

* wip tails

* shape style

* show tail only on last msg in group

* roundings

* padding for direct chats

* groups padding

* space between messages in settings preview

* refactor group paddings

* simplify

* simplify

* RcvDeleted handling

* revert uncessary

* import

* always maintain tail position

* rename

* reactions should not move

* short emoji shouldn't have tail

* remove invisible tail for voice without text

* better usage of gutters

* simplify

* rename

* simplify reactions

* linter happy

* exclude moderated items from shape

* uncessary diff

* func position

* fix chat view align on font resize (with image)

* fix tails moving bubble on max width

* fix big group names sometimes changing position

* small refactor

* fix top left corner end position

* rename

* sticky steps

* revert whitespace changes

---------

Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-10-05 19:02:09 +01:00
Stanislav Dmitrenko 95c1d8d798 android, desktop: calls switching from audio to video and back (#4814)
* android, desktop: calls switching from audio to video and back

* refactor

* working all 4 streams with mute handling differently

* changes

* changes

* wrong file

* changes

* padding

* android camera service type

* icons, sizes, clickable

* refactor

* Revert "android camera service type"

This reverts commit 9878ff38e9.

* late init camera permissions

* enabling camera sooner than call establishes (not fully done)

* changes

* alpha

* fixes for Safari

* enhancements

* fix Safari sound

* padding between buttons on desktop

* android default values for padding

* changes

* calls without encryption are supported and flipping camera on some devices works

* unused param

* logs

* background color

* play local video in Safari

* no line height

* removed one listener from per frame processing

* enhancements

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2024-09-26 20:18:05 +01:00