Flutter Friendly
588 subscribers
84 photos
45 videos
1 file
75 links
Канал Friflex о разработке на Flutter. Обновления, плагины, полезные материалы — превращаем знания в реальный опыт, доступный каждому разработчику.

🔗 Наш канал для разработчиков: @friflex_dev
🔗 Канал о продуктовой разработке: @friflex_product
Download Telegram
Привет, это Катя, Flutter Dev Friflex.

При разработке на Flutter важно не просто уметь писать рабочий код, но и понимать, как работает язык Dart, на котором он основан. Одна из базовых тем — ключевые слова final, const и var. Они отвечают за то, как переменные создаются и ведут себя в процессе выполнения программы. Давайте разберем и повторим базу😁

var (переменная)

Используется для объявления переменной, значение которой может изменяться со временем. Тип переменной определяется автоматически при присвоении значения. Но после первого присвоения типа, переменная не может быть использована с другим типом данных.

Пример:
void main() {   
   var name = 'Alice';  // Тип определяется как String   
   print(name);  // Alice      
   name = 'Bob';  // Допустимо, так как тип остаётся String   
   print(name);  // Bob 
}

Если тип данных переменной var известен при создании, Dart сам выводит тип переменной (например, String, int и т.д.).
Переменная, объявленная с var, может изменять свое значение, но не тип.

Пример попытки изменить тип переменной:
var age = 30; age = "thirty";  // Ошибка: String нельзя присвоить переменной типа int.

​​
final (константа во время выполнения)

Используется для переменных, значение которых можно установить только один раз. После инициализации переменной значение нельзя изменить. В отличие от const, переменная с final может быть инициализирована значением, которое становится известно только во время выполнения программы.

Пример:
void main() {   
    final name = 'Charlie';  // name будет неизменяемым   
    print(name);  // Charlie    
    name = 'Dave';  // Ошибка, нельзя изменить значение переменной 
}

final используется для значений, которые известны только во время выполнения программы.

Пример использования переменной, которая зависит от выполнения программы:
void main() {   
    final currentTime = DateTime.now();  // Значение определяется во время выполнения   
    print(currentTime); 
}

В этом примере время будет определено при выполнении программы и больше не изменится.

const (константа времени компиляции)

Это неизменяемая константа, значение которой должно быть известно на этапе компиляции. Это означает, что значения const должны быть определены заранее и не могут изменяться или вычисляться во время выполнения программы.

Пример:
void main() {   
    const pi = 3.1415;   
    print(pi);  // 3.1415   
    pi = 3.14;  // Ошибка, нельзя изменить значение константы 
}

◽️Переменные, объявленные с const, являются неизменяемыми и создаются во время компиляции программы.

◽️Если переменная const имеет сложный тип (например, список), то она становится полностью неизменяемой (не только ссылка, но и сам объект).

Пример со списком:
void main() {   
    const numbers = [1, 2, 3];   
    // numbers[0] = 10;  // Ошибка, элементы списка изменить нельзя
    print(numbers); 
}


Различия между final и const
▫️final позволяет установить значение переменной один раз, но это значение может быть вычислено во время выполнения программы.
▫️const требует, чтобы значение было известно на этапе компиляции.
▫️const можно использовать для создания неизменяемых объектов, которые становятся доступными еще до выполнения программы, в отличие от final.

Пример разницы:
final currentTime = DateTime.now();  // Работает, так как значение вычисляется во время выполнения. 
const timeConst = DateTime.now();  // Ошибка: const переменные не могут быть вычислены во время выполнения.


Итоговое сравнение:
▪️var — изменяемая переменная, тип выводится автоматически.
▪️final — неизменяемая переменная, значение можно присвоить один раз, но это может произойти во время выполнения.
▪️const — неизменяемая переменная, значение которой должно быть известно во время компиляции.
Привет, это Анна, Friflex Flutter Team Lead!👋

Один из базовых приемов для повышения уровня безопасности вашего Flutter-приложения — это обфускация кода. Сегодня разберем, что это, как использовать и какие есть нюансы.

Обфускация простыми словами — некоторое запутывание кода с помощью определенного набора символов. При обфускации код сборки становится нечитаемым для человека. Названия всех методов и классов подменяются другими символами.

Какую проблему решает? Обфускация сильно затрудняет процесс понимания кода, полученного в процессе реверс-инжиниринга. Посмотрим, как это работает.

