mod: 最热合并到首页

This commit is contained in:
guozhigq
2023-07-11 13:01:51 +08:00
parent bc3ac3c9f6
commit e5a05c22ea
16 changed files with 405 additions and 272 deletions

Binary file not shown.

BIN
assets/fonts/Jura-Bold.ttf Normal file

Binary file not shown.

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/rcmd/controller.dart';
import 'package:pilipala/utils/utils.dart';
class LiveCard extends StatelessWidget {
@ -96,7 +96,7 @@ class LiveContent extends StatelessWidget {
liveItem.title,
textAlign: TextAlign.start,
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
maxLines: Get.find<HomeController>().crossAxisCount,
maxLines: Get.find<RcmdController>().crossAxisCount,
overflow: TextOverflow.ellipsis,
),
SizedBox(

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/stat/danmu.dart';
import 'package:pilipala/common/widgets/stat/view.dart';
import 'package:pilipala/pages/rcmd/index.dart';
import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/pages/home/controller.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
@ -123,7 +124,7 @@ class VideoContent extends StatelessWidget {
// fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
fontSize: 13,
),
maxLines: Get.find<HomeController>().crossAxisCount,
maxLines: Get.find<RcmdController>().crossAxisCount,
overflow: TextOverflow.ellipsis,
),
SizedBox(

View File

@ -1,77 +1,42 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
class HomeController extends GetxController {
final ScrollController scrollController = ScrollController();
int count = 12;
int _currentPage = 1;
int crossAxisCount = 2;
RxList<RecVideoItemModel> videoList = [RecVideoItemModel()].obs;
bool isLoadingMore = false;
class HomeController extends GetxController with GetTickerProviderStateMixin {
bool flag = false;
OverlayEntry? popupDialog;
Box recVideo = GStrorage.recVideo;
List tabs = [
{'label': '直播', 'type': 'live'},
{'label': '推荐', 'type': 'rcm'},
{'label': '热门', 'type': 'hot'},
];
int initialIndex = 1;
late TabController tabController;
List ctrList = [
'',
Get.find<RcmdController>,
Get.find<HotController>,
];
@override
void onInit() {
super.onInit();
if (recVideo.get('cacheList') != null &&
recVideo.get('cacheList').isNotEmpty) {
List<RecVideoItemModel> list = [];
for (var i in recVideo.get('cacheList')) {
list.add(i);
}
videoList.value = list;
}
}
// 获取推荐
Future queryRcmdFeed(type) async {
var res = await VideoHttp.rcmdVideoList(
ps: count,
freshIdx: _currentPage,
tabController = TabController(
initialIndex: initialIndex,
length: tabs.length,
vsync: this,
);
if (res['status']) {
if (type == 'init') {
if (videoList.length > 1) {
videoList.addAll(res['data']);
} else {
videoList.value = res['data'];
}
} else if (type == 'onRefresh') {
videoList.insertAll(0, res['data']);
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
recVideo.put('cacheList', res['data']);
_currentPage += 1;
}
isLoadingMore = false;
return res;
}
// 下拉刷新
Future onRefresh() async {
queryRcmdFeed('onRefresh');
void onRefresh() {
int index = tabController.index;
var ctr = ctrList[index];
ctr().onRefresh();
}
// 上拉加载
Future onLoad() async {
queryRcmdFeed('onLoad');
}
// 返回顶部并刷新
void animateToTop() async {
if (scrollController.offset >=
MediaQuery.of(Get.context!).size.height * 5) {
scrollController.jumpTo(0);
} else {
await scrollController.animateTo(0,
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
}
void animateToTop() {
int index = tabController.index;
var ctr = ctrList[index];
ctr().animateToTop();
}
}

View File

@ -1,13 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_card_v.dart';
import 'package:pilipala/common/widgets/animated_dialog.dart';
import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/video_card_v.dart';
import 'package:pilipala/pages/hot/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
import './controller.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/pages/home/widgets/app_bar.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@ -17,10 +13,10 @@ class HomePage extends StatefulWidget {
}
class _HomePageState extends State<HomePage>
with AutomaticKeepAliveClientMixin {
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
final HomeController _homeController = Get.put(HomeController());
Future? _futureBuilderFuture;
List videoList = [];
// late TabController? _tabController;
@override
bool get wantKeepAlive => true;
@ -28,181 +24,93 @@ class _HomePageState extends State<HomePage>
@override
void initState() {
super.initState();
_futureBuilderFuture = _homeController.queryRcmdFeed('init');
_homeController.videoList.listen((value) {
videoList = value;
setState(() {});
});
_homeController.scrollController.addListener(
() {
if (_homeController.scrollController.position.pixels >=
_homeController.scrollController.position.maxScrollExtent - 200) {
if (!_homeController.isLoadingMore) {
_homeController.isLoadingMore = true;
_homeController.onLoad();
}
}
},
);
// _tabController = TabController(
// initialIndex: _homeController.initialIndex,
// length: _homeController.tabs.length,
// vsync: this,
// );
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
// body: NestedScrollView(
// headerSliverBuilder: (context, innerBoxIsScrolled) => [
// const HomeAppBar()
// ],
body: RefreshIndicator(
displacement: kToolbarHeight + MediaQuery.of(context).padding.top,
onRefresh: () async {
return await _homeController.onRefresh();
},
child: CustomScrollView(
controller: _homeController.scrollController,
slivers: [
const HomeAppBar(),
// SliverPersistentHeader(
// delegate: MySliverPersistentHeaderDelegate(),
// pinned: true,
// ),
SliverPadding(
// 单列布局 EdgeInsets.zero
padding: _homeController.crossAxisCount == 1
? EdgeInsets.zero
: const EdgeInsets.fromLTRB(
StyleString.cardSpace, 0, StyleString.cardSpace, 8),
sliver: FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(() => contentGrid(
_homeController, _homeController.videoList));
} else {
return HttpError(
errMsg: data['msg'],
fn: () => setState(() {}),
);
}
} else {
// 缓存数据
if (_homeController.videoList.length > 1) {
return contentGrid(
_homeController, _homeController.videoList);
}
// 骨架屏
else {
return contentGrid(_homeController, []);
}
}
},
appBar: AppBar(
titleSpacing: 0,
title: Padding(
padding: const EdgeInsets.only(left: 4, right: 4),
child: Stack(
children: [
const Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 8),
child: Text(
'PLPL',
style: TextStyle(
height: 2.8,
fontSize: 17,
fontWeight: FontWeight.bold,
letterSpacing: 1,
fontFamily: 'Jura-Bold',
),
),
),
),
),
const LoadingMore()
],
),
),
// ),
);
}
OverlayEntry _createPopupDialog(videoItem) {
return OverlayEntry(
builder: (context) => AnimatedDialog(
child: OverlayPop(videoItem: videoItem),
));
}
Widget contentGrid(ctr, videoList) {
return SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// 行间距
mainAxisSpacing: StyleString.cardSpace,
// 列间距
crossAxisSpacing: StyleString.cardSpace,
// 列数
crossAxisCount: ctr.crossAxisCount,
mainAxisExtent: MediaQuery.of(context).size.width /
ctr.crossAxisCount /
StyleString.aspectRatio +
70,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return videoList!.isNotEmpty
?
// VideoCardV(videoItem: videoList![index])
VideoCardV(
videoItem: videoList[index],
longPress: () {
_homeController.popupDialog =
_createPopupDialog(videoList[index]);
Overlay.of(context).insert(_homeController.popupDialog!);
},
longPressEnd: () {
_homeController.popupDialog?.remove();
},
)
: const VideoCardVSkeleton();
},
childCount: videoList!.isNotEmpty ? videoList!.length : 10,
),
);
}
}
class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
)),
child: const Text(
'我是一个SliverPersistentHeader',
),
);
}
@override
double get maxExtent => 55.0;
@override
double get minExtent => 55.0;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) =>
true; // 如果内容需要更新设置为true
}
// loading more
class LoadingMore extends StatelessWidget {
const LoadingMore({super.key});
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).padding.bottom + 80,
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
child: Center(
child: Text(
'加载中...',
style: TextStyle(
color: Theme.of(context).colorScheme.outline, fontSize: 13),
Align(
alignment: Alignment.center,
child: Theme(
data: ThemeData(
splashColor: Colors.transparent, // 点击时的水波纹颜色设置为透明
highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明
),
child: TabBar(
controller: _homeController.tabController,
tabs: [
for (var i in _homeController.tabs) Tab(text: i['label']),
],
isScrollable: true,
indicatorWeight: 0,
indicatorPadding:
const EdgeInsets.symmetric(horizontal: 3, vertical: 8),
indicator: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
indicatorSize: TabBarIndicatorSize.tab,
labelColor:
Theme.of(context).colorScheme.onSecondaryContainer,
labelStyle: const TextStyle(fontSize: 13),
dividerColor: Colors.transparent,
unselectedLabelColor: Theme.of(context).colorScheme.outline,
onTap: (value) => {_homeController.initialIndex = value},
),
),
),
Align(
alignment: Alignment.centerRight,
child: Hero(
tag: 'searchTag',
child: IconButton(
onPressed: () {
Get.toNamed('/search');
},
icon: const Icon(CupertinoIcons.search, size: 21),
),
),
),
],
),
),
),
body: TabBarView(
controller: _homeController.tabController,
children: const [
SizedBox(),
RcmdPage(),
HotPage(),
],
),
);
}
}

