Flutter: адаптивные шрифты и размеры

С размерами блоков воFlutter относительно всё в порядке — очень помогает виджет Expanded. Некоторое же неудобство разработки как оказалось — это отсутствие в «из коробки» возможности указывать размер шрифтов в «адаптиве» под разные разрешения экрана.

Что делать? Решений множество. Ниже некоторые варианты:

Вариант 1:

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

class ScaleSize {
  static double textScaleFactor(BuildContext context, {double maxTextScaleFactor = 2}) {
    final width = MediaQuery.of(context).size.width;
    double val = (width / 1400) * maxTextScaleFactor;
    return max(1, min(val, maxTextScaleFactor));
  }
}

Text(
     intro.subtitle,
     style: Theme.of(context).textTheme.subtitle1,
     textAlign: TextAlign.center,
     textScaleFactor: ScaleSize.textScaleFactor(context),
   ),

Вариант 2:

Использовать различную отрисовку виджетов в зависимости от размера экранов. Как-то типа:

Widget build(BuildContext context) {

  final isSmall = MediaQuery.of(context).size.width < 500;

  return Provider.value(

    value: isSmall

        ? AdaptativeTheme(

            smallFontSize: 10,

            bigSpace: 20,

            smallSpace: 10,

          )

        : AdaptativeTheme(

            smallFontSize: 20,

            bigSpace: 40,

            smallSpace: 12,

          ),

    child: Child(),

  );

}

Вариант 3:

Использовать один из множества пакетов. Например Sizer. Тогда вся адаптация сведется к обёртыванию корневого виджета через виджет Sizer, и далее указание во всех нижележащих виджетах относительных размеров. Например так:

   return Sizer(
        builder: (context, orientation, deviceType) {
        return
          Scaffold(
...
...
                          child: Container(
                            width: 48.sp,
                            height: 48.sp,
...
...
child: Text(ListEZS[index]["nameazs"],style: TextStyle(fontSize: 14.0.sp, color: Colors.black)),

Flutter: переименование пакета

Ситуация: при создании приложения было выбрано не то имя для пакета.

Решение: для решения проблемы, в pubspec.yaml добавим пакет change_app_package_name (в секцию dev_depencies), после чего в командной строке в папке приложения выполним:

flutter pub run change_app_package_name:main ru.цву.увцувцу

1c 7.7 Выборка всех элементов справочника без группировки

1С 7.7 не умеет выбирать все элементы справочника в запросе без группировки по какому то реквизиту. Обычно группируют по Коду. А что делать, если какой-то талантливый программист, решил что поле Код в справочнике например может быть не уникальным? Тогда будем группировать по текущему элементу справочника. Например:

	ТекстЗапроса=
	"//{{ЗАПРОС(СформироватьСЧТ)
	|ОбрабатыватьДокументы все;
	|Обрабатывать НеПомеченныеНаУдаление;
	|Владелец = Справочник.Счетчики.Владелец;
	|Наименование = Справочник.Счетчики.Наименование;
	|ТекущийЭлемент = Справочник.Счетчики.ТекущийЭлемент;
	|Группировка ТекущийЭлемент  Без Групп;
	|"//}}ЗАПРОС
	;             
            
		Запрос = СоздатьОбъект("Запрос");		
		Запрос.Выполнить(ТекстЗапроса);		 
		Пока Запрос.Группировка() = 1 Цикл
...
...

Драйвер принтера TCS-210 Linux

Ну не хотят еще до сих пор разработчики драйверов под Linux писать их нормально. Ну как можно сделать драйвера, без возможности добавить свои размеры бумаги? Только хардкор, только ручная правка файла ppd для CUPS.

В ниже представленном драйвере, добавлен размер бумаги 58х28мм, один из распространённых размеров для печати этикеток.

OTP авторизация

Суть в чём: для каждого пользователя хранится некий OTP ключ (соль), на основании которого генерируется некий код, который в один момент времени (плюс-минус 30 секунд) будет одинаковый с ключём сгенерированным сторонним приложением. Естественно этому стороннему приложению сначала необходимо передать ключ.

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

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

Соберём класс для генерации кода на основании токена:

class TOTP {

 const keyRegeneration  = 30; // Время действия ключа
 const otpLength  = 6; // длина кода OTP

 private static $lut = array( 
  "A" => 0, "B" => 1,"C" => 2, "D" => 3,"E" => 4, "F" => 5,"G" => 6, "H" => 7,"I" => 8, "J" => 9,"K" => 10, "L" => 11,
  "M" => 12, "N" => 13,"O" => 14, "P" => 15,"Q" => 16, "R" => 17,"S" => 18, "T" => 19,"U" => 20, "V" => 21,"W" => 22, "X" => 23,
  "Y" => 24, "Z" => 25,"2" => 26, "3" => 27,"4" => 28, "5" => 29,"6" => 30, "7" => 31
 );


 /**
 * Возвратим текущее время Unix Timestamp округлённое до времени действия ключа
 * @return integer
 **/
 public static function get_timestamp() {
  return floor( (microtime(true) + 10) /self::keyRegeneration);
 }

 /**
 * Перекодируем строку base32 в бинарный вид
 **/
 public static function base32_decode($b32) {
  $b32  = strtoupper($b32);
  if (!preg_match('/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match))
   throw new Exception('Используются не верные символы в ключе.');
  $l  = strlen($b32);
  $n = 0;
  $j = 0;
  $binary = "";
  for ($i = 0; $i < $l; $i++) {
   $n = $n << 5;     // Move buffer left by 5 to make room
   $n = $n + self::$lut[$b32[$i]];  // Add value into buffer
   $j = $j + 5;    // Keep track of number of bits in buffer
   if ($j >= 8) {
    $j = $j - 8;
    $binary .= chr(($n & (0xFF << $j)) >> $j);
   }
  }
  return $binary;
 }

 /**
 * Вернём текущий код
 * @param binary $key - бинарный ключ
 * @param integer $counter - Timestamp
 * @return string
 **/
 public static function oath_hotp($key, $counter){
    if (strlen($key) < 8)
      throw new Exception('Секретный ключ слишком мал.Он должен быть больше 16 символов');
    $bin_counter = pack('N*', 0) . pack('N*', $counter);  
    $hash  = hash_hmac ('sha1', $bin_counter, $key, true);
    return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT);
 }

 /**
 * Вычленяет OTP из SHA1 hash.
 * @param binary $hash
 * @return integer
 **/
 public static function oath_truncate($hash){
    $offset = ord($hash[19]) & 0xf;
    return (
        ((ord($hash[$offset+0]) & 0x7f) << 24 ) |
        ((ord($hash[$offset+1]) & 0xff) << 16 ) |
        ((ord($hash[$offset+2]) & 0xff) << 8 ) |
        (ord($hash[$offset+3]) & 0xff)
    ) % pow(10, self::otpLength);
 }
}

Использование:

$InitalizationKey = "QWERTYUIOPASDFGH";     // Начальный ключ

$TimeStamp  = TOTP::get_timestamp();
$secretkey   = TOTP::base32_decode($InitalizationKey); // Перекодируем в бинарную строку
$otp         = TOTP::oath_hotp($secretkey, $TimeStamp); // получим текщий токен

echo("Ключ: $InitalizationKey\n");
echo("Timestamp: $TimeStamp\n");
echo("Код OTP: $otp\n");

Для того чтобы руками не вводить в OTP приложение начальный токен, можно генерировать QR код, с текстом вида:

otpauth://totp/мой_сайт:логин?secret=токен&issuer=логин

1 48 49 50 51 52 310