Возьмем простое приложение, тот шаблон, который генерируется автоматически при создании Flutter-проекта. Соберем две сборки, одну с обфускацией, другую — без. Затем проведем процесс реверс-инжиниринга обеих сборок с помощью инструмента Blutter.

Результат — на карточке👆
Вывод — код сборки с обфускацией прочитать почти невозможно.

Обфусцировать код Flutter-приложения очень просто – достаточно запустить команду сборки следующим образом:

flutter build <build-target> \ 
--obfuscate \
--split-debug-info=/<symbols-directory>


Здесь очень важно использовать опцию --split-debug-info, она по указанному пути выгрузит символы обфускации, с помощью которых можно будет в дальнейшем расшифровывать важные логи, например, стектрейсы ошибок.

При обфускации нельзя в коде использовать сравнение строковых представлений runtime-типов.

Попробуйте для примера сделать подобную реализацию в сборке с обфускацией и без.

class User {}

Text(user.runtimeType.toString());

Text ("${user.runtimeType.toString() == "User"");

Без обфускации на экране появятся значения User и true. С обфускацией в первом виджете будет набор рандомных символов, во втором — false.

🔥 — если используете обфускацию в своих проектах.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет! Это Роза, Flutter Dev Friflex! 👋

Когда я только начинала работать, почти не пользовалась горячими клавишами. У меня была мышка. И этого вроде бы хватало, но со временем мне захотелось ускорить свою работу, поэтому я целенаправленно начала внедрять шорткаты в свою разработку. И это было лучшим решением!
Хочу поделиться и с вами самыми полезными из них — вдруг пригодятся.

🔴Начнем с навигации и поиска:
⌘ + P — открыть файл по имени
⌘ + Shift + F — поиск по всему проекту
⌘ + G — перейти к строке
⌘ + Shift + O — перейти к функции или символу в файле

🔴Редактирование кода:
Control + Space — автодополнение
⌘ + / — закомментировать или раскомментировать строку
Option + ↑/↓ — переместить строку вверх или вниз
Shift + Option + ↑/↓ — скопировать строку вверх или вниз
⌘ + Shift + K — удалить строку
Shift + Option + F — отформатировать документ
Option + Click — добавить множественный курсор
⌘ + Shift + L — выделить все вхождения слова
⌘ + F, затем ⌘ + Option + Enter — быстрая замена

🔴Мультикурсор и выделения:
Option + Click — добавить курсор в точку клика
⌥⌘ + ↑/↓ — вставить курсор выше / ниже
⌘ + U — отменить последнее действие с курсором
⇧⌥ + I — вставить курсор в конец каждой выбранной строки
⌘ + L — выделить текущую строку
⇧⌘ + L — выделить все вхождения текущего выделения
⌘ + F2 — выделить все вхождения текущего слова
Control + ⇧⌘ + →/← — расширить/уменьшить выделение
    
🔴Блочное выделение:
⇧⌥ + drag — выделение прямоугольником (box selection)
⇧⌥⌘ + ↑/↓/←/→ — выделение вверх/вниз/влево/вправо
⇧⌥⌘ + PgUp/PgDn — постраничное вертикальное выделение

💡Конечно, вы можете настроить сочетания клавиш под себя и увидеть весь их список:  
Code → Settings → Keyboard Shortcuts или нажмите ⌘ + K, затем ⌘ + S.

✏️Также полный список есть тут: PDF от VSCode.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Friflex Dev
🔥Статья нашей Flutter-разработчицы Кати — в шорт-листе «Технотекста» Хабра

Норм или стрем использовать сторонние библиотеки под любую проблему? А выносить виджеты в методы вместо создания отдельных классов? Ответы — в Катиной статье «Антитренды в мобильной разработке на Flutter».

Она разобрала решения, которые кажутся удобными, а на деле раздражают и замедляют работу, и предложила, чем их стоит заменить.

🔜 Читать на Хабре
💜 Поддержать автора лайком
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет, с вами вновь Катя, Flutter Dev Friflex.

Сегодня поговорим про библиотеку equatable, которая помогает упростить сравнение объектов.

Установка
Yaml
dependencies:
  equatable: ^2.0.7


Зачем нужна библиотека?
В Dart по умолчанию два объекта считаются равными, только если они ссылаются на один и тот же экземпляр в памяти. Но часто требуется сравнивать объекты по их полям. Equatable автоматически реализует методы == (оператор равенства) и hashCode, что избавляет разработчиков от написания шаблонного кода.

Без Equatable:
class Person {
  Person(this.name, this.age);

  final String name;
  final int age;
  
  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is Person && 
           other.name == name && 
           other.age == age;
  }

  @override
  int get hashCode => name.hashCode ^ age.hashCode;
}


С Equatable:
import 'package:equatable/equatable.dart';

class Person extends Equatable {
  Person(this.name, this.age);

  final String name;
  final int age;
  
  @override
  List<Object?> get props => [name, age]; // Поля для сравнения
}


Основные возможности
▫️
Equatable переопределяет == и hashCode на основе списка полей (props)
▫️Можно использовать Equatable в иерархии классов
▫️Рекомендуется использовать с неизменяемыми (final) полями
▫️Часто применяется в State Management для эффективного сравнения состояний

Использование EquatableMixin
Если ваш класс уже наследуется от другого класса, но вам нужна функциональность Equatable, можно использовать

EquatableMixin:
import 'package:equatable/equatable.dart';

class Person extends SomeOtherClass with EquatableMixin {
  Person(this.name, this.age);
 
  final String name;
  final int age;
  
  @override
  List<Object?> get props => [name, age];
}


Преимущества EquatableMixin
▫️
Позволяет добавить сравнение объектов без изменения иерархии наследования
▫️Сохраняет все возможности Equatable, но в виде миксина

Пример использования
void main() {
  final person1 = Person("Alice", 30);
  final person2 = Person("Alice", 30);

  print(person1 == person2); // true (без Equatable было бы false)
}


📎 Ссылка на библиотеку

❤️ — если используете Equatable в ваших проетах
Всем привет! С вами Анна, Friflex Flutter Team Lead👋

Одна из самых распространенных болей многих Flutter-проектов — это отсутствие тестов в коде. И хоть тема не новая, поговорим сегодня о том, какие виды тестов бывают, для чего они нужны и почему их наличие может спасти ваш проект.

Существуют три вида тестов:

🔸 Unit-тесты
Их основная задача —протестировать работоспособность какой-то одной конкретной функции, метода, класса по всем возможным сценариям

🔸 Widget-тесты
Этот тип тестов призван проверять именно отдельные виджеты. Widget-тесты позволяют проверить, действительно ли тот или иной виджет корректно располагается на экране и правильно себя ведет при взаимодействии с ним пользователя

🔸 Integration-тесты
Интеграционные тесты — самый сложный в настройке, но очень полезный тип тестов. Он позволяет проверить большие участки вашего приложения, протестировать взаимодействие разных модулей и виджетов между собой. Если юнит- и виджет-тесты призваны проверять работу отдельно только одного объекта в проекте, то интеграционные проверяет все в совокупности. Кроме этого, они также позволяют проверить производительность всего приложения.

Почему же отсутствие тестов является проблемой? Многие разработчики скажут, что написание тестов — лишняя трата времени, человеческих ресурсов и вообще занятие монотонное и скучное. Но здесь есть пара весомых доводов.

Когда проект маленький, простой, не нагружен сложной логикой, его ручное тестирование занимает немного времени и усилий QA-специалистов. Но с ростом приложения, с течением времени многие нюансы той или иной фичи забываются, их ручная проверка становится все менее эффективной.
Сюда же можно отнести и человеческий фактор — разработчики, тестировщики могут меняться, а знания — теряться.

Здесь на помощь приходят тесты в коде проекта. Стоит всего один раз при разработке того или иного функционала покрыть тестами всевозможные сценарии, и в будущем вероятность пропустить в продакшн сломанный функционал сильно снижается.

💡Совет: интегрируйте в свой CI/CD процесс проверки всех написанных тестов в проекте. Если тесты не проходят, сборке или пул-реквесту лучше не попадать на следующий этап жизненного цикла задачи. Так вы не будете забывать вовремя править тесты в случае изменения логики работы приложения, а также сэкономите время коллег на проверку.
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Привет, это Роза, Flutter Dev Friflex! 👋

Рано или поздно в вашем проекте может возникнуть задача — получить скриншот конкретного виджета. Как это реализовать?

Существует несколько подходов:
▪️Готовое решение — например, пакет screenshot
▪️Более низкоуровневый подход — через RenderRepaintBoundary
    
💡Интересный факт: внутри себя screenshot использует RenderRepaintBoundary, поэтому понимание его работы будет полезным даже при использовании готового пакета.

В этом посте мы рассмотрим, как превратить любой виджет в изображение, готовое для ваших дальнейших действий.

