1// Copyright 2014 The Flutter 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.
4
5import 'package:flutter/material.dart';
6
7class PictureCachePage extends StatelessWidget {
8 const PictureCachePage({super.key});
9
10 static const List<String> kTabNames = <String>['1', '2', '3', '4', '5'];
11
12 @override
13 Widget build(BuildContext context) {
14 return DefaultTabController(
15 length: kTabNames.length, // This is the number of tabs.
16 child: Scaffold(
17 appBar: AppBar(
18 title: const Text('Picture Cache'),
19 // pinned: true,
20 // expandedHeight: 50.0,
21 // forceElevated: innerBoxIsScrolled,
22 bottom: TabBar(tabs: kTabNames.map((String name) => Tab(text: name)).toList()),
23 ),
24 body: TabBarView(
25 key: const Key('tabbar_view'), // this key is used by the driver test
26 children: kTabNames.map((String name) {
27 return SafeArea(
28 top: false,
29 bottom: false,
30 child: Builder(
31 builder: (BuildContext context) {
32 return ListView.builder(
33 itemBuilder: (BuildContext context, int index) => ListItem(index: index),
34 );
35 },
36 ),
37 );
38 }).toList(),
39 ),
40 ),
41 );
42 }
43}
44
45class ListItem extends StatelessWidget {
46 const ListItem({super.key, required this.index});
47
48 final int index;
49
50 static const String kMockChineseTitle = '复杂的中文标题?复杂的中文标题!';
51 static const String kMockName = '李耳123456';
52 static const int kMockCount = 999;
53
54 @override
55 Widget build(BuildContext context) {
56 final List<Widget> contents = <Widget>[
57 const SizedBox(height: 15),
58 _buildUserInfo(),
59 const SizedBox(height: 10),
60 ];
61 if (index % 3 != 0) {
62 contents.add(_buildImageContent());
63 } else {
64 contents.addAll(<Widget>[
65 Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildContentText()),
66 const SizedBox(height: 10),
67 Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildBottomRow()),
68 ]);
69 }
70 contents.addAll(<Widget>[
71 const SizedBox(height: 13),
72 buildDivider(0.5, const EdgeInsets.only(left: 40, right: 15)),
73 ]);
74 return MaterialButton(
75 onPressed: () {},
76 padding: EdgeInsets.zero,
77 child: Column(
78 mainAxisSize: MainAxisSize.min,
79 crossAxisAlignment: CrossAxisAlignment.start,
80 children: contents,
81 ),
82 );
83 }
84
85 Text _buildRankText() {
86 return Text(
87 (index + 1).toString(),
88 style: TextStyle(
89 fontSize: 15,
90 color: index + 1 <= 3 ? const Color(0xFFE5645F) : Colors.black,
91 fontWeight: FontWeight.bold,
92 ),
93 );
94 }
95
96 Widget _buildImageContent() {
97 return Row(
98 children: <Widget>[
99 const SizedBox(width: 40),
100 Expanded(
101 child: Column(
102 mainAxisSize: MainAxisSize.min,
103 crossAxisAlignment: CrossAxisAlignment.start,
104 children: <Widget>[
105 Padding(padding: const EdgeInsets.only(right: 30), child: _buildContentText()),
106 const SizedBox(height: 10),
107 _buildBottomRow(),
108 ],
109 ),
110 ),
111 Image.asset(
112 index.isEven ? 'food/butternut_squash_soup.png' : 'food/cherry_pie.png',
113 package: 'flutter_gallery_assets',
114 fit: BoxFit.cover,
115 width: 110,
116 height: 70,
117 ),
118 const SizedBox(width: 15),
119 ],
120 );
121 }
122
123 Widget _buildContentText() {
124 return const Text(
125 kMockChineseTitle,
126 style: TextStyle(fontSize: 16),
127 maxLines: 2,
128 overflow: TextOverflow.ellipsis,
129 );
130 }
131
132 Widget _buildBottomRow() {
133 return Row(
134 children: <Widget>[
135 Container(
136 padding: const EdgeInsets.symmetric(horizontal: 7),
137 height: 16,
138 alignment: Alignment.center,
139 decoration: BoxDecoration(
140 borderRadius: BorderRadius.circular(8),
141 color: const Color(0xFFFBEEEE),
142 ),
143 child: Row(
144 children: <Widget>[
145 const SizedBox(width: 3),
146 Text(
147 'hot:${_convertCountToStr(kMockCount)}',
148 style: const TextStyle(color: Color(0xFFE5645F), fontSize: 11),
149 ),
150 ],
151 ),
152 ),
153 const SizedBox(width: 9),
154 const Text('ans:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
155 const SizedBox(width: 9),
156 const Text('like:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
157 ],
158 );
159 }
160
161 String _convertCountToStr(int count) {
162 return switch (count) {
163 < 10000 => count.toString(),
164 < 100000 => '${(count / 10000).toStringAsPrecision(2)}w',
165 _ => '${(count / 10000).floor()}w',
166 };
167 }
168
169 Widget _buildUserInfo() {
170 return GestureDetector(
171 onTap: () {},
172 child: Row(
173 children: <Widget>[
174 Container(width: 40, alignment: Alignment.center, child: _buildRankText()),
175 const CircleAvatar(radius: 11.5),
176 const SizedBox(width: 6),
177 ConstrainedBox(
178 constraints: const BoxConstraints(maxWidth: 250),
179 child: const Text(
180 kMockName,
181 maxLines: 1,
182 overflow: TextOverflow.ellipsis,
183 style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
184 ),
185 ),
186 const SizedBox(width: 4),
187 const SizedBox(width: 15),
188 ],
189 ),
190 );
191 }
192
193 Widget buildDivider(double height, EdgeInsets padding) {
194 return Container(padding: padding, height: height, color: const Color(0xFFF5F5F5));
195 }
196}
197