完成Application-Main页面的一部分
This commit is contained in:
parent
6c2bc89f91
commit
69f3d9d64c
|
@ -2,8 +2,7 @@
|
|||
const ProxyEnable = false;
|
||||
|
||||
/// 代理服务IP
|
||||
// const PROXY_IP = '192.168.1.105';
|
||||
const ProxyIP = '172.16.43.74';
|
||||
const ProxyIP = '172.31.163.87';
|
||||
|
||||
/// 代理服务端口
|
||||
const ProxyPort = 8866;
|
||||
const ProxyPort = 7890;
|
|
@ -0,0 +1,31 @@
|
|||
import 'dart:convert';
|
||||
|
||||
/// 新闻分类 response
|
||||
class CategoryResponse {
|
||||
String code;
|
||||
String title;
|
||||
|
||||
CategoryResponse({
|
||||
required this.code,
|
||||
required this.title,
|
||||
});
|
||||
|
||||
factory CategoryResponse.fromRawJson(String str) => CategoryResponse.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory CategoryResponse.fromJson(Map<String, dynamic> json) => CategoryResponse(
|
||||
code: json["code"],
|
||||
title: json["title"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"code": code,
|
||||
"title": title,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "$title【$code】";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import 'dart:convert';
|
||||
|
||||
|
||||
/// 频道列表 response
|
||||
class ChannelResponse {
|
||||
String code;
|
||||
String title;
|
||||
|
||||
ChannelResponse({
|
||||
required this.code,
|
||||
required this.title,
|
||||
});
|
||||
|
||||
factory ChannelResponse.fromRawJson(String str) => ChannelResponse.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory ChannelResponse.fromJson(Map<String, dynamic> json) => ChannelResponse(
|
||||
code: json["code"],
|
||||
title: json["title"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"code": code,
|
||||
"title": title,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/// 新闻分页 request
|
||||
class NewsPageListRequest {
|
||||
String? categoryCode;
|
||||
String? channelCode;
|
||||
String? tag;
|
||||
String? keyword;
|
||||
int? pageNum;
|
||||
int? pageSize;
|
||||
|
||||
NewsPageListRequest({
|
||||
this.categoryCode,
|
||||
this.channelCode,
|
||||
this.tag,
|
||||
this.keyword,
|
||||
this.pageNum,
|
||||
this.pageSize,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"categoryCode": categoryCode,
|
||||
"channelCode": channelCode,
|
||||
"tag": tag,
|
||||
"keyword": keyword,
|
||||
"pageNum": pageNum,
|
||||
"pageSize": pageSize,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// 新闻分页 response
|
||||
class NewsPageListResponse {
|
||||
int? counts;
|
||||
int? pagesize;
|
||||
int? pages;
|
||||
int? page;
|
||||
List<NewsItem>? items;
|
||||
|
||||
NewsPageListResponse({
|
||||
this.counts,
|
||||
this.pagesize,
|
||||
this.pages,
|
||||
this.page,
|
||||
this.items,
|
||||
});
|
||||
|
||||
factory NewsPageListResponse.fromJson(Map<String, dynamic> json) =>
|
||||
NewsPageListResponse(
|
||||
counts: json["counts"],
|
||||
pagesize: json["pagesize"],
|
||||
pages: json["pages"],
|
||||
page: json["page"],
|
||||
items: json["items"] == null
|
||||
? []
|
||||
: List<NewsItem>.from(
|
||||
json["items"].map((x) => NewsItem.fromJson(x))),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"counts": counts ?? 0,
|
||||
"pagesize": pagesize ?? 0,
|
||||
"pages": pages ?? 0,
|
||||
"page": page ?? 0,
|
||||
"items": items == null
|
||||
? []
|
||||
: List<dynamic>.from(items!.map((x) => x.toJson())),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class NewsItem {
|
||||
String? id;
|
||||
String? title;
|
||||
String? category;
|
||||
String? thumbnail;
|
||||
String? author;
|
||||
DateTime? addtime;
|
||||
String? url;
|
||||
|
||||
NewsItem({
|
||||
this.id,
|
||||
this.title,
|
||||
this.category,
|
||||
this.thumbnail,
|
||||
this.author,
|
||||
this.addtime,
|
||||
this.url,
|
||||
});
|
||||
|
||||
factory NewsItem.fromJson(Map<String, dynamic> json) => NewsItem(
|
||||
id: json["id"],
|
||||
title: json["title"],
|
||||
category: json["category"],
|
||||
thumbnail: json["thumbnail"],
|
||||
author: json["author"],
|
||||
addtime: DateTime.parse(json["addtime"]),
|
||||
url: json["url"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id,
|
||||
"title": title,
|
||||
"category": category,
|
||||
"thumbnail": thumbnail,
|
||||
"author": author,
|
||||
"addtime": addtime?.toIso8601String(),
|
||||
"url": url,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// 新闻推荐 request
|
||||
class NewsRecommendRequest {
|
||||
String? categoryCode;
|
||||
String? channelCode;
|
||||
String? tag;
|
||||
String? keyword;
|
||||
|
||||
NewsRecommendRequest({
|
||||
this.categoryCode,
|
||||
this.channelCode,
|
||||
this.tag,
|
||||
this.keyword,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"categoryCode": categoryCode,
|
||||
"channelCode": channelCode,
|
||||
"tag": tag,
|
||||
"keyword": keyword,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import 'dart:convert';
|
||||
|
||||
/// 标签列表 Request
|
||||
class TagRequest {
|
||||
String categoryCode;
|
||||
String channelCode;
|
||||
String tag;
|
||||
String keyword;
|
||||
String newsId;
|
||||
|
||||
TagRequest({
|
||||
required this.categoryCode,
|
||||
required this.channelCode,
|
||||
required this.tag,
|
||||
required this.keyword,
|
||||
required this.newsId,
|
||||
});
|
||||
|
||||
factory TagRequest.fromRawJson(String str) => TagRequest.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory TagRequest.fromJson(Map<String, dynamic> json) => TagRequest(
|
||||
categoryCode: json["categoryCode"],
|
||||
channelCode: json["channelCode"],
|
||||
tag: json["tag"],
|
||||
keyword: json["keyword"],
|
||||
newsId: json["newsID"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"categoryCode": categoryCode,
|
||||
"channelCode": channelCode,
|
||||
"tag": tag,
|
||||
"keyword": keyword,
|
||||
"newsID": newsId,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// 标签列表 Response
|
||||
class TagResponse {
|
||||
String? tag;
|
||||
|
||||
TagResponse({
|
||||
this.tag,
|
||||
});
|
||||
|
||||
factory TagResponse.fromRawJson(String str) => TagResponse.fromJson(json.decode(str));
|
||||
|
||||
String toRawJson() => json.encode(toJson());
|
||||
|
||||
factory TagResponse.fromJson(Map<String, dynamic> json) => TagResponse(
|
||||
tag: json["tag"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"tag": tag,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import 'package:news_getx/config/storage.dart';
|
||||
import 'package:news_getx/data/model/categories.dart';
|
||||
import 'package:news_getx/data/model/channels.dart';
|
||||
import 'package:news_getx/data/model/news.dart';
|
||||
import 'package:news_getx/data/model/tag.dart';
|
||||
import 'package:news_getx/utils/http.dart';
|
||||
|
||||
/// 新闻API
|
||||
class NewsAPI {
|
||||
/// 翻页
|
||||
/// refresh 是否刷新
|
||||
static Future<NewsPageListResponse> newsPageList({
|
||||
NewsPageListRequest? params,
|
||||
bool refresh = false,
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
var response = await HttpUtil().get(
|
||||
"/news",
|
||||
queryParameters: params?.toJson(),
|
||||
refresh: refresh,
|
||||
cacheDisk: cacheDisk,
|
||||
cacheKey: StorageIndexNewsCacheKey,
|
||||
);
|
||||
return NewsPageListResponse.fromJson(response);
|
||||
}
|
||||
|
||||
/// 推荐
|
||||
static Future<NewsItem> newsRecommend({
|
||||
NewsRecommendRequest? params,
|
||||
bool refresh = false,
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
var response = await HttpUtil().get(
|
||||
'/news/recommend',
|
||||
queryParameters: params?.toJson(),
|
||||
refresh: refresh,
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
return NewsItem.fromJson(response);
|
||||
}
|
||||
|
||||
/// 分类
|
||||
static Future<List<CategoryResponse>> categories({
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
var response = await HttpUtil().get(
|
||||
'/categories',
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
return response
|
||||
.map<CategoryResponse>((item) => CategoryResponse.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 频道
|
||||
static Future<List<ChannelResponse>> channels({
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
var response = await HttpUtil().get(
|
||||
'/channels',
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
return response
|
||||
.map<ChannelResponse>((item) => ChannelResponse.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 标签列表
|
||||
static Future<List<TagResponse>> tags({
|
||||
TagRequest? params,
|
||||
bool cacheDisk = false,
|
||||
}) async {
|
||||
var response = await HttpUtil().get(
|
||||
'/tags',
|
||||
queryParameters: params?.toJson(),
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
|
||||
return response
|
||||
.map<TagResponse>((item) => TagResponse.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import 'package:news_getx/data/model/news.dart';
|
||||
import 'package:news_getx/data/provider/news.dart';
|
||||
|
||||
import '../model/categories.dart';
|
||||
import '../model/channels.dart';
|
||||
import '../model/tag.dart';
|
||||
|
||||
class NewsRepository {
|
||||
Future<NewsPageListResponse> newsPageList({
|
||||
NewsPageListRequest? params,
|
||||
bool refresh = false,
|
||||
bool cacheDisk = false,
|
||||
}) {
|
||||
return NewsAPI.newsPageList(
|
||||
params: params,
|
||||
refresh: refresh,
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
}
|
||||
|
||||
Future<NewsItem> newsRecommend({
|
||||
NewsRecommendRequest? params,
|
||||
bool refresh = false,
|
||||
bool cacheDisk = false,
|
||||
}) {
|
||||
return NewsAPI.newsRecommend(
|
||||
params: params,
|
||||
refresh: refresh,
|
||||
cacheDisk: cacheDisk,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<CategoryResponse>> categories({
|
||||
bool cacheDisk = false,
|
||||
}) {
|
||||
return NewsAPI.categories(cacheDisk: cacheDisk);
|
||||
}
|
||||
|
||||
Future<List<ChannelResponse>> channels({
|
||||
bool cacheDisk = false,
|
||||
}) {
|
||||
return NewsAPI.channels(cacheDisk: cacheDisk);
|
||||
}
|
||||
|
||||
Future<List<TagResponse>> tags({
|
||||
TagRequest? params,
|
||||
bool cacheDisk = false,
|
||||
}) {
|
||||
return NewsAPI.tags(params: params, cacheDisk: cacheDisk);
|
||||
}
|
||||
}
|
|
@ -34,7 +34,8 @@ class MyApp extends StatelessWidget {
|
|||
title: 'News',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.light,
|
||||
initialRoute: AppRoutes.Initial,
|
||||
// initialRoute: AppRoutes.Initial,
|
||||
initialRoute: AppRoutes.Application,
|
||||
getPages: AppPages.pages,
|
||||
builder: EasyLoading.init(),
|
||||
),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/category/category_page.dart';
|
||||
import 'package:news_getx/modules/main/main_page.dart';
|
||||
import 'package:news_getx/modules/widgets/app_bar.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
|
||||
|
@ -41,8 +43,8 @@ class ApplicationPage extends GetView<ApplicationController> {
|
|||
controller: controller.pageController,
|
||||
onPageChanged: controller.handlePageChange,
|
||||
children: <Widget>[
|
||||
Text('Main'),
|
||||
Text('Category'),
|
||||
MainPage(),
|
||||
Text('Categories'),
|
||||
Text('BookmarksPage'),
|
||||
Text('AccountPage'),
|
||||
],
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:get/get.dart';
|
||||
|
||||
import 'category_controller.dart';
|
||||
|
||||
class CategoryBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => CategoryController());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import 'package:get/get.dart';
|
||||
|
||||
class CategoryController extends GetxController {
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'category_controller.dart';
|
||||
|
||||
class CategoryPage extends StatelessWidget {
|
||||
const CategoryPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = Get.find<CategoryController>();
|
||||
|
||||
return Container();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/repository/news_repository.dart';
|
||||
|
||||
import 'main_controller.dart';
|
||||
|
||||
class MainBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => MainController());
|
||||
Get.lazyPut(() => MainController(
|
||||
newsRepository: NewsRepository(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,56 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/news.dart';
|
||||
import 'package:news_getx/data/repository/news_repository.dart';
|
||||
import 'package:news_getx/modules/main/main_state.dart';
|
||||
|
||||
class MainController extends GetxController {
|
||||
NewsRepository newsRepository;
|
||||
|
||||
MainController({required this.newsRepository});
|
||||
|
||||
/// 响应式成员变量
|
||||
/// 在Getx中,当一个对象被注册为可观察对象(Observable),
|
||||
/// Getx会自动将其所有属性都转换为可观察属性(Observable)。
|
||||
/// 这意味着,无论是直接在GetxController中定义的属性,
|
||||
/// 还是在其内部嵌套的对象中定义的属性,
|
||||
/// 只要它们被定义为可观察属性,GetxController都会监听它们的变化。
|
||||
final state = MainState();
|
||||
|
||||
/// 方法
|
||||
// 拉取数据
|
||||
asyncLoadAllData() async {
|
||||
state.categories = await newsRepository.categories(cacheDisk: true);
|
||||
state.channels = await newsRepository.channels(cacheDisk: true);
|
||||
// 分类对应的数据(推荐、新闻)
|
||||
state.newsRecommend = await newsRepository.newsRecommend(cacheDisk: true);
|
||||
state.newsPageList = await newsRepository.newsPageList(cacheDisk: true);
|
||||
// 所选分类
|
||||
state.selCategoryCode = state.categories?.first.code;
|
||||
}
|
||||
|
||||
// 拉取推荐、新闻
|
||||
asyncLoadNewsData(
|
||||
categoryCode, {
|
||||
bool refresh = false,
|
||||
}) async {
|
||||
state.selCategoryCode = categoryCode;
|
||||
state.newsRecommend = await newsRepository.newsRecommend(
|
||||
params: NewsRecommendRequest(categoryCode: categoryCode),
|
||||
refresh: refresh,
|
||||
cacheDisk: true,
|
||||
);
|
||||
state.newsPageList = await newsRepository.newsPageList(
|
||||
params: NewsPageListRequest(categoryCode: categoryCode),
|
||||
refresh: refresh,
|
||||
cacheDisk: true,
|
||||
);
|
||||
}
|
||||
|
||||
/// 生命周期
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
// 异步拉取数据
|
||||
asyncLoadAllData();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/main/widgets/categories.dart';
|
||||
import 'package:news_getx/modules/main/widgets/recommend.dart';
|
||||
|
||||
import 'main_controller.dart';
|
||||
|
||||
class MainPage extends StatelessWidget {
|
||||
class MainPage extends GetView<MainController> {
|
||||
const MainPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = Get.find<MainController>();
|
||||
|
||||
return Container();
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
NewsCategoriesWidget(),
|
||||
Divider(height: 1),
|
||||
NewsRecommendWidget(),
|
||||
Divider(height: 1),
|
||||
Text('NewsChannelsWidget'),
|
||||
Divider(height: 1),
|
||||
Text('NewsListWidget'),
|
||||
Divider(height: 1),
|
||||
Text('NewsletterWidget'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/categories.dart';
|
||||
import 'package:news_getx/data/model/channels.dart';
|
||||
import 'package:news_getx/data/model/news.dart';
|
||||
|
||||
class MainState {
|
||||
// 分类
|
||||
var _categories = Rx<List<CategoryResponse>?>(null);
|
||||
|
||||
set categories(value) => _categories.value = value;
|
||||
|
||||
List<CategoryResponse>? get categories => _categories.value;
|
||||
|
||||
// 新闻翻页
|
||||
var _newsPageList = Rx<NewsPageListResponse?>(null);
|
||||
|
||||
set newsPageList(value) => _newsPageList.value = value;
|
||||
|
||||
NewsPageListResponse? get newsPageList => _newsPageList.value;
|
||||
|
||||
void appendNewsPageList(NewsPageListResponse value) {
|
||||
if (_newsPageList.value != null) {
|
||||
_newsPageList.value!.items?.addAll(value.items!.toList());
|
||||
}
|
||||
}
|
||||
|
||||
// 新闻推荐
|
||||
var _newsRecommend = Rx<NewsItem?>(null);
|
||||
|
||||
set newsRecommend(value) => _newsRecommend.value = value;
|
||||
|
||||
NewsItem? get newsRecommend => _newsRecommend.value;
|
||||
|
||||
// 频道
|
||||
var _channels = Rx<List<ChannelResponse>?>(null);
|
||||
|
||||
set channels(value) => _channels.value = value;
|
||||
|
||||
List<ChannelResponse>? get channels => _channels.value;
|
||||
|
||||
// 选中的分类Code
|
||||
var _selCategoryCode = "".obs;
|
||||
|
||||
set selCategoryCode(value) => _selCategoryCode.value = value;
|
||||
|
||||
String get selCategoryCode => _selCategoryCode.value;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/main/main_controller.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
|
||||
class NewsCategoriesWidget extends GetView<MainController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 用的是Row 而不是 Tab
|
||||
return Obx(
|
||||
() => controller.state.categories == null
|
||||
? Container()
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: controller.state.categories!.map<Widget>(
|
||||
(item) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
height: 52.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// 拉取对应分类的数据
|
||||
controller.asyncLoadNewsData(item.code);
|
||||
},
|
||||
child: Text(
|
||||
item.title,
|
||||
style: TextStyle(
|
||||
color: controller.state.selCategoryCode == item.code
|
||||
? AppColors.secondaryElementText
|
||||
: AppColors.primaryText,
|
||||
fontSize: 18.h,
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/main/main_controller.dart';
|
||||
import 'package:news_getx/modules/widgets/image.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
import 'package:news_getx/utils/date.dart';
|
||||
|
||||
class NewsRecommendWidget extends GetView<MainController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print(controller.state.newsRecommend?.thumbnail);
|
||||
return Obx(
|
||||
() => controller.state.newsRecommend == null
|
||||
? Container()
|
||||
: Container(
|
||||
margin: EdgeInsets.all(20.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 图
|
||||
InkWell(
|
||||
onTap: () {
|
||||
print("进入详情页");
|
||||
},
|
||||
child: netImageCached(
|
||||
controller.state.newsRecommend?.thumbnail ?? "",
|
||||
width: 335.w,
|
||||
height: 290.h,
|
||||
),
|
||||
),
|
||||
// 作者
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 14.h),
|
||||
child: Text(
|
||||
controller.state.newsRecommend!.author ?? "",
|
||||
style: TextStyle(
|
||||
fontFamily: 'Avenir',
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.thirdElementText,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 标题
|
||||
|
||||
// 一行 3 列
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 10.h),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 120),
|
||||
child: Text(
|
||||
controller.state.newsRecommend!.category ?? "",
|
||||
style: TextStyle(
|
||||
fontFamily: 'Avenir',
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.secondaryElementText,
|
||||
fontSize: 14.sp,
|
||||
height: 1,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
// 添加时间
|
||||
Container(
|
||||
width: 15.w,
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 120),
|
||||
child: Text(
|
||||
'• ${timeLineFormat(controller.state.newsRecommend!.addtime!)}',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Avenir',
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.thirdElementText,
|
||||
fontSize: 14.sp,
|
||||
height: 1,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
// 占满剩余空间
|
||||
Spacer(),
|
||||
// 更多
|
||||
InkWell(
|
||||
child: Icon(
|
||||
Icons.more_horiz,
|
||||
color: AppColors.primaryText,
|
||||
size: 24,
|
||||
),
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:news_getx/theme/app_radii.dart';
|
||||
|
||||
/// 缓存图片
|
||||
Widget netImageCached(
|
||||
String url, {
|
||||
double width = 48,
|
||||
double height = 48,
|
||||
EdgeInsetsGeometry? margin,
|
||||
}) {
|
||||
return CachedNetworkImage(
|
||||
imageUrl: url,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
height: height.h,
|
||||
width: width.w,
|
||||
margin: margin,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: Radii.k6pxRadius,
|
||||
image: DecorationImage(
|
||||
image: imageProvider,
|
||||
fit: BoxFit.cover,
|
||||
)),
|
||||
),
|
||||
placeholder: (context, url) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
},
|
||||
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||
);
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/modules/application/application_binding.dart';
|
||||
import 'package:news_getx/modules/application/application_page.dart';
|
||||
import 'package:news_getx/modules/category/category_binding.dart';
|
||||
import 'package:news_getx/modules/category/category_page.dart';
|
||||
import 'package:news_getx/modules/main/main_binding.dart';
|
||||
import 'package:news_getx/modules/not_found/not_found_binding.dart';
|
||||
import 'package:news_getx/modules/not_found/not_found_page.dart';
|
||||
import 'package:news_getx/modules/sign_in/sign_in_binding.dart';
|
||||
|
@ -40,6 +43,13 @@ abstract class AppPages {
|
|||
name: AppRoutes.Application,
|
||||
page: () => ApplicationPage(),
|
||||
binding: ApplicationBinding(),
|
||||
bindings: [MainBinding(), CategoryBinding()]
|
||||
),
|
||||
// 分类页
|
||||
GetPage(
|
||||
name: AppRoutes.Category,
|
||||
page: () => CategoryPage(),
|
||||
binding: CategoryBinding(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import 'package:intl/intl.dart';
|
||||
|
||||
/// 格式化时间
|
||||
String timeLineFormat(DateTime dt) {
|
||||
var now = DateTime.now();
|
||||
var difference = now.difference(dt);
|
||||
|
||||
// 1天内
|
||||
if (difference.inHours < 24) {
|
||||
return "${difference.inHours} hours ago";
|
||||
}
|
||||
// 30天内
|
||||
else if (difference.inDays < 30) {
|
||||
return "${difference.inDays} days ago";
|
||||
}
|
||||
// MM-dd
|
||||
else if (difference.inDays < 365) {
|
||||
final dtFormat = DateFormat('MM-dd');
|
||||
return dtFormat.format(dt);
|
||||
}
|
||||
// yyyy-MM-dd
|
||||
else {
|
||||
final dtFormat = DateFormat('yyyy-MM-dd');
|
||||
var str = dtFormat.format(dt);
|
||||
return str;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ class CacheObject {
|
|||
|
||||
class NetCache extends Interceptor {
|
||||
// 为确保迭代器顺序和对象插入时间一致顺序一致,我们使用LinkedHashMap, 默认的字面量{}就是有序的
|
||||
// 内存缓存
|
||||
var cache = <String, CacheObject>{};
|
||||
|
||||
@override
|
||||
|
|
Loading…
Reference in New Issue