1. Создаем глобальный ключ
Он нужен, чтобы получить доступ к RenderRepaintBoundary:

final GlobalKey _widgetKey = GlobalKey(); 


2. Оборачиваем нужный виджет в RepaintBoundary
Это гарантирует, что будет захвачен только нужный виджет.

RepaintBoundary(
  key: _widgetKey,
  child: const SomeWidget(),
)


3. Захватываем изображение
Метод, который преобразует виджет в Uint8List:
 
Future<void> _captureAndSave(BuildContext context) async {
  try {
    // Получаем рендер-границу по ключу
    final boundary = _widgetKey.currentContext!.findRenderObject() as RenderRepaintBoundary;

    // Захватываем изображение (можно увеличить pixelRatio для лучшего качества)
    final image = await boundary.toImage(pixelRatio: 3.0);

    // Преобразуем изображение в байты
    final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    final pngBytes = byteData!.buffer.asUint8List();

    // Тут можно сохранить файл.
    ...
  } catch (e) {
    debugPrint('Ошибка при захвате: $e');
  }
}


Вот и все! Теперь у нас есть изображение в виде байтов (Uint8List), с которым можно делать все, что угодно:
✔️сохранить в файл
✔️передать по сети
✔️вложить в PDF
✔️отобразить в UI

 🧠 Немного теории:
RepaintBoundary – важный инструмент для оптимизации производительности. Он создает «графическую границу», отделяя часть дерева виджетов от остального. Это позволяет:
▫️изолировать перерисовки
▫️ повысить производительность
▫️ использовать offscreen rendering
▫️ делать захват изображения (как в нашем примере)

Ставьте ❤️ — и в следующем посте глубже рассмотрим RepaintBoundary: как он работает,  влияет на рендеринг и какие у него есть особенности
Привет, с вами вновь Катя, Flutter Dev Friflex. Сегодня разберем основные способы декомпозиции и лучшие практики.

Декомпозиция виджетов — это процесс разделения сложного виджета на более простые и независимые компоненты.

Зачем это нужно?

▫️ Упрощение кода: когда разделяешь виджеты на более мелкие компоненты, код становится более понятным и легким для восприятия
▫️ Повторное использование: мелкие виджеты можно использовать в разных частях приложения, что снижает дублирование кода
▫️ Улучшение производительности: использование отдельных виджетов позволяет более эффективно управлять состоянием и перерисовкой интерфейса
▫️ Тестируемость: мелкие виджеты легче тестировать, что способствует созданию более надежного кода

Виды декомпозирования
1. Использование билд-методов
Вынесение частей виджета в отдельные методы внутри того же класса.

class ProductCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: [
          _buildTitle(),
          _buildPrice(),
        ],
      ),
    );
  }

  Widget _buildTitle() { ... }
  Widget _buildPrice() { ... }
}


Маленький плюсик:
Мало кода — не требует создания новых классов

Минусы:
▫️Нет переиспользуемости — методы привязаны к конкретному виджету
▫️Сложность тестирования — нельзя протестировать отдельно от родителя
▫️Риск создания «метод-супов» — чрезмерное количество методов ухудшает читаемость
▫️Ухудшает производительность — каждый setState в таком методе будет полностью перерисовывать виджет

2. Разделение на Stateful и Stateless виджеты
Выделение логики с состоянием в отдельные StatefulWidget, а статичной верстки — в StatelessWidget.

// Stateful часть
class Counter extends StatefulWidget {
  @override
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;
  
  void increment() => setState(() => count++);

  @override
  Widget build(BuildContext context) {
    return CounterView(
      count: count,
      onIncrement: increment,
    );
  }
}

// Stateless часть
class CounterView extends StatelessWidget {
  // Логика
}

        
Плюсы:
▫️Четкое разделение ответственности — состояние отделено от представления
▫️Упрощенное тестирование — Stateless-часть можно тестировать без состояния
▫️Повышенная производительность — Stateless-виджеты не перестраиваются без необходимости
▫️Гибкость — можно менять состояние без изменения UI и наоборот

Минусы:
Больше кода — требуется создание дополнительных классов

Если заметили, то плюсы и минусы у этих вариантов противоположны.

📎Есть классное короткое видео от Flutter-команды, рекомендую посмотреть его.
Какой вид декомпозирования вы чаще всего используете?
Anonymous Poll
5%
Использование билд-методов
71%
Разделение на Stateful и Stateless виджеты
25%
Оба
Всем привет! Это Анна, Friflex Flutter Team Lead👋

