Flutter Pulse
418 subscribers
271 photos
543 links
На канале будут новости про flutter с сайтов, информация об обновлении пакетов, а также авторский контент.
Download Telegram
Умный запрос оценки
Не спамите запросом оценки! 🤔

Почему?
• Apple Store ограничивает запрос оценки через нативное всплывающее окно до 2 раз в год 📆
• Google Play Store ограничивает запрос почти 2 раза каждые 3 месяца... 🤷‍♂️
• Вы не хотите раздражать пользователей и получать плохие оценки 😠

Мы создаем метод, подобный showDialog, чтобы можно было запрашивать оценку где угодно в приложении 📱


class RatingSettings {
final Duration delayBeforeAsking;
final Duration delayBeforeAskingAgain;

RatingSettings({
required this.delayBeforeAsking,
required this.delayBeforeAskingAgain,
});
}

class Rating {
final RatingApi _ratingApi;
final RatingSettings settings;
final DateTime? lastAskingDate;
final DateTime userCreationDate;
final DateTime _current;
final bool hasRateApp;

Rating({
required this.settings,
required RatingApi ratingApi,
required this.lastAskingDate,
required this.userCreationDate,
required this.hasRateApp,
}) : _ratingApi = ratingApi,
_current = DateTime.now();

bool shouldAsk() {
// Если пользователь уже оценил приложение или мы не знаем дату создания пользователя, пропустим
if (userCreationDate == null || hasRateApp) {
return false;
}

final appInstallDiff = _current.difference(userCreationDate);
if (appInstallDiff < settings.delayBeforeAsking) {
return false;
}

if (lastAskingDate == null) {
return true;
}
return lastAskingDate!.difference(_current) > settings.delayBeforeAskingAgain;
}

Future<void> openStoreListing() => _ratingApi.openStoreListing();
Future<void> showRatingDialog() => _ratingApi.showRatingDialog();
}



void showRatingPopup(WidgetRef ref) {
final ratingRepository = ref.watch(ratingRepositoryProvider);
final userState = ref.watch(userStateNotifierProvider);
final ratingFuture = ratingRepository.getUserState(user);

ratingFuture.then((rating) {
if (rating.shouldAsk()) {
rating.delay();
showDialog(
context: context,
builder: (context) => AlertDialog.adaptive(
title: const Text('Спасибо за использование ULY'),
content: const Text('У вас есть минута, чтобы оставить отзыв?'),
actions: [
TextButton(
child: const Text('Позже'),
onPressed: () async {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Да, конечно!'),
onPressed: () async {
Navigator.of(context).pop();
rating.rate();
},
),
],
),
);
}
});
}


Вы можете хранить RatingSettings в Firebase Remote Config, чтобы регулировать эти настройки без пересборки приложения и находить оптимальные значения 🔧

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

Оцените новую рубрику! 👍👎
Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #SmartRating #RatingSystem #UXTips
Как открыть страницу настроек приложения в системе
Привет, друзья! 👋 Сегодня мы поделимся с вами полезным советом о том, как открыть страницу настроек вашего приложения на устройстве пользователя. 📱💻

Зачем это нужно? 🤔
Например, если пользователь отклонил уведомления, система больше не будет запрашивать разрешение. В этом случае вы можете помочь пользователю перейти в настройки и включить уведомления вручную. 🔔

Используем url_launcher 📲

import 'package:url_launcher/url_launcher.dart';

Future<void> openSettings() async {
Uri url;
if (defaultTargetPlatform == TargetPlatform.iOS) {
url = Uri.parse('app-settings:');
} else if (defaultTargetPlatform == TargetPlatform.android) {
url = Uri.parse('package:uly.vlog.diary');
} else {
throw Exception('Unsupported platform');
}

if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
throw 'Could not launch $url';
}
}


Или проще с permission_handler 📦

import 'package:permission_handler/permission_handler.dart';

openAppSettings();



Оцените новую рубрику и напишите в комментариях, что вы думаете о ней! 💬 Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #ProgrammingTips #CodingTips
Flutter tips: how to create a responsive layout
Адаптивный макет: советы по Flutter

Привет, разработчики! 👋 Сегодня мы поговорим о создании адаптивного макета в Flutter. 📱💻

Адаптация макета под разные размеры экранов 📐
Чтобы ваше приложение выглядело отлично на разных устройствах, необходимо адаптировать макет под различные размеры экранов. 📊


import 'package:flutter/widgets.dart';

// Перечисление типов устройств
enum DeviceType { small, medium, large, xlarge }

// Виджет, который адаптирует свой контент к текущему типу устройства
class ResponsiveLayout extends StatelessWidget {
final Widget? small; // Виджет для маленьких экранов
final Widget? medium; // Виджет для средних экранов
final Widget? large; // Виджет для больших экранов
final Widget? xlarge; // Виджет для очень больших экранов

const ResponsiveLayout({
super.key,
required this.small,
this.medium,
this.large,
this.xlarge,
});

@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Определение типа устройства на основе ширины экрана
switch (getDeviceType(constraints)) {
case DeviceType.small:
return small!; // Возвращаем виджет для маленьких экранов
case DeviceType.medium:
return medium ?? small!; // Возвращаем виджет для средних экранов или fallback к маленькому
case DeviceType.large:
return large ?? medium ?? small!; // Возвращаем виджет для больших экранов или fallback
case DeviceType.xlarge:
return xlarge ?? large ?? medium ?? small!; // Возвращаем виджет для очень больших экранов или fallback
}
},
);
}

// Метод для определения типа устройства на основе ограничений
DeviceType getDeviceType(BoxConstraints constraints) {
return switch (constraints.maxWidth) {
> 1200 => DeviceType.xlarge, // Очень большой экран
> 1024 => DeviceType.large, // Большой экран
> 768 => DeviceType.medium, // Средний экран
_ => DeviceType.small, // Маленький экран
};
}
}


Пример использования:

ResponsiveLayout(
small: SigninForm(), // Форма входа для маленьких экранов
medium: Center( // Центрирование для средних экранов и больше
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 600), // Ограничение максимальной ширины
child: SigninForm(), // Форма входа
),
),
)


Этот код позволяет создать адаптивный макет, который будет корректно отображаться на различных устройствах. 📱💻

Оцените новую рубрику и напишите своё мнение в комментариях! 💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #UIUX #ProgrammingTips #CodingTips
Flutter tips: Расширения для работы с датами

Привет, подписчики! Сегодня мы поговорим о полезных расширениях для работы с датами в Flutter. Расширения позволяют писать более чистый и читаемый код, что упрощает разработку и поддержку приложений.

Использование расширений для дат

Расширения в Dart позволяют добавлять новые методы к существующим классам. В данном случае мы будем использовать расширение для класса DateTime, чтобы добавить полезные методы для работы с датами.

extension DateExtension on DateTime {
DateTime get firstDayOfWeek {
return subtract(Duration(days: weekday - 1));
}

DateTime get lastDayOfWeek {
return add(Duration(days: 7 - weekday));
}

DateTime get firstDayOfMonth {
return DateTime(year, month);
}

bool isToday() => isSameDay(DateTime.now());

bool isSameDay(DateTime other) {
return day == other.day && month == other.month && year == other.year;
}

bool isAfterDayOrEqual(DateTime other) {
return isAfter(other) || isSameDay(other);
}

bool isBeforeDayOrEqual(DateTime other) {
return isBefore(other) || isSameDay(other);
}

bool isSameWeek(DateTime other) {
final kfirstDayOfTheWeek = firstDayOfWeek;
return other.isAfterDayOrEqual(kfirstDayOfTheWeek) &&
other.isBefore(lastDayOfWeek);
}
}


Пример использования

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

if (!activities.hasActivity(date) && date.isToday()) {
// код
}


Это намного чище и читаемее, чем:

final today = DateTime.now();
if (!activities.hasActivity(date) && date.day == today.day && date.month == today.month && date.year == today.year) {
// код
}


Оцените новую рубрику! Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #CodingTips #AppDev #FlutterTips