完成Application-Main页,调整构建代理以及仓库地址。
This commit is contained in:
parent
69f3d9d64c
commit
91c50070ec
|
@ -3,6 +3,8 @@ buildscript {
|
|||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -15,6 +17,9 @@ allprojects {
|
|||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
|
||||
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
#org.gradle.java.home=D\:\\Android\\Android Studio\\jbr
|
||||
#org.gradle.java.home=D\:\\Android\\Android Studio\\jbr
|
||||
|
||||
# 配置 VPN 加快下载速度
|
||||
systemProp.http.proxyHost=127.0.0.1
|
||||
systemProp.http.proxyPort=7890
|
||||
systemProp.https.proxyHost=127.0.0.1
|
||||
systemProp.https.proxyPort=7890
|
|
@ -1,4 +1,5 @@
|
|||
/// Api地址
|
||||
const String ServerApiUrl = "http://172.31.163.87:4523/m1/2998542-0-default";
|
||||
// const String ServerApiUrl = "http://172.31.163.87:4523/m1/2998542-0-default";
|
||||
const String ServerApiUrl = "http://192.168.1.5:4523/m1/2998542-0-default";
|
||||
|
||||
const CryptoSalt = "E1pWsyfiy@R@X#qn17!StJNdZK1fFF8iV6ffN!goZkqt#JxO";
|
|
@ -44,7 +44,7 @@ class ApplicationPage extends GetView<ApplicationController> {
|
|||
onPageChanged: controller.handlePageChange,
|
||||
children: <Widget>[
|
||||
MainPage(),
|
||||
Text('Categories'),
|
||||
CategoryPage(),
|
||||
Text('BookmarksPage'),
|
||||
Text('AccountPage'),
|
||||
],
|
||||
|
@ -68,6 +68,7 @@ class ApplicationPage extends GetView<ApplicationController> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xfff6f6f6),
|
||||
appBar: _buildAppBar(),
|
||||
body: _buildPageView(),
|
||||
bottomNavigationBar: _buildBottomNavigationBar(),
|
||||
|
|
|
@ -3,13 +3,11 @@ import 'package:get/get.dart';
|
|||
|
||||
import 'category_controller.dart';
|
||||
|
||||
class CategoryPage extends StatelessWidget {
|
||||
class CategoryPage extends GetView<CategoryController> {
|
||||
const CategoryPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = Get.find<CategoryController>();
|
||||
|
||||
return Container();
|
||||
return Text('Categories');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ class MainController extends GetxController {
|
|||
/// 方法
|
||||
// 拉取数据
|
||||
asyncLoadAllData() async {
|
||||
print('开始拉取数据');
|
||||
state.categories = await newsRepository.categories(cacheDisk: true);
|
||||
state.channels = await newsRepository.channels(cacheDisk: true);
|
||||
// 分类对应的数据(推荐、新闻)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
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/channels.dart';
|
||||
import 'package:news_getx/modules/main/widgets/news_letter.dart';
|
||||
import 'package:news_getx/modules/main/widgets/news_list.dart';
|
||||
import 'package:news_getx/modules/main/widgets/recommend.dart';
|
||||
|
||||
import 'main_controller.dart';
|
||||
|
@ -17,11 +20,11 @@ class MainPage extends GetView<MainController> {
|
|||
Divider(height: 1),
|
||||
NewsRecommendWidget(),
|
||||
Divider(height: 1),
|
||||
Text('NewsChannelsWidget'),
|
||||
NewsChannelsWidget(),
|
||||
Divider(height: 1),
|
||||
Text('NewsListWidget'),
|
||||
NewsListWidget(),
|
||||
Divider(height: 1),
|
||||
Text('NewsletterWidget'),
|
||||
NewsLetterWidget(),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
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/theme/app_borders.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
import 'package:news_getx/theme/app_radii.dart';
|
||||
|
||||
class AdWidget extends GetView<MainController>{
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 100.h,
|
||||
padding: EdgeInsets.all(20.w),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
// border
|
||||
border: Border.fromBorderSide(AppBorders.primaryBorder),
|
||||
borderRadius: Radii.k6pxRadius,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"Tired of Ads? Get Premium - \$9.99",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryText,
|
||||
fontFamily: "Avenir",
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 18.sp,
|
||||
height: 18.sp / 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/channels.dart';
|
||||
import 'package:news_getx/modules/main/main_controller.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
import 'package:news_getx/theme/app_shadows.dart';
|
||||
|
||||
class NewsChannelsWidget extends GetView<MainController> {
|
||||
Widget _buildChannelItem(ChannelResponse item) {
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10),
|
||||
width: 70.w,
|
||||
height: 97.h,
|
||||
child: InkWell(
|
||||
// 没有水波纹 是有原因的 看splashColor文档 主体splashColor是透明纯黑色 所以不显示
|
||||
// splashColor: Colors.cyanAccent,
|
||||
onTap: () {
|
||||
print(item.title);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
// 当 `child` 是图片这种有具体宽高的组件时,
|
||||
// 如果 `Container` 的宽高只设置期中一个,
|
||||
// 则另一个的值会根据 `child` 的宽高比例计算得出,
|
||||
// 如果是大于图片对应的宽高, 则图片原宽高居中显示,
|
||||
// 此时 `Container` 留有空白.
|
||||
// https://juejin.cn/post/7016649859008725022#heading-9
|
||||
Container(
|
||||
width: 64.w,
|
||||
height: 64.w,
|
||||
margin: EdgeInsets.symmetric(horizontal: 3.w),
|
||||
// 之所以设置padding而不是居中对齐
|
||||
// 是因为如果设置居中对齐的话展示的是图片本身的大小,而不是我们需要的内边距大小
|
||||
padding: EdgeInsets.all(10.w),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryBackground,
|
||||
boxShadow: [AppShadows.primaryShadow],
|
||||
borderRadius: BorderRadius.all(Radius.circular(32.w)),
|
||||
),
|
||||
child: Image.asset(
|
||||
"assets/images/channel-${item.code}.png",
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0),
|
||||
child: Text(
|
||||
item.title,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: AppColors.thirdElementText,
|
||||
fontFamily: "Avenir",
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
height: 14.sp / 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(
|
||||
() => controller.state.channels == null
|
||||
? Container()
|
||||
: Container(
|
||||
height: 137.h,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: controller.state.channels!.map<Widget>((item) {
|
||||
return _buildChannelItem(item);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
import 'package:flutter/gestures.dart';
|
||||
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/button.dart';
|
||||
import 'package:news_getx/modules/widgets/input.dart';
|
||||
import 'package:news_getx/modules/widgets/toast.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
|
||||
/// 邮件订阅
|
||||
class NewsLetterWidget extends GetView<MainController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(20.w),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'Newsletter',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: AppColors.thirdElementText,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
alignment: Alignment.centerRight,
|
||||
onPressed: () {},
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: AppColors.thirdElementText,
|
||||
size: 18.sp,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
// email
|
||||
inputEmailEdit(
|
||||
marginTop: 19,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
hintText: "Email",
|
||||
isPassword: false,
|
||||
controller: null,
|
||||
),
|
||||
|
||||
// btn subcrible
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: FlatButton(
|
||||
onPressed: () {},
|
||||
width: 335.w,
|
||||
height: 44.h,
|
||||
fontWeight: FontWeight.w600,
|
||||
title: "Subscribe",
|
||||
),
|
||||
),
|
||||
|
||||
// disc
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 29.h),
|
||||
width: 261.w,
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'By clicking on Subscribe button you agree to accept',
|
||||
style: TextStyle(
|
||||
color: AppColors.thirdElementText,
|
||||
fontFamily: "Avenir",
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Privacy Policy',
|
||||
style: TextStyle(
|
||||
color: AppColors.secondaryElementText,
|
||||
fontFamily: "Avenir",
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
toastInfo(msg: 'Privacy Policy');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:news_getx/data/model/news.dart';
|
||||
import 'package:news_getx/modules/main/main_controller.dart';
|
||||
import 'package:news_getx/modules/main/widgets/ad.dart';
|
||||
import 'package:news_getx/modules/widgets/image.dart';
|
||||
import 'package:news_getx/theme/app_colors.dart';
|
||||
import 'package:news_getx/utils/date.dart';
|
||||
|
||||
/// 新闻行 Item
|
||||
class NewsListWidget extends GetView<MainController> {
|
||||
Widget _buildListItem(NewsItem item) {
|
||||
return Container(
|
||||
height: 161.h,
|
||||
padding: EdgeInsets.all(20.w),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// 左侧图
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// 到详情页
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 121.w,
|
||||
height: 121.w,
|
||||
child: netImageCached(
|
||||
item.thumbnail ?? "",
|
||||
width: 121.w,
|
||||
height: 121.w,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 右侧内容
|
||||
SizedBox(
|
||||
width: 194.w,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 作者
|
||||
Container(
|
||||
margin: EdgeInsets.all(0),
|
||||
child: Text(
|
||||
item.author ?? '',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Avenir',
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.thirdElementText,
|
||||
fontSize: 14.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
// 标题
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// 到详情页
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 10.h),
|
||||
child: Text(
|
||||
item.title ?? '',
|
||||
overflow: TextOverflow.clip,
|
||||
maxLines: 3,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryText,
|
||||
fontSize: 16.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
// 一行 3 列
|
||||
Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
// 分类
|
||||
constraints: BoxConstraints(maxWidth: 60.w),
|
||||
child: Text(
|
||||
item.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: BoxConstraints(maxWidth: 100.w),
|
||||
child: Text(
|
||||
'• ${timeLineFormat(item.addtime ?? DateTime(0))}',
|
||||
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: () {
|
||||
print('查看更多...');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
), ],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 这不是应该用ListView.build吗
|
||||
return Obx(
|
||||
() => controller.state.newsPageList == null
|
||||
? Container()
|
||||
: Column(
|
||||
children:
|
||||
controller.state.newsPageList!.items!.map<Widget>((item) {
|
||||
// 新闻行
|
||||
List<Widget> widgets = [
|
||||
_buildListItem(item),
|
||||
Divider(height: 1),
|
||||
];
|
||||
|
||||
// 每 5 条 显示广告
|
||||
int index = controller.state.newsPageList!.items!.indexOf(item);
|
||||
if ((index + 1) % 5 == 0) {
|
||||
widgets.addAll([
|
||||
AdWidget(),
|
||||
Divider(height: 1),
|
||||
]);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: widgets,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import 'package:news_getx/utils/date.dart';
|
|||
class NewsRecommendWidget extends GetView<MainController> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print(controller.state.newsRecommend?.thumbnail);
|
||||
print('推荐信息:${controller.state.newsRecommend?.thumbnail}');
|
||||
return Obx(
|
||||
() => controller.state.newsRecommend == null
|
||||
? Container()
|
||||
|
@ -93,7 +93,9 @@ class NewsRecommendWidget extends GetView<MainController> {
|
|||
color: AppColors.primaryText,
|
||||
size: 24,
|
||||
),
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
print('查看更多...');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:news_getx/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue