Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
Expand Down Expand Up @@ -94,6 +96,8 @@ internal fun AccountsScreen(
val state by producePresenter {
accountsPresenter()
}
var pendingDeleteAccountKey by remember { mutableStateOf<MicroBlogKey?>(null) }
var pendingDeleteAccountLabel by remember { mutableStateOf<String?>(null) }
val lazyListState = rememberLazyListState()
val haptics = LocalHapticFeedback.current
val reorderableLazyColumnState =
Expand Down Expand Up @@ -144,7 +148,13 @@ internal fun AccountsScreen(
LaunchedEffect(swipeState.settledValue) {
if (swipeState.settledValue != SwipeToDismissBoxValue.Settled) {
delay(AnimationConstants.DefaultDurationMillis.toLong())
state.deleteItem(account.accountKey)
pendingDeleteAccountKey = account.accountKey
pendingDeleteAccountLabel =
when (val profile = data) {
is UiState.Success -> profile.data.handle.canonical
is UiState.Error, is UiState.Loading -> account.accountKey.toString()
}
swipeState.snapTo(SwipeToDismissBoxValue.Settled)
}
}
ReorderableItem(
Expand Down Expand Up @@ -268,7 +278,12 @@ internal fun AccountsScreen(
},
onClick = {
showMenu = false
state.deleteItem(account.accountKey)
pendingDeleteAccountKey = account.accountKey
pendingDeleteAccountLabel =
when (val profile = data) {
is UiState.Success -> profile.data.handle.canonical
is UiState.Error, is UiState.Loading -> account.accountKey.toString()
}
},
leadingIcon = {
FAIcon(
Expand All @@ -291,6 +306,48 @@ internal fun AccountsScreen(
}
}
}
pendingDeleteAccountKey?.let { accountKey ->
AlertDialog(
onDismissRequest = {
pendingDeleteAccountKey = null
pendingDeleteAccountLabel = null
},
confirmButton = {
TextButton(
onClick = {
state.deleteItem(accountKey)
pendingDeleteAccountKey = null
pendingDeleteAccountLabel = null
},
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error),
) {
Text(text = stringResource(id = R.string.delete))
}
},
dismissButton = {
TextButton(
onClick = {
pendingDeleteAccountKey = null
pendingDeleteAccountLabel = null
},
) {
Text(text = stringResource(id = android.R.string.cancel))
}
},
title = {
Text(text = stringResource(id = R.string.settings_accounts_remove))
},
text = {
Text(
text =
stringResource(
id = R.string.settings_accounts_remove_confirm,
pendingDeleteAccountLabel ?: accountKey.toString(),
),
)
},
)
}
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
<string name="media_viewer_title">Media viewer</string>

<string name="settings_accounts_remove">Remove</string>
<string name="settings_accounts_remove_confirm">Are you sure you want to remove account %1$s from this device?</string>

<string name="media_menu_save">Save screenshot</string>
<string name="media_menu_share_image">Share screenshot</string>
Expand Down
1 change: 1 addition & 0 deletions compose-ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ kotlin {
implementation(project.dependencies.platform(libs.koin.bom))
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.qrose)
}
}
val commonTest by getting {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,16 @@
<string name="login_button">ログイン</string>
<string name="mastodon_login_verify_message">認証情報を確認するまでしばらくお待ちください。</string>
<string name="nostr_login_title">Nostr アカウントをインポート</string>
<string name="nostr_login_hint">読み取り専用アクセス用に npub または hexpubkey を貼り付けるか、書き込み可能なアカウントをインポートするために nsecを提供します。</string>
<string name="nostr_login_account_hint">npub, nsec, hexキー</string>
<string name="nostr_login_hint">読み取り専用には npub または hex 公開鍵、ローカル署名には nsec、リモート署名には bunker URI、または Amber と QR ベースの Nostr Connect signer を利用できます。</string>
<string name="nostr_login_account_hint">npubnsec、hex キー、bunker://、または nostrconnect://</string>
<string name="nostr_login_bunker_hint">bunker:// or nostrconnect:// URI</string>
<string name="nostr_login_bunker_button">バンカーを接続する</string>
<string name="nostr_login_amber_button">琥珀を接続する</string>
<string name="nostr_login_qr_button">QR で接続</string>
<string name="nostr_login_qr_hint">Amber、Alby、または他の Nostr Connect signer でスキャンしてください。</string>
<string name="nostr_login_qr_waiting">signer の承認を待っています…</string>
<string name="nostr_login_qr_link_label">Nostr Connect リンク</string>
<string name="cancel_button">キャンセル</string>
<string name="nostr_login_generate_button">生成してログイン</string>
<string name="nostr_login_npub_hint">npub または hexpubkey (nsecが設定されている場合はオプション)</string>
<string name="nostr_login_nsec_hint">nsecまたはhex秘密キー</string>
Expand Down
9 changes: 7 additions & 2 deletions compose-ui/src/commonMain/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -463,11 +463,16 @@
<string name="login_button">Login</string>
<string name="mastodon_login_verify_message">Please wait while we verify your credentials.</string>
<string name="nostr_login_title">Import Nostr account</string>
<string name="nostr_login_hint">Paste an npub or hex pubkey for read-only access, or provide an nsec to import a writable account.</string>
<string name="nostr_login_account_hint">npub, nsec, or hex key</string>
<string name="nostr_login_hint">Paste an npub or hex pubkey for read-only access, provide an nsec for local signing, use a bunker URI for remote signing, or connect Amber and QR-based Nostr Connect signers.</string>
<string name="nostr_login_account_hint">npub, nsec, hex key, bunker://, or nostrconnect://</string>
<string name="nostr_login_bunker_hint">bunker:// or nostrconnect:// URI</string>
<string name="nostr_login_bunker_button">Connect bunker</string>
<string name="nostr_login_amber_button">Connect Amber</string>
<string name="nostr_login_qr_button">Connect with QR</string>
<string name="nostr_login_qr_hint">Scan with Amber, Alby, or another Nostr Connect signer.</string>
<string name="nostr_login_qr_waiting">Waiting for signer approval…</string>
<string name="nostr_login_qr_link_label">Nostr Connect link</string>
<string name="cancel_button">Cancel</string>
<string name="nostr_login_generate_button">Generate and login</string>
<string name="nostr_login_npub_hint">npub or hex pubkey (optional if nsec is set)</string>
<string name="nostr_login_nsec_hint">nsec or hex private key</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,40 @@ import kotlin.native.HiddenFromObjC

@HiddenFromObjC
public class NostrInputPresenter : PresenterBase<NostrInputPresenter.State>() {
public enum class Mode {
Key,
Qr,
Amber,
}

@Immutable
public interface State {
public val accountInput: TextFieldState
public val bunkerInput: TextFieldState
public val canLoginAccount: Boolean
public val canLoginBunker: Boolean
public val credentialInput: TextFieldState
public val canLogin: Boolean
public val mode: Mode

public fun setMode(value: Mode)
}

@Composable
override fun body(): State {
val accountInput = rememberTextFieldState()
val bunkerInput = rememberTextFieldState()
val credentialInput = rememberTextFieldState()
val mode = remember { androidx.compose.runtime.mutableStateOf(Mode.Key) }

val canLoginAccount by remember(accountInput) {
derivedStateOf {
accountInput.text.isNotEmpty()
}
}
val canLoginBunker by remember(bunkerInput) {
val canLogin by remember(credentialInput) {
derivedStateOf {
bunkerInput.text.isNotEmpty()
credentialInput.text.isNotEmpty()
}
}

return object : State {
override val accountInput: TextFieldState = accountInput
override val bunkerInput: TextFieldState = bunkerInput
override val canLoginAccount: Boolean = canLoginAccount
override val canLoginBunker: Boolean = canLoginBunker
override val credentialInput: TextFieldState = credentialInput
override val canLogin: Boolean = canLogin
override val mode: Mode = mode.value

override fun setMode(value: Mode) {
mode.value = value
}
}
}
}
Loading
Loading