mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 12:19:54 +00:00
ui: smaller QR code for verify code view, change iOS layout (#5948)
* ui: smaller QR code for verify code view, change iOS layout * ios: fix layout for editing group profile
This commit is contained in:
parent
cbaab06975
commit
686145ba36
9 changed files with 167 additions and 180 deletions
|
@ -633,9 +633,6 @@ struct GroupChatInfoView: View {
|
|||
groupInfo: $groupInfo,
|
||||
groupProfile: groupInfo.groupProfile
|
||||
)
|
||||
.navigationBarTitle("Group profile")
|
||||
.modifier(ThemedBackground())
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
} label: {
|
||||
Label("Edit group profile", systemImage: "pencil")
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ struct GroupProfileView: View {
|
|||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@Binding var groupInfo: GroupInfo
|
||||
@State var groupProfile: GroupProfile
|
||||
@State private var currentProfileHash: Int?
|
||||
@State private var showChooseSource = false
|
||||
@State private var showImagePicker = false
|
||||
@State private var showTakePhoto = false
|
||||
|
@ -34,60 +35,40 @@ struct GroupProfileView: View {
|
|||
@FocusState private var focusDisplayName
|
||||
|
||||
var body: some View {
|
||||
return VStack(alignment: .leading) {
|
||||
Text("Group profile is stored on members' devices, not on the servers.")
|
||||
.padding(.vertical)
|
||||
List {
|
||||
EditProfileImage(profileImage: $groupProfile.image, showChooseSource: $showChooseSource)
|
||||
.if(!focusDisplayName) { $0.padding(.top) }
|
||||
|
||||
ZStack(alignment: .center) {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
profileImageView(groupProfile.image)
|
||||
if groupProfile.image != nil {
|
||||
Button {
|
||||
groupProfile.image = nil
|
||||
} label: {
|
||||
Image(systemName: "multiply")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 12)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
editImageButton { showChooseSource = true }
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
ZStack(alignment: .topLeading) {
|
||||
if !validNewProfileName() {
|
||||
Section {
|
||||
HStack {
|
||||
TextField("Group display name", text: $groupProfile.displayName)
|
||||
.focused($focusDisplayName)
|
||||
if !validNewProfileName {
|
||||
Button {
|
||||
alert = .invalidName(validName: mkValidName(groupProfile.displayName))
|
||||
} label: {
|
||||
Image(systemName: "exclamationmark.circle").foregroundColor(.red)
|
||||
}
|
||||
} else {
|
||||
Image(systemName: "exclamationmark.circle").foregroundColor(.clear)
|
||||
}
|
||||
profileNameTextEdit("Group display name", $groupProfile.displayName)
|
||||
.focused($focusDisplayName)
|
||||
}
|
||||
.padding(.bottom)
|
||||
let fullName = groupInfo.groupProfile.fullName
|
||||
if fullName != "" && fullName != groupProfile.displayName {
|
||||
profileNameTextEdit("Group full name (optional)", $groupProfile.fullName)
|
||||
.padding(.bottom)
|
||||
}
|
||||
HStack(spacing: 20) {
|
||||
Button("Cancel") { dismiss() }
|
||||
Button("Save group profile") { saveProfile() }
|
||||
.disabled(!canUpdateProfile())
|
||||
TextField("Group full name (optional)", text: $groupProfile.fullName)
|
||||
}
|
||||
} footer: {
|
||||
Text("Group profile is stored on members' devices, not on the servers.")
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 120, alignment: .leading)
|
||||
|
||||
Section {
|
||||
Button("Reset") {
|
||||
groupProfile = groupInfo.groupProfile
|
||||
currentProfileHash = groupProfile.hashValue
|
||||
}
|
||||
.disabled(currentProfileHash == groupProfile.hashValue)
|
||||
Button("Save group profile", action: saveProfile)
|
||||
.disabled(!canUpdateProfile)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(maxHeight: .infinity, alignment: .top)
|
||||
.confirmationDialog("Group image", isPresented: $showChooseSource, titleVisibility: .visible) {
|
||||
Button("Take picture") {
|
||||
showTakePhoto = true
|
||||
|
@ -95,6 +76,11 @@ struct GroupProfileView: View {
|
|||
Button("Choose from library") {
|
||||
showImagePicker = true
|
||||
}
|
||||
if UIPasteboard.general.hasImages {
|
||||
Button("Paste image") {
|
||||
chosenImage = UIPasteboard.general.image
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $showTakePhoto) {
|
||||
ZStack {
|
||||
|
@ -120,8 +106,20 @@ struct GroupProfileView: View {
|
|||
}
|
||||
}
|
||||
.onAppear {
|
||||
currentProfileHash = groupProfile.hashValue
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
focusDisplayName = true
|
||||
withAnimation { focusDisplayName = true }
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
if canUpdateProfile {
|
||||
showAlert(
|
||||
title: NSLocalizedString("Save group profile?", comment: "alert title"),
|
||||
message: NSLocalizedString("Group profile was changed. If you save it, the updated profile will be sent to group members.", comment: "alert message"),
|
||||
buttonTitle: NSLocalizedString("Save (and notify members)", comment: "alert button"),
|
||||
buttonAction: saveProfile,
|
||||
cancelButton: true
|
||||
)
|
||||
}
|
||||
}
|
||||
.alert(item: $alert) { a in
|
||||
|
@ -135,30 +133,30 @@ struct GroupProfileView: View {
|
|||
return createInvalidNameAlert(name, $groupProfile.displayName)
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { hideKeyboard() }
|
||||
.navigationBarTitle("Group profile")
|
||||
.modifier(ThemedBackground(grouped: true))
|
||||
.navigationBarTitleDisplayMode(focusDisplayName ? .inline : .large)
|
||||
}
|
||||
|
||||
private func canUpdateProfile() -> Bool {
|
||||
groupProfile.displayName.trimmingCharacters(in: .whitespaces) != "" && validNewProfileName()
|
||||
private var canUpdateProfile: Bool {
|
||||
currentProfileHash != groupProfile.hashValue &&
|
||||
groupProfile.displayName.trimmingCharacters(in: .whitespaces) != "" &&
|
||||
validNewProfileName
|
||||
}
|
||||
|
||||
private func validNewProfileName() -> Bool {
|
||||
private var validNewProfileName: Bool {
|
||||
groupProfile.displayName == groupInfo.groupProfile.displayName
|
||||
|| validDisplayName(groupProfile.displayName.trimmingCharacters(in: .whitespaces))
|
||||
}
|
||||
|
||||
func profileNameTextEdit(_ label: LocalizedStringKey, _ name: Binding<String>) -> some View {
|
||||
TextField(label, text: name)
|
||||
.padding(.leading, 32)
|
||||
}
|
||||
|
||||
func saveProfile() {
|
||||
Task {
|
||||
do {
|
||||
groupProfile.displayName = groupProfile.displayName.trimmingCharacters(in: .whitespaces)
|
||||
groupProfile.fullName = groupProfile.fullName.trimmingCharacters(in: .whitespaces)
|
||||
let gInfo = try await apiUpdateGroup(groupInfo.groupId, groupProfile)
|
||||
await MainActor.run {
|
||||
currentProfileHash = groupProfile.hashValue
|
||||
groupInfo = gInfo
|
||||
chatModel.updateGroup(gInfo)
|
||||
dismiss()
|
||||
|
|
|
@ -24,85 +24,70 @@ struct VerifyCodeView: View {
|
|||
}
|
||||
|
||||
private func verifyCodeView(_ code: String) -> some View {
|
||||
ScrollView {
|
||||
let splitCode = splitToParts(code, length: 24)
|
||||
VStack(alignment: .leading) {
|
||||
Group {
|
||||
let splitCode = splitToParts(code, length: 24)
|
||||
return List {
|
||||
Section {
|
||||
QRCode(uri: code, small: true)
|
||||
|
||||
Text(splitCode)
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.body.monospaced())
|
||||
.lineLimit(20)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
} header: {
|
||||
if connectionVerified {
|
||||
HStack {
|
||||
if connectionVerified {
|
||||
Image(systemName: "checkmark.shield")
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
Text("\(displayName) is verified")
|
||||
} else {
|
||||
Text("\(displayName) is not verified")
|
||||
}
|
||||
Image(systemName: "checkmark.shield").foregroundColor(theme.colors.secondary)
|
||||
Text("\(displayName) is verified").textCase(.none)
|
||||
}
|
||||
.frame(height: 24)
|
||||
|
||||
QRCode(uri: code)
|
||||
.padding(.horizontal)
|
||||
|
||||
Text(splitCode)
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.body.monospaced())
|
||||
.lineLimit(20)
|
||||
.padding(.bottom, 8)
|
||||
} else {
|
||||
Text("\(displayName) is not verified").textCase(.none)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
|
||||
} footer: {
|
||||
Text("To verify end-to-end encryption with your contact compare (or scan) the code on your devices.")
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
Group {
|
||||
if connectionVerified {
|
||||
Button {
|
||||
verifyCode(nil)
|
||||
} label: {
|
||||
Label("Clear verification", systemImage: "shield")
|
||||
}
|
||||
.padding()
|
||||
} else {
|
||||
HStack {
|
||||
NavigationLink {
|
||||
ScanCodeView(connectionVerified: $connectionVerified, verify: verify)
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
.navigationTitle("Scan code")
|
||||
.modifier(ThemedBackground())
|
||||
} label: {
|
||||
Label("Scan code", systemImage: "qrcode")
|
||||
}
|
||||
.padding()
|
||||
Button {
|
||||
verifyCode(code) { verified in
|
||||
if !verified { showCodeError = true }
|
||||
}
|
||||
} label: {
|
||||
Label("Mark verified", systemImage: "checkmark.shield")
|
||||
}
|
||||
.padding()
|
||||
.alert(isPresented: $showCodeError) {
|
||||
Alert(title: Text("Incorrect security code!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Section {
|
||||
if connectionVerified {
|
||||
Button {
|
||||
showShareSheet(items: [splitCode])
|
||||
verifyCode(nil)
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
Label("Clear verification", systemImage: "shield")
|
||||
}
|
||||
} else {
|
||||
NavigationLink {
|
||||
ScanCodeView(connectionVerified: $connectionVerified, verify: verify)
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
.navigationTitle("Scan code")
|
||||
.modifier(ThemedBackground())
|
||||
} label: {
|
||||
Label("Scan code", systemImage: "qrcode")
|
||||
}
|
||||
Button {
|
||||
verifyCode(code) { verified in
|
||||
if !verified { showCodeError = true }
|
||||
}
|
||||
} label: {
|
||||
Label("Mark verified", systemImage: "checkmark.shield")
|
||||
}
|
||||
.alert(isPresented: $showCodeError) {
|
||||
Alert(title: Text("Incorrect security code!"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: connectionVerified) { _ in
|
||||
if connectionVerified { dismiss() }
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
showShareSheet(items: [splitCode])
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: connectionVerified) { _ in
|
||||
if connectionVerified { dismiss() }
|
||||
}
|
||||
}
|
||||
|
||||
private func verifyCode(_ code: String?, _ cb: ((Bool) -> Void)? = nil) {
|
||||
|
|
|
@ -21,7 +21,7 @@ enum DatabaseAlert: Identifiable {
|
|||
case deleteLegacyDatabase
|
||||
case deleteFilesAndMedia
|
||||
case setChatItemTTL(ttl: ChatItemTTL)
|
||||
case error(title: LocalizedStringKey, error: String = "")
|
||||
case error(title: String, error: String = "")
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
|
@ -456,7 +456,7 @@ struct DatabaseView: View {
|
|||
}
|
||||
} catch let error {
|
||||
await MainActor.run {
|
||||
alert = .error(title: "Error exporting chat database", error: responseError(error))
|
||||
alert = .error(title: NSLocalizedString("Error exporting chat database", comment: "alert title"), error: responseError(error))
|
||||
progressIndicator = false
|
||||
}
|
||||
}
|
||||
|
@ -492,10 +492,10 @@ struct DatabaseView: View {
|
|||
return migration
|
||||
}
|
||||
} catch let error {
|
||||
await operationEnded(.error(title: "Error importing chat database", error: responseError(error)), progressIndicator, alert)
|
||||
await operationEnded(.error(title: NSLocalizedString("Error importing chat database", comment: "alert title"), error: responseError(error)), progressIndicator, alert)
|
||||
}
|
||||
} catch let error {
|
||||
await operationEnded(.error(title: "Error deleting chat database", error: responseError(error)), progressIndicator, alert)
|
||||
await operationEnded(.error(title: NSLocalizedString("Error deleting chat database", comment: "alert title"), error: responseError(error)), progressIndicator, alert)
|
||||
}
|
||||
} else {
|
||||
showAlert("Error accessing database file")
|
||||
|
@ -513,7 +513,7 @@ struct DatabaseView: View {
|
|||
await DatabaseView.operationEnded(.chatDeleted, $progressIndicator, $alert)
|
||||
return true
|
||||
} catch let error {
|
||||
await DatabaseView.operationEnded(.error(title: "Error deleting database", error: responseError(error)), $progressIndicator, $alert)
|
||||
await DatabaseView.operationEnded(.error(title: NSLocalizedString("Error deleting database", comment: "alert title"), error: responseError(error)), $progressIndicator, $alert)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -522,7 +522,7 @@ struct DatabaseView: View {
|
|||
if removeLegacyDatabaseAndFiles() {
|
||||
legacyDatabase = false
|
||||
} else {
|
||||
alert = .error(title: "Error deleting old database")
|
||||
alert = .error(title: NSLocalizedString("Error deleting old database", comment: "alert title"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +546,7 @@ struct DatabaseView: View {
|
|||
let (title, message) = chatDeletedAlertText()
|
||||
showAlert(title, message: message, actions: { [okAlertActionWaiting] })
|
||||
} else if case let .error(title, error) = dbAlert {
|
||||
showAlert("\(title)", message: error, actions: { [okAlertActionWaiting] })
|
||||
showAlert(title, message: error, actions: { [okAlertActionWaiting] })
|
||||
} else {
|
||||
alert.wrappedValue = dbAlert
|
||||
cont.resume()
|
||||
|
@ -567,7 +567,7 @@ struct DatabaseView: View {
|
|||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
alert = .error(title: "Error changing setting", error: responseError(error))
|
||||
alert = .error(title: NSLocalizedString("Error changing setting", comment: "alert title"), error: responseError(error))
|
||||
chatItemTTL = currentChatItemTTL
|
||||
afterSetCiTTL()
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ struct NewChatSheet: View {
|
|||
}
|
||||
NavigationLink {
|
||||
AddGroupView()
|
||||
.navigationTitle("Create secret group")
|
||||
.navigationTitle("Create group")
|
||||
.modifier(ThemedBackground(grouped: true))
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
} label: {
|
||||
|
|
|
@ -25,28 +25,8 @@ struct UserProfile: View {
|
|||
|
||||
var body: some View {
|
||||
List {
|
||||
Group {
|
||||
if profile.image != nil {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
profileImageView(profile.image)
|
||||
.onTapGesture { showChooseSource = true }
|
||||
overlayButton("multiply", edge: .top) { profile.image = nil }
|
||||
}
|
||||
overlayButton("camera", edge: .bottom) { showChooseSource = true }
|
||||
}
|
||||
} else {
|
||||
ZStack(alignment: .center) {
|
||||
profileImageView(profile.image)
|
||||
editImageButton { showChooseSource = true }
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
.padding(.top)
|
||||
.contentShape(Rectangle())
|
||||
EditProfileImage(profileImage: $profile.image, showChooseSource: $showChooseSource)
|
||||
.padding(.top)
|
||||
|
||||
Section {
|
||||
HStack {
|
||||
|
@ -133,25 +113,6 @@ struct UserProfile: View {
|
|||
.alert(item: $alert) { a in userProfileAlert(a, $profile.displayName) }
|
||||
}
|
||||
|
||||
private func overlayButton(
|
||||
_ systemName: String,
|
||||
edge: Edge.Set,
|
||||
action: @escaping () -> Void
|
||||
) -> some View {
|
||||
Image(systemName: systemName)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 12)
|
||||
.foregroundColor(theme.colors.primary)
|
||||
.padding(6)
|
||||
.frame(width: 36, height: 36, alignment: .center)
|
||||
.background(radius >= 20 ? Color.clear : theme.colors.background.opacity(0.5))
|
||||
.clipShape(Circle())
|
||||
.contentShape(Circle())
|
||||
.padding([.trailing, edge], -12)
|
||||
.onTapGesture(perform: action)
|
||||
}
|
||||
|
||||
private func showFullName(_ user: User) -> Bool {
|
||||
user.profile.fullName != "" && user.profile.fullName != user.profile.displayName
|
||||
}
|
||||
|
@ -189,8 +150,54 @@ struct UserProfile: View {
|
|||
}
|
||||
}
|
||||
|
||||
func profileImageView(_ imageStr: String?) -> some View {
|
||||
ProfileImage(imageStr: imageStr, size: 192)
|
||||
struct EditProfileImage: View {
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
@AppStorage(DEFAULT_PROFILE_IMAGE_CORNER_RADIUS) private var radius = defaultProfileImageCorner
|
||||
@Binding var profileImage: String?
|
||||
@Binding var showChooseSource: Bool
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if profileImage != nil {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
ProfileImage(imageStr: profileImage, size: 160)
|
||||
.onTapGesture { showChooseSource = true }
|
||||
overlayButton("multiply", edge: .top) { profileImage = nil }
|
||||
}
|
||||
overlayButton("camera", edge: .bottom) { showChooseSource = true }
|
||||
}
|
||||
} else {
|
||||
ZStack(alignment: .center) {
|
||||
ProfileImage(imageStr: profileImage, size: 160)
|
||||
editImageButton { showChooseSource = true }
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
private func overlayButton(
|
||||
_ systemName: String,
|
||||
edge: Edge.Set,
|
||||
action: @escaping () -> Void
|
||||
) -> some View {
|
||||
Image(systemName: systemName)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 12)
|
||||
.foregroundColor(theme.colors.primary)
|
||||
.padding(6)
|
||||
.frame(width: 36, height: 36, alignment: .center)
|
||||
.background(radius >= 20 ? Color.clear : theme.colors.background.opacity(0.5))
|
||||
.clipShape(Circle())
|
||||
.contentShape(Circle())
|
||||
.padding([.trailing, edge], -12)
|
||||
.onTapGesture(perform: action)
|
||||
}
|
||||
}
|
||||
|
||||
func editImageButton(action: @escaping () -> Void) -> some View {
|
||||
|
|
|
@ -1596,13 +1596,13 @@ set passcode view */
|
|||
|
||||
/* delete after time
|
||||
pref value */
|
||||
"default (%@)" = "по умолчанию (%@)";
|
||||
"default (%@)" = "базовый (%@)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"default (no)" = "по умолчанию (нет)";
|
||||
"default (no)" = "базовый (нет)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"default (yes)" = "по умолчанию (да)";
|
||||
"default (yes)" = "базовый (да)";
|
||||
|
||||
/* alert action
|
||||
swipe action */
|
||||
|
@ -1705,7 +1705,7 @@ swipe action */
|
|||
"Delete messages" = "Удалить сообщения";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete messages after" = "Удалять сообщения через";
|
||||
"Delete messages after" = "Удалять сообщения";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete old database" = "Удалить предыдущую версию данных";
|
||||
|
@ -4633,7 +4633,7 @@ chat item action */
|
|||
"Send questions and ideas" = "Отправьте вопросы и идеи";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Send receipts" = "Отправлять отчёты о доставке";
|
||||
"Send receipts" = "Отчёты о доставке";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Send them from gallery or custom keyboards." = "Отправьте из галереи или из дополнительных клавиатур.";
|
||||
|
|
|
@ -68,7 +68,7 @@ private fun VerifyCodeLayout(
|
|||
}
|
||||
}
|
||||
|
||||
QRCode(connectionCode, padding = PaddingValues(vertical = DEFAULT_PADDING_HALF))
|
||||
QRCode(connectionCode, small = true, padding = PaddingValues(vertical = DEFAULT_PADDING_HALF))
|
||||
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(Modifier.weight(2f))
|
||||
|
|
|
@ -84,7 +84,7 @@ fun QRCode(
|
|||
Modifier
|
||||
.padding(padding)
|
||||
.widthIn(max = 400.dp)
|
||||
.fillMaxWidth(if (small) 0.67f else 1f)
|
||||
.fillMaxWidth(if (small) 0.63f else 1f)
|
||||
.aspectRatio(1f)
|
||||
.then(modifier)
|
||||
.clickable {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue