From e6e7c2cb63f50a6f6ce5616785caf1f035250cf3 Mon Sep 17 00:00:00 2001 From: Olivier Revial Date: Tue, 1 Aug 2023 15:06:08 +0200 Subject: [PATCH] Allow some components to be customized Closes #55 --- README.md | 23 ++++--- example/pubspec.lock | 4 +- lib/giphy_get.dart | 33 +++++++--- lib/src/views/appbar/searchappbar.dart | 87 +++++++++++++++---------- lib/src/views/main_view.dart | 12 +++- lib/src/views/tab/giphy_tab_detail.dart | 28 ++++---- pubspec.lock | 4 +- pubspec.yaml | 16 ++--- 8 files changed, 125 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index 5a67d0d..3059d2d 100644 --- a/README.md +++ b/README.md @@ -66,16 +66,19 @@ GiphyGif gif = await GiphyGet.getGif( ### Options -| Value | Type | Description | Default | -| ---------------------------- | ------ | --------------------------------------------------------------------------------------------------------------- | ------------------------------- | -| `lang` | String | Use [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language code or use GiphyLanguage constants | `GiphyLanguage.english` | -| `randomID` | String | An ID/proxy for a specific user. | `null` | -| `searchText` | String | Input search hint, we recomend use [flutter_18n package](https://pub.dev/packages/flutter_i18n) for translation | `"Search GIPHY"` | -| `tabColor` | Color | Color for tabs and loading progress, | `Theme.of(context).accentColor` | -| `debounceTimeInMilliseconds` | int | Time to pause between search keystrokes | `350` | -| `showGIFs` | bool | Whether to show the GIFs tab or not | `true` | -| `showStickers` | bool | Whether to show the stickers tab or not | `true` | -| `showEmojis` | bool | Whether to show the emojis tab or not | `true` | +| Value | Type | Description | Default | +|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| +| `lang` | String | Use [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language code or use GiphyLanguage constants | `GiphyLanguage.english` | +| `randomID` | String | An ID/proxy for a specific user. | `null` | +| `searchText` | String | Input search hint, we recomend use [flutter_18n package](https://pub.dev/packages/flutter_i18n) for translation | `"Search GIPHY"` | +| `tabColor` | Color | Color for tabs and loading progress, | `Theme.of(context).accentColor` | +| `debounceTimeInMilliseconds` | int | Time to pause between search keystrokes | `350` | +| `showGIFs` | bool | Whether to show the GIFs tab or not | `true` | +| `showStickers` | bool | Whether to show the stickers tab or not | `true` | +| `showEmojis` | bool | Whether to show the emojis tab or not | `true` | +| `tapTopBuilder` | `Widget Function(BuildContext context)` | A custom builder for tab top. Must return a widget that will replace default Giphy-like tab top | `null`. Displays default Giphy-like tab top | +| `tabBottomBuilder` | `Widget Function(BuildContext context)` | A custom builder for tab bottom. Must return a widget that will replace default Giphy credits logo. Note that credits are required to be shown by Giphy | `null`. Displays default Giphy credits logo | +| `searchAppBarBuilder` | `Widget Function(BuildContext context,FocusNode focusNode,bool autofocus,TextEditingController textEditingController,void Function() onClearSearch)` | A custom builder for search app bar. Must return a widget that will replace default Giphy-like search bar input | `null`. Displays default Giphy-like search bar input | ### [Get Random ID](https://developers.giphy.com/docs/api/endpoint#random-id) diff --git a/example/pubspec.lock b/example/pubspec.lock index ef690d3..77f5d36 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -116,10 +116,10 @@ packages: dependency: transitive description: name: flutter_staggered_grid_view - sha256: "1312314293acceb65b92754298754801b0e1f26a1845833b740b30415bbbcf07" + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" url: "https://pub.dev" source: hosted - version: "0.6.2" + version: "0.7.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/lib/giphy_get.dart b/lib/giphy_get.dart index d24b0ec..204c672 100644 --- a/lib/giphy_get.dart +++ b/lib/giphy_get.dart @@ -7,8 +7,8 @@ import 'package:giphy_get/src/client/models/languages.dart'; import 'package:giphy_get/src/client/models/rating.dart'; import 'package:giphy_get/src/providers/app_bar_provider.dart'; import 'package:giphy_get/src/providers/sheet_provider.dart'; -import 'package:giphy_get/src/views/main_view.dart'; import 'package:giphy_get/src/providers/tab_provider.dart'; +import 'package:giphy_get/src/views/main_view.dart'; import 'package:provider/provider.dart'; // Giphy Client Export @@ -19,10 +19,20 @@ export 'package:giphy_get/src/client/models/image.dart'; export 'package:giphy_get/src/client/models/images.dart'; export 'package:giphy_get/src/client/models/languages.dart'; export 'package:giphy_get/src/client/models/rating.dart'; -export 'package:giphy_get/src/client/models/user.dart'; export 'package:giphy_get/src/client/models/type.dart'; -export 'package:giphy_get/src/widgets/giphy_gif.widget.dart'; +export 'package:giphy_get/src/client/models/user.dart'; export 'package:giphy_get/src/widgets/giphy_get.widget.dart'; +export 'package:giphy_get/src/widgets/giphy_gif.widget.dart'; + +typedef TabTopBuilder = Widget Function(BuildContext context); +typedef TabBottomBuilder = Widget Function(BuildContext context); +typedef SearchAppBarBuilder = Widget Function( + BuildContext context, + FocusNode focusNode, + bool autofocus, + TextEditingController textEditingController, + void Function() onClearSearch, +); class GiphyGet { // Show Bottom Sheet @@ -42,6 +52,9 @@ class GiphyGet { Color? textSelectedColor, Color? textUnselectedColor, int debounceTimeInMilliseconds = 350, + TabTopBuilder? tapTopBuilder, + TabBottomBuilder? tabBottomBuilder, + SearchAppBarBuilder? searchAppBarBuilder, }) { if (apiKey == "") { throw Exception("apiKey must be not null or not empty"); @@ -49,11 +62,12 @@ class GiphyGet { return showModalBottomSheet( clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(10.0), - ), - ), + shape: Theme.of(context).bottomSheetTheme.shape ?? + RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(10.0), + ), + ), isScrollControlled: true, context: context, builder: (ctx) => MultiProvider( @@ -87,6 +101,9 @@ class GiphyGet { showGIFs: showGIFs, showStickers: showStickers, showEmojis: showEmojis, + tabTopBuilder: tapTopBuilder, + tabBottomBuilder: tabBottomBuilder, + searchAppBarBuilder: searchAppBarBuilder, ), ), ), diff --git a/lib/src/views/appbar/searchappbar.dart b/lib/src/views/appbar/searchappbar.dart index f394283..35a0b7b 100644 --- a/lib/src/views/appbar/searchappbar.dart +++ b/lib/src/views/appbar/searchappbar.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:giphy_get/giphy_get.dart'; -import 'package:giphy_get/src/client/models/type.dart'; import 'package:giphy_get/src/l10n/l10n.dart'; import 'package:giphy_get/src/providers/app_bar_provider.dart'; import 'package:giphy_get/src/providers/sheet_provider.dart'; @@ -14,8 +13,13 @@ import 'package:provider/provider.dart'; class SearchAppBar extends StatefulWidget { // Scroll Controller final ScrollController scrollController; + final SearchAppBarBuilder? searchAppBarBuilder; - SearchAppBar({Key? key, required this.scrollController}) : super(key: key); + SearchAppBar({ + Key? key, + required this.scrollController, + this.searchAppBarBuilder, + }) : super(key: key); @override _SearchAppBarState createState() => _SearchAppBarState(); @@ -102,43 +106,56 @@ class _SearchAppBarState extends State { children: [ _tabProvider.tabType == GiphyType.emoji ? Container() - : SizedBox( - height: 40, - child: Center( - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: TextField( - textAlignVertical: TextAlignVertical.center, - autofocus: _sheetProvider.initialExtent == - SheetProvider.maxExtent, - focusNode: _focus, - controller: _textEditingController, - decoration: InputDecoration( - isDense: true, - filled: true, - prefixIcon: _searchIcon(), - hintText: l.searchInputLabel, - suffixIcon: IconButton( - icon: Icon( - Icons.clear, - color: - Theme.of(context).textTheme.bodyLarge!.color!, - ), - onPressed: () { - setState(() { - _textEditingController.clear(); - }); - }), - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, + : widget.searchAppBarBuilder?.call( + context, + _focus, + _sheetProvider.initialExtent == SheetProvider.maxExtent, + _textEditingController, + () { + setState(() { + _textEditingController.clear(); + }); + }, + ) ?? + SizedBox( + height: 40, + child: Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: TextField( + textAlignVertical: TextAlignVertical.center, + autofocus: _sheetProvider.initialExtent == + SheetProvider.maxExtent, + focusNode: _focus, + controller: _textEditingController, + decoration: InputDecoration( + isDense: true, + filled: true, + prefixIcon: _searchIcon(), + hintText: l.searchInputLabel, + suffixIcon: IconButton( + icon: Icon( + Icons.clear, + color: Theme.of(context) + .textTheme + .bodyLarge! + .color!, + ), + onPressed: () { + setState(() { + _textEditingController.clear(); + }); + }), + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + ), + autocorrect: false, ), - autocorrect: false, ), ), ), - ), ], ); } diff --git a/lib/src/views/main_view.dart b/lib/src/views/main_view.dart index a81c862..b34897e 100644 --- a/lib/src/views/main_view.dart +++ b/lib/src/views/main_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:giphy_get/giphy_get.dart'; import 'package:giphy_get/src/providers/sheet_provider.dart'; import 'package:giphy_get/src/views/appbar/searchappbar.dart'; import 'package:giphy_get/src/views/tab/giphy_tab_bar.dart'; @@ -13,11 +14,17 @@ class MainView extends StatefulWidget { this.showEmojis = true, this.showGIFs = true, this.showStickers = true, + this.tabTopBuilder, + this.tabBottomBuilder, + this.searchAppBarBuilder, }) : super(key: key); final bool showGIFs; final bool showStickers; final bool showEmojis; + final TabTopBuilder? tabTopBuilder; + final TabBottomBuilder? tabBottomBuilder; + final SearchAppBarBuilder? searchAppBarBuilder; @override _MainViewState createState() => _MainViewState(); @@ -80,7 +87,7 @@ class _MainViewState extends State Widget _bottomSheetBody() => Column( mainAxisSize: MainAxisSize.min, children: [ - GiphyTabTop(), + widget.tabTopBuilder?.call(context) ?? GiphyTabTop(), GiphyTabBar( tabController: _tabController, showGIFs: widget.showGIFs, @@ -89,6 +96,7 @@ class _MainViewState extends State ), SearchAppBar( scrollController: this._scrollController, + searchAppBarBuilder: widget.searchAppBarBuilder, ), Expanded( child: GiphyTabView( @@ -99,7 +107,7 @@ class _MainViewState extends State showEmojis: widget.showEmojis, ), ), - GiphyTabBottom() + widget.tabBottomBuilder?.call(context) ?? GiphyTabBottom(), ], ); } diff --git a/lib/src/views/tab/giphy_tab_detail.dart b/lib/src/views/tab/giphy_tab_detail.dart index 3ccad51..3251612 100644 --- a/lib/src/views/tab/giphy_tab_detail.dart +++ b/lib/src/views/tab/giphy_tab_detail.dart @@ -122,21 +122,18 @@ class _GiphyTabDetailState extends State { ); } - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - // child: StaggeredGrid.countB - child: MasonryGridView.count( - scrollDirection: _scrollDirection, - controller: widget.scrollController, - itemCount: _list.length, - crossAxisCount: _crossAxisCount, - mainAxisSpacing: _spacing, - crossAxisSpacing: _spacing, - itemBuilder: (ctx, idx) { - GiphyGif _gif = _list[idx]; - return _item(_gif); - }, - ), + return MasonryGridView.count( + padding: EdgeInsets.symmetric(horizontal: 8.0), + scrollDirection: _scrollDirection, + controller: widget.scrollController, + itemCount: _list.length, + crossAxisCount: _crossAxisCount, + mainAxisSpacing: _spacing, + crossAxisSpacing: _spacing, + itemBuilder: (ctx, idx) { + GiphyGif _gif = _list[idx]; + return _item(_gif); + }, ); } @@ -152,6 +149,7 @@ class _GiphyTabDetailState extends State { ? Container() : ExtendedImage.network( gif.images!.fixedWidth.webp!, + semanticLabel: gif.title, cache: true, gaplessPlayback: true, fit: BoxFit.fill, diff --git a/pubspec.lock b/pubspec.lock index 6d548c2..5a29244 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -188,10 +188,10 @@ packages: dependency: "direct main" description: name: flutter_staggered_grid_view - sha256: "1312314293acceb65b92754298754801b0e1f26a1845833b740b30415bbbcf07" + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" url: "https://pub.dev" source: hosted - version: "0.6.2" + version: "0.7.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 970bf03..4e6577b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,21 +13,21 @@ dependencies: flutter_localizations: sdk: flutter - provider: ^6.0.3 - extended_image: ^8.0.0 - flutter_staggered_grid_view: ^0.6.0 - meta: ^1.7.0 + provider: ^6.0.5 + extended_image: ^8.0.2 + flutter_staggered_grid_view: ^0.7.0 + meta: ^1.9.1 http: ^1.1.0 - url_launcher: ^6.1.3 + url_launcher: ^6.1.12 dev_dependencies: flutter_test: sdk: flutter integration_test: sdk: flutter - mockito: ^5.0.7 - pedantic: ^1.11.0 - matcher: ^0.12.10 + mockito: ^5.4.2 + pedantic: ^1.11.1 + matcher: ^0.12.15 flutter: assets: