Skip to content

Commit c1361bc

Browse files
authored
Merge pull request #2 from ionicfirebaseapp/master
master pull
2 parents e4ca9fc + 47e426a commit c1361bc

10 files changed

Lines changed: 1079 additions & 747 deletions

File tree

example/lib/assets/food.jpeg

33.6 KB
Loading

example/lib/main.dart

Lines changed: 535 additions & 150 deletions
Large diffs are not rendered by default.

example/pubspec.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: ui_kit_example
1+
name: example
22
description: A new Flutter project.
33

44
version: 1.0.0+1
@@ -19,4 +19,6 @@ dev_dependencies:
1919
sdk: flutter
2020

2121
flutter:
22-
uses-material-design: true
22+
uses-material-design: true
23+
assets:
24+
- lib/assets/food.jpeg

lib/colors/gf_color.dart

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@ enum GFColor {
1212
light,
1313
dark,
1414
white,
15+
transparent
1516
}
1617

17-
const PRIMARY = Colors.blue;
18-
const SECONDARY = Colors.grey;
19-
const SUCCESS = Colors.green;
20-
const INFO = Colors.yellow;
21-
const WARNING = Colors.lightBlueAccent;
22-
const DANGER = Colors.red;
23-
const FOCUS = Colors.black38;
24-
const ALT = Colors.purple;
25-
const LIGHT = Colors.white30;
26-
const DARK = Colors.black;
27-
const WHITE = Colors.white;
18+
const PRIMARY = Color(0xff3f6ad8);
19+
const SECONDARY = Color(0xff6c757c);
20+
const SUCCESS =Color(0xff3ac47c);
21+
const INFO = Color(0xff13aaff);
22+
const WARNING = Color(0xfff7b825);
23+
const DANGER = Color(0xffd92550);
24+
const FOCUS = Color(0xff434054);
25+
const ALT = Color(0xff794c8a);
26+
const LIGHT = Color(0xffededed);
27+
const DARK = Color(0xff333a40);
28+
const WHITE = Color(0xffffffff);
29+
const TRANSPARENT = Colors.transparent;
2830