Сегодня затронем еще одну тему, которая в сообществе разработчиков всегда вызывает бурные обсуждения. Поговорим о документации и комментировании кода: насколько это необходимо и каких правил стоит придерживаться.

Для начала разберемся, чем отличается документация от комментария в коде.

▫️Документация — это характеристика конкретного объекта, класса, метода, описание его назначения, параметров и механики работы. Оформляется в коде через ///. Например, возьмем школьную задачку — надо написать метод, который по значениям катетов прямоугольного треугольника будет рассчитывать значение гипотенузы.

/// Метод для вычисления гипотенузы по известным значениям
/// катетов прямоугольного треугольника
///
/// Принимает:
/// - [firstLeg] - первый катет прямоугольного треугольника
/// - [secondLeg] - второй катет прямоугольного треугольника
double calculateHypotenuse(double firstLeg, double secondLeg) {
final hypotenuse = sqrt(firstLeg * firstLeg + secondLeg * secondLeg);

return hypotenuse;
}


Если мы добавим этот пример в любую IDE, при наведении мышью на метод будет высвечиваться наша добавленная документация. При этом специальные знаки помогают удобно форматировать описание. Например, квадратные скобки позволяют обозначить параметр, а дефисы — организовать маркированный список.

▫️Комментарий — это обычное словесное описание алгоритма действий. Если в коде встречается сложный участок, где логика не совсем очевидна, или имеются какие-то важные сведения, которые разработчик хочет передать своим коллегам и себе в будущее, оформлять их стоит именно как комментарий. Они выделяются с помощью //.

Как показывает практика, и документация, и комметрирование кода — очень удобные инструменты, которые позволяют сделать проект максимально понятным и простым для вхождения новых разработчиков.

Так почему же тема холиварная?
В первую очередь потому что зачастую и документация, и комментарии в проекте не систематизированы, оформляются хаотично, чем только мешают и запутывают. Разработчики из-за этих проблем не видят в них никакой пользы, только лишь дополнительную трату времени.

Как это исправить?
Поможет соответствие ряду правил.

1. Зафиксировать в проекте порядок комментирования и документации кода.
Очень удобно на уровне всей команды заранее определить шаблоны. В будущем это позволит держать весь проект в едином формате.

2. Думать о том, как этот участок кода может восприниматься другими разработчиками или тобой через большой промежуток времени.
В больших проектах, которые разрабатываются и поддерживаются долгое время, не стоит полагаться на свою память или память коллег. Нюансы имеют свойство забываться, разработчики могут менять проекты и место работы, поэтому полезно фиксировать сложные места сразу.

3. Не комментировать лишнее.
Такая ошибка часто встречается, что вызывает негатив к комментированию в целом. Важно покрывать комментариями только то, что действительно нуждается в пояснении. Например, переменные с говорящими названиями или простые условия в блоке if описывать смысла нет.

4. Больше текста — не значит лучше.
Документация и комментарии должны быть емкими, простыми для восприятия. Если текста будет слишком много, вероятность, что его будут пропускать, увеличивается.

💬Делитесь своим опытом и лучшими практиками в комментариях.
This media is not supported in your browser
VIEW IN TELEGRAM
Все привет, с вами Роза, Flutter Dev Friflex💫

В прошлом посте я поделилась, как сделать скриншот экрана во Flutter, и упомянула RepaintBoundary. Сегодня расскажу о нем подробнее.

Что такое RepaintBoundary?
RepaintBoundary — это виджет, который помогает избежать лишних перерисовок. Он отделяет своего потомка в отдельный слой. Это значит, что если внутри происходит обновление, Flutter перерисует только эту часть, не затрагивая все дерево. Это важно для производительности и плавности интерфейса.

Как это работает?
Обычно если один виджет требует обновления, Flutter перерисовывает все поддерево, даже если остальные элементы не менялись. Это может замедлить работу приложения.

RepaintBoundary создает «границу», чтобы обновлялась только нужная часть. Все, что находится внутри него, будет рендериться отдельно и не затронет остальной интерфейс.

ListView.builder(
  itemCount: 20,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Загрузка элемента $index'),
      trailing: RepaintBoundary(
        child: const SizedBox(
          width: 24,
          height: 24,
          child: CircularProgressIndicator(strokeWidth: 2),
        ),
      ),
    );
  },
)
// Мы изолируем `CircularProgressIndicator`, чтобы его анимация не вызывала перерисовку всей строки


