update the text input to support multiple lines

pull/891/head
Ryan ZHAO 1 year ago
parent 1a799d5565
commit 0fc40edb71

@ -30,14 +30,15 @@ struct NewMessageScreen: View {
if tabIndex == 0 {
EnterAccountIdScreen(
accountIdOrONS: $accountIdOrONS,
error: $errorString
error: $errorString,
continueAction: continueWithAccountIdOrONS
)
}
else {
ScanQRCodeScreen(
$accountIdOrONS,
error: $errorString,
continueAction: continueWithAccountId
continueAction: continueWithAccountIdFromQRCode
)
}
}
@ -54,10 +55,14 @@ struct NewMessageScreen: View {
}
}
func continueWithAccountId(onError: (() -> ())?) {
func continueWithAccountIdFromQRCode(onError: (() -> ())?) {
startNewPrivateChatIfPossible(with: accountIdOrONS, onError: onError)
}
func continueWithAccountIdOrONS() {
startNewDMIfPossible(with: accountIdOrONS, onError: nil)
}
fileprivate func startNewDMIfPossible(with onsNameOrPublicKey: String, onError: (() -> ())?) {
let maybeSessionId: SessionId? = SessionId(from: onsNameOrPublicKey)
@ -67,10 +72,10 @@ struct NewMessageScreen: View {
startNewDM(with: onsNameOrPublicKey)
case .blinded15, .blinded25:
errorString = "DM_ERROR_DIRECT_BLINDED_ID".localized()
errorString = "new_message_screen_error_msg_invalid_account_id".localized()
default:
errorString = "DM_ERROR_INVALID".localized()
break
}
return
}
@ -93,6 +98,8 @@ struct NewMessageScreen: View {
switch error {
case .decryptionFailed, .hashingFailed, .validationFailed:
messageOrNil = error.errorDescription
case .generic:
messageOrNil = "new_message_screen_error_msg_network_issue".localized()
default: break
}
}
@ -102,8 +109,8 @@ struct NewMessageScreen: View {
}
return (maybeSessionId?.prefix == .blinded15 || maybeSessionId?.prefix == .blinded25 ?
"DM_ERROR_DIRECT_BLINDED_ID".localized() :
"DM_ERROR_INVALID".localized()
"new_message_screen_error_msg_invalid_account_id".localized() :
"new_message_screen_error_msg_unrecognized_ons".localized()
)
}()
@ -133,6 +140,8 @@ struct NewMessageScreen: View {
struct EnterAccountIdScreen: View {
@Binding var accountIdOrONS: String
@Binding var error: String?
@State var isTextFieldInErrorMode: Bool = false
var continueAction: () -> ()
var body: some View {
VStack(
@ -143,9 +152,7 @@ struct EnterAccountIdScreen: View {
$accountIdOrONS,
placeholder: "new_message_screen_enter_account_id_hint".localized(),
error: $error
)
if error?.isEmpty != true {
) {
ZStack {
if #available(iOS 14.0, *) {
Text("\("new_message_screen_enter_account_id_explanation".localized())\(Image(systemName: "questionmark.circle"))")
@ -160,7 +167,7 @@ struct EnterAccountIdScreen: View {
}
}
.padding(.horizontal, Values.smallSpacing)
.padding(.top, -50)
.padding(.top, Values.smallSpacing)
.onTapGesture {
if let url: URL = URL(string: "https://sessionapp.zendesk.com/hc/en-us/articles/4439132747033-How-do-Session-ID-usernames-work-") {
UIApplication.shared.open(url)
@ -172,7 +179,7 @@ struct EnterAccountIdScreen: View {
if !accountIdOrONS.isEmpty {
Button {
continueAction()
} label: {
Text("next".localized())
.bold()

@ -877,3 +877,6 @@ The point that a message will disappear in a disappearing message update message
"new_message_screen_enter_account_id_tab_title" = "Enter Account ID";
"new_message_screen_enter_account_id_hint" = "Enter Account ID or ONS";
"new_message_screen_enter_account_id_explanation" = "Start a new conversation by entering your friend's Account ID, ONS or scanning their QR code.";
"new_message_screen_error_msg_invalid_account_id" = "This Account ID is invalid. Please check and try again.";
"new_message_screen_error_msg_unrecognized_ons" = "We couldnt recognize this ONS. Please check and try again.";
"new_message_screen_error_msg_network_issue" = "We were unable to search for this ONS. Please try again later.";

@ -53,7 +53,7 @@ struct DisplayNameScreen: View {
$displayName,
placeholder: "onboarding_display_name_hint".localized(),
error: $error
)
) {}
Spacer(minLength: 0)
.frame(maxHeight: Values.massiveSpacing)

@ -163,7 +163,7 @@ struct EnterRecoveryPasswordScreen: View{
$recoveryPassword,
placeholder: "onboarding_recovery_password_hint".localized(),
error: $error
)
) {}
Spacer(minLength: 0)
.frame(maxHeight: Values.massiveSpacing)

@ -2,12 +2,14 @@
import SwiftUI
import Combine
import UIKit
public struct SessionTextField: View {
public struct SessionTextField<ExplanationView>: View where ExplanationView: View {
@Binding var text: String
@Binding var error: String?
@State var previousError: String = ""
let explanationView: () -> ExplanationView
let placeholder: String
var textThemeColor: ThemeValue {
(error?.isEmpty == false) ? .danger : .textPrimary
@ -18,13 +20,15 @@ public struct SessionTextField: View {
return false
}
static let height: CGFloat = isIPhone5OrSmaller ? CGFloat(48) : CGFloat(80)
static let cornerRadius: CGFloat = 13
let height: CGFloat = isIPhone5OrSmaller ? CGFloat(48) : CGFloat(80)
let cornerRadius: CGFloat = 13
public init(_ text: Binding<String>, placeholder: String, error: Binding<String?>) {
public init(_ text: Binding<String>, placeholder: String, error: Binding<String?>, @ViewBuilder explanationView: @escaping () -> ExplanationView) {
self._text = text
self.placeholder = placeholder
self._error = error
self.explanationView = explanationView
UITextView.appearance().backgroundColor = .clear
}
public var body: some View {
@ -32,49 +36,95 @@ public struct SessionTextField: View {
alignment: .center,
spacing: Values.smallSpacing
) {
ZStack(alignment: .topLeading) {
ZStack(alignment: .leading) {
if text.isEmpty {
Text(placeholder)
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: isErrorMode ? .danger : .textSecondary)
}
SwiftUI.TextField(
"",
text: $text.onChange{ value in
if error?.isEmpty == false && text != value {
previousError = error!
error = nil
}
if #available(iOS 16.0, *) {
SwiftUI.TextField(
"",
text: $text.onChange{ value in
if error?.isEmpty == false && text != value {
previousError = error!
error = nil
}
},
axis: .vertical
)
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: textThemeColor)
} else if #available(iOS 14.0, *) {
ZStack {
TextEditor(
text: $text.onChange{ value in
if error?.isEmpty == false && text != value {
previousError = error!
error = nil
}
}
)
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: textThemeColor)
.transparentScrolling()
.frame(maxHeight: self.height)
.padding(.all, -4)
// FIXME: This is a workaround for dynamic height of the TextEditor.
Text(text.isEmpty ? placeholder : text)
.font(.system(size: Values.smallFontSize))
.opacity(0)
.padding(.all, 4)
.frame(
maxWidth: .infinity,
maxHeight: self.height
)
}
)
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: textThemeColor)
.fixedSize(horizontal: false, vertical: true)
} else {
SwiftUI.TextField(
"",
text: $text.onChange{ value in
if error?.isEmpty == false && text != value {
previousError = error!
error = nil
}
}
)
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: textThemeColor)
}
}
.padding(.horizontal, Values.largeSpacing)
.frame(maxWidth: .infinity)
.frame(height: Self.height)
.frame(height: self.height)
.overlay(
RoundedRectangle(
cornerSize: CGSize(
width: Self.cornerRadius,
height: Self.cornerRadius
width: self.cornerRadius,
height: self.cornerRadius
)
)
.stroke(themeColor: isErrorMode ? .danger : .borderSeparator)
)
ZStack {
Text(error ?? previousError)
.bold()
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: .danger)
.multilineTextAlignment(.center)
if isErrorMode {
ZStack {
Text(error ?? previousError)
.bold()
.font(.system(size: Values.smallFontSize))
.foregroundColor(themeColor: .danger)
.multilineTextAlignment(.center)
}
.frame(
height: 50,
alignment: .top
)
} else {
explanationView()
}
.frame(
height: 50,
alignment: .top
)
}
}
}
@ -82,7 +132,13 @@ public struct SessionTextField: View {
struct SessionTextField_Previews: PreviewProvider {
@State static var text: String = "test"
@State static var error: String? = "test error"
@State static var emptyText: String = ""
@State static var emptyError: String? = nil
static var previews: some View {
SessionTextField($text, placeholder: "Placeholder", error: $error)
VStack {
SessionTextField($text, placeholder: "Placeholder", error: $error) {}
SessionTextField($emptyText, placeholder: "Placeholder", error: $emptyError) {}
}
}
}

@ -102,6 +102,16 @@ extension View {
public func toastView(message: Binding<String?>) -> some View {
self.modifier(ToastModifier(message: message))
}
public func transparentScrolling() -> some View {
if #available(iOS 16.0, *) {
return scrollContentBackground(.hidden)
} else {
return onAppear {
UITextView.appearance().backgroundColor = .clear
}
}
}
}
extension Binding {

Loading…
Cancel
Save