Каждый Flutter разработчик рано или поздно сталкивался с DartPad. Но у него гораздо больше возможностей, чем просто запускать код. В этот раз поделимся как просто шарить код через DartPad.
Меня зовут Ахмедов Самир, я Flutter разработчик в Surf, и я расскажу о том, что же ещё умеет DartPad.
Конфигурация
dartpad.dev позволяет заранее настроить внешний вид и функционал.
Страницы
DartPad предоставляет нам на выбор 6 разных страниц. Разница между ними лишь в том, какой функционал нам будет предоставлен.
embed-dart
Уже привычный сайт с вводом кода на Dart слева и консолью справа.

embed-inline
То же, что и первое, только консоль не справа, а снизу

embed-flutter
Редактор кода с динамической отрисовкой UI.

embed-flutter_showcase
В отличие от прошлого, показывает только готовый UI, а код — только после нажатия «show code». Отлично подходит для демонстрации результата, когда реализация не слишком важна.

embed-html
Редактор HTML страниц, но вместо Javascript можно использовать Dart. Стили CSS можно писать тут же и видеть результат.

workshops
DartPad с функционалом воркшопа.

Query-параметры
Также мы можем выбрать не только функционал страницы, но и настроить, что в нем будет и как оно будет выглядеть. Конфигурация Dartpad добавляется в URL как query параметры.
split
Часть экрана в процентах, что будет занята кодом.
Пример:


theme
Значения — dark и любое другое. Если theme = dark, то тема редактора — тёмная, иначе — светлая.
Пример:


run
Значения — true и другие. Если значение — true, код запускается сразу после запуска страницы.
Интеграция с Github
В Dartpad можно загружать код напрямую из Github и создавать кастомные воркшопы.
Github Gist
Код можно загрузить с любого публичного аккаунта GitHub, добавив в URL query id.
К примеру, вот URL вашего Gist: https://gist.github.com/{username}/0b4eaa233d04a2d62a63ceb337375c7d
То, что идёт после {username}/, и есть ID Gist.

Github Repo
Если же вы хотите сделать код интерактивней, например, чтобы всплывали подсказки или был пример готового решения — всё это можно сделать через создание репозитория на Github с конфигурацией окружения.
Чтобы привязать Github репозиторий к DartPad, нужно обязательно добавить 3 query поля:
gh_owner — название вашего аккаунта на Github.
gh_repo — название публичного репозитория, где лежат все нужные файлы.
gh_path — папка, в котором находится нужные файлы.
Все поля обязательны, даже gh_path: нужно будет обязательно поместить все файлы в какую-то одну папку, не дальше и не ближе.
Можно ещё добавить gh_ref — название ветки, которую нужно использовать, но это опционально. После того как вы создали репозиторий и папки, осталось только понять, что же нужно в них положить.

Код с подсказками и примером исполнения
Чтобы загрузить код из репозитория, структура отведённой под это папки должна выглядеть вот так:

Где:
dartpad_metadata.yaml — конфигурация для DartPad, из которого он понимает, какой файл, где его читать и для чего он служит.
name: Flutter DartPad repo
# Какой код перед нами - чистый Dart или Flutter.
mode: dart # or 'flutter'
# Какие файлы DartPad должен прочитать.
files:
- name: main.dart
Для того чтобы показать просто код, надо указать только main.dart. А в main.dart просто пишем код:
/// Просто файл с кодом. Ничего необычного.
void main() {
print("Test!");
}
Выгружаем изменения в репозиторий и через минуту смотрим на результат:

Код с подсказками и примером исполнения
Также к нашему коду можно добавить примеры и комментарии. Для этого надо изменить dartpad_metadata.yaml:
name: Flutter DartPad repo
mode: dart # or 'flutter'
files:
- name: main.dart
- name: solution.dart
- name: hint.txt
И соответственно туда же добавляем 2 новых файла — solution.dart и hint.txt — по желанию.
Важно: файлы должны называться только так.

