Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form Validation Message #16

Merged
merged 3 commits into from
Oct 17, 2024
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
26 changes: 20 additions & 6 deletions data/Application.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
@keyframes fancy-turn {
0% { -gtk-icon-transform: rotate(0deg); }
25% { -gtk-icon-transform: rotate(-30deg); }
50% { -gtk-icon-transform: rotate(0deg); }
75% { -gtk-icon-transform: rotate(30deg); }
100% { -gtk-icon-transform: rotate(0deg); }
0% {
-gtk-icon-transform: rotate(0deg);
}

25% {
-gtk-icon-transform: rotate(-30deg);
}

50% {
-gtk-icon-transform: rotate(0deg);
}

75% {
-gtk-icon-transform: rotate(30deg);
}

100% {
-gtk-icon-transform: rotate(0deg);
}
}

.fancy-turn.animation {
Expand All @@ -18,4 +32,4 @@

.fw-500 {
font-weight: 500;
}
}
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ executable(
'src/Views/Developer.vala',
'src/Views/Form.vala',
'src/Views/Success.vala',
'src/Widgets/InvalidLabel.vala',
'src/Widgets/Stepper.vala',
dependencies: deps,
install: true
Expand Down
1 change: 1 addition & 0 deletions po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ src/MainWindow.vala
src/Views/Developer.vala
src/Views/Form.vala
src/Views/Success.vala
src/Widgets/InvalidLabel.vala
src/Widgets/Stepper.vala
9 changes: 8 additions & 1 deletion src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,15 @@ public class MainWindow : Gtk.ApplicationWindow {
});
main_box.append (form_box);

var scrolled_window = new Gtk.ScrolledWindow () {
child = main_box,
vscrollbar_policy = NEVER,
hscrollbar_policy = NEVER
};

var toolbar_view = new Adw.ToolbarView ();
toolbar_view.add_top_bar (headerbar);
toolbar_view.content = main_box;
toolbar_view.content = scrolled_window;

child = toolbar_view;

Expand Down Expand Up @@ -126,6 +132,7 @@ public class MainWindow : Gtk.ApplicationWindow {

form_view.developer_name = name;
form_view.developer_email = email;
form_view.focus_name ();
});

