Skip to content

Commit

Permalink
(android) Check payer_note origin
Browse files Browse the repository at this point in the history
Added a method in contacts manager to find a contact
given a payer key.

Needs ACINQ/lightning-kmp#676
  • Loading branch information
dpad85 committed Jun 20, 2024
1 parent 023e149 commit ee93aa9
Show file tree
Hide file tree
Showing 22 changed files with 276 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,26 @@ import fr.acinq.phoenix.data.ContactInfo
@Composable
fun ContactCompactView(
contact: ContactInfo,
currentOffer: OfferTypes.Offer,
currentOffer: OfferTypes.Offer?,
onContactChange: (ContactInfo?) -> Unit,
) {
var showSheet by remember { mutableStateOf(false) }

Clickable(
onClick = { showSheet = true },
modifier = Modifier.offset(x = (-6).dp),
modifier = Modifier.offset(x = (-8).dp),
shape = RoundedCornerShape(12.dp)
) {
Column(modifier = Modifier.padding(6.dp)) {
Column(modifier = Modifier.padding(8.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
ContactPhotoView(image = contact.photo?.toByteArray(), name = contact.name, onChange = null, imageSize = 28.dp, borderSize = 2.dp)
Spacer(modifier = Modifier.width(8.dp))
Text(text = contact.name, maxLines = 1, overflow = TextOverflow.Ellipsis)
}
Spacer(modifier = Modifier.height(4.dp))
Text(text = currentOffer.encode(), maxLines = 2, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.subtitle2)
currentOffer?.let {
Spacer(modifier = Modifier.height(4.dp))
Text(text = it.encode(), maxLines = 2, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.subtitle2)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ import kotlinx.coroutines.launch
* A contact detail is a bottom sheet dialog that display the contact's name, photo, and
* associated offers/lnids.
*
* The contact can be edited and deleted from that screen.
* The contact may be edited and deleted from that screen.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ContactDetailsView(
contact: ContactInfo,
currentOffer: OfferTypes.Offer?,
onDismiss: () -> Unit,
onContactChange: (ContactInfo?) -> Unit,
onContactChange: ((ContactInfo?) -> Unit)?,
) {
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val contactsManager = business.contactsManager
Expand All @@ -103,45 +103,53 @@ fun ContactDetailsView(
modifier = Modifier.padding(top = 0.dp, start = 24.dp, end = 24.dp, bottom = 0.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
ContactPhotoView(image = photo, name = contact.name, onChange = { photo = it })
if (onContactChange != null) {
ContactPhotoView(image = photo, name = contact.name, onChange = { photo = it })
} else {
ContactPhotoView(image = photo, name = contact.name, onChange = null)
}
Spacer(modifier = Modifier.height(24.dp))
TextInput(
text = name,
onTextChange = { name = it },
textStyle = MaterialTheme.typography.h3.copy(textAlign = TextAlign.Center),
staticLabel = null,
textFieldColors = invisibleOutlinedTextFieldColors(),
showResetButton = false
showResetButton = false,
enabled = onContactChange != null,
enabledEffect = false,
)

Row(horizontalArrangement = Arrangement.Center) {
Button(
text = stringResource(id = R.string.contact_delete_button),
icon = R.drawable.ic_trash,
iconTint = negativeColor,
onClick = {
scope.launch {
contactsManager.deleteContact(contact.id)
onContactChange(null)
onDismiss()
}
},
shape = CircleShape,
)
Spacer(modifier = Modifier.width(8.dp))
Button(
text = stringResource(id = R.string.contact_save_button),
icon = R.drawable.ic_check,
enabled = contact.name != name || contact.photo != photo?.byteVector(),
onClick = {
scope.launch {
val newContact = contactsManager.updateContact(contact.id, name, photo, contact.offers)
onContactChange(newContact)
onDismiss()
}
},
shape = CircleShape,
)
if (onContactChange != null) {
Row(horizontalArrangement = Arrangement.Center) {
Button(
text = stringResource(id = R.string.contact_delete_button),
icon = R.drawable.ic_trash,
iconTint = negativeColor,
onClick = {
scope.launch {
contactsManager.deleteContact(contact.id)
onContactChange(null)
onDismiss()
}
},
shape = CircleShape,
)
Spacer(modifier = Modifier.width(8.dp))
Button(
text = stringResource(id = R.string.contact_save_button),
icon = R.drawable.ic_check,
enabled = contact.name != name || contact.photo != photo?.byteVector(),
onClick = {
scope.launch {
val newContact = contactsManager.updateContact(contact.id, name, photo, contact.offers)
onContactChange(newContact)
onDismiss()
}
},
shape = CircleShape,
)
}
}

if (currentOffer != null) {
Expand All @@ -161,7 +169,7 @@ fun ContactDetailsView(
Box(contentAlignment = Alignment.Center) {
HSeparator()
Button(
text = "Known offers for this contact",
text = stringResource(id = R.string.contact_offers_list_title),
textStyle = MaterialTheme.typography.caption.copy(fontSize = 12.sp),
icon = if (showAllDetails) R.drawable.ic_chevron_up else R.drawable.ic_chevron_down,
iconTint = MaterialTheme.typography.caption.color,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -120,7 +121,7 @@ fun ContactPhotoView(
modifier = Modifier.size(imageSize)
)
if (cameraAccessDenied) {
Text(text = "No camera permission", style = MaterialTheme.typography.subtitle2)
Text(text = stringResource(id = R.string.scan_request_camera_access_denied), style = MaterialTheme.typography.subtitle2)
}
} else {
Image(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import fr.acinq.phoenix.android.R
Expand Down Expand Up @@ -69,7 +70,7 @@ fun ContactsListView(
text = nameFilterInput,
staticLabel = null,
leadingIcon = { PhoenixIcon(resourceId = R.drawable.ic_inspect, tint = MaterialTheme.typography.caption.color) },
placeholder = { Text(text = "Search by name") },
placeholder = { Text(text = stringResource(id = R.string.contact_search_name)) },
singleLine = true,
onTextChange = { nameFilterInput = it },
textFieldColors = mutedTextFieldColors(),
Expand All @@ -86,7 +87,7 @@ fun ContactsListView(
},
isOnSurface = isOnSurface
)
} ?: ProgressView(text = "Fetching contacts...")
} ?: ProgressView(text = stringResource(id = R.string.utils_loading_data))
}

@Composable
Expand All @@ -101,16 +102,15 @@ private fun ContactsList(

if (contacts.isEmpty()) {
Text(
text = "No contacts found...",
text = stringResource(id = R.string.contact_none),
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.caption
)
} else {
LazyColumn(state = listState) {
itemsIndexed(contacts) { index, contact ->
val onClick = {
// TODO order the offers listed by the group_concat in the sql query, take most recent one
contact.offers.firstOrNull()?.let {
contact.mostRelevantOffer?.let {
navController.navigate("${Screen.ScanData.route}?input=${it.encode()}")
} ?: run { if (canEditContact) { onEditContact(contact) } }
}
Expand Down Expand Up @@ -154,7 +154,7 @@ private fun ContactRow(contact: ContactInfo, canEditContact: Boolean, onEditCont
Button(
icon = R.drawable.ic_edit,
onClick = { onEditContact(contact) },
padding = PaddingValues(horizontal = 12.dp, vertical = 16.dp),
padding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,37 @@
package fr.acinq.phoenix.android.components.contact

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import fr.acinq.lightning.wire.OfferTypes
import fr.acinq.phoenix.android.R
import fr.acinq.phoenix.android.business
import fr.acinq.phoenix.android.components.Button
import fr.acinq.phoenix.android.components.Clickable
import fr.acinq.phoenix.android.components.HSeparator
import fr.acinq.phoenix.android.components.PhoenixIcon
import fr.acinq.phoenix.android.utils.mutedTextColor
import fr.acinq.phoenix.data.ContactInfo
import kotlinx.coroutines.launch

@Composable
fun DetachedOfferView(
offer: OfferTypes.Offer,
onContactSaved: (ContactInfo) -> Unit
) {
var showSaveContactDialog by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val contactsManager = business.contactsManager

val encoded = remember(offer) { offer.encode() }
Clickable(onClick = { showSaveContactDialog = true }, shape = RoundedCornerShape(12.dp), modifier = Modifier.offset((-8).dp)) {
Expand All @@ -66,7 +57,7 @@ fun DetachedOfferView(
Row {
PhoenixIcon(resourceId = R.drawable.ic_user, tint = mutedTextColor)
Spacer(modifier = Modifier.width(6.dp))
Text(text = stringResource(id = R.string.contact_add_contact), style = MaterialTheme.typography.subtitle2)
Text(text = stringResource(id = R.string.contact_add_contact_button), style = MaterialTheme.typography.subtitle2)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -74,6 +75,7 @@ fun SaveNewContactDialog(
onDismiss: () -> Unit,
onSaved: (ContactInfo) -> Unit,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)

Expand Down Expand Up @@ -109,7 +111,7 @@ fun SaveNewContactDialog(
.padding(top = 0.dp, start = 24.dp, end = 24.dp, bottom = 100.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(text = "Attach a contact to an invoice", style = MaterialTheme.typography.h4, textAlign = TextAlign.Center)
Text(text = stringResource(id = R.string.contact_add_title), style = MaterialTheme.typography.h4, textAlign = TextAlign.Center)
Spacer(modifier = Modifier.height(24.dp))
ContactPhotoView(image = photo, name = name, onChange = { photo = it })
Spacer(modifier = Modifier.height(24.dp))
Expand Down Expand Up @@ -138,7 +140,7 @@ fun SaveNewContactDialog(
)
Spacer(modifier = Modifier.height(24.dp))
FilledButton(
text = stringResource(id = R.string.contact_add_contact),
text = stringResource(id = R.string.contact_add_contact_button),
icon = R.drawable.ic_check,
onClick = {
scope.launch {
Expand All @@ -149,18 +151,18 @@ fun SaveNewContactDialog(
val decodedOffer = res.result
val existingContact = contactsManager.getContactForOffer(decodedOffer)
if (existingContact != null) {
offerErrorMessage = "Offer already known (${existingContact.name})"
offerErrorMessage = context.getString(R.string.contact_error_offer_known, existingContact.name)
} else {
val contact = contactsManager.saveNewContact(name, photo, res.result)
onSaved(contact)
}
}
is Try.Failure -> { offerErrorMessage = "invalid offer" }
is Try.Failure -> { offerErrorMessage = context.getString(R.string.contact_error_offer_invalid) }
}
} else {
val existingContact = contactsManager.getContactForOffer(initialOffer)
if (existingContact != null) {
offerErrorMessage = "Offer already known (${existingContact.name})"
offerErrorMessage = context.getString(R.string.contact_error_offer_known, existingContact.name)
} else {
val contact = contactsManager.saveNewContact(name, photo, initialOffer)
onSaved(contact)
Expand All @@ -172,15 +174,6 @@ fun SaveNewContactDialog(
shape = CircleShape,
modifier = Modifier.align(Alignment.End),
)
Spacer(modifier = Modifier.height(8.dp))
FilledButton(
text = stringResource(id = R.string.contact_attach_existing_contact),
icon = R.drawable.ic_user_search,
onClick = { },
shape = CircleShape,
modifier = Modifier.align(Alignment.End),
backgroundColor = Color.Transparent,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ fun ScanDataView(
ReadDataView(
initialInput = initialInput,
model = model,
onBackClick = onBackClick,
onFeedbackDismiss = {
initialInput = ""
postIntent(Scan.Intent.Reset)
Expand Down Expand Up @@ -177,7 +176,6 @@ fun ReadDataView(
initialInput: String?,
model: Scan.Model,
onFeedbackDismiss: () -> Unit,
onBackClick: () -> Unit,
onScannedText: (String) -> Unit,
) {
val context = LocalContext.current.applicationContext
Expand All @@ -203,10 +201,6 @@ fun ReadDataView(
}
}

Column(modifier = Modifier.align(Alignment.TopStart).padding(top = 16.dp)) {
BackButton(onClick = onBackClick, backgroundColor = MaterialTheme.colors.surface)
}

// buttons at the bottom of the screen
Column(
Modifier
Expand Down
Loading

0 comments on commit ee93aa9

Please sign in to comment.