💡 Кстати, ListView, GridView и другие scroll-виджеты уже автоматически добавляют RepaintBoundary к своим элементам, если они создаются через builder.

Где стоит использовать:
▫️Анимации и загрузки, чтобы они не затрагивали остальной интерфейс
▫️Списки с часто обновляемыми элементами
▫️Графики и визуализации с динамическими данными
▫️ Сложные экраны с множеством отдельных зон
 ▫️Глубокие деревья виджетов, где важна локальная оптимизация
    
Когда лучше не использовать:
▫️Простые статичные элементы — лишние границы только увеличат дерево
▫️Виджеты без состояния — они и так не нуждаются в перерисовке

💡Важно: RepaintBoundary действительно помогает улучшить производительность, но его чрезмерное использование может, наоборот, навредить. Каждый такой виджет увеличивает нагрузку на память и процессор.

Как отладить перерисовки?
Во Flutter есть инструмент, который показывает, какие части экрана обновляются чаще всего — debugRepaintRainbowEnabled.

import 'package:flutter/rendering.dart';

void main() {
  debugRepaintRainbowEnabled = true;
  runApp(MyApp());
}


С этим флагом перерисовываемые области будут мигать радужными цветами. Это помогает быстро найти «узкие места» в производительности.

📌 Рекомендую наглядный пример от Michael Lazebny тут.

❤️ — если пост был полезным
Hola, это Сергей, Flutter Team Lead в Friflex🧑‍💻

21 мая захожу в этот канал с мини-рейдом — будем в лайве разбирать секцию Flutter на Google I/O 2025, надеюсь покажут что-то интересное:

🔴 Что там придумали с фреймворком
🔴 Что будет с Dart
🔴 И что-то еще... (но это не точно)

📍 Где? Здесь, в @flutterfriendly
📆 Когда? 21 мая, 21:00
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Привет, с вами вновь Катя, Flutter Dev Friflex. Сегодня разберем ключевые слова, которые помогают управлять видимостью и использованием библиотек, а также упрощают работу с импортированными компонентами.

▫️import
Используется для подключения внешних библиотек или файлов. С его помощью можно получить доступ к классам, функциям и переменным, определенным в других файлах.

import 'package:my_package/my_file.dart';


▫️export
Позволяет сделать доступными определенные элементы из одного файла для других файлов через единую точку подключения. Это полезно для создания библиотек и API.

export 'src/my_class.dart';


▫️as
Позволяет задать алиас (псевдоним) для импортированной библиотеки. Это помогает, когда импортируются несколько библиотек с одинаковыми именами.

import 'package:libraryA/my_class.dart' as libA; 
import 'package:libraryB/my_class.dart' as libB;  

void main() {   
    var a = libA.MyClass();   
    var b = libB.MyClass(); 
    }


▫️show
Позволяет импортировать только определенные элементы из библиотеки. Это помогает избежать конфликтов имен и уменьшить количество загружаемых элементов.

import 'package:my_package/my_file.dart' show MyClass, MyFunction;


▫️hide
Позволяет исключить определенные элементы из импорта. Это также помогает избежать конфликтов имен.

import 'package:my_package/my_file.dart' hide MyFunction;


▫️part of
Указывает, что текущий файл является частью другой библиотеки (основного файла). Это позволяет разбивать код на несколько файлов, но работать с ними, как с единой библиотекой.

// В основном файле (my_library.dart):
library my_library;

part 'part_file.dart';

// В part_file.dart:
part of 'my_library.dart';


🔥 — если используете все эти ключевые слова в своих проектах
Смотрим Google IO С:

Буду обновлять пост по мере новостей

Хороший дяденька менеджер рассказал, что Flutter #1 среди фреймворков для приложений

Целых 843 контрибьютора на GitHub за непонятно какой период :D

Рассказали про новые null операторы в Dart 3.8 и сокращение через точку в будущем релизе у енамов

Показали и рассказали про Property Editor (Интересно сколько людей будут им пользоваться :?)

Великолепные обновления паб дев в виде темной темы и счетчика загрузок

Рассказали про кросс компиляцию (Не упомянули аврору, немного растроен C: )

А ТЕПЕРЬ РЕАЛЬНО ПОЛЕЗНАЯ ВЕЩЬ: чуть-чуть ускорили dart cli

Грег рассказал про нативный интероп и объеденения платформеного и ui треда

