Skip to content

Commit

Permalink
Merge pull request #92 from gldiazcardenas/issue-88-phonnumberfield
Browse files Browse the repository at this point in the history
PhoneNumberField - Added factory for changing country flags
  • Loading branch information
dlemmermann authored Oct 23, 2023
2 parents a67fbe2 + 6deeabf commit 984f590
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
Expand All @@ -29,7 +28,7 @@ public class PhoneNumberFieldApp extends Application {
return null;
}
PhoneNumberField.CountryCallingCode code = (PhoneNumberField.CountryCallingCode) c;
return "(+" + code.countryCode() + ") " + code.displayName("en");
return "(+" + code.countryCode() + ") " + code;
};

@Override
Expand All @@ -42,12 +41,12 @@ public void start(Stage stage) throws Exception {
addControl("Preferred Countries", preferredCountriesSelector(field), controls);
addControl("Force Local Phone", forceLocalPhoneNumberCheck(field), controls);
addControl("Fixed Country", fixedCountrySelector(field), controls);
addControl("Mask", maskInputField(field), controls);

VBox fields = new VBox(10);
addField(fields, "Country Code", field.countryCodeProperty(), COUNTRY_CODE_CONVERTER);
addField(fields, "Phone Number", field.phoneNumberProperty());
addField(fields, "Local Number", field.localPhoneNumberProperty());
addField(fields, "Mask", field.maskProperty());

VBox vBox = new VBox(20);
vBox.setPadding(new Insets(20));
Expand Down Expand Up @@ -106,12 +105,6 @@ private Node preferredCountriesSelector(PhoneNumberField view) {
return comboBox;
}

private Node maskInputField(PhoneNumberField field) {
TextField mask = new TextField();
mask.textProperty().bindBidirectional(field.maskProperty());
return mask;
}

private Node forceLocalPhoneNumberCheck(PhoneNumberField field) {
CheckBox localCheck = new CheckBox();
localCheck.selectedProperty().bindBidirectional(field.forceLocalPhoneNumberProperty());
Expand Down
82 changes: 65 additions & 17 deletions gemsfx/src/main/java/com/dlsc/gemsfx/PhoneNumberField.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@
import javafx.scene.control.Skin;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.util.Callback;
import javafx.util.Pair;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
Expand All @@ -36,6 +34,7 @@
public class PhoneNumberField extends Control {

public static final String DEFAULT_STYLE_CLASS = "phone-number-field";
public static final String DEFAULT_MASK = "(###) ###-##-##";

private final TextField textField = new TextField();

Expand Down Expand Up @@ -142,6 +141,8 @@ public void set(CountryCallingCode countryCallingCode) {
.map(CountryCallingCode::defaultPhonePrefix)
.orElse(null));

Optional.ofNullable(getMaskProvider()).ifPresent(m -> setMask(m.call(countryCallingCode)));

} finally {
selfUpdate = false;
}
Expand Down Expand Up @@ -252,18 +253,53 @@ public final void setForceLocalPhoneNumber(boolean forceLocalPhoneNumber) {
forceLocalPhoneNumberProperty().set(forceLocalPhoneNumber);
}

private final StringProperty mask = new SimpleStringProperty(this, "mask");
private final ObjectProperty<Callback<CountryCallingCode, String>> maskProvider = new SimpleObjectProperty<>(this, "maskProvider", code ->
Optional.ofNullable(code).map(CountryCallingCode::mask).orElse(null)) {
@Override
public void set(Callback<CountryCallingCode, String> newMaskProvider) {
super.set(newMaskProvider);
setMask(Optional.ofNullable(newMaskProvider).map(p -> p.call(getCountryCode())).orElse(null));
}
};

public final StringProperty maskProperty() {
return mask;
public final ObjectProperty<Callback<CountryCallingCode, String>> maskProviderProperty() {
return maskProvider;
}

public final Callback<CountryCallingCode, String> getMaskProvider() {
return maskProviderProperty().get();
}

public final void setMaskProvider(Callback<CountryCallingCode, String> mask) {
maskProviderProperty().set(mask);
}

private final ReadOnlyStringWrapper mask = new ReadOnlyStringWrapper(this, "mask");

public final ReadOnlyStringProperty maskProperty() {
return mask.getReadOnlyProperty();
}

public final String getMask() {
return maskProperty().get();
return mask.get();
}

public final void setMask(String mask) {
maskProperty().set(mask);
private void setMask(String mask) {
this.mask.set(mask);
}

private final ObjectProperty<Callback<CountryCallingCode, Node>> countryCodeViewFactory = new SimpleObjectProperty<>(this, "countryCodeViewFactory");

public final ObjectProperty<Callback<CountryCallingCode, Node>> countryCodeViewFactoryProperty() {
return countryCodeViewFactory;
}

public final Callback<CountryCallingCode, Node> getCountryCodeViewFactory() {
return countryCodeViewFactoryProperty().get();
}

public final void setCountryCodeViewFactory(Callback<CountryCallingCode, Node> countryCodeViewFactory) {
countryCodeViewFactoryProperty().set(countryCodeViewFactory);
}

public interface CountryCallingCode {
Expand All @@ -272,9 +308,9 @@ public interface CountryCallingCode {

int[] areaCodes();

String displayName(String language);
String iso2Code();

Node flagView();
String mask();

default Integer defaultAreaCode() {
return areaCodes().length > 0 ? areaCodes()[0] : null;
Expand Down Expand Up @@ -540,13 +576,17 @@ enum Defaults implements CountryCallingCode {
private final int code;
private final String iso2Code;
private final int[] areaCodes;
private final Image flagImage;
private final String mask;

Defaults(int code, String iso2Code, int... areaCodes) {
this(code, iso2Code, DEFAULT_MASK, areaCodes);
}

Defaults(int code, String iso2Code, String mask, int... areaCodes) {
this.code = code;
this.iso2Code = iso2Code;
this.mask = mask;
this.areaCodes = Optional.ofNullable(areaCodes).orElse(new int[0]);
this.flagImage = new Image(Objects.requireNonNull(PhoneNumberField.class.getResource("phonenumberfield/country-flags/20x13/" + iso2Code.toLowerCase() + ".png")).toExternalForm());
}

@Override
Expand All @@ -560,13 +600,13 @@ public int[] areaCodes() {
}

@Override
public String displayName(String language) {
return new Locale(language, iso2Code).getDisplayCountry();
public String iso2Code() {
return iso2Code;
}

@Override
public Node flagView() {
return new ImageView(flagImage);
public String mask() {
return mask;
}

}
Expand Down Expand Up @@ -642,6 +682,13 @@ private static Pair<Integer, String> scoreAndLocalNumber(CountryCallingCode code
}

private final class PhoneNumberFormatter implements UnaryOperator<TextFormatter.Change> {

private PhoneNumberFormatter() {
maskProperty().addListener((observable, oldMask, newMask) -> {

});
}

@Override
public TextFormatter.Change apply(TextFormatter.Change change) {
if (change.isAdded() || change.isReplaced()) {
Expand All @@ -660,6 +707,7 @@ public TextFormatter.Change apply(TextFormatter.Change change) {
}
}
}

return change;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand All @@ -29,6 +32,14 @@ public class PhoneNumberFieldSkin extends SkinBase<PhoneNumberField> {

private static final Image WORLD_ICON = new Image(Objects.requireNonNull(PhoneNumberField.class.getResource("phonenumberfield/world.png")).toExternalForm());

private static final Map<PhoneNumberField.CountryCallingCode, Image> FLAG_IMAGES = new HashMap<>();

static {
for (PhoneNumberField.CountryCallingCode code : PhoneNumberField.CountryCallingCode.Defaults.values()) {
FLAG_IMAGES.put(code, new Image(Objects.requireNonNull(PhoneNumberField.class.getResource("phonenumberfield/country-flags/20x13/" + code.iso2Code().toLowerCase() + ".png")).toExternalForm()));
}
}

public PhoneNumberFieldSkin(PhoneNumberField field, ReadOnlyObjectWrapper<PhoneNumberField.CountryCallingCode> countryCode) {
super(field);

Expand All @@ -49,8 +60,10 @@ public PhoneNumberFieldSkin(PhoneNumberField field, ReadOnlyObjectWrapper<PhoneN
}
};

getSkinnable().getAvailableCountryCodes().addListener((InvalidationListener) obs -> callingCodesUpdater.run());
getSkinnable().getPreferredCountryCodes().addListener((InvalidationListener) obs -> callingCodesUpdater.run());
InvalidationListener listener = obs -> callingCodesUpdater.run();
getSkinnable().getAvailableCountryCodes().addListener(listener);
getSkinnable().getPreferredCountryCodes().addListener(listener);
getSkinnable().countryCodeViewFactoryProperty().addListener(listener);
callingCodesUpdater.run();

PhoneNumberEditor editor = new PhoneNumberEditor();
Expand Down Expand Up @@ -105,11 +118,9 @@ public PhoneNumberEditor() {
StackPane flagBox = new StackPane();
flagBox.getStyleClass().add("flag-box");

Runnable flagUpdater = () -> flagBox.getChildren().setAll(Optional.ofNullable(getSkinnable().getCountryCode())
.map(PhoneNumberField.CountryCallingCode::flagView)
.orElse(new ImageView(WORLD_ICON)));

Runnable flagUpdater = () -> flagBox.getChildren().setAll(getCountryCodeFlagView(getSkinnable().getCountryCode()));
getSkinnable().countryCodeProperty().addListener(obs -> flagUpdater.run());
getSkinnable().countryCodeViewFactoryProperty().addListener(obs -> flagUpdater.run());
flagUpdater.run();

Region arrow = new Region();
Expand Down Expand Up @@ -177,8 +188,8 @@ protected void updateItem(PhoneNumberField.CountryCallingCode item, boolean empt
int index = -1;

if (item != null && !empty) {
setText("(+" + item.countryCode() + ") " + item.displayName("en"));
setGraphic(item.flagView());
setText("(+" + item.countryCode() + ") " + new Locale("en", item.iso2Code()).getDisplayCountry());
setGraphic(getCountryCodeFlagView(item));
index = getSkinnable().getPreferredCountryCodes().indexOf(item);
} else {
setText(null);
Expand All @@ -200,4 +211,18 @@ protected void updateItem(PhoneNumberField.CountryCallingCode item, boolean empt

}

private Node getCountryCodeFlagView(PhoneNumberField.CountryCallingCode code) {
Node flagView;
if (code != null) {
if (getSkinnable().getCountryCodeViewFactory() != null) {
flagView = getSkinnable().getCountryCodeViewFactory().call(code);
} else {
flagView = new ImageView(Optional.ofNullable(FLAG_IMAGES.get(code)).orElse(WORLD_ICON));
}
} else {
flagView = new ImageView(WORLD_ICON);
}
return flagView;
}

}

0 comments on commit 984f590

Please sign in to comment.