This commit is contained in:
2026-03-07 17:24:59 +08:00
parent 4418ebecac
commit b0ec8ab4bd
417 changed files with 42546 additions and 2 deletions

View File

@@ -0,0 +1,67 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_dmzj/app/controller/base_controller.dart';
import 'package:flutter_dmzj/app/event_bus.dart';
import 'package:flutter_dmzj/models/news/news_tag_model.dart';
import 'package:flutter_dmzj/modules/news/home/news_list_controller.dart';
import 'package:flutter_dmzj/requests/news_request.dart';
import 'package:get/get.dart';
class NewsHomeController extends GetxController
with GetTickerProviderStateMixin {
NewsRequest request = NewsRequest();
late TabController tabController;
var loadding = true;
List<NewsTagModel> categores = [];
var error = false;
var errorMsg = "";
StreamSubscription<dynamic>? streamSubscription;
@override
void onInit() {
streamSubscription = EventBus.instance.listen(
EventBus.kBottomNavigationBarClicked,
(index) {
if (index == 1) {
refreshOrScrollTop();
}
},
);
loadCategores();
super.onInit();
}
@override
void onClose() {
streamSubscription?.cancel();
super.onClose();
}
void loadCategores() async {
try {
loadding = true;
error = false;
update();
var category = await request.category();
category.insert(0, NewsTagModel(id: 0, name: "最新"));
tabController = TabController(length: category.length, vsync: this);
categores = category;
} catch (e) {
errorMsg = e.toString();
error = true;
} finally {
loadding = false;
update();
}
}
void refreshOrScrollTop() {
var tabIndex = tabController.index;
BasePageController controller;
controller = Get.find<NewsListController>(tag: "${categores[tabIndex].id}");
controller.scrollToTopOrRefresh();
}
}

View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_dmzj/app/platform_utils.dart';
import 'package:flutter_dmzj/modules/news/home/news_home_controller.dart';
import 'package:flutter_dmzj/modules/news/home/news_list_view.dart';
import 'package:flutter_dmzj/widgets/status/app_error_widget.dart';
import 'package:flutter_dmzj/widgets/status/app_loadding_widget.dart';
import 'package:flutter_dmzj/widgets/tab_appbar.dart';
import 'package:flutter_dmzj/widgets/windows_tab_page.dart';
import 'package:get/get.dart';
class NewsHomePage extends GetView<NewsHomeController> {
const NewsHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetBuilder<NewsHomeController>(
init: controller,
builder: (controller) {
if (controller.loadding) {
return const Scaffold(
body: AppLoaddingWidget(),
);
}
if (!controller.loadding && controller.error) {
return Scaffold(
body: AppErrorWidget(
errorMsg: controller.errorMsg,
onRefresh: controller.loadCategores,
),
);
}
if (PlatformUtils.isWindows) {
return WindowsTabPage(
tabs: controller.categores
.map((e) => WindowsTabItem(
label: e.name,
body: NewsListView(tag: e),
))
.toList(),
);
}
return Scaffold(
appBar: TabAppBar(
tabs: controller.categores.map((e) => Tab(text: e.name)).toList(),
controller: controller.tabController,
),
body: TabBarView(
controller: controller.tabController,
children:
controller.categores.map((e) => NewsListView(tag: e)).toList(),
),
);
},
);
}
}

View File

@@ -0,0 +1,40 @@
import 'package:flutter_dmzj/app/controller/base_controller.dart';
import 'package:flutter_dmzj/models/news/news_banner_model.dart';
import 'package:flutter_dmzj/models/news/news_list_item_model.dart';
import 'package:flutter_dmzj/models/news/news_tag_model.dart';
import 'package:flutter_dmzj/requests/news_request.dart';
import 'package:flutter_dmzj/routes/app_navigator.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class NewsListController extends BasePageController<NewsListItemModel> {
final NewsRequest request = NewsRequest();
final NewsTagModel tag;
NewsListController(this.tag);
RxList<NewsBannerModel> banners = RxList<NewsBannerModel>();
@override
Future<List<NewsListItemModel>> getData(int page, int pageSize) async {
if (tag.id == 0 && page == 1) {
loadBanner();
}
return await request.getNewsList(tag.id, page);
}
void loadBanner() async {
try {
banners.value = await request.banner();
} catch (e) {
SmartDialog.showToast(e.toString());
}
}
void openBanner(NewsBannerModel item) {
AppNavigator.toNewsDetail(
url: item.objectUrl ?? "",
newsId: item.objectId ?? 0,
title: item.title,
);
}
}

