mirror of https://github.com/flutter/samples.git
parent
0a88d4519e
commit
a1998e6186
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Tim Sneath
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,4 +0,0 @@
|
||||
A fun little app for groan-worthy dad jokes.
|
||||
|
||||
Original source at
|
||||
[github.com/timsneath/dadjokes](https://github.com/timsneath/dadjokes/).
|
@ -1,93 +0,0 @@
|
||||
include: package:pedantic/analysis_options.1.8.0.yaml
|
||||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
||||
linter:
|
||||
rules:
|
||||
- always_declare_return_types
|
||||
- annotate_overrides
|
||||
- avoid_bool_literals_in_conditional_expressions
|
||||
- avoid_classes_with_only_static_members
|
||||
- avoid_empty_else
|
||||
- avoid_function_literals_in_foreach_calls
|
||||
- avoid_init_to_null
|
||||
- avoid_null_checks_in_equality_operators
|
||||
- avoid_relative_lib_imports
|
||||
- avoid_renaming_method_parameters
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_returning_null
|
||||
- avoid_returning_null_for_future
|
||||
- avoid_returning_null_for_void
|
||||
- avoid_returning_this
|
||||
- avoid_shadowing_type_parameters
|
||||
- avoid_single_cascade_in_expression_statements
|
||||
- avoid_types_as_parameter_names
|
||||
- avoid_unused_constructor_parameters
|
||||
- await_only_futures
|
||||
- camel_case_types
|
||||
- cancel_subscriptions
|
||||
- cascade_invocations
|
||||
- comment_references
|
||||
- constant_identifier_names
|
||||
- control_flow_in_finally
|
||||
- directives_ordering
|
||||
- empty_catches
|
||||
- empty_constructor_bodies
|
||||
- empty_statements
|
||||
- file_names
|
||||
- hash_and_equals
|
||||
- implementation_imports
|
||||
- invariant_booleans
|
||||
- iterable_contains_unrelated_type
|
||||
- join_return_with_assignment
|
||||
- library_names
|
||||
- library_prefixes
|
||||
- list_remove_unrelated_type
|
||||
- literal_only_boolean_expressions
|
||||
- no_adjacent_strings_in_list
|
||||
- no_duplicate_case_values
|
||||
- non_constant_identifier_names
|
||||
- null_closures
|
||||
- omit_local_variable_types
|
||||
- only_throw_errors
|
||||
- overridden_fields
|
||||
- package_api_docs
|
||||
- package_names
|
||||
- package_prefixed_library_names
|
||||
- prefer_adjacent_string_concatenation
|
||||
- prefer_collection_literals
|
||||
- prefer_conditional_assignment
|
||||
- prefer_const_constructors
|
||||
- prefer_contains
|
||||
- prefer_equal_for_default_values
|
||||
- prefer_final_fields
|
||||
- prefer_final_locals
|
||||
- prefer_generic_function_type_aliases
|
||||
- prefer_initializing_formals
|
||||
- prefer_interpolation_to_compose_strings
|
||||
- prefer_is_empty
|
||||
- prefer_is_not_empty
|
||||
- prefer_null_aware_operators
|
||||
- prefer_single_quotes
|
||||
- prefer_typing_uninitialized_variables
|
||||
- recursive_getters
|
||||
- slash_for_doc_comments
|
||||
- test_types_in_equals
|
||||
- throw_in_finally
|
||||
- type_init_formals
|
||||
- unawaited_futures
|
||||
- unnecessary_await_in_return
|
||||
- unnecessary_brace_in_string_interps
|
||||
- unnecessary_const
|
||||
- unnecessary_getters_setters
|
||||
- unnecessary_lambdas
|
||||
- unnecessary_new
|
||||
- unnecessary_null_aware_assignments
|
||||
- unnecessary_parenthesis
|
||||
- unnecessary_statements
|
||||
- unnecessary_this
|
||||
- unrelated_type_equality_checks
|
||||
- use_function_type_syntax_for_parameters
|
||||
- use_rethrow_when_possible
|
||||
- valid_regexps
|
||||
- void_checks
|
@ -1,18 +0,0 @@
|
||||
[
|
||||
{
|
||||
"family": "MaterialIcons",
|
||||
"fonts": [
|
||||
{
|
||||
"asset": "https://fonts.gstatic.com/s/materialicons/v42/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"family": "Patrick Hand",
|
||||
"fonts": [
|
||||
{
|
||||
"asset": "fonts/PatrickHand-Regular.ttf"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Binary file not shown.
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 7.5 KiB |
@ -1,404 +0,0 @@
|
||||
// Package auto_size_text:
|
||||
// https://pub.dartlang.org/packages/auto_size_text
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
bool checkTextFits(TextSpan text, Locale locale, double scale, int maxLines,
|
||||
double maxWidth, double maxHeight) {
|
||||
final tp = TextPainter(
|
||||
text: text,
|
||||
textAlign: TextAlign.left,
|
||||
textDirection: TextDirection.ltr,
|
||||
textScaleFactor: scale ?? 1,
|
||||
maxLines: maxLines,
|
||||
locale: locale,
|
||||
)..layout(maxWidth: maxWidth);
|
||||
|
||||
return !(tp.didExceedMaxLines ||
|
||||
tp.height > maxHeight ||
|
||||
tp.width > maxWidth);
|
||||
}
|
||||
|
||||
/// Flutter widget that automatically resizes text to fit perfectly within its bounds.
|
||||
///
|
||||
/// All size constraints as well as maxLines are taken into account. If the text
|
||||
/// overflows anyway, you should check if the parent widget actually constraints
|
||||
/// the size of this widget.
|
||||
class AutoSizeText extends StatefulWidget {
|
||||
/// Creates a [AutoSizeText] widget.
|
||||
///
|
||||
/// If the [style] argument is null, the text will use the style from the
|
||||
/// closest enclosing [DefaultTextStyle].
|
||||
const AutoSizeText(
|
||||
this.data, {
|
||||
Key key,
|
||||
this.style,
|
||||
this.minFontSize = 12.0,
|
||||
this.maxFontSize,
|
||||
this.stepGranularity = 1.0,
|
||||
this.presetFontSizes,
|
||||
this.group,
|
||||
this.textAlign,
|
||||
this.textDirection,
|
||||
this.locale,
|
||||
this.softWrap,
|
||||
this.overflow,
|
||||
this.textScaleFactor,
|
||||
this.maxLines,
|
||||
this.semanticsLabel,
|
||||
}) : assert(data != null),
|
||||
assert(stepGranularity >= 0.1),
|
||||
textSpan = null,
|
||||
super(key: key);
|
||||
|
||||
/// Creates a [AutoSizeText] widget with a [TextSpan].
|
||||
const AutoSizeText.rich(
|
||||
this.textSpan, {
|
||||
Key key,
|
||||
this.style,
|
||||
this.minFontSize = 12.0,
|
||||
this.maxFontSize,
|
||||
this.stepGranularity = 1.0,
|
||||
this.presetFontSizes,
|
||||
this.group,
|
||||
this.textAlign,
|
||||
this.textDirection,
|
||||
this.locale,
|
||||
this.softWrap,
|
||||
this.overflow,
|
||||
this.textScaleFactor,
|
||||
this.maxLines,
|
||||
this.semanticsLabel,
|
||||
}) : assert(textSpan != null),
|
||||
assert(stepGranularity >= 0.1),
|
||||
data = null,
|
||||
super(key: key);
|
||||
|
||||
/// The text to display.
|
||||
///
|
||||
/// This will be null if a [textSpan] is provided instead.
|
||||
final String data;
|
||||
|
||||
/// The text to display as a [TextSpan].
|
||||
///
|
||||
/// This will be null if [data] is provided instead.
|
||||
final TextSpan textSpan;
|
||||
|
||||
/// If non-null, the style to use for this text.
|
||||
///
|
||||
/// If the style's "inherit" property is true, the style will be merged with
|
||||
/// the closest enclosing [DefaultTextStyle]. Otherwise, the style will
|
||||
/// replace the closest enclosing [DefaultTextStyle].
|
||||
final TextStyle style;
|
||||
|
||||
/// The minimum text size constraint to be used when auto-sizing text.
|
||||
///
|
||||
/// Is being ignored if [presetFontSizes] is set.
|
||||
final double minFontSize;
|
||||
|
||||
/// The maximum text size constraint to be used when auto-sizing text.
|
||||
///
|
||||
/// Is being ignored if [presetFontSizes] is set.
|
||||
final double maxFontSize;
|
||||
|
||||
/// The steps in which the font size is being adapted to constraints.
|
||||
///
|
||||
/// The Text scales uniformly in a range between [minFontSize] and
|
||||
/// [maxFontSize].
|
||||
/// Each increment occurs as per the step size set in stepGranularity.
|
||||
///
|
||||
/// Most of the time you don't want a stepGranularity below 1.0.
|
||||
///
|
||||
/// Is being ignored if [presetFontSizes] is set.
|
||||
final double stepGranularity;
|
||||
|
||||
/// Lets you specify all the possible font sizes.
|
||||
///
|
||||
/// **Important:** The presetFontSizes are used the order they are given in.
|
||||
/// If the first fontSize matches, all others are being ignored.
|
||||
final List<double> presetFontSizes;
|
||||
|
||||
/// Synchronizes the size of multiple [AutoSizeText]s.
|
||||
///
|
||||
/// If you want multiple [AutoSizeText]s to have the same text size, give all
|
||||
/// of them the same [AutoSizeGroup] instance. All of them will have the
|
||||
/// size of the smallest [AutoSizeText]
|
||||
final AutoSizeGroup group;
|
||||
|
||||
/// How the text should be aligned horizontally.
|
||||
final TextAlign textAlign;
|
||||
|
||||
/// The directionality of the text.
|
||||
///
|
||||
/// This decides how [textAlign] values like [TextAlign.start] and
|
||||
/// [TextAlign.end] are interpreted.
|
||||
///
|
||||
/// This is also used to disambiguate how to render bidirectional text. For
|
||||
/// example, if the [data] is an English phrase followed by a Hebrew phrase,
|
||||
/// in a [TextDirection.ltr] context the English phrase will be on the left
|
||||
/// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
|
||||
/// context, the English phrase will be on the right and the Hebrew phrase on
|
||||
/// its left.
|
||||
///
|
||||
/// Defaults to the ambient [Directionality], if any.
|
||||
final TextDirection textDirection;
|
||||
|
||||
/// Used to select a font when the same Unicode character can
|
||||
/// be rendered differently, depending on the locale.
|
||||
///
|
||||
/// It's rarely necessary to set this property. By default its value
|
||||
/// is inherited from the enclosing app with `Localizations.localeOf(context)`.
|
||||
final Locale locale;
|
||||
|
||||
/// Whether the text should break at soft line breaks.
|
||||
///
|
||||
/// If false, the glyphs in the text will be positioned as if there was
|
||||
/// unlimited horizontal space.
|
||||
final bool softWrap;
|
||||
|
||||
/// How visual overflow should be handled.
|
||||
final TextOverflow overflow;
|
||||
|
||||
/// The number of font pixels for each logical pixel.
|
||||
///
|
||||
/// For example, if the text scale factor is 1.5, text will be 50% larger than
|
||||
/// the specified font size.
|
||||
///
|
||||
/// This property also affects [minFontSize], [maxFontSize] and [presetFontSizes].
|
||||
///
|
||||
/// The value given to the constructor as textScaleFactor. If null, will
|
||||
/// use the [MediaQueryData.textScaleFactor] obtained from the ambient
|
||||
/// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope.
|
||||
final double textScaleFactor;
|
||||
|
||||
/// An optional maximum number of lines for the text to span, wrapping if necessary.
|
||||
/// If the text exceeds the given number of lines, it will be resized according
|
||||
/// to the specified bounds and if necessary truncated according to [overflow].
|
||||
///
|
||||
/// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
|
||||
/// edge of the box.
|
||||
///
|
||||
/// If this is null, but there is an ambient [DefaultTextStyle] that specifies
|
||||
/// an explicit number for its [DefaultTextStyle.maxLines], then the
|
||||
/// [DefaultTextStyle] value will take precedence. You can use a [RichText]
|
||||
/// widget directly to entirely override the [DefaultTextStyle].
|
||||
final int maxLines;
|
||||
|
||||
/// An alternative semantics label for this text.
|
||||
///
|
||||
/// If present, the semantics of this widget will contain this value instead
|
||||
/// of the actual text.
|
||||
final String semanticsLabel;
|
||||
|
||||
@override
|
||||
_AutoSizeTextState createState() => _AutoSizeTextState();
|
||||
}
|
||||
|
||||
class _AutoSizeTextState extends State<AutoSizeText> {
|
||||
double _previousFontSize;
|
||||
|
||||
Text _cachedText;
|
||||
double _cachedFontSize;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if (widget.group != null) {
|
||||
widget.group._register(this);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(AutoSizeText oldWidget) {
|
||||
_cachedText = null;
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(builder: (context, size) {
|
||||
final defaultTextStyle = DefaultTextStyle.of(context);
|
||||
|
||||
var style = widget.style;
|
||||
if (widget.style == null || widget.style.inherit) {
|
||||
style = defaultTextStyle.style.merge(widget.style);
|
||||
}
|
||||
|
||||
final fontSize = _calculateFontSize(size, style, defaultTextStyle);
|
||||
|
||||
Widget text;
|
||||
|
||||
if (widget.group != null) {
|
||||
if (fontSize != _previousFontSize) {
|
||||
widget.group._updateFontSize(this, fontSize);
|
||||
}
|
||||
text = _buildText(widget.group._fontSize, style);
|
||||
} else {
|
||||
text = _buildText(fontSize, style);
|
||||
}
|
||||
|
||||
_previousFontSize = fontSize;
|
||||
|
||||
return text;
|
||||
});
|
||||
}
|
||||
|
||||
double _calculateFontSize(
|
||||
BoxConstraints size, TextStyle style, DefaultTextStyle defaultStyle) {
|
||||
final userScale =
|
||||
widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context);
|
||||
|
||||
final minFontSize = widget.minFontSize ?? 0;
|
||||
assert(
|
||||
minFontSize >= 0, 'MinFontSize has to be greater than or equal to 0.');
|
||||
|
||||
final maxFontSize = widget.maxFontSize ?? double.infinity;
|
||||
assert(maxFontSize > 0, 'MaxFontSize has to be greater than 0.');
|
||||
|
||||
assert(minFontSize <= maxFontSize,
|
||||
'MinFontSize has to be smaller or equal than maxFontSize.');
|
||||
|
||||
final maxLines = widget.maxLines ?? defaultStyle.maxLines;
|
||||
|
||||
var presetIndex = 0;
|
||||
if (widget.presetFontSizes != null) {
|
||||
assert(widget.presetFontSizes.isNotEmpty, 'PresetFontSizes is empty.');
|
||||
}
|
||||
|
||||
double initialFontSize;
|
||||
if (widget.presetFontSizes == null) {
|
||||
final current = style.fontSize;
|
||||
initialFontSize = current.clamp(minFontSize, maxFontSize).toDouble();
|
||||
} else {
|
||||
initialFontSize = widget.presetFontSizes[presetIndex++];
|
||||
}
|
||||
|
||||
var fontSize = initialFontSize * userScale;
|
||||
|
||||
final span = TextSpan(
|
||||
style: widget.textSpan?.style ?? style,
|
||||
text: widget.textSpan?.text ?? widget.data,
|
||||
children: widget.textSpan?.children,
|
||||
recognizer: widget.textSpan?.recognizer,
|
||||
);
|
||||
while (!checkTextFits(span, widget.locale, fontSize / style.fontSize,
|
||||
maxLines, size.maxWidth, size.maxHeight)) {
|
||||
if (widget.presetFontSizes == null) {
|
||||
final newFontSize = fontSize - widget.stepGranularity;
|
||||
if (newFontSize < (minFontSize * userScale)) break;
|
||||
fontSize = newFontSize;
|
||||
} else if (presetIndex < widget.presetFontSizes.length) {
|
||||
fontSize = widget.presetFontSizes[presetIndex++] * userScale;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fontSize;
|
||||
}
|
||||
|
||||
Widget _buildText(double fontSize, TextStyle style) {
|
||||
if (_cachedText != null && _cachedFontSize == fontSize) {
|
||||
return _cachedText;
|
||||
}
|
||||
|
||||
Text text;
|
||||
if (widget.data != null) {
|
||||
text = Text(
|
||||
widget.data,
|
||||
style: style.copyWith(fontSize: fontSize),
|
||||
textAlign: widget.textAlign,
|
||||
textDirection: widget.textDirection,
|
||||
locale: widget.locale,
|
||||
softWrap: widget.softWrap,
|
||||
overflow: widget.overflow,
|
||||
textScaleFactor: 1,
|
||||
maxLines: widget.maxLines,
|
||||
semanticsLabel: widget.semanticsLabel,
|
||||
);
|
||||
} else {
|
||||
text = Text.rich(
|
||||
widget.textSpan,
|
||||
style: style,
|
||||
textAlign: widget.textAlign,
|
||||
textDirection: widget.textDirection,
|
||||
locale: widget.locale,
|
||||
softWrap: widget.softWrap,
|
||||
overflow: widget.overflow,
|
||||
textScaleFactor: fontSize / style.fontSize,
|
||||
maxLines: widget.maxLines,
|
||||
semanticsLabel: widget.semanticsLabel,
|
||||
);
|
||||
}
|
||||
|
||||
_cachedText = text;
|
||||
_cachedFontSize = fontSize;
|
||||
return text;
|
||||
}
|
||||
|
||||
void _notifySync() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.group != null) {
|
||||
widget.group._remove(this);
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class AutoSizeGroup {
|
||||
final _listeners = <_AutoSizeTextState, double>{};
|
||||
var _widgetsNotified = false;
|
||||
double _fontSize = double.infinity;
|
||||
|
||||
void _register(_AutoSizeTextState text) {
|
||||
_listeners[text] = double.infinity;
|
||||
}
|
||||
|
||||
void _updateFontSize(_AutoSizeTextState text, double maxFontSize) {
|
||||
final oldFontSize = _fontSize;
|
||||
if (maxFontSize <= _fontSize) {
|
||||
_fontSize = maxFontSize;
|
||||
_listeners[text] = maxFontSize;
|
||||
} else if (_listeners[text] == _fontSize) {
|
||||
_listeners[text] = maxFontSize;
|
||||
_fontSize = double.infinity;
|
||||
for (var size in _listeners.values) {
|
||||
if (size < _fontSize) _fontSize = size;
|
||||
}
|
||||
} else {
|
||||
_listeners[text] = maxFontSize;
|
||||
}
|
||||
|
||||
if (oldFontSize != _fontSize) {
|
||||
_widgetsNotified = false;
|
||||
// Timer.run(_notifyListeners);
|
||||
_notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void _notifyListeners() {
|
||||
if (_widgetsNotified) {
|
||||
return;
|
||||
} else {
|
||||
_widgetsNotified = true;
|
||||
}
|
||||
|
||||
for (var text in _listeners.keys.toList()) {
|
||||
if (text.mounted) {
|
||||
text._notifySync();
|
||||
} else {
|
||||
_listeners.remove(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _remove(_AutoSizeTextState text) {
|
||||
_updateFontSize(text, double.infinity);
|
||||
_listeners.remove(text);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'main_page.dart';
|
||||
|
||||
void main() => runApp(MyApp());
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Dad Jokes',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.deepOrange,
|
||||
),
|
||||
home: MainPage(title: 'Dad Jokes'),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'auto_size_text.dart';
|
||||
|
||||
const _dadJokeApi = 'https://icanhazdadjoke.com/';
|
||||
const _httpHeaders = {
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
|
||||
const jokeTextStyle = TextStyle(
|
||||
fontFamily: 'Patrick Hand',
|
||||
fontSize: 36,
|
||||
fontStyle: FontStyle.normal,
|
||||
fontWeight: FontWeight.normal);
|
||||
|
||||
class MainPage extends StatefulWidget {
|
||||
MainPage({Key key, this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
MainPageState createState() => MainPageState();
|
||||
}
|
||||
|
||||
class MainPageState extends State<MainPage> {
|
||||
Future<String> _response;
|
||||
String _displayedJoke = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refreshAction();
|
||||
}
|
||||
|
||||
void _refreshAction() {
|
||||
setState(() {
|
||||
_response = http.read(_dadJokeApi, headers: _httpHeaders);
|
||||
});
|
||||
}
|
||||
|
||||
void _aboutAction() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return const AlertDialog(
|
||||
title: Text('About Dad Jokes'),
|
||||
content: Text(
|
||||
'Dad jokes is brought to you by Tim Sneath (@timsneath), '
|
||||
'proud dad of Naomi, Esther, and Silas. May your children '
|
||||
'groan like mine will.\n\nDad jokes come from '
|
||||
'https://icanhazdadjoke.com with thanks.'));
|
||||
});
|
||||
}
|
||||
|
||||
FutureBuilder<String> _jokeBody() {
|
||||
return FutureBuilder<String>(
|
||||
future: _response,
|
||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
return const ListTile(
|
||||
leading: Icon(Icons.sync_problem),
|
||||
title: Text('No connection'),
|
||||
);
|
||||
case ConnectionState.waiting:
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
default:
|
||||
if (snapshot.hasError) {
|
||||
return const Center(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.error),
|
||||
title: Text('Network error'),
|
||||
subtitle: Text(
|
||||
'Sorry - this isn\'t funny, we know, but something went '
|
||||
'wrong when connecting to the Internet. Check your '
|
||||
'network connection and try again.'),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final decoded = json.decode(snapshot.data);
|
||||
if (decoded['status'] == 200) {
|
||||
_displayedJoke = decoded['joke'] as String;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Dismissible(
|
||||
key: const Key('joke'),
|
||||
direction: DismissDirection.horizontal,
|
||||
onDismissed: (direction) {
|
||||
_refreshAction();
|
||||
},
|
||||
child: AutoSizeText(_displayedJoke, style: jokeTextStyle),
|
||||
));
|
||||
} else {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.sync_problem),
|
||||
title: Text('Unexpected error: ${snapshot.data}'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: Image.asset(
|
||||
'icon.png',
|
||||
fit: BoxFit.scaleDown,
|
||||
),
|
||||
title: Text(widget.title),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info),
|
||||
tooltip: 'About Dad Jokes',
|
||||
onPressed: _aboutAction,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Center(
|
||||
child: SafeArea(child: _jokeBody()),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: _refreshAction,
|
||||
icon: const Icon(Icons.mood),
|
||||
label: const Text('NEW JOKE'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.11"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.0+4"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.8"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
pedantic:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
sdks:
|
||||
dart: ">=2.6.0 <3.0.0"
|
@ -1,18 +0,0 @@
|
||||
name: dad_jokes
|
||||
|
||||
environment:
|
||||
sdk: ">=2.2.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
http: ^0.12.0
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: ^1.8.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- icon.png
|
||||
- preview.png
|
@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title></title>
|
||||
<script defer src="main.dart.js" type="application/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in new issue