Commit c08a5cd4 authored by 关振斌's avatar 关振斌

uikit

parent 44c8a09d
[
{
"author": {
"firstName": "John",
"id": "4c2307ba-3d40-442f-b1ff-b271f63904ca",
"lastName": "Doe"
},
"createdAt": 1655648404000,
"id": "c67ed376-52bf-4d4e-ba2a-7a0f8467b22a",
"status": "seen",
"text": "Ooowww ☺️",
"type": "text"
},
{
"author": {
"firstName": "Janice",
"id": "e52552f4-835d-4dbe-ba77-b076e659774d",
"imageUrl": "https://i.pravatar.cc/300?u=e52552f4-835d-4dbe-ba77-b076e659774d",
"lastName": "King"
},
"createdAt": 1655648403000,
"height": 1280,
"id": "02797655-4d73-402e-a319-50fde79e2bc4",
"name": "madrid",
"size": 585000,
"status": "seen",
"type": "image",
"uri": "https://source.unsplash.com/WBGjg0DsO_g/1920x1280",
"width": 1920
},
{
"author": {
"firstName": "Janice",
"id": "e52552f4-835d-4dbe-ba77-b076e659774d",
"imageUrl": "https://i.pravatar.cc/300?u=e52552f4-835d-4dbe-ba77-b076e659774d",
"lastName": "King"
},
"createdAt": 1655648402000,
"id": "4e048753-2d60-4144-bc28-9967050aaf12",
"status": "seen",
"text": "What a ~nice~ _wonderful_ sunset! 😻",
"type": "text"
},
{
"author": {
"firstName": "Matthew",
"id": "82091008-a484-4a89-ae75-a22bf8d6f3ac",
"lastName": "White"
},
"createdAt": 1655648401000,
"id": "64747b28-df19-4a0c-8c47-316dc3546e3c",
"status": "seen",
"text": "Here you go buddy! 💪",
"type": "text"
},
{
"author": {
"firstName": "Matthew",
"id": "82091008-a484-4a89-ae75-a22bf8d6f3ac",
"lastName": "White"
},
"createdAt": 1655648400000,
"id": "6a1a4351-cf05-4d0c-9d0f-47ed378b6112",
"mimeType": "application/pdf",
"name": "city_guide-madrid.pdf",
"size": 10550000,
"status": "seen",
"type": "file",
"uri": "https://www.esmadrid.com/sites/default/files/documentos/madrid_imprescindible_2016_ing_web_0.pdf"
},
{
"author": {
"firstName": "John",
"id": "4c2307ba-3d40-442f-b1ff-b271f63904ca",
"lastName": "Doe"
},
"createdAt": 1655624464000,
"id": "38681a33-2563-42aa-957b-cfc12f791d16",
"status": "seen",
"text": "Matt, where is my Madrid guide?",
"type": "text"
},
{
"author": {
"firstName": "Matthew",
"id": "82091008-a484-4a89-ae75-a22bf8d6f3ac",
"lastName": "White"
},
"createdAt": 1655624463000,
"id": "113bb2e8-f74e-42cd-aa30-4085a0f52c58",
"status": "seen",
"text": "Awesome! 😍",
"type": "text"
},
{
"author": {
"firstName": "Janice",
"id": "e52552f4-835d-4dbe-ba77-b076e659774d",
"imageUrl": "https://i.pravatar.cc/300?u=e52552f4-835d-4dbe-ba77-b076e659774d",
"lastName": "King"
},
"createdAt": 1655624462000,
"id": "22212d42-1252-4641-9786-d6f83b2ce4a8",
"status": "seen",
"text": "Matt, what do you think?",
"type": "text"
},
{
"author": {
"firstName": "Janice",
"id": "e52552f4-835d-4dbe-ba77-b076e659774d",
"imageUrl": "https://i.pravatar.cc/300?u=e52552f4-835d-4dbe-ba77-b076e659774d",
"lastName": "King"
},
"createdAt": 1655624461000,
"id": "afc2269a-374b-4382-8864-b3b60d1e8cd7",
"status": "seen",
"text": "Yeah! Together with Demna, Mark Hamill and others 🥰",
"type": "text"
},
{
"author": {
"firstName": "John",
"id": "4c2307ba-3d40-442f-b1ff-b271f63904ca",
"lastName": "Doe"
},
"createdAt": 1655624460000,
"id": "634b2f0b-2486-4bfe-b36d-1c7d6313c7b3",
"status": "seen",
"text": "Guys! Did you know Imagine Dragons became ambassadors for u24.gov.ua ?",
"type": "text"
}
]
PODS:
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_icmp_ping (0.0.1):
- Flutter
......@@ -12,13 +46,21 @@ PODS:
- fluttertoast (0.0.2):
- Flutter
- Toast
- image_picker_ios (0.0.1):
- Flutter
- open_filex (0.0.2):
- Flutter
- OrderedSet (5.0.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SDWebImage (5.15.2):
- SDWebImage/Core (= 5.15.2)
- SDWebImage/Core (5.15.2)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.4)
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
......@@ -26,10 +68,13 @@ PODS:
- Flutter
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
......@@ -37,10 +82,16 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- OrderedSet
- SDWebImage
- SwiftyGif
- Toast
EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_icmp_ping:
......@@ -49,6 +100,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
open_filex:
:path: ".symlinks/plugins/open_filex/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios"
shared_preferences_foundation:
......@@ -59,13 +114,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
SPEC CHECKSUMS:
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_icmp_ping: 2b159955eee0c487c766ad83fec224ae35e7c935
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
SDWebImage: 8ab87d4b3e5cc4927bd47f78db6ceb0b94442577
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: fb12c43172927bb5cf75aeebd073f883801f1993
webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f
......
......@@ -10,4 +10,5 @@ class AppStrings {
static const String isFirstOpen = "IS_FIRST_OPEN";
static const String openDoor = '开启加速服务';
static const String crispWebsiteId = 'b7b8fcd4-9857-42b7-a39d-51fb4930130d';
static const String logName = "login";
}
class AppUrls {
static const String baseUrl = 'https://dns.github.bet'; // 基础接口地址
static const String baseApiUrl = '$baseUrl/api/v1'; // 基础接口地址
static const String baseUrl = 'http://1.12.240.104:8081'; // 基础接口地址
static const String baseApiUrl = '$baseUrl'; // 基础接口地址
static const String login = '$baseApiUrl/passport/auth/login';
static const String register = '$baseApiUrl/passport/auth/register';
static const String getQuickLoginUrl = '$baseApiUrl/passport/auth/getQuickLoginUrl';
static const String getQuickLoginUrl =
'$baseApiUrl/passport/auth/getQuickLoginUrl';
static const String userSubscribe = '$baseApiUrl/user/getSubscribe';
static const String plan = '$baseApiUrl/guest/plan/fetch';
static const String server = '$baseApiUrl/user/server/fetch';
static const String userInfo = '$baseApiUrl/user/info';
static const String message = '$baseApiUrl/openAi/aiAnswer';
}
// To parse this JSON data, do
//
// final loginEntity = loginEntityFromMap(jsonString);
import 'dart:convert';
class LoginEntity {
LoginEntity({
required this.token,
required this.authData,
});
final String token;
final String authData;
factory LoginEntity.fromJson(String str) => LoginEntity.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory LoginEntity.fromMap(Map<String, dynamic> json) => LoginEntity(
token: json["token"],
authData: json["auth_data"],
);
Map<String, dynamic> toMap() => {
"token": token,
"auth_token": authData,
};
}
// To parse this JSON data, do
//
// final planEntity = planEntityFromMap(jsonString);
import 'package:meta/meta.dart';
import 'dart:convert';
List<PlanEntity> planEntityFromList(List data) => List<PlanEntity>.from(data.map((x) => PlanEntity.fromMap(x)));
class PlanEntity {
PlanEntity({
required this.id,
required this.groupId,
required this.transferEnable,
required this.name,
required this.show,
@required this.sort,
required this.renew,
required this.content,
@required this.monthPrice,
@required this.quarterPrice,
@required this.halfYearPrice,
@required this.yearPrice,
@required this.twoYearPrice,
@required this.threeYearPrice,
@required this.onetimePrice,
@required this.resetPrice,
required this.createdAt,
required this.updatedAt,
});
final int id;
final int groupId;
final int transferEnable;
final String name;
final int show;
final dynamic sort;
final int renew;
final String content;
final dynamic monthPrice;
final dynamic quarterPrice;
final dynamic halfYearPrice;
final dynamic yearPrice;
final dynamic twoYearPrice;
final dynamic threeYearPrice;
final dynamic onetimePrice;
final dynamic resetPrice;
final DateTime? createdAt;
final DateTime? updatedAt;
factory PlanEntity.fromJson(String str) => PlanEntity.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory PlanEntity.fromMap(Map<String, dynamic> json) => PlanEntity(
id: json["id"],
groupId: json["group_id"],
transferEnable: json["transfer_enable"],
name: json["name"],
show: json["show"],
sort: json["sort"],
renew: json["renew"],
content: json["content"],
monthPrice: json["month_price"],
quarterPrice: json["quarter_price"],
halfYearPrice: json["half_year_price"],
yearPrice: json["year_price"],
twoYearPrice: json["two_year_price"],
threeYearPrice: json["three_year_price"],
onetimePrice: json["onetime_price"],
resetPrice: json["reset_price"],
createdAt: json["created_at"] == null ? null : DateTime.fromMillisecondsSinceEpoch(json["created_at"] * 1000),
updatedAt: json["updated_at"] == null ? null : DateTime.fromMillisecondsSinceEpoch(json["updated_at"] * 1000),
);
Map<String, dynamic> toMap() => {
"id": id,
"group_id": groupId,
"transfer_enable": transferEnable,
"name": name,
"show": show,
"sort": sort,
"renew": renew,
"content": content,
"month_price": monthPrice,
"quarter_price": quarterPrice,
"half_year_price": halfYearPrice,
"year_price": yearPrice,
"two_year_price": twoYearPrice,
"three_year_price": threeYearPrice,
"onetime_price": onetimePrice,
"reset_price": resetPrice,
"created_at": createdAt == null ? null : createdAt!.millisecondsSinceEpoch ~/ 1000,
"updated_at": updatedAt == null ? null : updatedAt!.millisecondsSinceEpoch ~/ 1000,
};
}
// To parse this JSON data, do
//
// final serverEntity = serverEntityFromMap(jsonString);
import 'dart:convert';
List<ServerEntity> serverEntityFromList(List<dynamic> data) =>
List<ServerEntity>.from(data.map((x) => ServerEntity.fromMap((x))));
class ServerEntity {
ServerEntity({
required this.id,
required this.groupId,
required this.parentId,
required this.tags,
required this.name,
required this.rate,
required this.host,
required this.port,
required this.serverPort,
required this.cipher,
required this.show,
required this.sort,
required this.createdAt,
required this.updatedAt,
required this.type,
required this.lastCheckAt,
});
final int id;
final List<String> groupId;
final int parentId;
final List<String> tags;
final String name;
final String rate;
final String host;
final int port;
final int serverPort;
final String cipher;
final int show;
final int sort;
Duration? ping;
final int createdAt;
final int updatedAt;
final String type;
final String lastCheckAt;
factory ServerEntity.fromJson(String str) => ServerEntity.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory ServerEntity.fromMap(Map<String, dynamic> json) => ServerEntity(
id: json["id"],
groupId: List<String>.from(json["group_id"]?.map((x) => x) ?? []),
parentId: json["parent_id"],
tags: List<String>.from(json["tags"]?.map((x) => x) ?? []),
name: json["name"],
rate: json["rate"],
host: json["host"],
port: json["port"],
serverPort: json["server_port"],
cipher: json["cipher"],
show: json["show"],
sort: json["sort"],
createdAt: json["created_at"],
updatedAt: json["updated_at"],
type: json["type"],
lastCheckAt: json["last_check_at"],
);
Map<String, dynamic> toMap() => {
"id": id,
"group_id": List<dynamic>.from(groupId.map((x) => x)),
"parent_id": parentId,
"tags": List<dynamic>.from(tags.map((x) => x)),
"name": name,
"rate": rate,
"host": host,
"port": port,
"server_port": serverPort,
"cipher": cipher,
"show": show,
"sort": sort,
"created_at": createdAt,
"updated_at": updatedAt,
"type": type,
"last_check_at": lastCheckAt,
};
}
// To parse this JSON data, do
//
// final userEntity = userEntityFromMap(jsonString);
import 'package:meta/meta.dart';
import 'dart:convert';
class UserEntity {
UserEntity({
required this.email,
required this.transferEnable,
required this.lastLoginAt,
required this.createdAt,
required this.banned,
required this.remindExpire,
required this.remindTraffic,
required this.expiredAt,
required this.balance,
required this.commissionBalance,
required this.planId,
@required this.discount,
@required this.commissionRate,
@required this.telegramId,
required this.uuid,
required this.avatarUrl,
});
final String email;
final int transferEnable;
final DateTime? lastLoginAt;
final DateTime? createdAt;
final int banned;
final int remindExpire;
final int remindTraffic;
final DateTime? expiredAt;
final int balance;
final int commissionBalance;
final int planId;
final dynamic discount;
final dynamic commissionRate;
final dynamic telegramId;
final String uuid;
final String avatarUrl;
factory UserEntity.fromJson(String str) => UserEntity.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory UserEntity.fromMap(Map<String, dynamic> json) => UserEntity(
email: json["email"],
transferEnable: json["transfer_enable"],
lastLoginAt: json["last_login_at"] == null ? null : DateTime.fromMillisecondsSinceEpoch(json["last_login_at"] * 1000),
createdAt: json["created_at"] == null ? null : DateTime.fromMillisecondsSinceEpoch(json["created_at"] * 1000),
banned: json["banned"],
remindExpire: json["remind_expire"],
remindTraffic: json["remind_traffic"],
expiredAt: json["expired_at"] == null ? null : DateTime.fromMillisecondsSinceEpoch(json["expired_at"] * 1000),
balance: json["balance"],
commissionBalance: json["commission_balance"],
planId: json["plan_id"],
discount: json["discount"],
commissionRate: json["commission_rate"],
telegramId: json["telegram_id"],
uuid: json["uuid"],
avatarUrl: json["avatar_url"],
);
Map<String, dynamic> toMap() => {
"email": email,
"transfer_enable": transferEnable,
"last_login_at": lastLoginAt == null ? null : lastLoginAt!.millisecondsSinceEpoch ~/ 1000,
"created_at": createdAt == null ? null : createdAt!.millisecondsSinceEpoch ~/ 1000,
"banned": banned,
"remind_expire": remindExpire,
"remind_traffic": remindTraffic,
"expired_at": expiredAt == null ? null : expiredAt!.millisecondsSinceEpoch ~/ 1000,
"balance": balance,
"commission_balance": commissionBalance,
"plan_id": planId,
"discount": discount,
"commission_rate": commissionRate,
"telegram_id": telegramId,
"uuid": uuid,
"avatar_url": avatarUrl,
};
}
// To parse this JSON data, do
//
// final userSubscribeEntity = userSubscribeEntityFromMap(jsonString);
import 'package:meta/meta.dart';
import 'dart:convert';
class UserSubscribeEntity {
UserSubscribeEntity({
required this.planId,
required this.token,
required this.expiredAt,
required this.u,
required this.d,
required this.transferEnable,
required this.email,
required this.plan,
required this.subscribeUrl,
required this.resetDay,
});
final int planId;
final String token;
final int expiredAt;
final int u;
final int d;
final int transferEnable;
final String email;
final Plan plan;
final String subscribeUrl;
final int resetDay;
factory UserSubscribeEntity.fromJson(String str) => UserSubscribeEntity.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory UserSubscribeEntity.fromMap(Map<String, dynamic> json) => UserSubscribeEntity(
planId: json["plan_id"],
token: json["token"],
expiredAt: json["expired_at"],
u: json["u"],
d: json["d"],
transferEnable: json["transfer_enable"],
email: json["email"],
plan: Plan.fromMap(json["plan"]),
subscribeUrl: json["subscribe_url"],
resetDay: json["reset_day"],
);
Map<String, dynamic> toMap() => {
"plan_id": planId,
"token": token,
"expired_at": expiredAt,
"u": u,
"d": d,
"transfer_enable": transferEnable,
"email": email,
"plan": plan.toMap(),
"subscribe_url": subscribeUrl,
"reset_day": resetDay,
};
}
class Plan {
Plan({
required this.id,
required this.groupId,
required this.transferEnable,
required this.name,
required this.show,
required this.sort,
required this.renew,
required this.content,
required this.monthPrice,
required this.quarterPrice,
required this.halfYearPrice,
required this.yearPrice,
@required this.twoYearPrice,
@required this.threeYearPrice,
@required this.onetimePrice,
required this.resetPrice,
required this.resetTrafficMethod,
required this.createdAt,
required this.updatedAt,
});
final int id;
final int groupId;
final int transferEnable;
final String name;
final int show;
final int sort;
final int renew;
final String content;
final int monthPrice;
final int quarterPrice;
final int halfYearPrice;
final int yearPrice;
final dynamic twoYearPrice;
final dynamic threeYearPrice;
final dynamic onetimePrice;
final int resetPrice;
final int resetTrafficMethod;
final int createdAt;
final int updatedAt;
factory Plan.fromJson(String str) => Plan.fromMap(json.decode(str));
String toJson() => json.encode(toMap());
factory Plan.fromMap(Map<String, dynamic> json) => Plan(
id: json["id"],
groupId: json["group_id"],
transferEnable: json["transfer_enable"],
name: json["name"],
show: json["show"],
sort: json["sort"],
renew: json["renew"],
content: json["content"],
monthPrice: json["month_price"],
quarterPrice: json["quarter_price"],
halfYearPrice: json["half_year_price"],
yearPrice: json["year_price"],
twoYearPrice: json["two_year_price"],
threeYearPrice: json["three_year_price"],
onetimePrice: json["onetime_price"],
resetPrice: json["reset_price"],
resetTrafficMethod: json["reset_traffic_method"],
createdAt: json["created_at"],
updatedAt: json["updated_at"],
);
Map<String, dynamic> toMap() => {
"id": id,
"group_id": groupId,
"transfer_enable": transferEnable,
"name": name,
"show": show,
"sort": sort,
"renew": renew,
"content": content,
"month_price": monthPrice,
"quarter_price": quarterPrice,
"half_year_price": halfYearPrice,
"year_price": yearPrice,
"two_year_price": twoYearPrice,
"three_year_price": threeYearPrice,
"onetime_price": onetimePrice,
"reset_price": resetPrice,
"reset_traffic_method": resetTrafficMethod,
"created_at": createdAt,
"updated_at": updatedAt,
};
}
......@@ -9,7 +9,7 @@ import 'package:chart/models/base_model.dart';
class AppModel extends BaseModel {
// VpnManager vpnManager = VpnManager();
// bool isOn = false;
bool isOn = false;
// PageController pageController = PageController(initialPage: 0);
// String appTitle = 'Sail';
// Config config = Config();
......
import 'package:chart/constant/app_strings.dart';
import 'package:chart/entity/login_entity.dart';
import 'package:chart/entity/user_entity.dart';
import 'package:chart/models/base_model.dart';
import 'package:chart/utils/navigator_util.dart';
import 'package:chart/utils/shared_preferences_util.dart';
class UserModel extends BaseModel {
late String _token;
late String _authData;
late UserEntity? _userEntity;
late bool _isFirstOpen;
bool _isLogin = false;
String get token => _token;
String get authData => _authData;
UserEntity? get userEntity => _userEntity;
bool get isFirstOpen => _isFirstOpen;
bool get isLogin => _isLogin;
Future<void> checkHasLogin(context, Function callback) async {
if (!isLogin) {
NavigatorUtil.goLogin(context);
} else {
return callback();
}
}
refreshData() async {
_isFirstOpen = await SharedPreferencesUtil.getInstance()
?.getBool(AppStrings.isFirstOpen) ??
true;
String token = await SharedPreferencesUtil.getInstance()
?.getString(AppStrings.token) ??
'';
String authData = await SharedPreferencesUtil.getInstance()
?.getString(AppStrings.authData) ??
'';
if (token != null &&
token.isNotEmpty &&
authData != null &&
authData.isNotEmpty) {
_isLogin = true;
_token = token;
_authData = authData;
Map<String, dynamic> userEntityMap =
await SharedPreferencesUtil.getInstance()
?.getMap(AppStrings.userInfo) ??
<String, dynamic>{};
_userEntity = UserEntity.fromMap(userEntityMap);
notifyListeners();
}
}
logout() {
SharedPreferencesUtil? sharedPreferencesUtil =
SharedPreferencesUtil.getInstance();
sharedPreferencesUtil?.clear();
setIsFirstOpen(false);
refreshData();
}
_saveIsFirstOpen() {
SharedPreferencesUtil.getInstance()
?.setBool(AppStrings.isFirstOpen, _isFirstOpen);
}
_saveUserToken(LoginEntity loginEntity) async {
SharedPreferencesUtil? sharedPreferencesUtil =
SharedPreferencesUtil.getInstance();
await sharedPreferencesUtil?.setString(AppStrings.token, loginEntity.token);
}
_setUserAuthData(LoginEntity loginEntity) async {
SharedPreferencesUtil? sharedPreferencesUtil =
SharedPreferencesUtil.getInstance();
await sharedPreferencesUtil?.setString(
AppStrings.authData, loginEntity.authData);
}
_saveUserInfo() async {
SharedPreferencesUtil? sharedPreferencesUtil =
SharedPreferencesUtil.getInstance();
await sharedPreferencesUtil?.setMap(
AppStrings.userInfo, _userEntity?.toMap());
}
setIsFirstOpen(bool isFirstOpen) {
_isFirstOpen = isFirstOpen;
_saveIsFirstOpen();
}
setToken(LoginEntity loginEntity) {
_token = loginEntity.token;
_authData = loginEntity.authData;
_isLogin = true;
_saveUserToken(loginEntity);
_setUserAuthData(loginEntity);
}
setUserInfo(UserEntity? userEntity) {
_userEntity = userEntity;
_saveUserInfo();
}
}
import 'package:flutter/material.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/constant/app_dimens.dart';
import 'package:chart/constant/app_images.dart';
import 'package:chart/constant/app_strings.dart';
import 'package:chart/models/user_model.dart';
import 'package:chart/utils/navigator_util.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
class GuidePage extends StatefulWidget {
const GuidePage({Key? key}) : super(key: key);
@override
GuidePageState createState() => GuidePageState();
}
class GuidePageState extends State<GuidePage> {
var guides = [AppImages.guide1, AppImages.guide2, AppImages.guide3];
var _showButton = false;
@override
Widget build(BuildContext context) {
UserModel().setIsFirstOpen(false);
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
_guideWidget(),
Positioned(
right: ScreenUtil().setWidth(30),
bottom: ScreenUtil().setHeight(30),
child: Offstage(
offstage: !_showButton,
child: Center(
child: TextButton(
style: TextButton.styleFrom(
primary: AppColors.themeColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30))),
),
onPressed: () {
NavigatorUtil.goHomePage(context);
},
child: const Text(AppStrings.openDoor,
style: TextStyle(fontSize: AppDimens.bigTextSize)),
)),
)),
],
));
}
Widget _guideWidget() {
return Swiper(
itemCount: guides.length,
//item数量
scrollDirection: Axis.horizontal,
//滚动方向 设置为Axis.vertical如果需要垂直滚动
itemBuilder: (BuildContext context, int index) {
return Image.asset(
guides[index],
fit: BoxFit.fill,
width: double.infinity,
height: double.infinity,
);
},
autoplay: false,
//自动滚动
loop: false,
//循环滚动
pagination: const SwiperPagination(
alignment: Alignment.bottomCenter,
builder: DotSwiperPaginationBuilder(
activeColor: Color(0xFFFF5722), //选中的颜色
color: Color(0xFF999999), //非选中的颜色
)),
onIndexChanged: ((value) {
//图片数组下标变化监听
if (value == guides.length - 1) {
setState(() {
_showButton = true;
});
} else if (_showButton && value != guides.length - 1) {
//减少非必要的setState 只有当滑动到最后一张图片然后向做滑动的时候触发
setState(() {
_showButton = false;
});
}
}),
);
}
}
This diff is collapsed.
// import 'package:flutter/cupertino.dart';
// import 'package:chart/constant/app_dimens.dart';
// import 'package:chart/pages/guide/guide_page.dart';
// import 'package:chart/models/user_model.dart';
// import 'package:flutter_screenutil/flutter_screenutil.dart';
// import 'package:provider/provider.dart';
// import 'home_page.dart';
// class MainPage extends StatefulWidget {
// const MainPage({Key? key}) : super(key: key);
// @override
// MainPageState createState() => MainPageState();
// }
// class MainPageState extends State<MainPage> {
// @override
// Widget build(BuildContext context) {
// UserModel userViewModel = Provider.of<UserModel>(context);
// ScreenUtil.init(context,
// designSize: const Size(AppDimens.maxWidth, AppDimens.maxHeight));
// return userViewModel.isFirstOpen
// ? const GuidePage()
// : const HomePage(
// title: "hello world",
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:chart/constant/app_strings.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewWidget extends StatefulWidget {
final String? url;
final String? name;
const WebViewWidget({Key? key, this.url, this.name}) : super(key: key);
@override
WebViewWidgetState createState() => WebViewWidgetState();
}
class WebViewWidgetState extends State<WebViewWidget> {
late WebViewController controller;
final String _javaScript = '''
const styles = `
#page-header {
display: none;
}
#main-container {
padding-top: 0 !important;
}
`
const styleSheet = document.createElement("style")
styleSheet.innerText = styles
document.head.appendChild(styleSheet)
''';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.name!),
centerTitle: true,
),
body: WebView(
initialUrl: "http://1.12.240.104:8081/",
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) => this.controller = controller,
onPageFinished: (url) {
print('url=$url');
controller.runJavascript(_javaScript);
},
),
);
}
}
......@@ -6,7 +6,14 @@ import 'package:chart/pages/login/login_page.dart';
// import 'package:sail/pages/plan/plan_page.dart';
// import 'package:sail/pages/server_list.dart';
// import 'package:sail/pages/webview_widget.dart';
import 'dart:convert';
// import 'package:chart/pages/home/main_page.dart';
// import 'dart:convert';
/// 入口
// Handler rootHandler = Handler(
// handlerFunc: (BuildContext? context, Map<String, List<String>> parameters) {
// return const MainPage();
// });
/// 登录页
Handler loginHandler = Handler(
......@@ -14,10 +21,10 @@ Handler loginHandler = Handler(
return const LoginPage(title: '登陆页');
});
/// 入口
/// 首页
Handler homeHandler = Handler(
handlerFunc: (BuildContext? context, Map<String, List<String>> parameters) {
return const HomePage(title: '首页');
return const HomePage();
});
/// 404页面
......
import 'package:chart/constant/app_urls.dart';
import 'package:chart/entity/plan_entity.dart';
import 'package:chart/utils/http_util.dart';
// data
// :
// "\n\nvOU2HR bbc com male dating services in st john jalandharwali KIDbT0 A9JmEG N8fEjw\n\ngfCRx1 seek com au adult dating and browse sites ‘arabkhel 2M2Qja\n\nYco4nZ 4c6V5a\n\nbjU6q5 espn com dating discussion board gbessavassou dYTPpW fGxmi7 lPpCmr\n\niyI1fQ commbank com au dating people online in lansing michigan n'tamana SECab7 h27lyd nvV8rl\n\n2SKO51 auspost com au adult singles dating juliette georgia kirkham rE2Uv3\n\n5LtaNf Lg9ClR\n\nRibGpH google ca flirt with women in sherbrooke chilongozi ConGpl swazsg yrivXK\n\nEx1q3d 9news com au adult singles dating marquette iowa xizhongtaidong 5bTdfT 7XfJBG X92AxF\n\n0ocF78 weather com dating dude omaha kolpino Oi08sn\n\nebLtGk SpGHKd\n\nAvUNRS xvideos com adult dating search oxnard sampiranpur suLHAy 5XeyzB OovFcO\n\nOLHfmu news yahoo co jp find adult friends burlington niufulu S2kXV7 Hvfdyn 09E90V\n\nKESxlr indeed co uk private fick treffen in deutschland 6 terriatui Anogru\n\nwkVgLF oEA5x6\n\nU6E"
// message
// :
// "操作成功"
// status
// :
// 200
// timestamp
// :
// 1675887721437
// class MessageEntity {
// late final String data;
// late final String message;
// late final int status;
// late final int timestamp;
// }
class MessageService {
// ?question=321321
// static const String message = '$baseApiUrl/openAi/aiAnswer';
Future<String>? getMessage(String message) {
return HttpUtil.instance
?.get("${AppUrls.message}?question=$message")
.then((result) {
return result['data'];
});
}
}
import 'package:chart/constant/app_urls.dart';
import 'package:chart/entity/plan_entity.dart';
import 'package:chart/utils/http_util.dart';
class PlanService {
Future<List<PlanEntity>>? plan() {
return HttpUtil.instance?.get(AppUrls.plan).then((result) {
return planEntityFromList(result['data']);
});
}
Future<PlanEntity>? planDetail(int id) {
return HttpUtil.instance
?.get(AppUrls.plan, parameters: {'id': id}).then((result) {
return PlanEntity.fromMap(result['data']);
});
}
}
import 'package:chart/constant/app_urls.dart';
import 'package:chart/entity/server_entity.dart';
import 'package:chart/utils/http_util.dart';
class ServerService {
Future<List<ServerEntity>>? server() {
return HttpUtil.instance?.get(AppUrls.server).then((result) {
return serverEntityFromList(result['data']);
});
}
}
import 'package:chart/constant/app_urls.dart';
import 'package:chart/entity/login_entity.dart';
import 'package:chart/entity/user_entity.dart';
import 'package:chart/entity/user_subscribe_entity.dart';
import 'package:chart/utils/http_util.dart';
class UserService {
Future<LoginEntity>? login(Map<String, dynamic> parameters) {
return HttpUtil.instance
?.post(AppUrls.login, parameters: parameters)
.then((result) {
return LoginEntity.fromMap(result['data']);
});
}
Future<String>? getQuickLoginUrl(Map<String, dynamic> parameters) {
return HttpUtil.instance
?.post(AppUrls.getQuickLoginUrl, parameters: parameters)
.then((result) {
return result['data'];
});
}
Future<bool>? register(parameters) {
return HttpUtil.instance
?.post(AppUrls.register, parameters: parameters)
.then((result) {
return result['data'];
});
}
Future<UserSubscribeEntity>? userSubscribe() {
return HttpUtil.instance?.get(AppUrls.userSubscribe).then((result) {
return UserSubscribeEntity.fromMap(result['data']);
});
}
Future<UserEntity>? info() {
return HttpUtil.instance?.get(AppUrls.userInfo).then((result) {
return UserEntity.fromMap(result['data']);
});
}
}
import 'dart:core' as core;
import 'package:flutter/foundation.dart';
void print (core.Object object) {
if (kDebugMode) {
core.print(object);
}
}
import 'package:dio/dio.dart';
import 'package:chart/constant/app_strings.dart';
import 'package:chart/router/application.dart';
import 'package:chart/router/routers.dart';
import 'package:chart/utils/common_util.dart';
import 'package:chart/utils/shared_preferences_util.dart';
class HttpUtil {
// 工厂模式
static HttpUtil? get instance => _getInstance();
static HttpUtil? _httpUtil;
late Dio dio;
static HttpUtil? _getInstance() {
_httpUtil ??= HttpUtil();
return _httpUtil;
}
HttpUtil() {
BaseOptions options = BaseOptions(
connectTimeout: 60000,
receiveTimeout: 60000,
);
dio = Dio(options);
dio.interceptors
.add(InterceptorsWrapper(onRequest: (options, handler) async {
print("========================请求数据===================");
print("url=${options.uri.toString()}");
print("headers=${options.headers}");
print("params=${options.data}");
//如果token存在在请求参数加上token
await SharedPreferencesUtil.getInstance()
?.getString(AppStrings.token)
.then((token) {
if (token != null) {
options.queryParameters[AppStrings.token] = token;
print("token=$token");
}
});
//如果auth_data存在在请求参数加上auth_data
await SharedPreferencesUtil.getInstance()
?.getString(AppStrings.authData)
.then((authData) {
if (authData != null) {
options.queryParameters[AppStrings.authData] = authData;
print("authData=$authData");
}
});
return handler.next(options);
}, onResponse: (response, handler) {
print("========================请求数据===================");
print("code=${response.statusCode}");
print("response=${response.data}");
// if (response.statusCode! < 200 || response.statusCode! >= 300) {
// if (response.statusCode == 403) {
// Application.navigatorKey.currentState?.pushNamed(Routers.login);
// }
// return handler.reject(DioError(
// requestOptions: response.requestOptions,
// response: response,
// type: DioErrorType.response));
// }
return handler.next(response);
}, onError: (error, handler) {
print("========================请求错误===================");
print("message =${error.message}");
print("code=${error.response?.statusCode}");
print("response=${error.response?.data}");
return handler.next(error);
}));
}
//get请求
Future get(String url,
{Map<String, dynamic>? parameters, Options? options}) async {
Response response;
if (parameters != null && options != null) {
response =
await dio.get(url, queryParameters: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.get(url, queryParameters: parameters);
} else if (parameters == null && options != null) {
response = await dio.get(url, options: options);
} else {
response = await dio.get(url);
}
return response.data;
}
//post请求
Future post(String url,
{Map<String, dynamic>? parameters, Options? options}) async {
Response response;
if (parameters != null && options != null) {
response = await dio.post(url, data: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.post(url, data: parameters);
} else if (parameters == null && options != null) {
response = await dio.post(url, options: options);
} else {
response = await dio.post(url);
}
return response.data;
}
//put请求
Future put(String url,
{Map<String, dynamic>? parameters, Options? options}) async {
Response response;
if (parameters != null && options != null) {
response = await dio.put(url, data: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.put(url, data: parameters);
} else if (parameters == null && options != null) {
response = await dio.put(url, options: options);
} else {
response = await dio.put(url);
}
return response.data;
}
//delete请求
Future delete(String url,
{Map<String, dynamic>? parameters, Options? options}) async {
Response response;
if (parameters != null && options != null) {
response = await dio.delete(url, data: parameters, options: options);
} else if (parameters != null && options == null) {
response = await dio.delete(url, data: parameters);
} else if (parameters == null && options != null) {
response = await dio.delete(url, options: options);
} else {
response = await dio.delete(url);
}
return response.data;
}
}
import 'dart:convert';
import 'package:fluro/fluro.dart';
import 'package:flutter/cupertino.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
// import 'package:chart/pages/crisp_page.dart';
// import 'package:chart/pages/plan/plan_page.dart';
// import 'package:chart/pages/server_list.dart';
import 'package:chart/router/application.dart';
import 'package:chart/router/routers.dart';
class NavigatorUtil {
// static goMainPage(BuildContext context) {
// Application.router?.navigateTo(context, Routers.root,
// transition: TransitionType.inFromRight, replace: true);
// }
// static goGuidePage(BuildContext context) {
// Application.router?.navigateTo(context, Routers.guide,
// transition: TransitionType.inFromRight, replace: true);
// }
static goHomePage(BuildContext context) {
Application.router?.navigateTo(context, Routers.home,
transition: TransitionType.inFromRight, replace: true);
}
static goLogin(BuildContext context) {
Application.router?.navigateTo(context, Routers.login,
transition: TransitionType.inFromRight, replace: true);
}
static goPlan(BuildContext context) {
// showCupertinoModalBottomSheet(
// context: context,
// builder: (context) => const PlanPage()
// );
// Application.router.navigateTo(context, Routers.plan,
// transition: TransitionType.inFromRight);
}
static goServerList(BuildContext context) {
// showCupertinoModalBottomSheet(
// context: context,
// builder: (context) => const ServerListPage()
// );
// Application.router.navigateTo(context, Routers.serverList,
// transition: TransitionType.inFromRight);
}
static goToCrisp(BuildContext context) {
// showCupertinoModalBottomSheet(
// context: context,
// builder: (context) => const CrispPage()
// );
}
static goWebView(BuildContext context, String titleName, String url) {
String encodeUrl = Uri.encodeComponent(jsonEncode(url));
String encodeTitleName = Uri.encodeComponent(jsonEncode(titleName));
return Application.router?.navigateTo(
context, "${Routers.webView}?titleName=$encodeTitleName&url=$encodeUrl",
transition: TransitionType.inFromRight);
}
static goBack(BuildContext context) {
Application.router?.pop(context);
}
}
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesUtil {
SharedPreferencesUtil._();
static SharedPreferencesUtil? _instance;
late SharedPreferences sharedPreferences;
static SharedPreferencesUtil? getInstance() {
_instance ??= SharedPreferencesUtil._();
return _instance;
}
static saveData<T>(String key, T value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
switch (T) {
case String:
prefs.setString(key, value as String);
break;
case int:
prefs.setInt(key, value as int);
break;
case bool:
prefs.setBool(key, value as bool);
break;
case double:
prefs.setDouble(key, value as double);
break;
}
}
static Future<T?> getData<T>(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
T? res;
switch (T) {
case String:
res = prefs.getString(key) as T;
break;
case int:
res = prefs.getInt(key) as T;
break;
case bool:
res = prefs.getBool(key) as T;
break;
case double:
res = prefs.getDouble(key) as T;
break;
}
return res;
}
Future<bool> setBool(String tag, bool isFirst) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.setBool(tag, isFirst);
}
Future<bool> setString(String tag, String data) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.setString(tag, data);
}
Future<bool> setMap(String tag, Map<String, dynamic>? data) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.setString(tag, jsonEncode(data));
}
Future<bool> setList(String tag, List<dynamic>? data) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.setString(tag, jsonEncode(data));
}
Future<bool?> getBool(String tag) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.getBool(tag);
}
Future<String?> getString(String tag) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.getString(tag);
}
Future<Map<String, dynamic>> getMap(String tag) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return jsonDecode(sharedPreferences.getString(tag) ?? '{}');
}
Future<List<dynamic>> getList(String tag) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return jsonDecode(sharedPreferences.getString(tag) ?? '[]');
}
Future<bool> clear() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.clear();
}
}
class TransferUtil {
double _transfer = 0;
int _level = 0;
List suffix = [
'B',
'KB',
'MB',
'GB',
'TB',
'PB'
];
String toHumanReadable(int transfer) {
_transfer = transfer.toDouble();
handleTransfer();
return '${_transfer.toStringAsFixed(2)} ${suffix[_level]}';
}
handleTransfer() {
if (_transfer > 1024) {
_transfer = _transfer / 1024;
++_level;
handleTransfer();
}
}
}
import 'package:flutter/material.dart';
// import 'package:flutter_icons/flutter_icons.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/models/user_model.dart';
import 'package:chart/utils/navigator_util.dart';
class ConnectionStats extends StatefulWidget {
const ConnectionStats({Key? key}) : super(key: key);
@override
ConnectionStatsState createState() => ConnectionStatsState();
}
class ConnectionStatsState extends State<ConnectionStats> {
late UserModel _userModel;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_userModel = Provider.of<UserModel>(context);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text("00:15:02",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 40,
color: AppColors.grayColor,
)),
Padding(
padding: EdgeInsets.symmetric(horizontal: ScreenUtil().setWidth(75)),
child: TextButton(
onPressed: () => _userModel.checkHasLogin(
context, () => NavigatorUtil.goServerList(context)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
// Icon(MaterialCommunityIcons.map_marker,
// color: AppColors.grayColor, size: 20),
Text("其他节点",
style: TextStyle(
fontSize: 12, color: AppColors.grayColor)),
Icon(Icons.chevron_right,
color: AppColors.grayColor, size: 20)
])),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil().setWidth(75), vertical: 10),
child: Row(
children: [
// Download Stats
Row(children: [
// Download Icon
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Color(0xffff0000),
blurRadius: 13,
spreadRadius: -2)
],
color: const Color(0xffff0000),
borderRadius: BorderRadius.circular(13)),
padding: const EdgeInsets.all(5),
child: const Icon(
Icons.arrow_downward,
color: Colors.white,
),
),
// Labels
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"下行速度",
style: TextStyle(
color: AppColors.grayColor,
fontWeight: FontWeight.w500),
),
RichText(
text: const TextSpan(
style: TextStyle(
color: AppColors.grayColor,
fontWeight: FontWeight.w900),
children: [
TextSpan(text: "75.9"),
TextSpan(
text: " KB/s",
style:
TextStyle(fontWeight: FontWeight.normal)),
]),
)
],
),
)
]),
Expanded(child: Container()),
// Upload Stats
Row(children: [
// Upload Icon
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Color(0xff03a305),
blurRadius: 13,
spreadRadius: -2)
],
color: const Color(0xff03a305),
borderRadius: BorderRadius.circular(13)),
padding: const EdgeInsets.all(5),
child: const Icon(
Icons.arrow_upward,
color: Colors.white,
),
),
// Labels
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"上行速度",
style: TextStyle(
color: AppColors.grayColor,
fontWeight: FontWeight.w500),
),
RichText(
text: const TextSpan(
style: TextStyle(
color: AppColors.grayColor,
fontWeight: FontWeight.w900),
children: [
TextSpan(text: "29.6"),
TextSpan(
text: " KB/s",
style:
TextStyle(fontWeight: FontWeight.normal)),
]),
)
],
),
)
]),
],
),
)
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/entity/plan_entity.dart';
import 'package:chart/models/app_model.dart';
import 'package:chart/models/user_model.dart';
// import 'package:chart/models/user_subscribe_model.dart';
import 'package:chart/service/plan_service.dart';
import 'package:chart/widgets/connection_stats.dart';
import 'package:chart/widgets/logo_bar.dart';
import 'package:chart/widgets/my_subscribe.dart';
import 'package:chart/widgets/plan_list.dart';
import 'package:chart/widgets/select_location.dart';
class HomeWidget extends StatefulWidget {
const HomeWidget({Key? key}) : super(key: key);
@override
HomeWidgetState createState() => HomeWidgetState();
}
class HomeWidgetState extends State<HomeWidget>
with AutomaticKeepAliveClientMixin {
late AppModel _appModel;
late UserModel _userModel;
// late UserSubscribeModel _userSubscribeModel;
List<PlanEntity> _planEntityList = [];
@override
void initState() {
super.initState();
PlanService().plan()?.then((planEntityList) {
setState(() {
_planEntityList = planEntityList;
});
});
}
@override
bool get wantKeepAlive => true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_appModel = Provider.of<AppModel>(context);
_userModel = Provider.of<UserModel>(context);
// _userSubscribeModel = Provider.of<UserSubscribeModel>(context);
}
@override
Widget build(BuildContext context) {
super.build(context);
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
children: [
// Logo bar
Padding(
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(75),
right: ScreenUtil().setWidth(75)),
child: LogoBar(
isOn: _appModel.isOn,
),
),
// Padding(
// padding: EdgeInsets.only(top: ScreenUtil().setWidth(30)),
// child: MySubscribe(
// isLogin: _userModel.isLogin,
// isOn: _appModel.isOn,
// userSubscribeEntity: _userSubscribeModel.userSubscribeEntity!,
// ),
// ),
// Padding(
// padding:
// EdgeInsets.symmetric(vertical: ScreenUtil().setWidth(30)),
// child: PlanList(
// isOn: _appModel.isOn,
// boughtPlanId:
// _userSubscribeModel.userSubscribeEntity?.planId ?? 0,
// plans: _planEntityList,
// ),
// ),
Container(
padding:
EdgeInsets.symmetric(horizontal: ScreenUtil().setWidth(75)),
child: Stack(alignment: Alignment.center, children: [
Image.asset(
"assets/map.png",
scale: 3,
color: _appModel.isOn
? const Color(0x15000000)
: AppColors.darkSurfaceColor,
),
])),
_appModel.isOn ? const ConnectionStats() : const SelectLocation(),
],
));
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/models/user_model.dart';
// import 'package:chart/models/user_subscribe_model.dart';
import 'package:chart/utils/navigator_util.dart';
class LogoBar extends StatelessWidget {
const LogoBar({
Key? key,
required this.isOn,
}) : super(key: key);
final bool isOn;
@override
Widget build(BuildContext context) {
UserModel userModel = Provider.of<UserModel>(context);
// UserSubscribeModel userSubscribeModel = Provider.of<UserSubscribeModel>(context);
return Container(
margin: EdgeInsets.only(top: ScreenUtil().setWidth(60)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Sail",
style: TextStyle(
fontWeight: FontWeight.w900,
fontSize: ScreenUtil().setSp(60),
color: isOn ? AppColors.grayColor : Colors.white,
),
),
Row(
children: [
Material(
color:
isOn ? const Color(0x66000000) : AppColors.darkSurfaceColor,
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
child: InkWell(
borderRadius:
BorderRadius.circular(ScreenUtil().setWidth(30)),
onTap: () => NavigatorUtil.goToCrisp(context),
child: Container(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(10),
horizontal: ScreenUtil().setWidth(30)),
child: Text(
"客服",
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: Colors.white,
fontWeight: FontWeight.w500),
),
),
),
),
Padding(
padding: EdgeInsets.only(left: ScreenUtil().setWidth(15))),
// Material(
// color: isOn ? const Color(0x66000000) : AppColors.darkSurfaceColor,
// borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
// child: InkWell(
// borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
// onTap: () {},
// child: Container(
// padding: EdgeInsets.symmetric(
// vertical: ScreenUtil().setWidth(10), horizontal: ScreenUtil().setWidth(30)),
// child: Text(
// userSubscribeModel?.userSubscribeEntity?.email ?? "欢迎光临",
// style:
// TextStyle(fontSize: ScreenUtil().setSp(32), color: Colors.white, fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
userModel.isLogin
? Padding(
padding: EdgeInsets.only(left: ScreenUtil().setWidth(15)))
: Container(),
userModel.isLogin
? Material(
color: isOn
? const Color(0x66000000)
: AppColors.darkSurfaceColor,
borderRadius:
BorderRadius.circular(ScreenUtil().setWidth(30)),
child: InkWell(
borderRadius:
BorderRadius.circular(ScreenUtil().setWidth(30)),
onTap: () {
userModel.logout();
NavigatorUtil.goLogin(context);
},
child: Container(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(10),
horizontal: ScreenUtil().setWidth(30)),
child: Text(
'退出',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: Colors.white,
fontWeight: FontWeight.w500),
),
),
),
)
: Container(),
],
)
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/intl.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/entity/user_subscribe_entity.dart';
import 'package:chart/utils/transfer_util.dart';
class MySubscribe extends StatefulWidget {
const MySubscribe(
{Key? key,
required this.isLogin,
required this.isOn,
required this.userSubscribeEntity})
: super(key: key);
final bool isLogin;
final bool isOn;
final UserSubscribeEntity userSubscribeEntity;
@override
MySubscribeState createState() => MySubscribeState();
}
class MySubscribeState extends State<MySubscribe> {
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.only(left: ScreenUtil().setWidth(75)),
child: Text(
"我的订阅",
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: widget.isOn ? AppColors.grayColor : Colors.grey[400],
fontWeight: FontWeight.w500),
),
),
SizedBox(height: ScreenUtil().setWidth(30)),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.only(bottom: ScreenUtil().setWidth(10)),
child: widget?.userSubscribeEntity?.plan == null
? _emptyWidget()
: _buildConnections(),
)
],
);
}
Widget _emptyWidget() {
return Container(
width: ScreenUtil().setWidth(1080),
height: ScreenUtil().setWidth(200),
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil().setWidth(75),
vertical: ScreenUtil().setWidth(0)),
child: Material(
elevation: widget.isOn ? 3 : 0,
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
color: widget.isOn ? Colors.white : AppColors.darkSurfaceColor,
child: Container(
alignment: Alignment.center,
child: Text(
!widget.isLogin ? '请先登陆' : '请先订阅下方套餐',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: ScreenUtil().setWidth(40),
color: widget.isOn ? Colors.black : Colors.white),
),
),
),
);
}
Widget _buildConnections() {
return Container(
width: ScreenUtil().setWidth(1080),
height: ScreenUtil().setWidth(240),
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil().setWidth(75),
vertical: ScreenUtil().setWidth(0)),
child: Material(
elevation: widget.isOn ? 3 : 0,
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
color: widget.isOn ? Colors.white : AppColors.darkSurfaceColor,
child: Container(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(30),
horizontal: ScreenUtil().setWidth(40)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.userSubscribeEntity.plan.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: ScreenUtil().setSp(35),
color: widget.isOn ? Colors.black : Colors.white),
),
Padding(
padding: EdgeInsets.only(
left: ScreenUtil().setWidth(15))),
Text(
widget.userSubscribeEntity?.expiredAt != null
? '${DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.fromMillisecondsSinceEpoch(widget.userSubscribeEntity.expiredAt * 1000))}过期'
: '长期有效',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: ScreenUtil().setSp(35),
color: widget.isOn ? Colors.black : Colors.white),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: ScreenUtil().setWidth(480),
padding: EdgeInsets.only(
bottom: ScreenUtil().setWidth(15)),
child: LinearProgressIndicator(
backgroundColor:
widget.isOn ? Colors.black : Colors.white,
valueColor:
AlwaysStoppedAnimation(Colors.yellow[600]),
value: double.parse(((widget
.userSubscribeEntity.u ??
0 + widget.userSubscribeEntity.d ??
0) /
widget.userSubscribeEntity
.transferEnable ??
1)
.toStringAsFixed(2)),
),
),
Text(
'已用 ${TransferUtil().toHumanReadable(widget.userSubscribeEntity.u + widget.userSubscribeEntity.d)} / 总计 ${TransferUtil().toHumanReadable(widget.userSubscribeEntity.transferEnable)}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: ScreenUtil().setSp(26),
color: widget.isOn ? Colors.black : Colors.white),
)
],
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Container(
// width: ScreenUtil().setWidth(160),
// height: ScreenUtil().setWidth(75),
// margin: EdgeInsets.only(right: ScreenUtil().setWidth(10)),
// child: FlatButton(
// color: Colors.yellow,
// highlightColor: Colors.yellow[700],
// colorBrightness: Brightness.dark,
// splashColor: Colors.grey,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(20.0)),
// onPressed: () {},
// child: Text(
// '续费',
// style: TextStyle(
// color: Colors.black87,
// fontSize: ScreenUtil().setSp(24)),
// ),
// ),
// ),
// SizedBox(
// width: ScreenUtil().setWidth(160),
// height: ScreenUtil().setWidth(75),
// child: FlatButton(
// color: Colors.yellow,
// highlightColor: Colors.yellow[700],
// colorBrightness: Brightness.dark,
// splashColor: Colors.grey,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(20.0)),
// onPressed: () {},
// child: Text(
// '重置',
// style: TextStyle(
// color: Colors.black87,
// fontSize: ScreenUtil().setSp(24)),
// ),
// ),
// )
],
)
],
),
),
));
}
}
import 'package:flutter/material.dart';
// import 'package:flutter_icons/flutter_icons.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/entity/plan_entity.dart';
import 'package:chart/models/user_model.dart';
import 'package:chart/utils/navigator_util.dart';
class PlanList extends StatefulWidget {
const PlanList(
{Key? key,
required this.isOn,
required this.boughtPlanId,
required this.plans})
: super(key: key);
final bool isOn;
final int boughtPlanId;
final List<PlanEntity> plans;
@override
PlanListState createState() => PlanListState();
}
class PlanListState extends State<PlanList> with AutomaticKeepAliveClientMixin {
late UserModel _userModel;
@override
bool get wantKeepAlive => true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_userModel = Provider.of<UserModel>(context);
}
@override
Widget build(BuildContext context) {
super.build(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: EdgeInsets.only(left: ScreenUtil().setWidth(75)),
child: Text(
"订阅套餐",
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: widget.isOn ? AppColors.grayColor : Colors.grey[400],
fontWeight: FontWeight.w500),
),
),
SizedBox(height: ScreenUtil().setWidth(30)),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.only(bottom: ScreenUtil().setWidth(10)),
child: Row(children: _buildConnections()),
)
],
);
}
List<Widget> _buildConnections() {
List<Widget> list =
List.generate(widget.plans.length * 2 + 1, (i) => Container());
list[0] = SizedBox(width: ScreenUtil().setWidth(75));
for (var i = 1; i < list.length; i++) {
list[i] = Material(
elevation: widget.isOn
? widget.plans[i ~/ 2].id == widget.boughtPlanId
? 3
: 0
: 0,
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
color: widget.isOn
? widget.plans[i ~/ 2].id == widget.boughtPlanId
? Colors.white
: const Color(0x15000000)
: AppColors.darkSurfaceColor,
child: InkWell(
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(30)),
onTap: widget.isOn && widget.plans[i ~/ 2].id == widget.boughtPlanId
? null
: () => _userModel.checkHasLogin(
context, () => NavigatorUtil.goPlan(context)),
child: Container(
// width: ScreenUtil().setWidth(300),
height: ScreenUtil().setWidth(200),
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil().setWidth(40),
vertical: ScreenUtil().setWidth(30)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Country name
Text(
widget.plans[i ~/ 2].name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: ScreenUtil().setSp(32),
color: widget.isOn
? widget.plans[i ~/ 2].id == widget.boughtPlanId
? Colors.black
: AppColors.grayColor
: Colors.white),
),
// Connection status
Padding(
padding: EdgeInsets.only(top: ScreenUtil().setWidth(40)),
child: widget.plans[i ~/ 2].id == widget.boughtPlanId
? Row(
children: [
// Icon(
// MaterialCommunityIcons.shield_check_outline,
// size: ScreenUtil().setWidth(32),
// color: const Color(0xFF1abb1d),
// ),
Text(
"已订阅",
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: const Color(0xFF1abb1d),
fontWeight: FontWeight.bold),
)
],
)
: Text("选购",
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
fontWeight: FontWeight.w500,
color: widget.isOn
? Colors.black
: Colors.yellow[700])),
)
],
))),
);
list[++i] = SizedBox(width: ScreenUtil().setWidth(30));
}
return list;
}
}
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/models/app_model.dart';
// import 'package:chart/models/server_model.dart';
import 'package:chart/models/user_model.dart';
class PowerButton extends StatefulWidget {
const PowerButton({Key? key}) : super(key: key);
@override
PowerButtonState createState() => PowerButtonState();
}
class PowerButtonState extends State<PowerButton> {
late AppModel _appModel;
late UserModel _userModel;
// late ServerModel _serverModel;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_appModel = Provider.of<AppModel>(context);
_userModel = Provider.of<UserModel>(context);
// _serverModel = Provider.of<ServerModel>(context);
}
Future<void> pressConnectBtn() async {
// if (_serverModel.selectServerEntity == null) {
// Fluttertoast.showToast(
// msg: "请选择服务器节点",
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// timeInSecForIosWeb: 2,
// textColor: Colors.white,
// fontSize: 14.0);
// return;
// }
// _appModel.togglePowerButton();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
color:
_appModel.isOn ? const Color(0x20000000) : const Color(0xff606060),
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(120)),
),
child: Material(
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(100)),
color: _appModel.isOn ? AppColors.themeColor : Colors.grey,
child: InkWell(
splashColor: AppColors.yellowColor,
onTap: () => _userModel.checkHasLogin(context, pressConnectBtn),
borderRadius: BorderRadius.circular(ScreenUtil().setWidth(100)),
child: Container(
padding: EdgeInsets.all(ScreenUtil().setWidth(20)),
child: Icon(
Icons.power_settings_new,
size: ScreenUtil().setWidth(100),
color: Colors.white,
)),
),
),
);
}
}
import 'package:flutter/material.dart';
class ProfileWidget extends StatelessWidget {
const ProfileWidget({Key? key, required this.userName, this.avatar, required this.onTap}) : super(key: key);
final String? avatar;
final String userName;
final void Function() onTap;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(right: 24, left: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
avatar != null
? Row(
children: <Widget>[
ClipOval(child: Image(image: NetworkImage(avatar!), width: 40, height: 40)),
Padding(
padding: const EdgeInsets.only(left: 12),
child: Text(
userName,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500, color: Colors.black),
),
)
],
)
: Text(
userName,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500, color: Colors.black),
),
avatar != null
? Material(
color: const Color(0x66000000),
borderRadius: BorderRadius.circular(30),
child: InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: const Text(
'退出',
style: TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.w500),
),
),
),
)
: Container(),
],
),
);
}
}
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:chart/constant/app_colors.dart';
double minHeight = ScreenUtil().setHeight(260);
const double iconStartSize = 44;
const double iconEndSize = 120;
const double iconStartMarginTop = 36;
const double iconEndMarginTop = 80;
const double iconsVerticalSpacing = 24;
const double iconsHorizontalSpacing = 16;
class RecentConnectionBottomSheet extends StatefulWidget {
const RecentConnectionBottomSheet({Key? key}) : super(key: key);
@override
RecentConnectionBottomSheetState createState() =>
RecentConnectionBottomSheetState();
}
class RecentConnectionBottomSheetState
extends State<RecentConnectionBottomSheet>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
double get maxHeight => MediaQuery.of(context).size.height;
double? get headerTopMargin =>
lerp(20, 20 + MediaQuery.of(context).padding.top);
double? get headerFontSize => lerp(14, 24);
double? get itemBorderRadius => lerp(8, 24);
double? get iconLeftBorderRadius => itemBorderRadius;
double? get iconRightBorderRadius => lerp(8, 0);
double? get iconSize => lerp(iconStartSize, iconEndSize);
double? iconTopMargin(int index) =>
lerp(iconStartMarginTop,
iconEndMarginTop + index * (iconsVerticalSpacing + iconEndSize))! +
headerTopMargin!;
double? iconLeftMargin(int index) =>
lerp(index * (iconsHorizontalSpacing + iconStartSize), 0);
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 600),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
double? lerp(double min, double max) =>
lerpDouble(min, max, _controller.value);
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Positioned(
height: lerp(minHeight, maxHeight),
left: 0,
right: 0,
bottom: 0,
child: GestureDetector(
onTap: _toggle,
onVerticalDragUpdate: _handleDragUpdate,
onVerticalDragEnd: _handleDragEnd,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 32),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [AppColors.themeColor, Colors.pink],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
borderRadius: BorderRadius.vertical(top: Radius.circular(32)),
),
child: Stack(
children: <Widget>[
const MenuButton(),
SheetHeader(
fontSize: headerFontSize,
topMargin: headerTopMargin,
),
for (Event event in events) _buildFullItem(event),
for (Event event in events) _buildIcon(event),
],
),
),
),
);
},
);
}
Widget _buildIcon(Event event) {
int index = events.indexOf(event);
return Positioned(
height: iconSize,
width: iconSize,
top: iconTopMargin(index),
left: iconLeftMargin(index),
child: ClipRRect(
borderRadius: BorderRadius.horizontal(
left: Radius.circular(iconLeftBorderRadius!),
right: Radius.circular(iconRightBorderRadius!),
),
child: Image.asset(
'assets/${event.assetName}',
fit: BoxFit.cover,
alignment: Alignment(lerp(1, 0)!, 0),
),
),
);
}
Widget _buildFullItem(Event event) {
int index = events.indexOf(event);
return ExpandedEventItem(
topMargin: iconTopMargin(index),
leftMargin: iconLeftMargin(index),
height: iconSize,
isVisible: _controller.status == AnimationStatus.completed,
borderRadius: itemBorderRadius,
title: event.title,
date: event.date,
);
}
void _toggle() {
final bool isOpen = _controller.status == AnimationStatus.completed;
_controller.fling(velocity: isOpen ? -2 : 2);
}
void _handleDragUpdate(DragUpdateDetails details) {
_controller.value -= details.primaryDelta! / maxHeight;
}
void _handleDragEnd(DragEndDetails details) {
if (_controller.isAnimating ||
_controller.status == AnimationStatus.completed) return;
final double flingVelocity =
details.velocity.pixelsPerSecond.dy / maxHeight;
if (flingVelocity < 0.0) {
_controller.fling(velocity: math.max(2.0, -flingVelocity));
} else if (flingVelocity > 0.0) {
_controller.fling(velocity: math.min(-2.0, -flingVelocity));
} else {
_controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0);
}
}
}
class ExpandedEventItem extends StatelessWidget {
final double? topMargin;
final double? leftMargin;
final double? height;
final bool isVisible;
final double? borderRadius;
final String title;
final String date;
const ExpandedEventItem(
{Key? key,
required this.topMargin,
required this.height,
required this.isVisible,
required this.borderRadius,
required this.title,
required this.date,
required this.leftMargin})
: super(key: key);
@override
Widget build(BuildContext context) {
return Positioned(
top: topMargin,
left: leftMargin,
right: 0,
height: height,
child: AnimatedOpacity(
opacity: isVisible ? 1 : 0,
duration: const Duration(milliseconds: 200),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius!),
color: Colors.white,
),
padding: EdgeInsets.only(left: height!).add(const EdgeInsets.all(8)),
child: _buildContent(),
),
),
);
}
Widget _buildContent() {
return Column(
children: <Widget>[
Text(title, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 8),
Row(
children: <Widget>[
Text(
'1 ticket',
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12,
color: Colors.grey.shade600,
),
),
const SizedBox(width: 8),
Text(
date,
style: const TextStyle(
fontWeight: FontWeight.w300,
fontSize: 12,
color: Colors.grey,
),
),
],
),
const Spacer(),
Row(
children: <Widget>[
Icon(Icons.place, color: Colors.grey.shade400, size: 16),
Text(
'Science Park 10 25A',
style: TextStyle(color: Colors.grey.shade400, fontSize: 13),
)
],
)
],
);
}
}
final List<Event> events = [
Event('steve-johnson.jpeg', 'Shenzhen GLOBAL DESIGN AWARD 2018', '4.20-30'),
Event('efe-kurnaz.jpg', 'Shenzhen GLOBAL DESIGN AWARD 2018', '4.20-30'),
Event('rodion-kutsaev.jpeg', 'Dawan District Guangdong Hong Kong', '4.28-31'),
];
class Event {
final String assetName;
final String title;
final String date;
Event(this.assetName, this.title, this.date);
}
class SheetHeader extends StatelessWidget {
final double? fontSize;
final double? topMargin;
const SheetHeader({Key? key, required this.fontSize, required this.topMargin})
: super(key: key);
@override
Widget build(BuildContext context) {
return Positioned(
top: topMargin,
child: Text(
'最近连接节点',
style: TextStyle(
color: Colors.grey[100],
fontSize: fontSize,
fontWeight: FontWeight.w500,
),
),
);
}
}
class MenuButton extends StatelessWidget {
const MenuButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Positioned(
right: 0,
bottom: 24,
child: Icon(
Icons.menu,
color: Colors.white,
size: 28,
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
import 'package:chart/models/app_model.dart';
class SailAppBar extends AppBar {
SailAppBar({Key? key, required this.appTitle}) : super(key: key);
final String appTitle;
@override
SailAppBarState createState() => SailAppBarState();
}
class SailAppBarState extends State<SailAppBar> {
late AppModel _appModel;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_appModel = Provider.of<AppModel>(context);
}
@override
Widget build(BuildContext context) {
return AppBar(
title: Text(
widget.appTitle,
style: const TextStyle(color: Colors.white),
),
backgroundColor: Color.fromRGBO(30, 28, 57, 1),
// backgroundColor:
// _appModel.isOn ? AppColors.grayColor : AppColors.themeColor,
// shape: const RoundedRectangleBorder(
// borderRadius: BorderRadius.only(
// bottomRight: Radius.circular(25),
// bottomLeft: Radius.circular(25)),
// )
);
}
}
import 'package:flutter/material.dart';
// import 'package:flutter_icons/flutter_icons.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/constant/app_colors.dart';
// import 'package:chart/models/server_model.dart';
import 'package:chart/models/user_model.dart';
import 'package:chart/utils/navigator_util.dart';
class SelectLocation extends StatefulWidget {
const SelectLocation({
Key? key,
}) : super(key: key);
@override
SelectLocationState createState() => SelectLocationState();
}
class SelectLocationState extends State<SelectLocation> {
// late ServerModel _serverModel;
late UserModel _userModel;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_userModel = Provider.of<UserModel>(context);
}
@override
Widget build(BuildContext context) {
// _serverModel = Provider.of<ServerModel>(context);
return Padding(
padding: EdgeInsets.symmetric(
vertical: 20, horizontal: ScreenUtil().setWidth(75)),
child: Material(
borderRadius: BorderRadius.circular(20),
color: Colors.yellow[600],
child: InkWell(
onTap: () => _userModel.checkHasLogin(
context, () => NavigatorUtil.goServerList(context)),
splashColor: Colors.grey,
borderRadius: BorderRadius.circular(20),
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: AppColors.yellowColor.withAlpha(200),
blurRadius: 20,
spreadRadius: -6,
offset: const Offset(
0.0,
3.0,
),
)
]),
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 25),
child: Row(
children: [
// const Icon(MaterialCommunityIcons.server_network),
Padding(
padding: EdgeInsets.only(left: ScreenUtil().setWidth(10))),
// Text(
// _serverModel.selectServerEntity?.name ?? "选择连接节点",
// style: const TextStyle(
// fontSize: 15, fontWeight: FontWeight.bold),
// ),
Expanded(child: Container()),
const Icon(Icons.chevron_right)
],
),
),
),
),
);
}
}
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:chart/entity/plan_entity.dart';
import 'package:chart/models/user_model.dart';
import 'package:chart/service/plan_service.dart';
import 'package:chart/service/user_service.dart';
import 'package:chart/utils/navigator_util.dart';
class SlidingCardsView extends StatefulWidget {
const SlidingCardsView({Key? key}) : super(key: key);
@override
SlidingCardsViewState createState() => SlidingCardsViewState();
}
class SlidingCardsViewState extends State<SlidingCardsView> {
late PageController pageController;
double pageOffset = 0;
List<PlanEntity> _planEntityList = [];
@override
void initState() {
super.initState();
pageController = PageController(viewportFraction: 0.8);
pageController.addListener(() {
setState(() => pageOffset = pageController.page!);
});
PlanService().plan()?.then((planEntityList) {
setState(() {
_planEntityList = planEntityList;
});
});
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.55,
child: PageView(
controller: pageController,
children: List.from(_planEntityList.map((e) => SlidingCard(
id: e.id,
name: e.name,
date: e.createdAt?.toIso8601String(),
onetimePrice: (e.onetimePrice ?? 0.0) / 100,
monthPrice: (e.monthPrice ?? 0.0) / 100,
quarterPrice: (e.quarterPrice ?? 0.0) / 100,
halfYearPrice: (e.halfYearPrice ?? 0.0) / 100,
yearPrice: (e.yearPrice ?? 0.0) / 100,
twoYearPrice: (e.twoYearPrice) ?? 0.0 / 100,
threeYearPrice: (e.threeYearPrice) ?? 0.0 / 100,
assetName: 'steve-johnson.jpeg',
offset: pageOffset)))),
);
}
}
class SlidingCard extends StatelessWidget {
final int id;
final String name;
final String? date;
final String assetName;
final double offset;
final double onetimePrice;
final double monthPrice;
final double quarterPrice;
final double halfYearPrice;
final double yearPrice;
final double twoYearPrice;
final double threeYearPrice;
const SlidingCard({
Key? key,
required this.id,
required this.name,
required this.date,
required this.assetName,
required this.offset,
required this.onetimePrice,
required this.monthPrice,
required this.quarterPrice,
required this.halfYearPrice,
required this.yearPrice,
required this.twoYearPrice,
required this.threeYearPrice,
}) : super(key: key);
double lowestPrice() {
List<double> list = [
onetimePrice,
monthPrice,
quarterPrice,
halfYearPrice,
yearPrice,
twoYearPrice,
threeYearPrice,
];
double min = double.maxFinite;
for (int i = 0; i < list.length; i++) {
if ((list[i] < min) && list[i] > 0) {
min = list[i];
}
}
return min;
}
@override
Widget build(BuildContext context) {
double gauss = math.exp(-(math.pow((offset.abs() - 0.5), 2) / 0.08));
return Transform.translate(
offset: Offset(-32 * gauss * offset.sign, 0),
child: Card(
margin: const EdgeInsets.only(left: 8, right: 8, bottom: 24),
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(32)),
child: Column(
children: <Widget>[
ClipRRect(
borderRadius:
const BorderRadius.vertical(top: Radius.circular(32)),
child: Image.asset(
'assets/$assetName',
height: MediaQuery.of(context).size.height * 0.3,
alignment: Alignment(-offset.abs(), 0),
fit: BoxFit.none,
),
),
const SizedBox(height: 8),
Expanded(
child: CardContent(
id: id,
name: name,
date: date,
offset: gauss,
lowestPrice: lowestPrice(),
),
),
],
),
),
);
}
}
class CardContent extends StatefulWidget {
final int id;
final String name;
final String? date;
final double offset;
final double lowestPrice;
const CardContent(
{Key? key,
required this.id,
required this.name,
required this.date,
required this.offset,
required this.lowestPrice})
: super(key: key);
@override
CardContentState createState() => CardContentState();
}
class CardContentState extends State<CardContent> {
late UserModel _userModel;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_userModel = Provider.of<UserModel>(context);
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Transform.translate(
offset: Offset(8 * widget.offset, 0),
child: Text(widget.name, style: const TextStyle(fontSize: 20)),
),
const SizedBox(height: 8),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child: Text(
widget.date!,
style: const TextStyle(color: Colors.grey),
),
),
const Spacer(),
Row(
children: <Widget>[
Transform.translate(
offset: Offset(48 * widget.offset, 0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.yellow,
onPrimary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
),
onPressed: () => _userModel.checkHasLogin(
context,
() => UserService().getQuickLoginUrl({
'redirect': "/plan/${widget.id}"
})?.then((value) {
NavigatorUtil.goWebView(context, "配置订阅", value);
})),
child: Transform.translate(
offset: Offset(24 * widget.offset, 0),
child: Text('购买',
style: TextStyle(
color: Colors.black87,
fontSize: ScreenUtil().setSp(36))),
),
),
),
const Spacer(),
Transform.translate(
offset: Offset(32 * widget.offset, 0),
child: Text(
${widget.lowestPrice} 起',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
const SizedBox(width: 16),
],
)
],
),
);
}
}
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
animated_text_kit:
dependency: "direct main"
description:
name: animated_text_kit
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.2"
another_flushbar:
dependency: transitive
description:
......@@ -29,6 +36,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
bubble:
dependency: "direct main"
description:
name: bubble
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
characters:
dependency: transitive
description:
......@@ -57,6 +71,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+4"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.2"
cupertino_icons:
dependency: "direct main"
description:
......@@ -64,6 +99,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
diffutil_dart:
dependency: transitive
description:
name: diffutil_dart
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
dio:
dependency: "direct main"
description:
......@@ -71,6 +113,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.6"
equatable:
dependency: transitive
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
fake_async:
dependency: transitive
description:
......@@ -92,6 +141,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.5"
fluro:
dependency: "direct main"
description:
......@@ -104,6 +160,20 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_chat_types:
dependency: "direct main"
description:
name: flutter_chat_types
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.0"
flutter_chat_ui:
dependency: "direct main"
description:
name: flutter_chat_ui
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.6"
flutter_easyrefresh:
dependency: "direct main"
description:
......@@ -118,6 +188,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
flutter_icons:
dependency: "direct main"
description:
name: flutter_icons
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
flutter_inappwebview:
dependency: transitive
description:
......@@ -125,6 +202,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.7.2+3"
flutter_link_previewer:
dependency: transitive
description:
name: flutter_link_previewer
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
flutter_linkify:
dependency: transitive
description:
name: flutter_linkify
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.2"
flutter_lints:
dependency: "direct dev"
description:
......@@ -151,6 +242,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.3"
flutter_parsed_text:
dependency: transitive
description:
name: flutter_parsed_text
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
flutter_screenutil:
dependency: "direct main"
description:
......@@ -203,6 +308,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "9.2.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.1"
http:
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.5"
http_parser:
dependency: transitive
description:
......@@ -210,6 +329,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.2"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.6+1"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+5"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.10"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.6+7"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.2"
intl:
dependency: "direct main"
description:
......@@ -224,6 +378,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.8.0"
linkify:
dependency: transitive
description:
name: linkify
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
lints:
dependency: transitive
description:
......@@ -252,6 +420,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
mime:
dependency: "direct main"
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
modal_bottom_sheet:
dependency: "direct main"
description:
......@@ -266,6 +441,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
open_filex:
dependency: "direct main"
description:
name: open_filex
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2"
path:
dependency: transitive
description:
......@@ -315,6 +497,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
photo_view:
dependency: transitive
description:
name: photo_view
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0"
platform:
dependency: transitive
description:
......@@ -350,6 +539,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
scroll_to_index:
dependency: transitive
description:
name: scroll_to_index
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
shared_preferences:
dependency: "direct main"
description:
......@@ -516,6 +712,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.3"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.7"
vector_math:
dependency: transitive
description:
......@@ -523,6 +726,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
visibility_detector:
dependency: transitive
description:
name: visibility_detector
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
webview_flutter:
dependency: "direct main"
description:
......
......@@ -3,7 +3,7 @@ description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
publish_to: "none" # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
......@@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: '>=2.18.6 <3.0.0'
sdk: ">=2.18.6 <3.0.0"
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
......@@ -33,12 +33,13 @@ dependencies:
sdk: flutter
flutter_localizations:
sdk: flutter
# dependencies:
# flutter:
# sdk: flutter
# flutter_localizations:
# sdk: flutter
# flutter_icons: ^1.1.0
flutter_icons: ^1.1.0
# dependencies:
# flutter:
# sdk: flutter
# flutter_localizations:
# sdk: flutter
# flutter_icons: ^1.1.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
......@@ -62,6 +63,17 @@ dependencies:
fluttertoast: ^8.0.9
meta: ^1.7.0
flutter_icmp_ping: ^3.1.0
flutter_chat_ui: ^1.6.6
flutter_chat_types: ^3.6.0
http: ^0.13.5
image_picker: ^0.8.6
mime: ^1.0.2
open_filex: ^4.2.2
uuid: ^3.0.6
file_picker: ^5.2.2
bubble: ^1.2.1
animated_text_kit: ^4.2.2
# package:bubble/bubble.dart
dev_dependencies:
flutter_test:
......@@ -78,12 +90,14 @@ dev_dependencies:
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/images/
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment