utills 2.0.1 copy "utills: ^2.0.1" to clipboard
utills: ^2.0.1 copied to clipboard

A comprehensive Flutter utility package providing layout gaps, form validators, a generic API handler, and a scroll-ready paginator.

example/example.md

How to use utills #

This example shows the common setup for the latest utills APIs, including animated toast notifications and navigation helpers.

Install #

dependencies:
  utills: ^2.0.1

Import #

import 'package:flutter/material.dart';
import 'package:utills/utills.dart';

CustomToast setup #

Create one navigator key, pass it to CustomToast.init(), and use the same key in MaterialApp.

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() {
  CustomToast.init(
    navigatorKey: navigatorKey,
    config: CustomToastConfig(
      duration: const Duration(seconds: 2),
      position: ToastPosition.top,
      // Add backgroundColors, textStyles, margin, and radius as needed.
    ),
  );

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      /// mention the key here
      navigatorKey: navigatorKey,
      home: const HomeScreen(),
    );
  }
}

Show toast messages from anywhere after initialization.

CustomToast.show(
  'Data saved successfully!',
  type: ToastType.success,
);

CustomToast.show(
  'Failed to connect to server.',
  type: ToastType.error,
);

CustomToast.show(
  'Your subscription expires soon!',
  type: ToastType.warning,
);

Use Navigate to reduce route boilerplate. Navigate.push() also supports slide direction and duration.

Navigate.push(context, const ProfileScreen());

Navigate.push(
  context,
  const DetailsScreen(),
  direction: NavDirection.bottomToUp,
  duration: const Duration(milliseconds: 400),
);

Navigate.pushReplacement(context, const HomeScreen());

Navigate.pushAndRemoveUntil(context, const WelcomeScreen());

Navigate.pop(context);

Attempt and failure handling #

Use Attempt<T> when a function can return either data or a typed Failure. This example uses the http package for the network call.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:utills/utills.dart';

Future<Attempt<String>> exampleApiFunction({
  required Map<String, String> header,
}) async {
  final url = Uri.parse('$baseUrl/example/$id/action');

  try {
    final response = await http
        .post(url, headers: header)
        .timeout(const Duration(seconds: 10));
    final data = jsonDecode(response.body);

    if (response.statusCode == 200) {
      Log.success(data);
      return success('successfully completed');
    } else {
      return failed(
        mapStatusCodeToFailure(
          response.statusCode,
          message: data['detail']?.toString(),
        ),
      );
    }
  } on TimeoutException catch (e) {
    Log.warning('Request timed out: $e');
    return failed(const TimeoutFailure());
  } on SocketException catch (e) {
    Log.warning('No Internet or Server unreachable: $e');
    return failed(const InternetFailure());
  } catch (e) {
    Log.error('Error : $e');
    return failed(const UnknownFailure());
  }
}

From the UI side, destructure the record returned by the function.

Future<void> exampleUiFunction() async {
  final (data, error) = await exampleApiFunction(
    header: {'Authorization': 'Bearer token'},
  );

  if (data != null) {
    CustomToast.showAnimation(data, type: ToastType.success);
  } else {
    CustomToast.showAnimation(
      error?.description ?? 'Something went wrong',
      type: ToastType.error,
    );
  }
}

Paginator #

RestPaginator<T> loads pages, stores the loaded items, and notifies listeners when its state changes.

class ExampleController extends ChangeNotifier {
  ExampleController() {
    paginator.addListener(notifyListeners);
  }

  late final RestPaginator<Map<String, dynamic>> paginator =
      RestPaginator<Map<String, dynamic>>(
    pageSize: 20,
    getPage: fetchExamplePage,
  );

  Future<RestPageData<Map<String, dynamic>>?> fetchExamplePage(
    int page,
    int pageSize,
  ) async {
    final response = await http.get(
      Uri.parse('https://api.example.com/items?page=$page&pageSize=$pageSize'),
    );

    if (response.statusCode != 200) return null;

    final body = jsonDecode(response.body) as Map<String, dynamic>;
    final items = (body['data'] as List).cast<Map<String, dynamic>>();
    final totalPages = body['totalPages'] as int;

    return (items: items, totalPages: totalPages);
  }

  @override
  void dispose() {
    paginator.removeListener(notifyListeners);
    paginator.dispose();
    super.dispose();
  }
}

Use getItem(index) in a list. It automatically asks for the next page when the user gets near the end.

ListView.builder(
  itemCount: controller.paginator.availableItemCount +
      (controller.paginator.endReached ? 0 : 1),
  itemBuilder: (context, index) {
    if (index >= controller.paginator.availableItemCount) {
      return const Center(child: CircularProgressIndicator());
    }

    final item = controller.paginator.getItem(index);
    return ListTile(
      title: Text(item['title'] ?? ''),
    );
  },
);

Debugger #

Use Log for colorized debug-only output. These helpers are no-ops in release builds.

Log.info('Loading items');
Log.success({'status': 'completed', 'count': 20});
Log.warning('Token will expire soon');
Log.error('Request failed');
Log.trace('exampleApiFunction() called');

Other utilities #

// Gaps
Column(
  children: [
    const Text('Title'),
    vPad10,
    const Text('Subtitle'),
  ],
);

// Validators
TextFormField(
  validator: CommonValidator.emailValidator,
);
0
likes
150
points
120
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter utility package providing layout gaps, form validators, a generic API handler, and a scroll-ready paginator.

Homepage
Repository (GitLab)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on utills