success_view.back.connect (() => {
Expand Down
39 changes: 34 additions & 5 deletions src/Views/Developer.vala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ public class Views.Developer : Adw.Bin {

public signal void next (string name, string email);

public bool is_valid {
get {
return name_entry.is_valid && email_entry.is_valid;
}
}

construct {
Regex? email_regex = null;
try {
Expand All @@ -23,11 +29,19 @@ public class Views.Developer : Adw.Bin {
text = GLib.Environment.get_real_name ()
};

var name_invalid = new Widgets.InvalidLabel () {
text = _("This field is required")
};

email_entry = new Granite.ValidatedEntry () {
regex = email_regex,
margin_top = 6
};

var email_invalid = new Widgets.InvalidLabel () {
text = _("The email is invalid")
};

next_button = new Gtk.Button.with_label (_("Next")) {
margin_bottom = 32,
sensitive = false,
Expand All @@ -43,8 +57,10 @@ public class Views.Developer : Adw.Bin {
});
form_box.append (new Granite.HeaderLabel (_("Name:")));
form_box.append (name_entry);
form_box.append (name_invalid);
form_box.append (new Granite.HeaderLabel (_("Email:")));
form_box.append (email_entry);
form_box.append (email_invalid);
form_box.append (next_button);

var content_box = new Adw.Bin () {
Expand All @@ -56,16 +72,29 @@ public class Views.Developer : Adw.Bin {

child = content_box;

name_entry.changed.connect (check_valid);
email_entry.changed.connect (check_valid);
name_entry.changed.connect (() => {
check_valid ();
name_invalid.reveal_child = !name_entry.is_valid;
});

next_button.clicked.connect (() => {
next (name_entry.text, email_entry.text);
email_entry.changed.connect (() => {
check_valid ();
email_invalid.reveal_child = !email_entry.is_valid;
});

name_entry.activate.connect (go_next);
email_entry.activate.connect (go_next);
next_button.clicked.connect (go_next);
}

private void go_next () {
if (is_valid) {
next (name_entry.text, email_entry.text);
}
}

private void check_valid () {
next_button.sensitive = name_entry.is_valid && email_entry.is_valid;
next_button.sensitive = is_valid;
}

public void reset_form () {
Expand Down
103 changes: 83 additions & 20 deletions src/Views/Form.vala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ public class Views.Form : Adw.Bin {
public string developer_name { get; set; }
public string developer_email { get; set; }

public bool is_valid {
get {
return project_name_entry.is_valid && identifier_entry.is_valid && location_entry.text.length > 0;
}
}

construct {
Regex? project_name_regex = null;
Regex? identifier_regex = null;
Expand All @@ -26,31 +32,63 @@ public class Views.Form : Adw.Bin {
critical (e.message);
}

var project_name_header = new Granite.HeaderLabel (_("Project Name:")) {
valign = CENTER
};

var project_name_info = new Gtk.MenuButton () {
can_focus = false,
hexpand = true,
halign = END,
icon_name = "dialog-information-symbolic",
popover = build_info_popover (_("A unique name that is used for the project folder and other resources. The name should be in lower case without spaces and should not start with a number"))
};
project_name_info.add_css_class (Granite.STYLE_CLASS_DIM_LABEL);
project_name_info.add_css_class (Granite.STYLE_CLASS_FLAT);

var project_name_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) {
margin_top = 12
};
project_name_box.append (project_name_header);
project_name_box.append (project_name_info);

project_name_entry = new Granite.ValidatedEntry () {
regex = project_name_regex,
margin_top = 6
};

var project_name_description = new Gtk.Label (_("A unique name that is used for the project folder and other resources. The name should be in lower case without spaces and should not start with a number.")) {
wrap = true,
xalign = 0,
margin_top = 3
var project_name_invalid = new Widgets.InvalidLabel () {
text = _("Project name must start with a lowercase letter and contain only letters and numbers")
};
project_name_description.add_css_class (Granite.STYLE_CLASS_DIM_LABEL);
project_name_description.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL);

var identifier_header = new Granite.HeaderLabel (_("Organization Identifier:")) {
valign = CENTER
};

var identifier_info = new Gtk.MenuButton () {
can_focus = false,
hexpand = true,
halign = END,
icon_name = "dialog-information-symbolic",
popover = build_info_popover (_("A reverse domain-name identifier used to identify the application, such as 'io.github.username'. It may not contain dashes"))
};
identifier_info.add_css_class (Granite.STYLE_CLASS_DIM_LABEL);
identifier_info.add_css_class (Granite.STYLE_CLASS_FLAT);

var identifier_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0) {
margin_top = 12
};
identifier_box.append (identifier_header);
identifier_box.append (identifier_info);

identifier_entry = new Granite.ValidatedEntry () {
regex = identifier_regex,
margin_top = 6
};

var identifier_description = new Gtk.Label (_("A reverse domain-name identifier used to identify the application, such as 'io.github.username'. It may not contain dashes.")) {
wrap = true,
xalign = 0,
margin_top = 3
var identifier_invalid = new Widgets.InvalidLabel () {
text = _("App ID must start with a lowercase letter, use dots to separate parts, contain only letters and numbers, and replace hyphens (-) with underscores (_)")
};
identifier_description.add_css_class (Granite.STYLE_CLASS_DIM_LABEL);
identifier_description.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL);

application_id_entry = new Gtk.Entry () {
margin_top = 6,
Expand Down Expand Up @@ -92,6 +130,7 @@ public class Views.Form : Adw.Bin {
vexpand = true,
valign = END,
margin_bottom = 32,
margin_top = 12
};
buttons_box.append (back_button);
buttons_box.append (create_button);
Expand All @@ -101,12 +140,12 @@ public class Views.Form : Adw.Bin {
halign = START,
css_classes = { Granite.STYLE_CLASS_H1_LABEL }
});
form_box.append (new Granite.HeaderLabel (_("Project Name:")));
form_box.append (project_name_box);
form_box.append (project_name_entry);
// form_box.append (project_name_description);
form_box.append (new Granite.HeaderLabel (_("Organization Identifier:")));
form_box.append (project_name_invalid);
form_box.append (identifier_box);
form_box.append (identifier_entry);
// form_box.append (identifier_description);
form_box.append (identifier_invalid);
form_box.append (new Granite.HeaderLabel (_("Application ID:")));
form_box.append (application_id_entry);
form_box.append (new Granite.HeaderLabel (_("Location:")));
Expand All @@ -133,16 +172,18 @@ public class Views.Form : Adw.Bin {

project_name_entry.changed.connect (() => {
application_id_entry.text = identifier_entry.text + "." + project_name_entry.text;
create_button.sensitive = project_name_entry.is_valid && identifier_entry.is_valid && location_entry.text.length > 0;
create_button.sensitive = is_valid;
project_name_invalid.reveal_child = !project_name_entry.is_valid;
});

identifier_entry.changed.connect (() => {
application_id_entry.text = identifier_entry.text + "." + project_name_entry.text;
create_button.sensitive = project_name_entry.is_valid && identifier_entry.is_valid && location_entry.text.length > 0;
create_button.sensitive = is_valid;
identifier_invalid.reveal_child = !identifier_entry.is_valid;
});

location_entry.changed.connect (() => {
create_button.sensitive = project_name_entry.is_valid && identifier_entry.is_valid && location_entry.text.length > 0;
create_button.sensitive = is_valid;
});

location_entry.icon_release.connect ((icon_pos) => {
Expand Down Expand Up @@ -281,7 +322,7 @@ public class Views.Form : Adw.Bin {
}
}

void rename_file (string old_name, string new_name) {
private void rename_file (string old_name, string new_name) {
try {
GLib.File old_file = GLib.File.new_for_path (old_name);
GLib.File new_file = GLib.File.new_for_path (new_name);
Expand All @@ -290,4 +331,26 @@ public class Views.Form : Adw.Bin {
debug (e.message);
}
}

private Gtk.Popover build_info_popover (string text) {
var label = new Gtk.Label (text) {
wrap = true,
margin_top = 6,
margin_bottom = 6,
margin_start = 6,
margin_end = 6,
max_width_chars = 24,
justify = CENTER
};

var popover = new Gtk.Popover () {
child = label
};

return popover;
}

public void focus_name () {
project_name_entry.grab_focus ();
}
}
45 changes: 45 additions & 0 deletions src/Widgets/InvalidLabel.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2024 Alain <[email protected]>
*/

public class Widgets.InvalidLabel : Gtk.Grid {
private Gtk.Label text_label;
private Gtk.Revealer label_revealer;

public string text {
set {
text_label.label = value;
}

get {
return text_label.label;
}
}

public bool reveal_child {
set {
label_revealer.reveal_child = value;
}

get {
return label_revealer.reveal_child;
}
}

construct {
text_label = new Gtk.Label (null) {
xalign = 0,
margin_top = 6,
wrap = true
};
text_label.add_css_class ("error");
text_label.add_css_class (Granite.STYLE_CLASS_SMALL_LABEL);

label_revealer = new Gtk.Revealer () {
child = text_label
};

attach (label_revealer, 0, 0, 1, 1);
}
}