1// Copyright 2018 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4import 'dart:async'; 5import 'dart:math' show Random; 6 7import 'package:flutter/cupertino.dart'; 8 9import '../../gallery/demo.dart'; 10 11class CupertinoRefreshControlDemo extends StatefulWidget { 12 static const String routeName = '/cupertino/refresh'; 13 14 @override 15 _CupertinoRefreshControlDemoState createState() => _CupertinoRefreshControlDemoState(); 16} 17 18class _CupertinoRefreshControlDemoState extends State<CupertinoRefreshControlDemo> { 19 List<List<String>> randomizedContacts; 20 21 @override 22 void initState() { 23 super.initState(); 24 repopulateList(); 25 } 26 27 void repopulateList() { 28 final Random random = Random(); 29 randomizedContacts = List<List<String>>.generate( 30 100, 31 (int index) { 32 return contacts[random.nextInt(contacts.length)] 33 // Randomly adds a telephone icon next to the contact or not. 34 ..add(random.nextBool().toString()); 35 }, 36 ); 37 } 38 39 @override 40 Widget build(BuildContext context) { 41 return DefaultTextStyle( 42 style: CupertinoTheme.of(context).textTheme.textStyle, 43 child: CupertinoPageScaffold( 44 child: DecoratedBox( 45 decoration: BoxDecoration( 46 color: CupertinoTheme.of(context).brightness == Brightness.light 47 ? CupertinoColors.extraLightBackgroundGray 48 : CupertinoColors.darkBackgroundGray, 49 ), 50 child: CustomScrollView( 51 // If left unspecified, the [CustomScrollView] appends an 52 // [AlwaysScrollableScrollPhysics]. Behind the scene, the ScrollableState 53 // will attach that [AlwaysScrollableScrollPhysics] to the output of 54 // [ScrollConfiguration.of] which will be a [ClampingScrollPhysics] 55 // on Android. 56 // To demonstrate the iOS behavior in this demo and to ensure that the list 57 // always scrolls, we specifically use a [BouncingScrollPhysics] combined 58 // with a [AlwaysScrollableScrollPhysics] 59 physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), 60 slivers: <Widget>[ 61 CupertinoSliverNavigationBar( 62 largeTitle: const Text('Refresh'), 63 // We're specifying a back label here because the previous page 64 // is a Material page. CupertinoPageRoutes could auto-populate 65 // these back labels. 66 previousPageTitle: 'Cupertino', 67 trailing: CupertinoDemoDocumentationButton(CupertinoRefreshControlDemo.routeName), 68 ), 69 CupertinoSliverRefreshControl( 70 onRefresh: () { 71 return Future<void>.delayed(const Duration(seconds: 2)) 72 ..then<void>((_) { 73 if (mounted) { 74 setState(() => repopulateList()); 75 } 76 }); 77 }, 78 ), 79 SliverSafeArea( 80 top: false, // Top safe area is consumed by the navigation bar. 81 sliver: SliverList( 82 delegate: SliverChildBuilderDelegate( 83 (BuildContext context, int index) { 84 return _ListItem( 85 name: randomizedContacts[index][0], 86 place: randomizedContacts[index][1], 87 date: randomizedContacts[index][2], 88 called: randomizedContacts[index][3] == 'true', 89 ); 90 }, 91 childCount: 20, 92 ), 93 ), 94 ), 95 ], 96 ), 97 ), 98 ), 99 ); 100 } 101} 102 103List<List<String>> contacts = <List<String>>[ 104 <String>['George Washington', 'Westmoreland County', ' 4/30/1789'], 105 <String>['John Adams', 'Braintree', ' 3/4/1797'], 106 <String>['Thomas Jefferson', 'Shadwell', ' 3/4/1801'], 107 <String>['James Madison', 'Port Conway', ' 3/4/1809'], 108 <String>['James Monroe', 'Monroe Hall', ' 3/4/1817'], 109 <String>['Andrew Jackson', 'Waxhaws Region South/North', ' 3/4/1829'], 110 <String>['John Quincy Adams', 'Braintree', ' 3/4/1825'], 111 <String>['William Henry Harrison', 'Charles City County', ' 3/4/1841'], 112 <String>['Martin Van Buren', 'Kinderhook New', ' 3/4/1837'], 113 <String>['Zachary Taylor', 'Barboursville', ' 3/4/1849'], 114 <String>['John Tyler', 'Charles City County', ' 4/4/1841'], 115 <String>['James Buchanan', 'Cove Gap', ' 3/4/1857'], 116 <String>['James K. Polk', 'Pineville North', ' 3/4/1845'], 117 <String>['Millard Fillmore', 'Summerhill New', '7/9/1850'], 118 <String>['Franklin Pierce', 'Hillsborough New', ' 3/4/1853'], 119 <String>['Andrew Johnson', 'Raleigh North', ' 4/15/1865'], 120 <String>['Abraham Lincoln', 'Sinking Spring', ' 3/4/1861'], 121 <String>['Ulysses S. Grant', 'Point Pleasant', ' 3/4/1869'], 122 <String>['Rutherford B. Hayes', 'Delaware', ' 3/4/1877'], 123 <String>['Chester A. Arthur', 'Fairfield', ' 9/19/1881'], 124 <String>['James A. Garfield', 'Moreland Hills', ' 3/4/1881'], 125 <String>['Benjamin Harrison', 'North Bend', ' 3/4/1889'], 126 <String>['Grover Cleveland', 'Caldwell New', ' 3/4/1885'], 127 <String>['William McKinley', 'Niles', ' 3/4/1897'], 128 <String>['Woodrow Wilson', 'Staunton', ' 3/4/1913'], 129 <String>['William H. Taft', 'Cincinnati', ' 3/4/1909'], 130 <String>['Theodore Roosevelt', 'New York City New', ' 9/14/1901'], 131 <String>['Warren G. Harding', 'Blooming Grove', ' 3/4/1921'], 132 <String>['Calvin Coolidge', 'Plymouth', '8/2/1923'], 133 <String>['Herbert Hoover', 'West Branch', ' 3/4/1929'], 134 <String>['Franklin D. Roosevelt', 'Hyde Park New', ' 3/4/1933'], 135 <String>['Harry S. Truman', 'Lamar', ' 4/12/1945'], 136 <String>['Dwight D. Eisenhower', 'Denison', ' 1/20/1953'], 137 <String>['Lyndon B. Johnson', 'Stonewall', '11/22/1963'], 138 <String>['Ronald Reagan', 'Tampico', ' 1/20/1981'], 139 <String>['Richard Nixon', 'Yorba Linda', ' 1/20/1969'], 140 <String>['Gerald Ford', 'Omaha', 'August 9/1974'], 141 <String>['John F. Kennedy', 'Brookline', ' 1/20/1961'], 142 <String>['George H. W. Bush', 'Milton', ' 1/20/1989'], 143 <String>['Jimmy Carter', 'Plains', ' 1/20/1977'], 144 <String>['George W. Bush', 'New Haven', ' 1/20, 2001'], 145 <String>['Bill Clinton', 'Hope', ' 1/20/1993'], 146 <String>['Barack Obama', 'Honolulu', ' 1/20/2009'], 147 <String>['Donald J. Trump', 'New York City', ' 1/20/2017'], 148]; 149 150class _ListItem extends StatelessWidget { 151 const _ListItem({ 152 this.name, 153 this.place, 154 this.date, 155 this.called, 156 }); 157 158 final String name; 159 final String place; 160 final String date; 161 final bool called; 162 163 @override 164 Widget build(BuildContext context) { 165 return Container( 166 color: CupertinoTheme.of(context).scaffoldBackgroundColor, 167 height: 60.0, 168 padding: const EdgeInsets.only(top: 9.0), 169 child: Row( 170 children: <Widget>[ 171 Container( 172 width: 38.0, 173 child: called 174 ? const Align( 175 alignment: Alignment.topCenter, 176 child: Icon( 177 CupertinoIcons.phone_solid, 178 color: CupertinoColors.inactiveGray, 179 size: 18.0, 180 ), 181 ) 182 : null, 183 ), 184 Expanded( 185 child: Container( 186 decoration: const BoxDecoration( 187 border: Border( 188 bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), 189 ), 190 ), 191 padding: const EdgeInsets.only(left: 1.0, bottom: 9.0, right: 10.0), 192 child: Row( 193 children: <Widget>[ 194 Expanded( 195 child: Column( 196 crossAxisAlignment: CrossAxisAlignment.start, 197 mainAxisAlignment: MainAxisAlignment.spaceBetween, 198 children: <Widget>[ 199 Text( 200 name, 201 maxLines: 1, 202 overflow: TextOverflow.ellipsis, 203 style: const TextStyle( 204 fontWeight: FontWeight.w600, 205 letterSpacing: -0.18, 206 ), 207 ), 208 Text( 209 place, 210 maxLines: 1, 211 overflow: TextOverflow.ellipsis, 212 style: const TextStyle( 213 fontSize: 15.0, 214 letterSpacing: -0.24, 215 color: CupertinoColors.inactiveGray, 216 ), 217 ), 218 ], 219 ), 220 ), 221 Text( 222 date, 223 style: const TextStyle( 224 color: CupertinoColors.inactiveGray, 225 fontSize: 15.0, 226 letterSpacing: -0.41, 227 ), 228 ), 229 Padding( 230 padding: const EdgeInsets.only(left: 9.0), 231 child: Icon( 232 CupertinoIcons.info, 233 color: CupertinoTheme.of(context).primaryColor, 234 ), 235 ), 236 ], 237 ), 238 ), 239 ), 240 ], 241 ), 242 ); 243 } 244} 245