View File

@ -6,7 +6,6 @@ import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/video_card_h.dart';
import 'package:pilipala/pages/hot/controller.dart';
import 'package:pilipala/pages/home/widgets/app_bar.dart';
class HotPage extends StatefulWidget {
const HotPage({Key? key}) : super(key: key);
@ -52,7 +51,6 @@ class _HotPageState extends State<HotPage> with AutomaticKeepAliveClientMixin {
child: CustomScrollView(
controller: _hotController.scrollController,
slivers: [
const HomeAppBar(),
FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {

View File

@ -13,7 +13,7 @@ import 'package:pilipala/utils/storage.dart';
class MainController extends GetxController {
List<Widget> pages = <Widget>[
const HomePage(),
const HotPage(),
// const HotPage(),
const DynamicsPage(),
const MediaPage(),
];
@ -25,13 +25,13 @@ class MainController extends GetxController {
),
'label': "推荐",
},
{
'icon': const Icon(
Icons.eco,
size: 20,
),
'label': "热门",
},
// {
// 'icon': const Icon(
// Icons.eco,
// size: 20,
// ),
// 'label': "热门",
// },
{
'icon': const Icon(
Icons.bolt,

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/pages/dynamics/index.dart';
import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/hot/index.dart';
import './controller.dart';
class MainApp extends StatefulWidget {
@ -15,7 +14,6 @@ class MainApp extends StatefulWidget {
class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
final MainController _mainController = Get.put(MainController());
final HomeController _homeController = Get.put(HomeController());
final HotController _hotController = Get.put(HotController());
final DynamicsController _dynamicController = Get.put(DynamicsController());
PageController? _pageController;
@ -70,22 +68,6 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
_homeController.flag = false;
}
if (currentPage is HotPage) {
if (_hotController.flag) {
// 单击返回顶部 双击并刷新
if (DateTime.now().millisecondsSinceEpoch - _lastSelectTime! < 500) {
_hotController.onRefresh();
} else {
await Future.delayed(const Duration(microseconds: 300));
_hotController.animateToTop();
}
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
}
_hotController.flag = true;
} else {
_hotController.flag = false;
}
if (currentPage is DynamicsPage) {
if (_dynamicController.flag) {
// 单击返回顶部 双击并刷新
@ -131,7 +113,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: selectedIndex,
type: BottomNavigationBarType.shifting,
// type: BottomNavigationBarType.shifting,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).colorScheme.onSurfaceVariant,
selectedFontSize: 12.4,

View File

@ -0,0 +1,77 @@
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart';
class RcmdController extends GetxController {
final ScrollController scrollController = ScrollController();
int count = 12;
int _currentPage = 1;
int crossAxisCount = 2;
RxList<RecVideoItemModel> videoList = [RecVideoItemModel()].obs;
bool isLoadingMore = false;
bool flag = false;
OverlayEntry? popupDialog;
Box recVideo = GStrorage.recVideo;
@override
void onInit() {
super.onInit();
if (recVideo.get('cacheList') != null &&
recVideo.get('cacheList').isNotEmpty) {
List<RecVideoItemModel> list = [];
for (var i in recVideo.get('cacheList')) {
list.add(i);
}
videoList.value = list;
}
}
// 获取推荐
Future queryRcmdFeed(type) async {
var res = await VideoHttp.rcmdVideoList(
ps: count,
freshIdx: _currentPage,
);
if (res['status']) {
if (type == 'init') {
if (videoList.length > 1) {
videoList.addAll(res['data']);
} else {
videoList.value = res['data'];
}
} else if (type == 'onRefresh') {
videoList.insertAll(0, res['data']);
} else if (type == 'onLoad') {
videoList.addAll(res['data']);
}
recVideo.put('cacheList', res['data']);
_currentPage += 1;
}
isLoadingMore = false;
return res;
}
// 下拉刷新
Future onRefresh() async {
queryRcmdFeed('onRefresh');
}
// 上拉加载
Future onLoad() async {
queryRcmdFeed('onLoad');
}
// 返回顶部并刷新
void animateToTop() async {
if (scrollController.offset >=
MediaQuery.of(Get.context!).size.height * 5) {
scrollController.jumpTo(0);
} else {
await scrollController.animateTo(0,
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
}
}
}

View File

@ -0,0 +1,4 @@
library recm_panel;
export './controller.dart';
export './view.dart';

153
lib/pages/rcmd/view.dart Normal file
View File

@ -0,0 +1,153 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/skeleton/video_card_v.dart';
import 'package:pilipala/common/widgets/animated_dialog.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/common/widgets/video_card_v.dart';
import 'controller.dart';
class RcmdPage extends StatefulWidget {
const RcmdPage({super.key});
@override
State<RcmdPage> createState() => _RcmdPageState();
}
class _RcmdPageState extends State<RcmdPage>
with AutomaticKeepAliveClientMixin {
final RcmdController _rcmdController = Get.put(RcmdController());
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
_rcmdController.scrollController.addListener(
() {
if (_rcmdController.scrollController.position.pixels >=
_rcmdController.scrollController.position.maxScrollExtent - 200) {
if (!_rcmdController.isLoadingMore) {
_rcmdController.isLoadingMore = true;
_rcmdController.onLoad();
}
}
},
);
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () async {
return await _rcmdController.onRefresh();
},
child: CustomScrollView(
controller: _rcmdController.scrollController,
slivers: [
SliverPadding(
// 单列布局 EdgeInsets.zero
padding: _rcmdController.crossAxisCount == 1
? EdgeInsets.zero
: const EdgeInsets.fromLTRB(
StyleString.cardSpace, 0, StyleString.cardSpace, 8),
sliver: FutureBuilder(
future: _rcmdController.queryRcmdFeed('init'),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(() => contentGrid(
_rcmdController, _rcmdController.videoList));
} else {
return HttpError(
errMsg: data['msg'],
fn: () => {},
);
}
} else {
// 缓存数据
if (_rcmdController.videoList.length > 1) {
return contentGrid(
_rcmdController, _rcmdController.videoList);
}
// 骨架屏
else {
return contentGrid(_rcmdController, []);
}
}
},
),
),
const LoadingMore()
],
),
);
}
OverlayEntry _createPopupDialog(videoItem) {
return OverlayEntry(
builder: (context) => AnimatedDialog(
child: OverlayPop(videoItem: videoItem),
));
}
Widget contentGrid(ctr, videoList) {
return SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
// 行间距
mainAxisSpacing: StyleString.cardSpace,
// 列间距
crossAxisSpacing: StyleString.cardSpace,
// 列数
crossAxisCount: ctr.crossAxisCount,
mainAxisExtent:
Get.size.width / ctr.crossAxisCount / StyleString.aspectRatio + 70,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return videoList!.isNotEmpty
?
// VideoCardV(videoItem: videoList![index])
VideoCardV(
videoItem: videoList[index],
longPress: () {
_rcmdController.popupDialog =
_createPopupDialog(videoList[index]);
Overlay.of(context).insert(_rcmdController.popupDialog!);
},
longPressEnd: () {
_rcmdController.popupDialog?.remove();
},
)
: const VideoCardVSkeleton();
},
childCount: videoList!.isNotEmpty ? videoList!.length : 10,
),
);
}
}
class LoadingMore extends StatelessWidget {
const LoadingMore({super.key});
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).padding.bottom + 80,
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
child: Center(
child: Text(
'加载中...',
style: TextStyle(
color: Theme.of(context).colorScheme.outline, fontSize: 13),
),
),
),
);
}
}

