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 @@ -92,7 +92,7 @@ struct CreateUsernameView: View {
.padding(.top, 20)
.focused($isTextInputFocused)

if viewModel.uiState.hasInvite && !viewModel.uiState.isInvitationForContested {
if !viewModel.uiState.contestedAllowed {
HStack(spacing: 0) {
Text(NSLocalizedString("The username must meet ", comment: "Usernames"))
Text(NSLocalizedString("one", comment: "Usernames"))
Expand All @@ -112,7 +112,7 @@ struct CreateUsernameView: View {
if viewModel.uiState.lengthRule != .hidden {
ValidationCheck(
validationResult: viewModel.uiState.lengthRule,
text: viewModel.uiState.hasInvite && !viewModel.uiState.isInvitationForContested ?
text: !viewModel.uiState.contestedAllowed ?
NSLocalizedString("Between 20 and 23 characters", comment: "Usernames") :
NSLocalizedString("Between 3 and 23 characters", comment: "Usernames")
).padding(.top, 20)
Expand All @@ -121,7 +121,7 @@ struct CreateUsernameView: View {
if viewModel.uiState.allowedCharactersRule != .hidden {
ValidationCheck(
validationResult: viewModel.uiState.allowedCharactersRule,
text: viewModel.uiState.hasInvite && !viewModel.uiState.isInvitationForContested ?
text: !viewModel.uiState.contestedAllowed ?
NSLocalizedString("Contains numbers 2-9", comment: "Usernames") :
NSLocalizedString("Letter, numbers and hyphens only", comment: "Usernames")
).padding(.top, 20)
Expand Down Expand Up @@ -158,48 +158,48 @@ struct CreateUsernameView: View {

Spacer()

if viewModel.uiState.hasInvite {
if !viewModel.uiState.isInvitationMixed {
HStack(alignment: .top) {
Image("invite.unmixed")
.resizable()
.scaledToFit()
.frame(width: 18, height: 18)

if viewModel.uiState.hasInvite && !viewModel.uiState.isInvitationMixed {
HStack(alignment: .top) {
Image("invite.unmixed")
.resizable()
.scaledToFit()
.frame(width: 18, height: 18)

Text(NSLocalizedString("The invitation was created with un-mixed funds", comment: "Invites"))
.foregroundColor(.primaryText)
.font(.body2)
}
.padding(.bottom, 16)
Text(NSLocalizedString("The invitation was created with un-mixed funds", comment: "Invites"))
.foregroundColor(.primaryText)
.font(.body2)
}

if !viewModel.uiState.isInvitationForContested {
HStack(alignment: .top) {
Image("invite.noncontested")
.padding(.bottom, 16)
}

if !viewModel.uiState.contestedAllowed {
HStack(alignment: .top) {
Image("invite.noncontested")
.resizable()
.scaledToFit()
.frame(width: 18, height: 18)

Text(viewModel.uiState.hasInvite ? NSLocalizedString("You can only create a non-contested username using this invitation", comment: "Invites") :
NSLocalizedString("You can only create a non-contested username at this time", comment: "Invites"))
.foregroundColor(.primaryText)
.font(.body2)

Spacer()

Button {
showContestedInfo = true
} label: {
Image(systemName: "info.circle.fill")
.resizable()
.scaledToFit()
.frame(width: 18, height: 18)

Text(NSLocalizedString("You can only create a non-contested username using this invitaiton", comment: "Invites"))
.foregroundColor(.primaryText)
.font(.body2)

Spacer()

Button {
showContestedInfo = true
} label: {
Image(systemName: "info.circle.fill")
.resizable()
.scaledToFit()
.padding(8)
.foregroundColor(.gray300)
}
.frame(width: 30, height: 30)
.padding(8)
.foregroundColor(.gray300)
}
.frame(minHeight: 36)
.padding(.bottom, 20)
.frame(width: 30, height: 30)
}
.frame(minHeight: 36)
.padding(.bottom, 20)
}

DashButton(
Expand Down Expand Up @@ -303,10 +303,6 @@ struct CreateUsernameView: View {
.sheet(isPresented: $showContestedInfo) {
let dialog = BottomSheet(showBackButton: Binding<Bool>.constant(false)) {
TextIntro(
buttonLabel: NSLocalizedString("OK", comment: ""),
action: {
showContestedInfo = false
},
inProgress: .constant(false)
) {
FeatureTopText(
Expand All @@ -318,7 +314,7 @@ struct CreateUsernameView: View {
}

if #available(iOS 16.0, *) {
dialog.presentationDetents([.height(500)])
dialog.presentationDetents([.height(400)])
} else {
dialog
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,26 @@

import Combine

private let ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE = false

struct CreateUsernameUIState {
var lengthRule: UsernameValidationRuleResult
var allowedCharactersRule: UsernameValidationRuleResult
var costRule: UsernameValidationRuleResult
var usernameBlockedRule: UsernameValidationRuleResult
var contestedAllowed: Bool
var hasInvite: Bool
var isInvitationMixed: Bool
var isInvitationForContested: Bool
var requiredDash: UInt64
var canContinue: Bool

init(lengthRule: UsernameValidationRuleResult, allowedCharactersRule: UsernameValidationRuleResult, costRule: UsernameValidationRuleResult, usernameBlockedRule: UsernameValidationRuleResult, hasInvite: Bool, isInvitationMixed: Bool, isInvitationForContested: Bool, requiredDash: UInt64, canContinue: Bool) {
init(lengthRule: UsernameValidationRuleResult, allowedCharactersRule: UsernameValidationRuleResult, costRule: UsernameValidationRuleResult, usernameBlockedRule: UsernameValidationRuleResult, contestedAllowed: Bool, hasInvite: Bool, isInvitationMixed: Bool, isInvitationForContested: Bool, requiredDash: UInt64, canContinue: Bool) {
self.lengthRule = lengthRule
self.allowedCharactersRule = allowedCharactersRule
self.costRule = costRule
self.usernameBlockedRule = usernameBlockedRule
self.contestedAllowed = contestedAllowed
self.hasInvite = hasInvite
self.isInvitationMixed = isInvitationMixed
self.isInvitationForContested = isInvitationForContested
Expand All @@ -45,6 +49,7 @@ struct CreateUsernameUIState {
self.allowedCharactersRule = .empty
self.costRule = .hidden
self.usernameBlockedRule = .hidden
self.contestedAllowed = ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE
self.hasInvite = false
self.isInvitationMixed = false
self.isInvitationForContested = false
Expand Down Expand Up @@ -173,6 +178,7 @@ class CreateUsernameViewModel: ObservableObject {
uiState.isInvitationMixed = await isInvitationMixed(assetLockTx: tx)
uiState.isInvitationForContested = await invitationAmount(assetLockTx: tx) >= DWDP_MIN_BALANCE_FOR_CONTESTED_USERNAME
uiState.hasInvite = true
uiState.contestedAllowed = uiState.isInvitationForContested
uiState.costRule = .hidden
}
}
Expand Down Expand Up @@ -219,23 +225,33 @@ class CreateUsernameViewModel: ObservableObject {
let hasInvite = uiState.hasInvite
let isMixed = uiState.isInvitationMixed
let isContested = uiState.isInvitationForContested
let contestedAllowed = uiState.contestedAllowed

uiState = CreateUsernameUIState()
uiState.hasInvite = hasInvite
uiState.isInvitationMixed = isMixed
uiState.isInvitationForContested = isContested
uiState.contestedAllowed = contestedAllowed
return
}

let isContestable = isUsernameContestable(username: username)
let isContested = isContestable // TODO: MOCK_DASHPAY
// Disable contested usernames if no invite and the constant is false
let isContested = if ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE {
isContestable // TODO: MOCK_DASHPAY
} else {
uiState.hasInvite ? isContestable : false
}
let lengthValid = isLengthValid(username: username)
let allowedCharactersRuleValid = allowedCharactersRuleValid(username: username)
let requiredCost = isContested ? DWDP_MIN_BALANCE_FOR_CONTESTED_USERNAME : DWDP_MIN_BALANCE_TO_CREATE_USERNAME
let balance = DWEnvironment.sharedInstance().currentWallet.balance
let hasEnoughBalance = balance >= requiredCost
let isAffordable = uiState.isInvitationForContested || (uiState.hasInvite && !isContested) || hasEnoughBalance
let criteriaValid = if uiState.hasInvite && !uiState.isInvitationForContested {

// Treat no-invite scenario like non-contested invite for validation rules
let shouldUseRelaxedValidation = (uiState.hasInvite && !uiState.isInvitationForContested) || (!uiState.hasInvite && !ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE)
let criteriaValid = if shouldUseRelaxedValidation {
lengthValid || allowedCharactersRuleValid
} else {
lengthValid && allowedCharactersRuleValid
Expand All @@ -248,6 +264,7 @@ class CreateUsernameViewModel: ObservableObject {
allowedCharactersRule: allowedCharactersRuleValid ? .valid : .invalid,
costRule: costRule,
usernameBlockedRule: canContinue && isContested ? .loading : .hidden,
contestedAllowed: uiState.contestedAllowed,
hasInvite: uiState.hasInvite,
isInvitationMixed: uiState.isInvitationMixed,
isInvitationForContested: uiState.isInvitationForContested,
Expand Down Expand Up @@ -305,7 +322,8 @@ class CreateUsernameViewModel: ObservableObject {
}

private func isLengthValid(username: String) -> Bool {
let minLength = uiState.hasInvite && !uiState.isInvitationForContested ? DW_MIN_USERNAME_NONCONTESTED_LENGTH : DW_MIN_USERNAME_LENGTH
let shouldUseRelaxedMinLength = (uiState.hasInvite && !uiState.isInvitationForContested) || (!uiState.hasInvite && !ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE)
let minLength = shouldUseRelaxedMinLength ? DW_MIN_USERNAME_NONCONTESTED_LENGTH : DW_MIN_USERNAME_LENGTH

return username.count >= minLength && username.count <= DW_MAX_USERNAME_LENGTH
}
Expand All @@ -315,7 +333,8 @@ class CreateUsernameViewModel: ObservableObject {
let containsDigits = username.rangeOfCharacter(from: .decimalDigits) != nil
let startsOrEndsWithHyphen = username.first == "-" || username.last == "-"

if uiState.hasInvite && !uiState.isInvitationForContested {
let shouldUseRelaxedCharacterRules = (uiState.hasInvite && !uiState.isInvitationForContested) || (!uiState.hasInvite && !ALLOW_CONTESTED_USERNAMES_WITHOUT_INVITE)
if shouldUseRelaxedCharacterRules {
return !hasIllegalCharacters && containsDigits && !startsOrEndsWithHyphen
}

Expand Down
Loading