View File

@@ -0,0 +1,200 @@
import 'package:flutter/material.dart';
import 'package:flutter_dmzj/app/app_style.dart';
import 'package:flutter_dmzj/app/utils.dart';
import 'package:flutter_dmzj/models/news/news_tag_model.dart';
import 'package:flutter_dmzj/modules/news/home/news_list_controller.dart';
import 'package:flutter_dmzj/routes/app_navigator.dart';
import 'package:flutter_dmzj/widgets/keep_alive_wrapper.dart';
import 'package:flutter_dmzj/widgets/net_image.dart';
import 'package:flutter_dmzj/widgets/page_list_view.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:get/get.dart';
class NewsListView extends StatelessWidget {
final NewsTagModel tag;
final NewsListController controller;
NewsListView({Key? key, required this.tag})
: controller = Get.put(NewsListController(tag), tag: tag.id.toString()),
super(key: key);
@override
Widget build(BuildContext context) {
return KeepAliveWrapper(
child: PageListView(
pageController: controller,
firstRefresh: true,
separatorBuilder: (context, i) => Divider(
endIndent: 12,
indent: 12,
color: Colors.grey.withOpacity(.2),
height: 1,
),
header: tag.id == 0 ? buildBanner() : null,
itemBuilder: (context, i) {
var item = controller.list[i];
return InkWell(
onTap: () {
AppNavigator.toNewsDetail(
newsId: item.articleId.toInt(),
title: item.title,
url: item.pageUrl ?? "",
);
},
child: Container(
padding: AppStyle.edgeInsetsA12,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
NetImage(
item.rowPicUrl ?? "",
width: 100,
height: 62,
borderRadius: 4,
),
AppStyle.hGap12,
Expanded(
child: SizedBox(
height: 62,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Text(
item.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
Utils.formatTimestamp(item.createTime ?? 0),
style: const TextStyle(
color: Colors.grey, fontSize: 12),
),
// Row(
// children: <Widget>[
// const Icon(
// Icons.thumb_up,
// size: 12.0,
// color: Colors.grey,
// ),
// AppStyle.hGap4,
// Text(
// item.moodAmount.toString(),
// style: const TextStyle(
// color: Colors.grey,
// fontSize: 12,
// ),
// ),
// AppStyle.hGap8,
// const Icon(
// Icons.chat,
// size: 12.0,
// color: Colors.grey,
// ),
// AppStyle.hGap4,
// Text(
// item.commentAmount.toString(),
// style: const TextStyle(
// color: Colors.grey,
// fontSize: 12,
// ),
// )
// ],
// )
],
)
],
),
),
),
],
),
),
);
},
),
);
}
Widget buildBanner() {
return Padding(
padding: AppStyle.edgeInsetsH12.copyWith(bottom: 4),
child: Obx(
() => ClipRRect(
borderRadius: AppStyle.radius4,
child: AspectRatio(
aspectRatio: 75 / 40,
child: controller.banners.isEmpty
? const SizedBox()
: Swiper(
itemWidth: 750,
itemHeight: 400,
autoplay: true,
itemCount: controller.banners.length,
onTap: (i) {
controller.openBanner(controller.banners[i]);
},
itemBuilder: (_, i) => NetImage(
controller.banners[i].picUrl,
width: 750,
height: 400,
),
pagination: SwiperCustomPagination(
builder:
(BuildContext context, SwiperPluginConfig config) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.only(
left: 8,
right: 12,
top: 4,
bottom: 4,
),
//color: Colors.black12,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.black38,
Colors.transparent,
],
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
controller
.banners[config.activeIndex].title,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 14, color: Colors.white),
),
),
AppStyle.hGap8,
PageIndicator(
controller: config.pageController!,
count: config.itemCount,
size: 10,
layout: PageIndicatorLayout.SCALE,
),
],
),
),
);
},
),
),
),
),
),
);
}
}