diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..10dc26c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,238 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 120 + +[{*.yml,*.xml,*.json,*.ini,*.md,*.bat,*.sh}] +indent_size = 2 + +[*.php] +indent_style = tab +ij_continuation_indent_size = 4 +ij_php_align_assignments = false +ij_php_align_class_constants = false +ij_php_align_enum_cases = false +ij_php_align_group_field_declarations = false +ij_php_align_inline_comments = false +ij_php_align_key_value_pairs = false +ij_php_align_match_arm_bodies = true +ij_php_align_multiline_array_initializer_expression = false +ij_php_align_multiline_binary_operation = false +ij_php_align_multiline_chained_methods = true +ij_php_align_multiline_extends_list = true +ij_php_align_multiline_for = true +ij_php_align_multiline_parameters = false +ij_php_align_multiline_parameters_in_calls = false +ij_php_align_multiline_ternary_operation = true +ij_php_align_named_arguments = false +ij_php_align_phpdoc_comments = true +ij_php_align_phpdoc_param_names = true +ij_php_anonymous_brace_style = end_of_line +ij_php_api_weight = 28 +ij_php_array_initializer_new_line_after_left_brace = true +ij_php_array_initializer_right_brace_on_new_line = true +ij_php_array_initializer_wrap = normal +ij_php_assignment_wrap = normal +ij_php_attributes_wrap = normal +ij_php_author_weight = 28 +ij_php_binary_operation_sign_on_next_line = true +ij_php_binary_operation_wrap = normal +ij_php_blank_lines_after_class_header = 0 +ij_php_blank_lines_after_function = 1 +ij_php_blank_lines_after_imports = 1 +ij_php_blank_lines_after_opening_tag = 1 +ij_php_blank_lines_after_package = 1 +ij_php_blank_lines_around_class = 1 +ij_php_blank_lines_around_constants = 0 +ij_php_blank_lines_around_enum_cases = 0 +ij_php_blank_lines_around_field = 0 +ij_php_blank_lines_around_method = 1 +ij_php_blank_lines_before_class_end = 0 +ij_php_blank_lines_before_imports = 1 +ij_php_blank_lines_before_method_body = 0 +ij_php_blank_lines_before_package = 0 +ij_php_blank_lines_before_return_statement = 0 +ij_php_blank_lines_between_imports = 1 +ij_php_block_brace_style = end_of_line +ij_php_call_parameters_new_line_after_left_paren = false +ij_php_call_parameters_right_paren_on_new_line = false +ij_php_call_parameters_wrap = normal +ij_php_catch_on_new_line = false +ij_php_category_weight = 28 +ij_php_class_brace_style = end_of_line +ij_php_comma_after_last_argument = false +ij_php_comma_after_last_array_element = false +ij_php_comma_after_last_closure_use_var = false +ij_php_comma_after_last_match_arm = false +ij_php_comma_after_last_parameter = false +ij_php_concat_spaces = true +ij_php_copyright_weight = 28 +ij_php_deprecated_weight = 28 +ij_php_do_while_brace_force = always +ij_php_else_if_style = combine +ij_php_else_on_new_line = false +ij_php_example_weight = 28 +ij_php_extends_keyword_wrap = normal +ij_php_extends_list_wrap = normal +ij_php_fields_default_visibility = private +ij_php_filesource_weight = 28 +ij_php_finally_on_new_line = false +ij_php_for_brace_force = always +ij_php_for_statement_new_line_after_left_paren = false +ij_php_for_statement_right_paren_on_new_line = true +ij_php_for_statement_wrap = normal +ij_php_force_empty_methods_in_one_line = true +ij_php_force_short_declaration_array_style = true +ij_php_getters_setters_naming_style = camel_case +ij_php_getters_setters_order_style = getters_first +ij_php_global_weight = 28 +ij_php_group_use_wrap = normal +ij_php_if_brace_force = always +ij_php_if_lparen_on_next_line = false +ij_php_if_rparen_on_next_line = false +ij_php_ignore_weight = 28 +ij_php_import_sorting = alphabetic +ij_php_indent_break_from_case = true +ij_php_indent_case_from_switch = true +ij_php_indent_code_in_php_tags = false +ij_php_internal_weight = 28 +ij_php_keep_blank_lines_after_lbrace = 0 +ij_php_keep_blank_lines_before_right_brace = 0 +ij_php_keep_blank_lines_in_code = 2 +ij_php_keep_blank_lines_in_declarations = 2 +ij_php_keep_control_statement_in_one_line = true +ij_php_keep_first_column_comment = true +ij_php_keep_indents_on_empty_lines = false +ij_php_keep_line_breaks = true +ij_php_keep_rparen_and_lbrace_on_one_line = true +ij_php_keep_simple_classes_in_one_line = true +ij_php_keep_simple_methods_in_one_line = false +ij_php_lambda_brace_style = end_of_line +ij_php_license_weight = 28 +ij_php_line_comment_add_space = false +ij_php_line_comment_at_first_column = true +ij_php_link_weight = 28 +ij_php_lower_case_boolean_const = true +ij_php_lower_case_keywords = true +ij_php_lower_case_null_const = true +ij_php_method_brace_style = end_of_line +ij_php_method_call_chain_wrap = normal +ij_php_method_parameters_new_line_after_left_paren = true +ij_php_method_parameters_right_paren_on_new_line = true +ij_php_method_parameters_wrap = normal +ij_php_method_weight = 28 +ij_php_modifier_list_wrap = false +ij_php_multiline_chained_calls_semicolon_on_new_line = false +ij_php_namespace_brace_style = 1 +ij_php_new_line_after_php_opening_tag = true +ij_php_null_type_position = in_the_end +ij_php_package_weight = 28 +ij_php_param_weight = 0 +ij_php_parameters_attributes_wrap = normal +ij_php_parentheses_expression_new_line_after_left_paren = false +ij_php_parentheses_expression_right_paren_on_new_line = false +ij_php_phpdoc_blank_line_before_tags = true +ij_php_phpdoc_blank_lines_around_parameters = true +ij_php_phpdoc_keep_blank_lines = true +ij_php_phpdoc_param_spaces_between_name_and_description = 1 +ij_php_phpdoc_param_spaces_between_tag_and_type = 1 +ij_php_phpdoc_param_spaces_between_type_and_name = 1 +ij_php_phpdoc_use_fqcn = false +ij_php_phpdoc_wrap_long_lines = true +ij_php_place_assignment_sign_on_next_line = false +ij_php_place_parens_for_constructor = 1 +ij_php_property_read_weight = 28 +ij_php_property_weight = 28 +ij_php_property_write_weight = 28 +ij_php_return_type_on_new_line = false +ij_php_return_weight = 1 +ij_php_see_weight = 28 +ij_php_since_weight = 28 +ij_php_sort_phpdoc_elements = true +ij_php_space_after_colon = true +ij_php_space_after_colon_in_enum_backed_type = true +ij_php_space_after_colon_in_named_argument = true +ij_php_space_after_colon_in_return_type = true +ij_php_space_after_comma = true +ij_php_space_after_for_semicolon = true +ij_php_space_after_quest = true +ij_php_space_after_type_cast = true +ij_php_space_after_unary_not = false +ij_php_space_before_array_initializer_left_brace = false +ij_php_space_before_catch_keyword = false +ij_php_space_before_catch_left_brace = false +ij_php_space_before_catch_parentheses = false +ij_php_space_before_class_left_brace = false +ij_php_space_before_closure_left_parenthesis = false +ij_php_space_before_colon = true +ij_php_space_before_colon_in_enum_backed_type = true +ij_php_space_before_colon_in_named_argument = false +ij_php_space_before_colon_in_return_type = true +ij_php_space_before_comma = false +ij_php_space_before_do_left_brace = false +ij_php_space_before_else_keyword = false +ij_php_space_before_else_left_brace = false +ij_php_space_before_finally_keyword = false +ij_php_space_before_finally_left_brace = false +ij_php_space_before_for_left_brace = false +ij_php_space_before_for_parentheses = false +ij_php_space_before_for_semicolon = false +ij_php_space_before_if_left_brace = false +ij_php_space_before_if_parentheses = false +ij_php_space_before_method_call_parentheses = false +ij_php_space_before_method_left_brace = false +ij_php_space_before_method_parentheses = false +ij_php_space_before_quest = true +ij_php_space_before_short_closure_left_parenthesis = false +ij_php_space_before_switch_left_brace = false +ij_php_space_before_switch_parentheses = false +ij_php_space_before_try_left_brace = false +ij_php_space_before_unary_not = false +ij_php_space_before_while_keyword = false +ij_php_space_before_while_left_brace = false +ij_php_space_before_while_parentheses = false +ij_php_space_between_ternary_quest_and_colon = false +ij_php_spaces_around_additive_operators = true +ij_php_spaces_around_arrow = false +ij_php_spaces_around_assignment_in_declare = false +ij_php_spaces_around_assignment_operators = true +ij_php_spaces_around_bitwise_operators = true +ij_php_spaces_around_equality_operators = true +ij_php_spaces_around_logical_operators = true +ij_php_spaces_around_multiplicative_operators = true +ij_php_spaces_around_null_coalesce_operator = true +ij_php_spaces_around_pipe_in_union_type = false +ij_php_spaces_around_relational_operators = true +ij_php_spaces_around_shift_operators = true +ij_php_spaces_around_unary_operator = false +ij_php_spaces_around_var_within_brackets = false +ij_php_spaces_within_array_initializer_braces = false +ij_php_spaces_within_brackets = false +ij_php_spaces_within_catch_parentheses = false +ij_php_spaces_within_for_parentheses = false +ij_php_spaces_within_if_parentheses = false +ij_php_spaces_within_method_call_parentheses = false +ij_php_spaces_within_method_parentheses = false +ij_php_spaces_within_parentheses = false +ij_php_spaces_within_short_echo_tags = false +ij_php_spaces_within_switch_parentheses = false +ij_php_spaces_within_while_parentheses = false +ij_php_special_else_if_treatment = true +ij_php_subpackage_weight = 28 +ij_php_ternary_operation_signs_on_next_line = true +ij_php_ternary_operation_wrap = normal +ij_php_throws_weight = 2 +ij_php_todo_weight = 28 +ij_php_treat_multiline_arrays_and_lambdas_multiline = false +ij_php_unknown_tag_weight = 28 +ij_php_upper_case_boolean_const = false +ij_php_upper_case_null_const = false +ij_php_uses_weight = 28 +ij_php_var_weight = 28 +ij_php_variable_naming_style = camel_case +ij_php_version_weight = 28 +ij_php_while_brace_force = always +ij_php_while_on_new_line = false \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.poggit.yml b/.poggit.yml new file mode 100644 index 0000000..cf22f2f --- /dev/null +++ b/.poggit.yml @@ -0,0 +1,12 @@ +--- +branches: + - main +projects: + libasynform: + path: "" + model: virion + type: library + libs: + - src: SOF3/await-generator/await-generator + version: "^3.6.1" +... diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..58c22a5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 PresentKim + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..9131c6b Binary files /dev/null and b/assets/icon.png differ diff --git a/conposer.json b/conposer.json new file mode 100644 index 0000000..7ca7fc7 --- /dev/null +++ b/conposer.json @@ -0,0 +1,22 @@ +{ + "name": "presentkim/libasynform", + "description": "Provides form classes for await-generator for PocketMine-MP", + "type": "library", + "license": "MIT", + "require": { + "pocketmine/pocketmine-mp": "^5.0.0" + }, + "autoload": { + "psr-4": { + "kim\\present\\libasynform\\": [ + "src/kim/present/libasynform/" + ] + } + }, + "extra": { + "virion": { + "spec": "3.0", + "namespace-root": "kim\\present\\libasynform" + } + } +} diff --git a/src/kim/present/libasynform/BaseForm.php b/src/kim/present/libasynform/BaseForm.php new file mode 100644 index 0000000..2535537 --- /dev/null +++ b/src/kim/present/libasynform/BaseForm.php @@ -0,0 +1,113 @@ +. + * + * @author PresentKim (debe3721@gmail.com) + * @link https://github.com/PresentKim + * @license https://opensource.org/licenses/MIT MIT License + * + * (\ /) + * ( . .) ♥ + * c(")(") + * + * @noinspection PhpUnused + */ + +declare(strict_types=1); + +namespace kim\present\libasynform; + +use pocketmine\form\Form; +use pocketmine\form\FormValidationException; +use pocketmine\player\Player; +use SOFe\AwaitGenerator\Await; + +use function spl_object_id; + +abstract class BaseForm implements Form{ + abstract public static function getType() : string; + + abstract protected function processData(mixed $data) : mixed; + + /** + * @var \Closure[] $promises + * @phpstan-var array + */ + private array $promises = []; + + protected array $data; + + public function __construct( + string $title = "" + ){ + $this->data = [ + "type" => static::getType(), + "title" => $title + ]; + } + + public function getTitle() : string{ + return $this->data["title"]; + } + + public function setTitle(string $title) : self{ + $this->data["title"] = $title; + return $this; + } + + public function handleResponse(Player $player, $data) : void{ + $id = spl_object_id($player); + if(!isset($this->promises[$id])){ + throw new FormValidationException("Received response from player who didn't receive the form"); + } + [$resolve, $reject] = $this->promises[$id]; + unset($this->promises[$id]); + + if($data === null){ + $resolve(null); + return; + } + + try{ + $data = $this->processData($data); + }catch(\Exception $e){ + $reject($e); + return; + } + + $resolve($data); + } + + public function send(Player $player) : \Generator{ + $recieve = null; + yield from Await::promise(function($resolve, $reject) use (&$recieve, $player){ + $id = spl_object_id($player); + if(isset($this->promises[$id])){ + $reject(new FormValidationException("Player is already viewing a form")); + return; + } + + $player->sendForm($this); + $this->promises[$id] = [ + function(mixed $recive) use (&$recieve, $resolve){ + $recieve = $recive; + $resolve(); + }, $reject + ]; + }); + return $recieve; + } + + public function jsonSerialize() : array{ + return $this->data; + } +} diff --git a/src/kim/present/libasynform/BaseStringContentForm.php b/src/kim/present/libasynform/BaseStringContentForm.php new file mode 100644 index 0000000..7de7c59 --- /dev/null +++ b/src/kim/present/libasynform/BaseStringContentForm.php @@ -0,0 +1,47 @@ +. + * + * @author PresentKim (debe3721@gmail.com) + * @link https://github.com/PresentKim + * @license https://opensource.org/licenses/MIT MIT License + * + * (\ /) + * ( . .) ♥ + * c(")(") + * + * @noinspection PhpUnused + */ + +declare(strict_types=1); + +namespace kim\present\libasynform; + +abstract class BaseStringContentForm extends BaseForm{ + + public function __construct( + string $title = "", + string $content = "" + ){ + parent::__construct($title); + $this->data["content"] = $content; + } + + public function getContent() : string{ + return $this->data["content"]; + } + + public function setContent(string $content) : self{ + $this->data["content"] = $content; + return $this; + } +} diff --git a/src/kim/present/libasynform/CustomForm.php b/src/kim/present/libasynform/CustomForm.php new file mode 100644 index 0000000..ec8efa6 --- /dev/null +++ b/src/kim/present/libasynform/CustomForm.php @@ -0,0 +1,143 @@ +. + * + * @author PresentKim (debe3721@gmail.com) + * @link https://github.com/PresentKim + * @license https://opensource.org/licenses/MIT MIT License + * + * (\ /) + * ( . .) ♥ + * c(")(") + * + * @noinspection PhpUnused + */ + +declare(strict_types=1); + +namespace kim\present\libasynform; + +use pocketmine\form\FormValidationException; + +use function count; +use function gettype; +use function is_array; +use function is_bool; +use function is_float; +use function is_int; +use function is_string; + +class CustomForm extends BaseForm{ + + private array $labelMap = []; + private array $validators = []; + + public function __construct(string $title = ""){ + parent::__construct($title); + $this->data["content"] = []; + } + + public function addLabel(string $text, ?string $label = null) : self{ + $this->addContent(["type" => "label", "text" => $text]); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => $v === null; + return $this; + } + + public function addToggle(string $text, bool $default = null, ?string $label = null) : self{ + $content = ["type" => "toggle", "text" => $text]; + if($default !== null){ + $content["default"] = $default; + } + $this->addContent($content); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => is_bool($v); + return $this; + } + + public function addSlider(string $text, int $min, int $max, int $step = -1, int $default = -1, ?string $label = null + ) : self{ + $content = ["type" => "slider", "text" => $text, "min" => $min, "max" => $max]; + if($step !== -1){ + $content["step"] = $step; + } + if($default !== -1){ + $content["default"] = $default; + } + $this->addContent($content); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => (is_float($v) || is_int($v)) && $v >= $min && $v <= $max; + return $this; + } + + public function addStepSlider(string $text, array $steps, int $defaultIndex = -1, ?string $label = null) : self{ + $content = ["type" => "step_slider", "text" => $text, "steps" => $steps]; + if($defaultIndex !== -1){ + $content["default"] = $defaultIndex; + } + $this->addContent($content); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => is_int($v) && isset($steps[$v]); + return $this; + } + + public function addDropdown(string $text, array $options, int $default = null, ?string $label = null) : self{ + $this->addContent(["type" => "dropdown", "text" => $text, "options" => $options, "default" => $default]); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => is_int($v) && isset($options[$v]); + return $this; + } + + public function addInput(string $text, string $placeholder = "", string $default = null, ?string $label = null + ) : self{ + $this->addContent(["type" => "input", "text" => $text, "placeholder" => $placeholder, "default" => $default]); + $this->labelMap[] = $label ?: count($this->labelMap); + $this->validators[] = static fn($v) => is_string($v); + return $this; + } + + private function addContent(array $content) : void{ + $this->data["content"][] = $content; + } + + public function processData($data) : array{ + if(!is_array($data)){ + throw new FormValidationException("Expected an array response, got " . gettype($data)); + } + + if(count($data) !== count($this->validators)){ + throw new FormValidationException( + "Expected an array response with the size " . count($this->validators) . ", got " . count($data) + ); + } + $new = []; + foreach($data as $i => $v){ + $validator = $this->validators[$i] ?? null; + if($validator === null){ + throw new FormValidationException("Invalid element " . $i); + } + if(!$validator($v)){ + throw new FormValidationException("Invalid type given for element " . $this->labelMap[$i]); + } + $new[$this->labelMap[$i]] = $v; + } + return $new; + } + + public static function getType() : string{ + return "custom_form"; + } + + public static function create(string $title) : self{ + return new self($title); + } +} diff --git a/src/kim/present/libasynform/ModalFormBase.php b/src/kim/present/libasynform/ModalFormBase.php new file mode 100644 index 0000000..cc63c4d --- /dev/null +++ b/src/kim/present/libasynform/ModalFormBase.php @@ -0,0 +1,85 @@ +. + * + * @author PresentKim (debe3721@gmail.com) + * @link https://github.com/PresentKim + * @license https://opensource.org/licenses/MIT MIT License + * + * (\ /) + * ( . .) ♥ + * c(")(") + * + * @noinspection PhpUnused + */ + +declare(strict_types=1); + +namespace kim\present\libasynform; + +use pocketmine\form\FormValidationException; + +use function gettype; +use function is_bool; + +class ModalFormBase extends BaseStringContentForm{ + + public function __construct( + string $title = "", + string $content = "", + string $button1 = "", + string $button2 = "" + ){ + parent::__construct($title, $content); + $this->data["button1"] = $button1; + $this->data["button2"] = $button2; + } + + public function getButton1() : string{ + return $this->data["button1"]; + } + + public function setButton1(string $text) : self{ + $this->data["button1"] = $text; + return $this; + } + + public function getButton2() : string{ + return $this->data["button2"]; + } + + public function setButton2(string $text) : self{ + $this->data["button2"] = $text; + return $this; + } + + protected function processData($data) : bool{ + if(!is_bool($data)){ + throw new FormValidationException("Expected a boolean response, got " . gettype($data)); + } + + return $data; + } + + public static function getType() : string{ + return "modal"; + } + + public static function create( + string $title = "", + string $content = "", + string $button1 = "", + string $button2 = "" + ) : self{ + return new self($title, $content, $button1, $button2); + } +} diff --git a/src/kim/present/libasynform/SimpleFormBase.php b/src/kim/present/libasynform/SimpleFormBase.php new file mode 100644 index 0000000..22616be --- /dev/null +++ b/src/kim/present/libasynform/SimpleFormBase.php @@ -0,0 +1,74 @@ +. + * + * @author PresentKim (debe3721@gmail.com) + * @link https://github.com/PresentKim + * @license https://opensource.org/licenses/MIT MIT License + * + * (\ /) + * ( . .) ♥ + * c(")(") + * + * @noinspection PhpUnused + */ + +declare(strict_types=1); + +namespace kim\present\libasynform; + +use pocketmine\form\FormValidationException; + +use function gettype; +use function is_int; + +class SimpleFormBase extends BaseStringContentForm{ + public const IMAGE_TYPE_PATH = 0; + public const IMAGE_TYPE_URL = 1; + + /** + * @param string $text + * @param int $imageType + * @param string $imagePath + * + * @return $this + */ + public function addButton(string $text, int $imageType = -1, string $imagePath = "") : self{ + $content = ["text" => $text]; + if($imageType !== -1){ + $content["image"]["type"] = $imageType === 0 ? "path" : "url"; + $content["image"]["data"] = $imagePath; + } + $this->data["buttons"][] = $content; + return $this; + } + + protected function processData(mixed $data) : int{ + if(!is_int($data)){ + throw new FormValidationException("Expected an integer response, got " . gettype($data)); + } + + if(!isset($this->data["buttons"][$data])){ + throw new FormValidationException("Button $data does not exist"); + } + + return $data; + } + + public static function getType() : string{ + return "form"; + } + + public static function create(string $title = "", string $content = "",) : self{ + return new self($title, $content); + } +} diff --git a/virion.yml b/virion.yml new file mode 100644 index 0000000..72dec19 --- /dev/null +++ b/virion.yml @@ -0,0 +1,8 @@ +--- +name: libasynform +antigen: kim\present\libasynform +version: 0.0.1 +api: [ 5.0.0 ] +author: PresentKim +description: "Provides form classes for await-generator" +...