diff --git a/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/settings/SettingsView.kt b/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/settings/SettingsView.kt index b19f7f368..ef2a27f59 100644 --- a/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/settings/SettingsView.kt +++ b/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/settings/SettingsView.kt @@ -16,6 +16,7 @@ package fr.acinq.phoenix.android.settings +import android.widget.Toast import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -26,8 +27,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -60,7 +63,7 @@ fun SettingsView( val nc = navController val context = LocalContext.current val scope = rememberCoroutineScope() - var debugClickCount by remember { mutableStateOf(0) } + var debugClickCount by remember { mutableIntStateOf(0) } val notices = noticesViewModel.notices val notifications = business.notificationsManager.notifications.collectAsState() @@ -78,6 +81,23 @@ fun SettingsView( ) } + if (debugClickCount > 10) { + LaunchedEffect(key1 = Unit) { + Toast.makeText(context, "Debug mode enabled", Toast.LENGTH_SHORT).show() + } + // -- debug + CardHeader(text = "DEBUG") + Card { + MenuButton( + text = "Switch to legacy app (DEBUG)", + icon = R.drawable.ic_settings, + onClick = { + scope.launch { LegacyPrefsDatastore.saveStartLegacyApp(context, LegacyAppStatus.Required.Expected) } + }, + ) + } + } + // -- general CardHeader(text = stringResource(id = R.string.settings_general_title)) Card { @@ -125,23 +145,6 @@ fun SettingsView( ) } - if (debugClickCount > 10) { - // -- debug - CardHeader(text = "DEBUG") - Card { - Button( - text = "Switch to legacy app (DEBUG)", - icon = R.drawable.ic_user, - onClick = { - scope.launch { - LegacyPrefsDatastore.saveStartLegacyApp(context, LegacyAppStatus.Required.Expected) - } - }, - modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Start - ) - } - } - Spacer(Modifier.height(32.dp)) } } diff --git a/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/main/MainFragment.kt b/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/main/MainFragment.kt index 73800f439..362646088 100644 --- a/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/main/MainFragment.kt +++ b/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/main/MainFragment.kt @@ -16,282 +16,154 @@ package fr.acinq.phoenix.legacy.main +import android.content.ClipData +import android.content.ClipboardManager import android.content.Context -import android.content.Intent -import android.content.SharedPreferences -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.animation.Animation -import android.view.animation.AnimationUtils +import android.widget.Toast +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.map +import androidx.lifecycle.viewModelScope import androidx.navigation.fragment.findNavController -import androidx.preference.PreferenceManager -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import fr.acinq.eclair.MilliSatoshi -import fr.acinq.eclair.WatchListener -import fr.acinq.eclair.channel.HasCommitments -import fr.acinq.eclair.channel.`WAIT_FOR_FUNDING_CONFIRMED$` +import fr.acinq.bitcoin.scala.Satoshi +import fr.acinq.eclair.`JsonSerializers$` +import fr.acinq.phoenix.legacy.AppViewModel import fr.acinq.phoenix.legacy.BaseFragment +import fr.acinq.phoenix.legacy.BuildConfig import fr.acinq.phoenix.legacy.R -import fr.acinq.phoenix.legacy.background.ChannelStateChange -import fr.acinq.phoenix.legacy.background.KitState -import fr.acinq.phoenix.legacy.background.PaymentPending -import fr.acinq.phoenix.legacy.databinding.FragmentMainBinding +import fr.acinq.phoenix.legacy.databinding.FragmentMainSunsetBinding import fr.acinq.phoenix.legacy.utils.Constants -import fr.acinq.phoenix.legacy.utils.Converter -import fr.acinq.phoenix.legacy.utils.Prefs import fr.acinq.phoenix.legacy.utils.Wallet import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Request +import okhttp3.Response import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import org.json.JSONObject import org.slf4j.Logger import org.slf4j.LoggerFactory -import java.text.DateFormat -import java.util.* +import upickle.`default$` +import java.io.IOException +import java.text.NumberFormat +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds -class MainFragment : BaseFragment(), SharedPreferences.OnSharedPreferenceChangeListener { +class MainFragment : BaseFragment() { override val log: Logger = LoggerFactory.getLogger(this::class.java) - private lateinit var mBinding: FragmentMainBinding - private lateinit var model: MainViewModel - - private lateinit var paymentsAdapter: PaymentsAdapter - private lateinit var paymentsManager: RecyclerView.LayoutManager - - private lateinit var notificationsAdapter: NotificationsAdapter - private lateinit var notificationsManager: RecyclerView.LayoutManager - - private lateinit var blinkingAnimation: Animation - - private val prefsListener = SharedPreferences.OnSharedPreferenceChangeListener { _: SharedPreferences, key: String? -> - if (key == Prefs.PREFS_SHOW_AMOUNT_IN_FIAT) { - refreshIncomingFundsAmountField() - } - } + private lateinit var mBinding: FragmentMainSunsetBinding + private lateinit var model: MainSunsetViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - mBinding = FragmentMainBinding.inflate(inflater, container, false) + mBinding = FragmentMainSunsetBinding.inflate(inflater, container, false) mBinding.lifecycleOwner = this - - // init payment recycler view - paymentsManager = LinearLayoutManager(context) - paymentsAdapter = PaymentsAdapter() - paymentsAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - mBinding.paymentList.scrollToPosition(0) - } - }) - mBinding.paymentList.apply { - setHasFixedSize(true) - layoutManager = paymentsManager - adapter = paymentsAdapter - } - // init notification recycler view - notificationsManager = LinearLayoutManager(context) - notificationsAdapter = NotificationsAdapter(mutableListOf()) - mBinding.notificationList.apply { - setHasFixedSize(true) - layoutManager = notificationsManager - adapter = notificationsAdapter - } - blinkingAnimation = AnimationUtils.loadAnimation(context, R.anim.blinking) return mBinding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - model = ViewModelProvider(this).get(MainViewModel::class.java) - context?.let { ctx -> - appContext(ctx).notifications.observe(viewLifecycleOwner) { - notificationsAdapter.update(it) - } - app.networkInfo.observe(viewLifecycleOwner) { - if (it.electrumServer == null || !it.lightningConnected) { - if (mBinding.connectivityButton.animation == null || !mBinding.connectivityButton.animation.hasStarted()) { - mBinding.connectivityButton.startAnimation(blinkingAnimation) - } - mBinding.connectivityButton.visibility = View.VISIBLE - mBinding.torConnectedButton.visibility = View.GONE - } else if (Prefs.isTorEnabled(ctx)) { - if (it.torConnections.isEmpty()) { - if (mBinding.connectivityButton.animation == null || !mBinding.connectivityButton.animation.hasStarted()) { - mBinding.connectivityButton.startAnimation(blinkingAnimation) - } - mBinding.connectivityButton.visibility = View.VISIBLE - mBinding.torConnectedButton.visibility = View.GONE - } else { - mBinding.connectivityButton.clearAnimation() - mBinding.connectivityButton.visibility = View.GONE - mBinding.torConnectedButton.visibility = View.VISIBLE - } - } else { - mBinding.connectivityButton.clearAnimation() - mBinding.connectivityButton.visibility = View.GONE - mBinding.torConnectedButton.visibility = View.GONE - } - } - appContext(ctx).balance.observe(viewLifecycleOwner) { - mBinding.balance.setAmount(it.sendable) - } - } - app.pendingSwapIns.observe(viewLifecycleOwner) { - refreshIncomingFunds() - } - app.payments.observe(viewLifecycleOwner) { (paymentsCount, payments) -> - paymentsAdapter.submitList( - showFooter = paymentsCount > Constants.LATEST_PAYMENTS_COUNT, - list = payments.take(Constants.LATEST_PAYMENTS_COUNT) - ) - } - model.incomingFunds.observe(viewLifecycleOwner) { amount -> - if (amount.`$greater`(MilliSatoshi(0))) { - refreshIncomingFundsAmountField() - mBinding.incomingFundsNotif.visibility = View.VISIBLE - } else { - mBinding.incomingFundsNotif.visibility = View.INVISIBLE - } - } + model = ViewModelProvider(this).get(MainSunsetViewModel::class.java) + mBinding.model = model + model.getFinalWalletBalance(app) } override fun onStart() { super.onStart() - if (!EventBus.getDefault().isRegistered(this)) { - EventBus.getDefault().register(this) - } - Wallet.hideKeyboard(context, mBinding.main) - context?.let { PreferenceManager.getDefaultSharedPreferences(it).registerOnSharedPreferenceChangeListener(prefsListener) } - - context?.let { - refreshNotifications(it) - refreshBalanceDisplay(it) - } mBinding.settingsButton.setOnClickListener { findNavController().navigate(R.id.action_main_to_settings) } - mBinding.receiveButton.setOnClickListener { findNavController().navigate(R.id.action_main_to_receive) } - mBinding.sendButton.setOnClickListener { findNavController().navigate(R.id.action_main_to_read_input) } - mBinding.helpButton.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://phoenix.acinq.co/faq"))) } - mBinding.torConnectedButton.setOnClickListener { findNavController().navigate(R.id.global_action_any_to_tor) } - mBinding.connectivityButton.setOnClickListener { findNavController().navigate(R.id.action_main_to_connectivity) } - } - - override fun onStop() { - super.onStop() - EventBus.getDefault().unregister(this) - context?.let { PreferenceManager.getDefaultSharedPreferences(it).unregisterOnSharedPreferenceChangeListener(prefsListener) } - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - context?.let { - when (key) { - Prefs.PREFS_SHOW_BALANCE_HOME -> refreshBalanceDisplay(it) - else -> refreshNotifications(it) + mBinding.upgradeButton.setOnClickListener { findNavController().navigate(R.id.action_main_to_migration) } + mBinding.copyDebugButton.setOnClickListener { + lifecycleScope.launch(CoroutineExceptionHandler { _, exception -> + log.error("error when retrieving list of channels: ", exception) + Toast.makeText(context, "Could not copy channel data", Toast.LENGTH_SHORT).show() + }) { + val kit = app.requireService.state.value?.kit() + val finalAddress = kit?.wallet()?.receiveAddress?.value()?.get()?.get() + val blockCount = kit?.nodeParams()?.currentBlockHeight() + val channels = app.requireService.getChannels(null).toMutableList() + val nodeId = kit?.nodeParams()?.nodeId()?.toString() ?: getString(R.string.legacy_utils_unknown) + val data = channels.joinToString("\n\n", "", "", -1) { `default$`.`MODULE$`.write(it, 1, `JsonSerializers$`.`MODULE$`.cmdResGetinfoReadWriter()) } + val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setPrimaryClip(ClipData.newPlainText("Legacy channels data", """ + commit=${BuildConfig.LIB_COMMIT} + legacy_node_id=$nodeId + block_count=$blockCount + final_balance=${model.finalWalletBalance.value} + final_address=$finalAddress + channels_data=${data.takeIf { it.isNotBlank() } ?: "none"} + """.trimIndent())) + Toast.makeText(context, "Data copied!", Toast.LENGTH_SHORT).show() } } } +} - private fun refreshBalanceDisplay(context: Context) { - if (Prefs.showBalanceHome(context)) { - mBinding.balance.visibility = View.VISIBLE - } else { - mBinding.balance.visibility = View.GONE - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - fun handleEvent(event: PaymentPending) { - log.debug("pending payment, refreshing list...") - app.refreshLatestPayments() - } +class MainSunsetViewModel : ViewModel() { + val log = LoggerFactory.getLogger(this::class.java) + val finalWalletBalance = MutableLiveData(null) - @Subscribe(threadMode = ThreadMode.BACKGROUND) - fun handleEvent(event: ChannelStateChange) { - log.debug("channel state changed, refreshing incoming funds...") - refreshIncomingFunds() + fun getFinalWalletBalance(appViewModel: AppViewModel) { + viewModelScope.launch { + fetchFinalWalletBalance(appViewModel) + } } - private fun refreshIncomingFunds() { - lifecycleScope.launch(CoroutineExceptionHandler { _, exception -> - log.error("error when refreshing the incoming funds notification: ", exception) - }) { - val totalSwapIns = app.pendingSwapIns.value?.values?.map { s -> Converter.any2Msat(s.amount()) } ?: emptyList() - val totalChannelsWaitingConf = app.service?.getChannels(`WAIT_FOR_FUNDING_CONFIRMED$`.`MODULE$`)?.map { c -> - if (c.data() is HasCommitments) { - (c.data() as HasCommitments).commitments().availableBalanceForSend() - } else { - MilliSatoshi(0) + private suspend fun fetchFinalWalletBalance(appViewModel: AppViewModel) { + val address = appViewModel.service?.state?.value?.kit()?.wallet()?.receiveAddress?.value()?.get()?.get() + if (!address.isNullOrBlank()) { + Wallet.httpClient.newCall(Request.Builder().url("${Constants.MEMPOOLSPACE_EXPLORER_URL}/api/address/$address").build()).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + log.warn("could not retrieve address details from mempool.space: ${e.localizedMessage}") + finalWalletBalance.postValue(null) } - } ?: emptyList() - val total = totalSwapIns + totalChannelsWaitingConf - model.incomingFunds.postValue(if (total.isEmpty()) { - MilliSatoshi(0) - } else { - total.reduce { acc, amount -> acc.`$plus`(amount) } - }) - } - } - private fun refreshIncomingFundsAmountField() { - model.incomingFunds.value?.let { amount -> - context?.let { ctx -> - mBinding.incomingFundsNotif.text = getString(R.string.legacy_main_swapin_incoming, - if (Prefs.getShowAmountInFiat(ctx)) { - Converter.printFiatPretty(ctx, amount, withUnit = true) + override fun onResponse(call: Call, response: Response) { + if (!response.isSuccessful) { + log.warn("mempool.space returned error=${response.code()}") + finalWalletBalance.postValue(null) } else { - Converter.printAmountPretty(amount, ctx, withUnit = true) - }) - } - } - } - - private fun refreshNotifications(context: Context) { - checkMnemonics(context) - checkBackgroundWorkerCanRun(context) - } - - /** - * If the background channels watcher has not run since (now) - (DELAY_BEFORE_BACKGROUND_WARNING), we consider that the device is - * blocking this application from working in background, and show a notification. - * - * Some devices vendors are known to aggressively kill applications (including background jobs) in order to save battery, - * unless the app is whitelisted by the user in a custom OS setting page. This behaviour is hard to detect and not - * standard, and does not happen on a stock android. In this case, the user has to whitelist the app. - */ - private fun checkBackgroundWorkerCanRun(context: Context) { - val channelsWatchOutcome = Prefs.getWatcherLastAttemptOutcome(context) - if (channelsWatchOutcome.second > 0 && System.currentTimeMillis() - channelsWatchOutcome.second > Constants.DELAY_BEFORE_BACKGROUND_WARNING) { - log.warn("watcher has not run since {}", DateFormat.getDateTimeInstance().format(Date(channelsWatchOutcome.second))) - appContext(context).notifications.value?.add(InAppNotifications.BACKGROUND_WORKER_CANNOT_RUN) - if (app.state.value is KitState.Started) { - // the user has been notified once, but since the node has started he is safe anyway - // the background watcher notification countdown can be reset so that it does not spam the user - Prefs.saveWatcherAttemptOutcome(context, WatchListener.`Ok$`.`MODULE$`) - } + response.body()?.let { + try { + val json = JSONObject(it.string()) + val (funded, spent) = json.getJSONObject("chain_stats").run { + getLong("funded_txo_sum") to getLong("spent_txo_sum") + } + val (pendingFunded, pendingSpent) = json.getJSONObject("mempool_stats").run { + getLong("funded_txo_sum") to getLong("spent_txo_sum") + } + val available = (funded - spent) + (pendingFunded - pendingSpent) + finalWalletBalance.postValue(Satoshi(available)) + } catch (e: Exception) { + log.error("could not parse address data from mempool.space: ${e.localizedMessage}", e) + finalWalletBalance.postValue(null) + } + } + } + } + }) + delay(10.minutes) } else { - appContext(context).notifications.value?.remove(InAppNotifications.BACKGROUND_WORKER_CANNOT_RUN) + delay(7.seconds) } + fetchFinalWalletBalance(appViewModel) } - private fun checkMnemonics(context: Context) { - val timestamp = Prefs.getMnemonicsSeenTimestamp(context) - if (timestamp == 0L) { - appContext(context).notifications.value?.add(InAppNotifications.MNEMONICS_NEVER_SEEN) - } else { - appContext(context).notifications.value?.remove(InAppNotifications.MNEMONICS_NEVER_SEEN) + val finalWalletBalanceDisplay : LiveData = finalWalletBalance.map { + when (it) { + null -> "scanning address..." + else -> "${NumberFormat.getInstance().format(it.toLong())} sat" } } - } - -class MainViewModel : ViewModel() { - val incomingFunds = MutableLiveData(MilliSatoshi(0)) -} - diff --git a/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/settings/SettingsFragment.kt b/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/settings/SettingsFragment.kt index a2474808e..2b19c4881 100644 --- a/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/settings/SettingsFragment.kt +++ b/phoenix-legacy/src/main/kotlin/fr/acinq/phoenix/legacy/settings/SettingsFragment.kt @@ -52,26 +52,18 @@ class SettingsFragment : BaseFragment(stayIfNotStarted = true) { mBinding.displaySeedButton.visibility = if (isStarted) View.VISIBLE else View.GONE mBinding.accessControlButton.visibility = if (isStarted) View.VISIBLE else View.GONE mBinding.listAllChannelsButton.visibility = if (isStarted) View.VISIBLE else View.GONE - mBinding.mutualCloseButton.visibility = if (isStarted) View.VISIBLE else View.GONE - mBinding.forceCloseButton.visibility = if (isStarted) View.VISIBLE else View.GONE - mBinding.paymentSettingsButton.visibility = if (isStarted) View.VISIBLE else View.GONE } override fun onStart() { super.onStart() mBinding.actionBar.setOnBackAction { findNavController().popBackStack() } - mBinding.prefsDisplayButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_prefs_display) } mBinding.electrumButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_electrum) } - mBinding.mutualCloseButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_mutual_close) } - mBinding.forceCloseButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_force_close) } mBinding.displaySeedButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_display_seed) } mBinding.accessControlButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_access_control) } mBinding.listAllChannelsButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_list_channels) } mBinding.logsButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_logs) } -// mBinding.feesButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_fees) } mBinding.torButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_tor) } mBinding.aboutButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_about) } - mBinding.paymentSettingsButton.setOnClickListener { findNavController().navigate(R.id.action_settings_to_payment_settings) } } } diff --git a/phoenix-legacy/src/main/res/layout/fragment_main_sunset.xml b/phoenix-legacy/src/main/res/layout/fragment_main_sunset.xml new file mode 100644 index 000000000..5725f7c19 --- /dev/null +++ b/phoenix-legacy/src/main/res/layout/fragment_main_sunset.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phoenix-legacy/src/main/res/layout/fragment_migration.xml b/phoenix-legacy/src/main/res/layout/fragment_migration.xml index c3603e916..33378a244 100644 --- a/phoenix-legacy/src/main/res/layout/fragment_migration.xml +++ b/phoenix-legacy/src/main/res/layout/fragment_migration.xml @@ -45,42 +45,23 @@ android:visibility="@{model.state instanceof MigrationScreenState.Ready}" app:layout_constraintTop_toTopOf="parent"> - - - - diff --git a/phoenix-legacy/src/main/res/layout/fragment_settings.xml b/phoenix-legacy/src/main/res/layout/fragment_settings.xml index 013d9d1d2..f61f19139 100644 --- a/phoenix-legacy/src/main/res/layout/fragment_settings.xml +++ b/phoenix-legacy/src/main/res/layout/fragment_settings.xml @@ -61,18 +61,6 @@ app:spacer_size="@dimen/space_md" app:text="@string/legacy_settings_about" /> - - @@ -97,24 +85,12 @@ app:spacer_size="@dimen/space_md" app:text="@string/legacy_settings_tor" /> - - + app:layout_constraintTop_toBottomOf="@id/tor_button" /> - - - - diff --git a/phoenix-legacy/src/main/res/navigation/nav_graph_main.xml b/phoenix-legacy/src/main/res/navigation/nav_graph_main.xml index e25e81821..c94b95cb9 100644 --- a/phoenix-legacy/src/main/res/navigation/nav_graph_main.xml +++ b/phoenix-legacy/src/main/res/navigation/nav_graph_main.xml @@ -120,6 +120,9 @@ + diff --git a/phoenix-legacy/src/main/res/values-cs/strings.xml b/phoenix-legacy/src/main/res/values-cs/strings.xml index 7e7043fa9..2c849a3ae 100644 --- a/phoenix-legacy/src/main/res/values-cs/strings.xml +++ b/phoenix-legacy/src/main/res/values-cs/strings.xml @@ -421,8 +421,11 @@ - Phoenix upgrade - Tato peněženka používá zastaralý formát kanálů. Většina funkcí je vypnuta.\n\nPřejděte na Phoenix v2 a získejte swapy bez důvěry, splicing, statické adresy a mnoho dalšího.\n\nOd října 2024 budou kanály, které nebyly migrovány, uzavřeny. + Starší peněženky jsou zastaralé. Kanály byly uzavřeny a finanční prostředky byly přesunuty zpět do řetězce. + Pokud máte problémy nebo očekáváte více prostředků v konečné peněžence, kontaktujte podporu na adrese phoenix@acinq.co a poskytněte informace o ladění + Prostředky dostupné v konečné peněžence: + Upgradujte na Phoenix V2 + Kopírování ladicích dat Upgrade Připojení… Teď ne diff --git a/phoenix-legacy/src/main/res/values-de/strings.xml b/phoenix-legacy/src/main/res/values-de/strings.xml index e802e06cd..f2419f887 100644 --- a/phoenix-legacy/src/main/res/values-de/strings.xml +++ b/phoenix-legacy/src/main/res/values-de/strings.xml @@ -814,8 +814,11 @@ - Phoenix Upgrade - Diese Wallet verwendet ein veraltetes Channel-Format. Die meisten Funktionen sind deaktiviert.\n\nWerden Sie auf Phoenix v2 upgraden und erhalten Sie vertrauenslose Swaps, Splicing, statische Adressen und vieles mehr.\n\nAb Oktober 2024 werden die Kanäle, die nicht migriert wurden, geschlossen. + Legacy-Wallets werden nicht mehr unterstützt. Kanäle wurden geschlossen und Gelder zurück On-Chain verschoben. + Wenn Sie Probleme haben oder mehr Gelder in der endgültigen Wallet erwarten, wenden Sie sich an den Support unter phoenix@acinq.co und stellen Sie die Debug-Daten bereit. + In der Final Wallet verfügbare Gelder: + Upgrade auf Phoenix V2 + Debug-Daten kopieren Upgrade Verbindung herstellen… Nicht jetzt diff --git a/phoenix-legacy/src/main/res/values-es/strings.xml b/phoenix-legacy/src/main/res/values-es/strings.xml index 86ca490df..2fc3b2a4d 100644 --- a/phoenix-legacy/src/main/res/values-es/strings.xml +++ b/phoenix-legacy/src/main/res/values-es/strings.xml @@ -465,8 +465,11 @@ - Actualización de Phoenix - Este monedero utiliza un formato de canales obsoleto. La mayoría de las características están deshabilitadas.\n\nActualízate a Phoenix v2 y obtén swaps sin confianza, splicing, direcciones estáticas y mucho más.\n\nA partir de octubre de 2024, los canales que no hayan sido migrados serán cerrados. + Las billeteras antiguas están obsoletas. Los canales se cerraron y los fondos se volvieron a transferir a la cadena. + Si tiene problemas o espera más fondos en la billetera final, comuníquese con el servicio de asistencia a phoenix@acinq.co y proporcione los datos de debug. + Fondos disponibles en la billetera final: + Actualizar a Phoenix V2 + Copiar datos de debug Actualizar Connecting… Ahora no diff --git a/phoenix-legacy/src/main/res/values-fr/strings.xml b/phoenix-legacy/src/main/res/values-fr/strings.xml index c01f976a7..fce71730e 100644 --- a/phoenix-legacy/src/main/res/values-fr/strings.xml +++ b/phoenix-legacy/src/main/res/values-fr/strings.xml @@ -691,8 +691,11 @@ - Mise à niveau de Phoenix - Ce wallet utilise un format de canaux obsolète. La majorité des fonctionnalités sont inactives.\n\nPassez à Phoenix v2 et profitez de swaps sans tiers de confiance, de splicing, des adresses statiques, et bien plus encore.\n\nÀ partir d\'octobre 2024, les canaux qui n\'ont pas été migrés seront fermés. + Les portefeuilles legacy sont dépréciés. Les canaux ont été fermés et les fonds ont été retournés sur la chaîne. + Si vous rencontrez des problèmes ou si vous vous attendez à avoir davantage de fonds dans le portefeuille final, contactez le support à l\'adresse phoenix@acinq.co en fournissez les données de débogage. + Fonds disponibles dans le portefeuille final : + Passer à Phoenix V2 + Copier les données de débogage Mettre à jour Connexion… Plus tard diff --git a/phoenix-legacy/src/main/res/values-pt-rBR/strings.xml b/phoenix-legacy/src/main/res/values-pt-rBR/strings.xml index bff62ed7c..f5f5f91f5 100644 --- a/phoenix-legacy/src/main/res/values-pt-rBR/strings.xml +++ b/phoenix-legacy/src/main/res/values-pt-rBR/strings.xml @@ -751,8 +751,11 @@ - Atualização do Phoenix - Esta carteira está usando um formato de canais obsoleto. A maioria dos recursos está desativada.\n\nAtualize para a Phoenix v2 e obtenha swaps sem confiança, splicing, endereços estáticos e muito mais.\n\nA partir de outubro de 2024, os canais que não tiverem sido migrados serão fechados. + As carteiras legadas estão obsoletas. Os canais foram fechados e os fundos foram movidos de volta para a cadeia. + Se você tiver problemas ou esperar mais fundos na carteira final, entre em contato com o suporte em phoenix@acinq.co e forneça os dados de depuração. + Fundos disponíveis na carteira final: + Atualizar para Phoenix V2 + Copiar dados de depuração Upgrade Conectando… Não agora diff --git a/phoenix-legacy/src/main/res/values/strings.xml b/phoenix-legacy/src/main/res/values/strings.xml index e210f7b3e..36c243426 100644 --- a/phoenix-legacy/src/main/res/values/strings.xml +++ b/phoenix-legacy/src/main/res/values/strings.xml @@ -785,11 +785,14 @@ legacy_ - Upgrade to Phoenix v2 - This wallet is using an obsolete channels format. Most features are disabled.\n\nUpgrade to Phoenix v2 and get trustless swaps, splicing, static addresses, and much more.\n\nStarting in October 2024, channels that have not been migrated will be closed. + Legacy wallets have reached end of life. Channels have been closed, and funds moved back on-chain. + If you have issues or expect more funds in the final wallet, contact support at phoenix@acinq.co and provide the debug data. + Funds available in final wallet: + Upgrade to Phoenix V2 + Copy debug data Upgrade now Connecting… - Not now + Later You cannot upgrade now: an on-chain deposit is pending.\n\nTry again later when this deposit has confirmed. You cannot upgrade now: some channels are currently being opened.\n\nTry again later when these channels have been opened and are active.