View File

@ -6,6 +6,7 @@ import 'package:pilipala/http/init.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/mine/index.dart';
import 'package:pilipala/pages/rcmd/controller.dart';
import 'package:pilipala/utils/cookie.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:webview_cookie_manager/webview_cookie_manager.dart';
@ -71,7 +72,7 @@ class WebviewController extends GetxController {
userInfoCache.put('userInfoCache', result['data']);
Get.find<MineController>().userInfo.value = result['data'];
Get.find<MineController>().onInit();
Get.find<HomeController>().queryRcmdFeed('onRefresh');
Get.find<RcmdController>().queryRcmdFeed('onRefresh');
Get.back();
}
} catch (e) {

View File

@ -321,6 +321,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.4.2"
extended_list:
dependency: transitive
description:
name: extended_list
sha256: "7eb3c21cd8b7710b0092cb0606807cd24614e5832e65f370e5dee226d317de44"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
extended_list_library:
dependency: transitive
description:
name: extended_list_library
sha256: cb424a04464e89bd6737f9ae025029bd8e913c7bf37101ad10c2defe0238d842
url: "https://pub.dev"
source: hosted
version: "3.0.0"
extended_nested_scroll_view:
dependency: "direct main"
description:
@ -598,6 +614,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
loading_more_list:
dependency: "direct main"
description:
name: loading_more_list
sha256: aa680edc81cf024c394dccfa7ba1db701a5efb23ec1b8c657308428ce9da11d1
url: "https://pub.dev"
source: hosted
version: "5.0.3"
loading_more_list_library:
dependency: transitive
description:
name: loading_more_list_library
sha256: "31348925a98748ffe04f661e4b47df37103fabad39442064fcf59148a5fee2dd"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
@ -1331,6 +1363,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.2"
waterfall_flow:
dependency: transitive
description:
name: waterfall_flow
sha256: "84486ac34f51977176990ada50b44d83be24726814fa03c22c1e10e3791cc3f2"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
web_socket_channel:
dependency: transitive
description:

View File

@ -85,6 +85,7 @@ dependencies:
ref: feature-custom
path: package
custom_sliding_segmented_control: ^1.7.5
loading_more_list: ^5.0.3
dev_dependencies:
flutter_test:
@ -144,9 +145,12 @@ flutter:
- family: fansCard
fonts:
- asset: assets/fonts/fansCard.ttf
- family: ArchivoNarrow
- family: Jura-Bold
fonts:
- asset: assets/fonts/ArchivoNarrow-BoldItalic.ttf
- asset: assets/fonts/Jura-Bold.ttf
- family: HarmonyOS
fonts:
- asset: assets/fonts/HarmonyOS_Sans_SC_Regular.ttf
# For details regarding fonts from package dependencies,