Флоу: main.dart — отсюда вы должны дойти до решения наподобие solution.dart, по надобности используя подсказку из hint.txt (опционально)
В main.dart:
/// Исправь этот код, пожалуйста, он какой-то не такой.
void main() {
print("Test!");
}
В solution.dart:
/// Вот так-то лучше...
void main() {
print("Correct test!");
}
В hint.txt пишем любую подсказку — по желанию. И вот что получается. Но на этом возможности Dartpad только начинаются.
Тест кода прямо в DartPad!
В Dartpad также можно создавать и проверять задачи наподобие LeetCode. К прежней структуре добавляется файл test.dart:

Опять же, файлы должны называться точно так и никак иначе. Пожалуй, и оформим мы этот кейс так, будто это настоящая задача из Leetcode:
main.dart:
/// Слушай, мне как-то впадлу и некогда, можешь
/// пожалуйста написать функцию, то сложит 2 числа через пробел
/// и вернет эту строку? Например: 2, 3 -> "2 3"
String stringify(int x, int y) {
return '$x $y';
}
solution.dart — по желанию:
String stringify(int x, int y) {
return '$x $y';
}
test.dart:
void main() {
try {
final str = stringify(2, 3);
if (str == '2 3') {
_result(true);
} else {
_result(false, ['Пока что не то, но ты в верном направлении!', 'Keep trying!']);
}
} catch (e) {
_result(false, ['Вызов метода stringify(2, 3) вызвало ошибку: ${e.runtimeType}']);
}
}
Теперь при каждом запуске кода будет срабатывать тест. Его стоит писать так, будто вы импортировали файл main.dart и используете его здесь (но не импортируйте — будет ошибка).
Для того чтобы оповестить пользователя о результате теста, используйте «функцию» _result и не обращайте внимания на ошибки Dart Analyzer. Она принимает 2 параметра: Bool (true — тест пройден, false — провален), и массив строк, всплывающий при вызове _result.
Ну и dartpad_metadata.yaml:
name: Flutter DartPad repo
mode: dart # or 'flutter'
files:
- name: main.dart
- name: solution.dart
- name: test.dart
- name: hint.txt
И по итогу у нас получается вот такой результат
Теперь мы можем писать задачки для Dart, но и это ещё не всё…
Workshop
И последнее, что мы можем создать с помощью DartPad — свой кастомный workshop с шагами, пояснениями, пояснениями, лунопарком с блекджеком и кастомной конфигурацией. Но его структура кардинально отличается:

По порядку:
meta.yaml — конфигурация нашего воркшопа:
# То, что будет написано в титуле
name: Example workshop
type: flutter # Какой здесь код
# Шаги, их названия и путь к файлам
steps:
# Шаг 1 - инициализация проекта
# Название шага
- name: Initialize
# Путь к файлам относительно корневого
directory: steps/initialize
# Имеется ли файл с примером кода
has_solution: true
- name: Build
directory: steps/build
has_solution: false
- name: Release
directory: steps/release
has_solution: false
В папке из поля directory l должны быть 2 файла: instructions.md и snippet.dart. Можно ещё указать solution.dart, но только в случае, если в meta.yaml в шаге указано has_solution: true
instructions.md — файл Markdown для пояснений, примеров, картинок и так далее, для каждого шага — отдельный:
во первых, создайте сам Flutter проект;
во вторых, удалите ненужные папки и оставьте только android, ios и lib, файлы не трогаем;
в третьих, заходим в файл lib/main.dart. Удаляем весь код, он пока что нам не нужен, и вводим следующее:
void main() {
runApp(MyApp());
}
Не пугайтесь красных линий, мы скоро это исправим. Что тут происходит? Мы устанавливаем переданный нами компонент со всем приложением в корень, и теперь он и будет нашим приложением!
В snippet.dart и/или solution.dart указываем произвольный код. Я не буду здесь показывать все файлы, просто оставлю пример на Github
Смотрим на результат
А как пользоваться?
Тема обширная и требует практики и демонстрации. Поэтому, для закрепления материала я приготовил небольшой сайт, в котором вы сможете сгенерировать ссылку для DartPad, исходя из собственной конфигурации. пример работы сайта.
Пробуйте, экспериментируйте, и вы сможете применить этот удивительный инструмент в своей работе! Все файлы и то, что вы можете использовать в качестве примера, лежат в репозитории.
Больше интересного контента для разработчиков → в телеграм-канале Surf Flutter Team
П.с там публикуем кейсы, лучшие практики, новости и вакансии Surf, а также проводим прямые эфиры.