Про то как они пытаются поддержать cupertino (им кто то пользуется ?:( ) пакет и введение суперэлипсов C:

Рассказали про поддержку рукописного ввода на android и поддержку Edge to Edge (которая будет работать только на самом последнем андройде 🙁)

Показали красивую циферку в 92% пакетов которые могут в webAssembly (не смотря на то, что 99% пакетов uiные C:)

ПОЛЕЗНАЯ ВЕЩЬ: hot-reload в вебе скрытое под фича флаг (до конца года) C:

Складывается ощущение что два последних Google I/O чисто реклама Gemini, впендюривают его везде (

Ну и так как больше нечего представить, то просто показывают юзкейсы:

- Flutter под webOS (ОС на теливизорах от LG)
- Canonical и вклад в flutter
- Флаттер на тостере !?!?
- Флаттер в спорт. инвентаре

Это был тролинг года, опять рассказывают про AI 😭


Было бы здорово еслиб они сказали, что Gemini умеет хорошо верстать по скриншотам или помогать в чем-то таком и как они его красиво натренировали, но нет, теперь вы можете просто кидать запросики в Google API из приложения (за которое вы будете платить), а так же писать бизнес логику
А по факту он полезен только в документации кода

Кратко содержание: Мы прикольные и нам помогают, AI,AI,AI, native Interop, ускорили dart cli, hot-realod в web, Юзкейс с тостером, AI, AI
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Привет! На связи Анна, Flutter Team Lead😉

Совсем недавно мы говорили про тесты во Flutter-приложениях, разобрались в видах и ситуациях использования. Сегодня поговорим об одном из самых известных инструментов для тестирования — библиотеке mocktail.

Часто в процессе написания тестов появляется необходимость имитировать работу того или иного экземпляра класса с целью проверить его работу в разных сценариях. В таком случае на помощь придет mocktail. Разберемся подробнее в возможностях этой библиотеки.

✔️ Создание Mock и Fake
Mock и Fake — понятия, которые существуют не только в тестировании Flutter-приложений. Это так называемые тестовые двойники — классы, предназначенные для упрощения процесса тестирования и изоляции тестируемого объекта от внешних зависимостей.

Оба понятия довольно схожи, но имеются небольшие различия. Моки имитируют поведения реальных объектов, а фейки — копируют функциональность реального объекта, но с некоторым упрощением.

Подробнее понять сущность тестовых двойников поможет эта статья.

Библиотека mocktail дает доступ к Mock- и Fake-классам. Чтобы создать моки или фейки, достаточно наследоваться от них.

class FakeExample extends Fake implements Example {}
class MockExample extends Mock implements Example {}


✔️ Определение поведения метода — when()
Метод when() позволяет к тестовому объекту определить конкретное поведение.

class Example {
String read() => 'ready!';
String write(String data) => 'data recorded!';
}

final mockExample = MockExample();

test(
'testing mockExample.read()',
() {
when(mockExample.read).thenReturn('successfully read');
expect(mockExample.read(), 'successfully read!');
},
);


✔️ Проверка вызовов метода — verify()
Метод verify() позволяет проверить, был ли вообще вызов того или иного метода, с какими параметрами и сколько раз.

Например, так мы можем проверить, что в нашем примере метод read() был вызван 1 раз.

verify(mockExample.read).called(1);


А так можно получить список параметров, с которыми был вызван метод write().

final list = verify(() => mockExample.write(captureAny())).captured;


✔️ Сбросить все настроенные поведения — reset()
Тут все просто — если вам нужно убрать все те настройки поведени, которые были заданы ранее, поможет метод reset().

reset(mockExample);


Как показывает практика, mocktail являтся достаточно гибким инструментом. С его помощью можно протестировать даже сложные сценарии.

➡️ Документация библиотеки содержит еще много интересных примеров, рекомендую ознакомиться.
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет, это Роза, Flutter Dev Friflex👋

Если ты хоть раз писал CLI-пакет на Dart, то точно задумывался, как обрабатывать аргументы в main().
Можно, конечно, написать свой парсер, но проще воспользоваться готовым решением, например, библиотекой args. Она превращает сырые аргументы из командной строки в понятный набор параметров и значений.

Как это работает?
Внутри args реализован простой парсер на основе Map, куда добавляются опции и флаги.  
При запуске команды с аргументами библиотека определяет, что передано, и возвращает готовую структуру — ArgResults.

Как работать с args?
Первым делом добавь зависимость в pubspec.yaml, затем — создай парсер:

final parser = ArgParser();


Также ты можешь задать дополнительные параметры при инициализации:
✔️ allowTrailingOptions (по умолчанию true) — позволяет указывать флаги и параметры после позиционных аргументов
✔️ usageLineLength — задает максимальную длину строки при выводе usage

Добавление параметров
🔹 Используй addOption, если параметр принимает значение
parser.addOption('output');


🔹 Используй addFlag, если параметр — просто переключатель
parser.addOption('env', defaultsTo: 'dev');


По умолчанию у флагов работает форма --no-flag. Если это не нужно, добавь negatable: false.

Дополнительные настройки
▫️Сокращения с помощью abbr:
parser.addFlag('screenshot', abbr: 's');


▫️ Значение по умолчанию:
parser.addOption('env', defaultsTo: 'dev');


Примеры использования
Команды с аргументами можно вызывать так:

dart run command_name --verbose=false
dart run command_name --output=somevalue


Если заданы сокращения, то можно:

dart run command_name -v=false
dart run command_name -o=somevalue


Валидация и обратные вызовы
▫️Хочешь ограничить допустимые значения? Используй allowed:

parser.addOption('mode', allowed: ['dev', 'prod']);


▫️ Если передано недопустимое значение — будет выброшено исключение ArgParserException
    
▫️ Для дополнительной логики можно также передать callback
    
Обязательные параметры
Если параметр помечен как mandatory: true, но не передан — при его извлечении Dart выбросит ArgumentError.

Вывод команд
Но и наконец, чтобы пользователи знали, какие аргументы доступны и как их использовать, добавь флаг --help и выведи справку через parser.usage:

parser.addFlag(
  'help',
  abbr: 'h',
  help: 'Show help information for available commands',
  negatable: false,
);

if (results['help'] as bool) {
  print('Command help:\n');
  print(parser.usage);
  exit(0);
}


📌 Рекомендую завершать выполнение программы после вывода справки, чтобы избежать лишнего кода, если help — единственный аргумент.

В посте рассмотрела не все возможности пакета: обязательно загляни в документацию на pub.dev, чтобы узнать больше.

❤️ — если пост был полезным
This media is not supported in your browser
VIEW IN TELEGRAM
Привет, это Катя, Flutter Dev Friflex👋

Сегодня разберемся что такое pubspec.yaml, зачем он нужен и что содержит.

Что это?
Файл pubspec.yaml — это настройка Flutter-приложения, без которого оно не соберется.

Что внутри этого файла?

1. Название и описание

Yaml
name: my_app  # Название приложения (только английскими буквами, без пробелов)
description: Моё первое приложение  # Описание (можно на любом языке)
version: 1.0.0+1  # Версия (1.0.0 — основная, +1 — номер сборки)


2. Какие версии Dart и Flutter нужны

Yaml
environment:
  sdk: ">=2.12.0 <3.0.0"  # Dart версии от 2.12.0 до 3.0.0
  flutter: ">=2.0.0"       # Flutter версии от 2.0.0


3. Библиотеки (дополнительные функции)

Yaml
dependencies:
  flutter:
    sdk: flutter  # Обязательная строка для Flutter-приложений
  http: ^0.13.3   # Библиотека для работы с интернетом
  provider: ^6.0.0  # Библиотека для управления состоянием приложения


После добавления библиотек нужно запустить flutter pub get, чтобы их скачать.

4. Библиотеки только для разработки

Yaml
dev_dependencies:
  flutter_test:
    sdk: flutter  # Нужно для тестирования
  build_runner: ^2.1.0  # Помогает генерировать код


5. Картинки, шрифты и другие файлы

Yaml
flutter:
  uses-material-design: true  # Включает стандартные иконки Google
  assets:
    - assets/images/  # Папка с картинками
    - assets/logo.png  # Конкретный файл
  fonts:
    - family: Roboto  # Шрифт Roboto
      fonts:
        - asset: assets/fonts/Roboto-Regular.ttf


Как обновлять библиотеки?

▫️Добавили новую библиотеку в pubspec.yaml?
✔️Запустите flutter pub get (чтобы скачать)

▫️Хотите обновить все библиотеки?
 ✔️Запустите flutter pub upgrade

▫️Хотите проверить, какие библиотеки устарели?
✔️Запустите flutter pub outdated

Важно:
▪️Если добавили картинку или шрифт, но забыли прописать его в pubspec.yaml — приложение не увидит этот файл
▪️Если указали не ту версию библиотеки — приложение может не запуститься

Этот файл — как инструкция для Flutter, где все должно быть четко прописано🚀