giphy_flutter
A Flutter SDK and picker UI for integrating GIPHY search and selection into your app.
Features
- Ready-made picker —
GiphyBottomSheethandles 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
GiphyExceptionsubtype, and the hierarchy issealedso aswitchover it is exhaustively checked. - Debounced search with supersession — a new query cancels the in-flight request and always wins.
- Lean dependencies —
dio,cached_network_imageandequatable. 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
limitis capped at 50 per request.offsetis capped at 4999;GiphyPagination.hasMoreaccounts for this, so paging stops cleanly instead of erroring at the boundary.total_counton 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.fixedHeightandimages.previeware 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.