hypi_tink_api 0.1.0 hypi_tink_api: ^0.1.0 copied to clipboard
A package containing public API definitions for building Hypi Tink Editor extensions
Hypi Tink #
This package provides the APIs needed to develop extenstions (Widgets or Actions) for Hypi's nocode platform.
Basics #
The platform supports two types of extensions:
- Widgets
- Actions
Widgets are any Flutter Stateful or Stateless widgets that you'd like to use in Hypi's editor.
Actions are any piece of code you'd like to use to provide custom behaviour for an app. An action can literally be made to do anything that's possible in a standard Flutter app.
Widget extension #
Developing a Widget extension involves building the widget itself and providing Hypi Tink with a handler implementation
for this widget. A handler is a class which mixes in the HypiTinkWidgetHandler
mixin AND has the @TinkEditorHandler
annotation.
For example:
//here, this handler will be used to manage the `MyWidget` widget
//MyWidget must be unique and should not conflict with any existing widget in the editor
//Use a prefix/suffix e.g. MyCompanyWidget
@TinkEditorHandler(['MyWidget'])
class MyWidgetHandler with TinkWidgetHandler {
String? myField;
//here you can override any of the methods from TinkWidgetHandler to customise how your widget is handled in the editor
//You MUST have a constructor which accepts a single parameter of type TinkWidgetHandler
MyWidgetHandler(TinkWidgetHandler delegate) {
//you MUST call initDelegate and pass the delegate and this to it - best practice is to call this as the first thing in the constructor of your handler
initDelegate(delegate, this);
//if your widget has properties that need to be persisted then you declare them e.g.
//As well as TSimpleField there are TDoubleField, EntityField, ListEntityField and MapEntityField
//the value returned MUST be int, double, float, Map, List or some combination of them
fields.add(TSimpleField('myField', (value) => myField = value, () => myField));
}
@override
Widget showWidgetProperties(BuildContext context, StateSetter setState) {
//override this to provide the widget that is displayed in the right side bar of editor
//it is typically used to show options for customising the widget that this handler is for
//if it is not provided the editor displays a message saying the widget does not support customisations
return _MyWidgetPanelProperties(handler: this);
}
}
class _MyWidgetPanelProperties extends StatefulWidget {
final MyWidgetEditorHandler handler;
const _MyWidgetPanelProperties({Key? key, required this.handler})
: super(key: key);
@override
State<_MyWidgetPanelProperties> createState() =>
_MyWidgetPanelPropertiesState();
}
class _MyWidgetPanelPropertiesState extends State<_MyWidgetPanelProperties> {
@override
Widget build(BuildContext context) {
return Text('This is where I would provide options to configure my widget');
}
}
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text('This is my widget');
}
}
The above is a simple if useless widget but demonstrates the minimum required code for developing a custom Hypi Tink widget extension.
Once you've finished developing your widget extension, provide the git repository URL in the editor and it will discover and load your widget from your repo (public or private).
Action extension #
An action extension is a class which mixes in the TinkActionLike
mixin.
For example:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:hypi_tink_api/hypi_tink_api.dart';
class HttpGetAction with TinkActionLike {
//uniquely identifies this action
@override
String id = 'http.get';
//The editor puts all actions with the same group under a single dropdown
@override
String groupId = 'http';
//The name shown to the user in the editor
@override
String label = 'GET request';
//A set of parameters that the action requires
@override
List<TinkParam>? inputs = [
const TinkParam('url', TinkVariableType.text),
const TinkParam('headers', TinkVariableType.json),
];
//Any variable/value that the action will output, MUST be primitive, Map or List
@override
List<TinkParam> outputs = [
const TinkParam('responseCode', TinkVariableType.int),
const TinkParam('contentLength', TinkVariableType.int, required: false),
const TinkParam('responseHeaders', TinkVariableType.json),
const TinkParam('responseBody', TinkVariableType.text),
const TinkParam('isRedirect', TinkVariableType.bool),
];
//Shown to the user to allow them to customise the action
//By default, delegate.config shows a UI that allows the user to bind a variable to each of the action's inputs
@override
Widget config(
ActionEnv<
TinkApplicationState<
TinkWidgetInputBinding<ScreenModel, TinkWidgetHandler>,
TinkWidgetOutputBinding<EventModel, TinkWidgetHandler>,
TinkWorkflowBinding<EventModel, WorkflowModel,
TinkWidgetHandler>,
TinkVariable>,
ScreenModel>
env,
WorkflowModel workflow,
String screenId,
TinkWorkflowBinding<EventModel, WorkflowModel, TinkWidgetHandler>
binding) {
return delegate.config(env, workflow, screenId, binding);
}
//Called when the action is executed, put your action's implementation here...it can do anything and use any library from pub.dev
@override
void next(ActionChain chain) async {
String value = chain.getState(this, 'url')?.value;
Map<String, String>? hdrs = chain.getState(this, 'headers')?.value;
Response response = await http.get(Uri.parse(value), headers: hdrs ?? {});
chain.emitState(this, TinkIntVariable('responseCode', response.statusCode));
if (response.contentLength != null) {
chain.emitState(
this, TinkIntVariable('contentLength', response.contentLength!));
}
chain.emitState(this, TinkBoolVariable('isRedirect', response.isRedirect));
chain.emitState(
this, TinkJsonVariable('responseHeaders', response.headers));
chain.emitState(this, TinkTextVariable('responseBody', response.body));
chain.next();
}
}
Extensions are automatically discovered and registered in the editor as long as they are annotated (for widget extensions) or mixes in TinkActionLike
.