2931
/// Pass [GFColor] or [Color]
3032
Color getGFColor(dynamic color) {
@@ -65,6 +67,9 @@ Color getGFColor(dynamic color) {
6567
case GFColor.white:
6668
return WHITE;
6769
break;
70+
case GFColor.transparent:
71+
return TRANSPARENT;
72+
break;
6873
default:
6974
return PRIMARY;
7075
break;

lib/components/header/gf_header.dart

Whitespace-only changes.
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
import 'dart:async';
2+
import 'dart:ffi';
3+
import 'package:flutter/material.dart';
4+
5+
List<T> map<T>(List list, Function handler) {
6+
List<T> result = [];
7+
for (var i = 0; i < list.length; i++) {
8+
result.add(handler(i, list[i]));
9+
}
10+
return result;
11+
}
12+
13+
class GFSlider extends StatefulWidget {
14+
GFSlider(
15+
{@required this.items,
16+
this.pagerSize,
17+
this.passiveIndicator,
18+
this.activeIndicator,
19+
this.pagination,
20+
this.height,
21+
this.aspectRatio: 16 / 9,
22+
this.viewportFraction: 0.8,
23+
this.initialPage: 0,
24+
int realPage: 10000,
25+
this.enableInfiniteScroll: true,
26+
this.reverse: false,
27+
this.autoPlay: false,
28+
this.autoPlayInterval: const Duration(seconds: 4),
29+
this.autoPlayAnimationDuration = const Duration(milliseconds: 800),
30+
this.autoPlayCurve: Curves.fastOutSlowIn,
31+
this.pauseAutoPlayOnTouch,
32+
this.enlargeMainPage = false,
33+
this.onPageChanged,
34+
this.scrollPhysics,
35+
this.scrollDirection: Axis.horizontal})
36+
: this.realPage = enableInfiniteScroll ? realPage + initialPage : initialPage,
37+
this.pageController = PageController(
38+
viewportFraction: viewportFraction,
39+
initialPage: enableInfiniteScroll ? realPage + initialPage : initialPage,
40+
);
41+
42+
/// The pagination dots size can be defined using [double].
43+
final double pagerSize;
44+
45+
/// The slider pagination's active color.
46+
final Color activeIndicator;
47+
48+
/// The slider pagination's passive color.
49+
final Color passiveIndicator;
50+
51+
/// The [GFSlider] shows pagination on state true.
52+
final bool pagination;
53+
54+
/// The widgets to be shown as sliders.
55+
final List<Widget> items;
56+
57+
/// Set slide widget height and overrides any existing [aspectRatio].
58+
final double height;
59+
60+
/// Aspect ratio is used if no height have been declared. Defaults to 16:9 aspect ratio.
61+
final double aspectRatio;
62+
63+
/// The fraction of the viewport that each page should occupy. Defaults to 0.8, which means each page fills 80% of the slide.
64+
final num viewportFraction;
65+
66+
/// The initial page to show when first creating the [GFSlider]. Defaults to 0.
67+
final num initialPage;
68+
69+
/// The actual index of the [PageView].
70+
final num realPage;
71+
72+
/// Determines if slides should loop infinitely or be limited to item length. Defaults to true, i.e. infinite loop.
73+
final bool enableInfiniteScroll;
74+
75+
/// Reverse the order of items if set to true. Defaults to false.
76+
final bool reverse;
77+
78+
/// Enables auto play, sliding one page at a time. Use [autoPlayInterval] to determent the frequency of slides. Defaults to false.
79+
final bool autoPlay;
80+
81+
/// Sets Duration to determent the frequency of slides when [autoPlay] is set to true. Defaults to 4 seconds.
82+
final Duration autoPlayInterval;
83+
84+
/// The animation duration between two transitioning pages while in auto playback. Defaults to 800 ms.
85+
final Duration autoPlayAnimationDuration;
86+
87+
/// Determines the animation curve physics. Defaults to [Curves.fastOutSlowIn].
88+
final Curve autoPlayCurve;
89+
90+
/// Sets a timer on touch detected that pause the auto play with the given [Duration]. Touch Detection is only active if [autoPlay] is true.
91+
final Duration pauseAutoPlayOnTouch;
92+
93+
/// Determines if current page should be larger then the side images,
94+
/// creating a feeling of depth in the carousel. Defaults to false.
95+
final bool enlargeMainPage;
96+
97+
/// The axis along which the page view scrolls. Defaults to [Axis.horizontal].
98+
final Axis scrollDirection;
99+
100+
/// Called whenever the page in the center of the viewport changes.
101+
final Function(int index) onPageChanged;
102+
103+
/// How the carousel should respond to user input.
104+
///
105+
/// For example, determines how the items continues to animate after the
106+
/// user stops dragging the page view.
107+
///
108+
/// The physics are modified to snap to page boundaries using
109+
/// [PageScrollPhysics] prior to being used.
110+
///
111+
/// Defaults to matching platform conventions.
112+
final ScrollPhysics scrollPhysics;
113+
114+
/// [pageController] is created using the properties passed to the constructor
115+
/// and can be used to control the [PageView] it is passed to.
116+
final PageController pageController;
117+
118+
/// Animates the controlled [GFSlider] to the next page.
119+
///
120+
/// The animation lasts for the given duration and follows the given curve.
121+
/// The returned [Future] resolves when the animation completes.
122+
Future<void> nextPage({Duration duration, Curve curve}) {
123+
return pageController.nextPage(duration: duration, curve: curve);
124+
}
125+
126+
/// Animates the controlled [GFSlider] to the previous page.
127+
///
128+
/// The animation lasts for the given duration and follows the given curve.
129+
/// The returned [Future] resolves when the animation completes.
130+
Future<void> previousPage({Duration duration, Curve curve}) {
131+
return pageController.previousPage(duration: duration, curve: curve);
132+
}
133+
134+
/// Changes which page is displayed in the controlled [GFSlider].
135+
///
136+
/// Jumps the page position from its current value to the given value,
137+
/// without animation, and without checking if the new value is in range.
138+
void jumpToPage(int page) {
139+
final index = _getRealIndex(pageController.page.toInt(), realPage, items.length);
140+
return pageController.jumpToPage(pageController.page.toInt() + page - index);
141+
}
142+
143+
/// Animates the controlled [GFSlider] from the current page to the given page.
144+
///
145+
/// The animation lasts for the given duration and follows the given curve.
146+
/// The returned [Future] resolves when the animation completes.
147+
Future<void> animateToPage(int page, {Duration duration, Curve curve}) {
148+
final index = _getRealIndex(pageController.page.toInt(), realPage, items.length);
149+
return pageController.animateToPage(pageController.page.toInt() + page - index,
150+
duration: duration, curve: curve);
151+
}
152+
153+
@override
154+
_GFSliderState createState() => _GFSliderState();
155+
}
156+
157+
class _GFSliderState extends State<GFSlider> with TickerProviderStateMixin {
158+
Timer timer;
159+
160+
@override
161+
void initState() {
162+
super.initState();
163+
timer = getPlayTimer();
164+
}
165+
166+
Timer getPlayTimer() {
167+
return Timer.periodic(widget.autoPlayInterval, (_) {
168+
if (widget.autoPlay) {
169+
widget.pageController
170+
.nextPage(duration: widget.autoPlayAnimationDuration, curve: widget.autoPlayCurve);
171+
}
172+
});
173+
}
174+
175+
void pauseOnTouch() {
176+
timer.cancel();
177+
timer = Timer(widget.pauseAutoPlayOnTouch, () {
178+
timer = getPlayTimer();
179+
});
180+
}
181+
182+
Widget getPageWrapper(Widget child) {
183+
if (widget.height != null) {
184+
final Widget wrapper = Container(height: widget.height, child: child);
185+
return widget.autoPlay && widget.pauseAutoPlayOnTouch != null
186+
? addGestureDetection(wrapper)
187+
: wrapper;
188+
} else {
189+
final Widget wrapper = AspectRatio(aspectRatio: widget.aspectRatio, child: child);
190+
return widget.autoPlay && widget.pauseAutoPlayOnTouch != null
191+
? addGestureDetection(wrapper)
192+
: wrapper;
193+
}
194+
}
195+
196+
Widget addGestureDetection(Widget child) =>
197+
GestureDetector(onPanDown: (_) => pauseOnTouch(), child: child);
198+
199+
@override
200+
void dispose() {
201+
super.dispose();
202+
timer?.cancel();
203+
}
204+
205+
int _current = 0;
206+
207+
@override
208+
Widget build(BuildContext context) {
209+
return Stack(
210+
children: <Widget>[
211+
getPageWrapper(PageView.builder(
212+
physics: widget.scrollPhysics,
213+
scrollDirection: widget.scrollDirection,
214+
controller: widget.pageController,
215+
reverse: widget.reverse,
216+
itemCount: widget.enableInfiniteScroll ? null : widget.items.length,
217+
onPageChanged: (int index) {
218+
219+
int currentPage = _getRealIndex(index + widget.initialPage, widget.realPage, widget.items.length);
220+
if (widget.onPageChanged != null) {
221+
widget.onPageChanged(currentPage);
222+
_current = currentPage;
223+
}
224+
_current = currentPage;
225+
},
226+
itemBuilder: (BuildContext context, int i) {
227+
final int index =
228+
_getRealIndex(i + widget.initialPage, widget.realPage, widget.items.length);
229+
230+
return AnimatedBuilder(
231+
animation: widget.pageController,
232+
child: widget.items[index],
233+
builder: (BuildContext context, child) {
234+
// on the first render, the pageController.page is null,
235+
// this is a dirty hack
236+
if (widget.pageController.position.minScrollExtent == null ||
237+
widget.pageController.position.maxScrollExtent == null) {
238+
Future.delayed(Duration(microseconds: 1), () {
239+
setState(() {});
240+
});
241+
return Container();
242+
}
243+
double value = widget.pageController.page - i;
244+
value = (1 - (value.abs() * 0.3)).clamp(0.0, 1.0);
245+
246+
final double height =
247+
widget.height ?? MediaQuery.of(context).size.width * (1 / widget.aspectRatio);
248+
final double distortionValue =
249+
widget.enlargeMainPage ? Curves.easeOut.transform(value) : 1.0;
250+
251+
if (widget.scrollDirection == Axis.horizontal) {
252+
return Center(child: SizedBox(height: distortionValue * height, child: child));
253+
} else {
254+
return Center(
255+
child: SizedBox(
256+
width: distortionValue * MediaQuery.of(context).size.width, child: child));
257+
}
258+
},
259+
);
260+
},
261+
)),
262+
widget.pagination == true ? Positioned(
263+
left: 0.0,
264+
right: 0.0,
265+
bottom: 0.0,
266+
child: Container(
267+
child: Row(
268+
mainAxisAlignment: MainAxisAlignment.center,
269+
children: map<Widget>(
270+
widget.items,
271+
(indexx, url) {
272+
return Container(
273+
width: widget.pagerSize == null ? 8.0 : widget.pagerSize,
274+
height: widget.pagerSize == null ? 8.0 : widget.pagerSize,
275+
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
276+
decoration: BoxDecoration(
277+
shape: BoxShape.circle,
278+
color: _current == indexx
279+
? widget.activeIndicator == null ? Color.fromRGBO(0, 0, 0, 0.9) : widget.activeIndicator
280+
: widget.passiveIndicator == null ? Color.fromRGBO(0, 0, 0, 0.4) : widget.passiveIndicator,
281+
),
282+
);
283+
},
284+
),
285+
),
286+
),
287+
) : Container(),
288+
],
289+
);
290+
}
291+
}
292+
293+
/// Converts an index of a set size to the corresponding index of a collection of another size
294+
/// as if they were circular.
295+
///
296+
/// Takes a [position] from collection Foo, a [base] from where Foo's index originated
297+
/// and the [length] of a second collection Baa, for which the correlating index is sought.
298+
///
299+
/// For example; We have a Carousel of 10000(simulating infinity) but only 6 images.
300+
/// We need to repeat the images to give the illusion of a never ending stream.
301+
/// By calling _getRealIndex with position and base we get an offset.
302+
/// This offset modulo our length, 6, will return a number between 0 and 5, which represent the image
303+
/// to be placed in the given position.
304+
int _getRealIndex(int position, int base, int length) {
305+
final int offset = position - base;
306+
return _remainder(offset, length);
307+
}
308+
309+
/// Returns the remainder of the modulo operation [input] % [source], and adjust it for
310+
/// negative values.
311+
int _remainder(int input, int source) {
312+
final int result = input % source;
313+
return result < 0 ? source + result : result;
314+
}

lib/components/tabs/gf_tabs.dart

Whitespace-only changes.

0 commit comments

Comments
 (0)