reason

fix 样式 && clear

import 'package:flutter/material.dart';
import 'package:one_poem/poem/poem_router.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
import 'package:one_poem/setting/setting_router.dart';
import 'package:one_poem/tiktok/style/style.dart';
......@@ -186,6 +187,12 @@ class _AccountPageState extends State<AccountPage> {
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 500),
height: double.infinity,
width: double.infinity,
color: ColorPlate.white,
),
body,
Container(
alignment: Alignment.centerRight,
......@@ -335,21 +342,14 @@ class _UserVideoTable extends StatelessWidget {
),
),
Row(
children: const <Widget>[
_SmallVideo(),
_SmallVideo(),
_SmallVideo(),
],
),
Row(
children: const <Widget>[
children: const [
_SmallVideo(),
_SmallVideo(),
_SmallVideo(),
],
),
Row(
children: const <Widget>[
children: const [
_SmallVideo(),
_SmallVideo(),
_SmallVideo(),
......@@ -368,22 +368,30 @@ class _SmallVideo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Expanded(
child: AspectRatio(
aspectRatio: 3.px / 4.0,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/poem/poem_background.png"),
fit: BoxFit.fill,
child: Tapped(
onTap: (){
NavigatorUtils.push(
context,
'${PoemRouter.poemDetailPage}?id=100',
);
},
child: AspectRatio(
aspectRatio: 3.px / 4.0,
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/poem/poem_background.png"),
fit: BoxFit.fill,
),
),
),
alignment: Alignment.center,
child: Text(
'一言',
style: TextStyle(
color: Colors.black54,
fontSize: 18.px,
fontWeight: FontWeight.w900,
alignment: Alignment.center,
child: Text(
'一言',
style: TextStyle(
color: Colors.black54,
fontSize: 18.px,
fontWeight: FontWeight.w900,
),
),
),
),
......
import 'package:flutter/material.dart';
import 'package:one_poem/category/provider/categories_page_provider.dart';
import 'package:one_poem/util/theme_utils.dart';
import 'package:one_poem/widgets/my_app_bar.dart';
import 'package:provider/provider.dart';
......@@ -13,11 +12,7 @@ class CategoriesPage extends StatefulWidget {
_CategoriesPageState createState() => _CategoriesPageState();
}
class _CategoriesPageState extends State<CategoriesPage>
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
TabController? _tabController;
final PageController _pageController = PageController();
class _CategoriesPageState extends State<CategoriesPage>{
final GlobalKey _bodyKey = GlobalKey();
CategoriesPageProvider provider = CategoriesPageProvider();
......@@ -25,19 +20,15 @@ class _CategoriesPageState extends State<CategoriesPage>
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 3);
}
@override
void dispose() {
_tabController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
final Color? _iconColor = ThemeUtils.getIconColor(context);
return ChangeNotifierProvider<CategoriesPageProvider>(
create: (_) => provider,
child: Scaffold(
......@@ -63,27 +54,13 @@ class _CategoriesPageState extends State<CategoriesPage>
body: Column(
key: _bodyKey,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
children: const <Widget>[
Expanded(
child: PageView.builder(
key: const Key('pageView'),
itemCount: 3,
onPageChanged: _onPageChange,
controller: _pageController,
itemBuilder: (_, int index) =>
CategoryListPage(index: index)),
child: CategoryListPage(index: 1),
)
],
),
),
);
}
void _onPageChange(int index) {
_tabController?.animateTo(index);
provider.setIndex(index);
}
@override
bool get wantKeepAlive => true;
}
......
......@@ -8,11 +8,7 @@ import 'package:one_poem/widgets/state_layout.dart';
import 'package:provider/provider.dart';
class CategoryListPage extends StatefulWidget {
const CategoryListPage({
Key? key,
required this.index
}): super(key: key);
const CategoryListPage({Key? key, required this.index}) : super(key: key);
final int index;
......@@ -20,34 +16,20 @@ class CategoryListPage extends StatefulWidget {
_CategoryListPageState createState() => _CategoryListPageState();
}
class _CategoryListPageState extends State<CategoryListPage> with AutomaticKeepAliveClientMixin<CategoryListPage>, SingleTickerProviderStateMixin {
class _CategoryListPageState extends State<CategoryListPage> {
final int _selectIndex = -1;
late Animation<double> _animation;
late AnimationController _controller;
List<CategoryItemEntity> _list = [];
AnimationStatus _animationStatus = AnimationStatus.dismissed;
@override
void initState() {
super.initState();
// 初始化动画控制
_controller = AnimationController(duration: const Duration(milliseconds: 450), vsync: this);
// 动画曲线
final _curvedAnimation = CurvedAnimation(parent: _controller, curve: Curves.easeOutSine);
_animation = Tween(begin: 0.0, end: 1.1).animate(_curvedAnimation) ..addStatusListener((status) {
_animationStatus = status;
});
//Item数量
_maxPage = widget.index == 0 ? 1 : (widget.index == 1 ? 2 : 3);
_onRefresh();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
......@@ -67,8 +49,11 @@ class _CategoryListPageState extends State<CategoryListPage> with AutomaticKeepA
await Future.delayed(const Duration(seconds: 2), () {
setState(() {
_page = 1;
_list = List.generate(widget.index == 0 ? 3 : 10, (i) =>
CategoryItemEntity(icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3));
_list = List.generate(
widget.index == 0 ? 3 : 10,
(i) => CategoryItemEntity(
icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3),
);
});
_setGoodsCount(_list.length);
});
......@@ -77,16 +62,20 @@ class _CategoryListPageState extends State<CategoryListPage> with AutomaticKeepA
Future _loadMore() async {
await Future.delayed(const Duration(seconds: 2), () {
setState(() {
_list.addAll(List.generate(10, (i) =>
CategoryItemEntity(icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3)));
_page ++;
_list.addAll(
List.generate(
10,
(i) => CategoryItemEntity(
icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3),
),
);
_page++;
});
_setGoodsCount(_list.length);
});
}
void _setGoodsCount(int count) {
// Provider.of<GoodsPageProvider>(context, listen: false).setGoodsCount(count);
/// 与上方等价,provider 4.1.0添加的拓展方法
context.read<CategoriesPageProvider>().setGoodsCount(count);
}
......@@ -97,23 +86,18 @@ class _CategoryListPageState extends State<CategoryListPage> with AutomaticKeepA
@override
Widget build(BuildContext context) {
super.build(context);
return DeerListView(
itemCount: _list.length,
stateType: _stateType,
onRefresh: _onRefresh,
loadMore: _loadMore,
hasMore: _page < _maxPage,
itemBuilder: (_, index) {
return CategoryItem(
index: index,
selectIndex: _selectIndex,
item: _list[index],
);
}
);
itemCount: _list.length,
stateType: _stateType,
onRefresh: _onRefresh,
loadMore: _loadMore,
hasMore: _page < _maxPage,
itemBuilder: (_, index) {
return CategoryItem(
index: index,
selectIndex: _selectIndex,
item: _list[index],
);
});
}
@override
bool get wantKeepAlive => true;
}
......
......@@ -12,7 +12,7 @@ FriendEntity $FriendEntityFromJson(Map<String, dynamic> json) {
Map<String, dynamic> $FriendEntityToJson(FriendEntity entity) {
final Map<String, dynamic> data = <String, dynamic>{};
data['data'] = entity.data.map((v) => v.toJson()).toList();
data['data'] = entity.data!.map((v) => v.toJson()).toList();
return data;
}
......
......@@ -29,6 +29,14 @@ import 'util/theme_utils.dart';
/// 3. 創建i18n文件
/// 4. 执行:flutter gen-l10n --template-arb-file intl_en.arb --output-class OnePoemLocalizations letLocalizations --output-localization-file one_poem_localizations.dart
///
/// json to model
/// 安装
/// dependencies:
/// json_annotation: ^4.4.0
/// dev_dependencies:
/// json_serializable: ^6.1.3
/// build_runner: ^2.1.7
/// 执行:flutter packages pub run build_runner build --delete-conflicting-outputs
Future<void> main() async {
// debugProfileBuildsEnabled = true;
......
......@@ -56,7 +56,9 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
},
funcRight: () {
NavigatorUtils.push(
context, '${PoemRouter.poemRecordAudioPage}?id=100');
context,
'${PoemRouter.poemRecordAudioPage}?id=100',
);
},
),
homeActionWidgets: HomeActionWidgets(
......@@ -133,7 +135,12 @@ class _PoemDetailPageState extends State<PoemDetailPage> {
Icons.mic_none,
size: 36.px,
),
onPressed: () {},
onPressed: () {
NavigatorUtils.push(
context,
'${PoemRouter.poemRecordAudioPage}?id=100',
);
},
),
Gaps.hGap16,
IconButton(
......
......@@ -89,6 +89,13 @@ class _PoemPageState extends State<PoemPage> with WidgetsBindingObserver {
}
@override
void setState(fn) {
if (mounted) {
super.setState(fn);
}
}
@override
Widget build(BuildContext context) {
Widget? currentPage;
double a = MediaQuery.of(context).size.aspectRatio;
......
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/material.dart';
class PoemVideoPlayer extends StatefulWidget {
final String url;
const PoemVideoPlayer({
Key? key,
required this.url,
}) : super(key: key);
@override
_PoemVideoPlayerState createState() => _PoemVideoPlayerState();
}
class _PoemVideoPlayerState extends State<PoemVideoPlayer> {
final FijkPlayer player = FijkPlayer();
_PoemVideoPlayerState();
@override
void initState() {
super.initState();
player.setDataSource(widget.url, autoPlay: true);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Fijkplayer Example")),
body: Container(
alignment: Alignment.center,
child: FijkView(
player: player,
),
));
}
@override
void dispose() {
super.dispose();
player.release();
}
}
......@@ -3,11 +3,13 @@ import 'package:one_poem/poem/page/poem_record_audio.dart';
import 'package:one_poem/routers/i_router.dart';
import 'page/poem_detail.dart';
import 'page/poem_page.dart';
import 'page/poem_video_player.dart';
class PoemRouter implements IRouterProvider {
static String poemPage = '/poem';
static String poemDetailPage = '/detail';
static String poemRecordAudioPage = '/poem_record_audio';
static String poemRecordAudioPage = '/poem/record/audio';
static String poemVidePlayer = '/poem/video/player';
@override
void initRouter(FluroRouter router) {
......@@ -27,5 +29,12 @@ class PoemRouter implements IRouterProvider {
poemId: int.parse(id!),
);
}));
router.define(poemVidePlayer,
handler: Handler(handlerFunc: (_, Map<String, List<String>> params) {
String? url = params['url']?.first;
return PoemVideoPlayer(
url: url!,
);
}));
}
}
......
......@@ -5,7 +5,7 @@ import 'package:one_poem/generated/json/friend_entity.g.dart';
@JsonSerializable()
class FriendEntity {
late List<FriendData> data;
List<FriendData>? data;
FriendEntity();
......
......@@ -17,8 +17,6 @@ class TimelinesPage extends StatefulWidget {
class _TimelinesPageState extends State<TimelinesPage> {
final ScrollController _scrollController = ScrollController();
double _opacity = 0;
FriendEntity _friendModelEntity = FriendEntity();
Future<String> loadAsset() async {
......@@ -43,14 +41,13 @@ class _TimelinesPageState extends State<TimelinesPage> {
alpha = 1;
}
setState(() {
_opacity = alpha;
});
});
}
Widget _mainListViewBuilder(BuildContext context, int index) {
return FriendCell(
model: _friendModelEntity.data[index],
model: _friendModelEntity.data![index],
);
}
......@@ -62,19 +59,21 @@ class _TimelinesPageState extends State<TimelinesPage> {
isTransparent: true,
homeMenuHeader: TimelineMenuHeader(),
),
body: ListView(
padding: const EdgeInsets.only(top: 0),
controller: _scrollController,
children: <Widget>[
ListView.builder(
padding: const EdgeInsets.only(top: 0),
itemBuilder: _mainListViewBuilder,
itemCount: _friendModelEntity.data.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
)
],
),
body: _friendModelEntity.data != null
? ListView(
padding: const EdgeInsets.only(top: 0),
controller: _scrollController,
children: <Widget>[
ListView.builder(
padding: const EdgeInsets.only(top: 0),
itemBuilder: _mainListViewBuilder,
itemCount: _friendModelEntity.data!.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
)
],
)
: const Center(child: CupertinoActivityIndicator(radius: 16.0)),
);
}
}
......
......@@ -6,7 +6,6 @@ import 'package:one_poem/widgets/state_layout.dart';
/// 封装下拉刷新与加载更多
class DeerListView extends StatefulWidget {
const DeerListView({
Key? key,
required this.itemCount,
......@@ -18,7 +17,7 @@ class DeerListView extends StatefulWidget {
this.pageSize = 10,
this.padding,
this.itemExtent,
}): super(key: key);
}) : super(key: key);
final RefreshCallback onRefresh;
final LoadMoreCallback? loadMore;
......@@ -26,8 +25,10 @@ class DeerListView extends StatefulWidget {
final bool hasMore;
final IndexedWidgetBuilder itemBuilder;
final StateType stateType;
/// 一页的数量,默认为10
final int pageSize;
/// padding属性使用时注意会破坏原有的SafeArea,需要自行计算bottom大小
final EdgeInsetsGeometry? padding;
final double? itemExtent;
......@@ -40,35 +41,40 @@ typedef RefreshCallback = Future<void> Function();
typedef LoadMoreCallback = Future<void> Function();
class _DeerListViewState extends State<DeerListView> {
/// 是否正在加载数据
bool _isLoading = false;
@override
Widget build(BuildContext context) {
final Widget child = RefreshIndicator(
onRefresh: widget.onRefresh,
child: widget.itemCount == 0 ?
StateLayout(type: widget.stateType) :
ListView.builder(
itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1,
padding: widget.padding,
itemExtent: widget.itemExtent,
itemBuilder: (BuildContext context, int index) {
/// 不需要加载更多则不需要添加FootView
if (widget.loadMore == null) {
return widget.itemBuilder(context, index);
} else {
return index < widget.itemCount ? widget.itemBuilder(context, index) : MoreWidget(widget.itemCount, widget.hasMore, widget.pageSize);
}
},
),
child: widget.itemCount == 0
? StateLayout(type: widget.stateType)
: ListView.builder(
itemCount: widget.loadMore == null
? widget.itemCount
: widget.itemCount + 1,
padding: widget.padding,
itemExtent: widget.itemExtent,
itemBuilder: (BuildContext context, int index) {
/// 不需要加载更多则不需要添加FootView
if (widget.loadMore == null) {
return widget.itemBuilder(context, index);
} else {
return index < widget.itemCount
? widget.itemBuilder(context, index)
: MoreWidget(
widget.itemCount, widget.hasMore, widget.pageSize);
}
},
),
);
return SafeArea(
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification note) {
/// 确保是垂直方向滚动,且滑动至底部
if (note.metrics.pixels == note.metrics.maxScrollExtent && note.metrics.axis == Axis.vertical) {
if (note.metrics.pixels == note.metrics.maxScrollExtent &&
note.metrics.axis == Axis.vertical) {
_loadMore();
}
return true;
......@@ -92,20 +98,21 @@ class _DeerListViewState extends State<DeerListView> {
await widget.loadMore?.call();
_isLoading = false;
}
}
class MoreWidget extends StatelessWidget {
const MoreWidget(this.itemCount, this.hasMore, this.pageSize, {Key? key}): super(key: key);
const MoreWidget(this.itemCount, this.hasMore, this.pageSize, {Key? key})
: super(key: key);
final int itemCount;
final bool hasMore;
final int pageSize;
@override
Widget build(BuildContext context) {
final TextStyle style = context.isDark ? TextStyles.textGray14 : const TextStyle(color: Color(0x8A000000));
final TextStyle style = context.isDark
? TextStyles.textGray14
: const TextStyle(color: Color(0x8A000000));
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
......@@ -113,8 +120,10 @@ class MoreWidget extends StatelessWidget {
children: <Widget>[
if (hasMore) const CupertinoActivityIndicator(),
if (hasMore) Gaps.hGap5,
/// 只有一页的时候,就不显示FooterView了
Text(hasMore ? '正在加载中...' : (itemCount < pageSize ? '' : '没有了呦~'), style: style),
Text(hasMore ? '正在加载中...' : (itemCount < pageSize ? '' : '没有了呦~'),
style: style),
],
),
);
......
......@@ -295,6 +295,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
fijkplayer:
dependency: "direct main"
description:
name: fijkplayer
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.1"
file:
dependency: transitive
description:
......
......@@ -89,6 +89,8 @@ dependencies:
tapped: ^2.0.0-nullsafety.0
# 加载动画库
flutter_spinkit: ^5.0.0
# fijkplayer (Video player plugin for Flutter) Flutter 媒体播放器
fijkplayer: ^0.10.1
json_annotation: ^4.4.0
flutter_plugin_record: ^1.0.1
......