giphy_flutter

A Flutter SDK and picker UI for integrating GIPHY search and selection into your app.

Features

  • Ready-made pickerGiphyBottomSheet handles search, paging, theming and selection.
  • Clean architecture — data, domain and presentation layers are separable; use the repository directly if you want your own UI.
  • Typed errors — every failure is a GiphyException subtype, and the hierarchy is sealed so a switch over it is exhaustively checked.
  • Debounced search with supersession — a new query cancels the in-flight request and always wins.
  • Lean dependenciesdio, cached_network_image and equatable. No state-management library is imposed on you.

Getting started

1. Add the dependency

dependencies:
  giphy_flutter: ^0.1.0

2. Get a GIPHY API key

Create an app on the GIPHY Developers Portal.

Treat the key as a secret: pass it in at build time (--dart-define) rather than committing it.

Usage

Open the picker

import 'package:giphy_flutter/giphy_flutter.dart';

final gif = await GiphyBottomSheet.open(
  context,
  apiKey: 'YOUR_GIPHY_API_KEY',
  rating: GiphyRating.g,          // optional: g, pg, pg13, r
  initialType: GiphyType.gif,     // optional: gif, sticker
  showTypeSelector: true,         // optional: show the GIFs/Stickers switch
  theme: GiphyTheme.light,        // optional: dark (default) or light
);

if (gif != null) {
  debugPrint('Selected: ${gif.images.original.url}');
}

open completes with null when the sheet is dismissed without a selection.

Customise appearance and copy

await GiphyBottomSheet.open(
  context,
  apiKey: apiKey,
  theme: GiphyTheme.light.copyWith(loadingIndicatorColor: Colors.purple),
  labels: const GiphyLabels(
    searchHint: 'Search GIPHY',
    noResults: 'Nothing here',
  ),
  pageSize: 40,   // clamped to GIPHY's maximum of 50
);

Direct API access

final repository = GiphyRepositoryImpl.withApiKey('YOUR_GIPHY_API_KEY');

try {
  final search = await repository.searchGifs(query: 'funny cats', limit: 30);
  final gifs = search.data;
  final morePages = search.pagination?.hasMore ?? false;

  final trending = await repository.trendingGifs();
  final random = await repository.randomGif(tag: 'cats');
} on GiphyException catch (e) {
  final message = switch (e) {
    GiphyAuthException() => 'Check your API key.',
    GiphyRateLimitException() => 'Too many requests — try again shortly.',
    GiphyCancelledException() => '',
    _ => e.message,
  };
  debugPrint(message);
} finally {
  repository.close();   // releases the underlying HTTP client
}

Build your own UI

GiphyPaginationController owns query, paging and cancellation state, and is a plain ChangeNotifier:

final controller = GiphyPaginationController(
  repository: GiphyRepositoryImpl.withApiKey(apiKey),
  pageSize: 30,
)..loadTrending();

ListenableBuilder(
  listenable: controller,
  builder: (context, _) {
    if (controller.error != null) return Text(controller.error!.message);
    return MyGrid(
      gifs: controller.gifs,
      onEndReached: controller.loadMore,
    );
  },
);

Remember to dispose() the controller, and close() the repository you gave it.

Architecture

lib/src/
  core/          Dio interceptor, sealed exceptions, service locator
  data/          JSON models, remote data source, repository implementation
  domain/        Entities, repository contract, use cases
  presentation/  Pagination controller, bottom sheet, theme

Anything not exported from lib/giphy_flutter.dart is internal and may change without a major version bump.

Notes on the GIPHY API

  • limit is capped at 50 per request.
  • offset is capped at 4999; GiphyPagination.hasMore accounts for this, so paging stops cleanly instead of erroring at the boundary.
  • total_count on trending endpoints is unreliable — treat it as advisory.
  • Not every rendition is present on every asset. Parsing falls back through alternatives, so images.original, images.fixedHeight and images.preview are always populated when a GIF parses at all.

Compliance

The picker displays "Powered by GIPHY" attribution and honours the rating filter you pass. GIPHY's marks guidelines also cover use of their logo; if your app needs the logo lockup rather than a text credit, supply it yourself via the surrounding UI. Review GIPHY's terms before shipping.

Testing

flutter test

To test your own code against the picker without touching the network, register a fake repository under the API key your widget uses. GiphyBottomSheet resolves its dependencies through the locator, so it will pick yours up instead of building a real Dio client:

setUp(() {
  GiphyServiceLocator.instance
    ..clear()
    ..register('test-key', GiphyDependencies.fromRepository(FakeRepository()));
});

tearDown(() => GiphyServiceLocator.instance.clear());

register throws if the key is already held by a live widget, so a leaked holder surfaces as a test failure rather than as a silent mix of real and fake data. The package's own test/giphy_ui_test.dart uses exactly this seam.

License

MIT — see LICENSE.

Libraries

giphy_flutter
A GIPHY SDK and picker UI for Flutter.