feat: init project

This commit is contained in:
liyi 2025-08-27 18:20:37 +08:00
parent 35c9f33051
commit f9821577b5
30 changed files with 670 additions and 112 deletions

View File

@ -1,16 +1,5 @@
# starwork_flutter
# 斯凯签勤
A new Flutter project.
## 开发环境
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
- flutter3.19.6

View File

@ -1,5 +1,12 @@
allprojects {
repositories {
// 使
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://storage.flutter-io.cn/download.flutter.io' } // Flutter
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
google()
mavenCentral()
}

View File

@ -0,0 +1,31 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
import 'package:starwork_flutter/i18n/app_i18n.dart';
class AppInitialization {
static Future<void> initializeApp() async {
// ,使
WidgetsFlutterBinding.ensureInitialized();
//
setSystemStatusBar();
// SharedPreferences
await SharedPreferencesUtils.init();
}
static void setSystemStatusBar() {
if (Platform.isAndroid) {
//
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
),
);
}
}
}

View File

@ -0,0 +1,5 @@
import 'package:get/get.dart';
class BaseController extends GetxController{
}

View File

@ -0,0 +1,3 @@
class CacheKeys {
static const String token = 'token';
}

View File

@ -0,0 +1,19 @@
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesUtils {
static SharedPreferences? _prefs;
//
static Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
// 使
static Future<bool> setString(String key, String value) async {
return _prefs?.setString(key, value) ?? Future.value(false);
}
static String? getString(String key) {
return _prefs?.getString(key);
}
}

22
lib/i18n/app_i18n.dart Normal file
View File

@ -0,0 +1,22 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/i18n/language/en_US.dart';
import 'package:starwork_flutter/i18n/language/zh_CN.dart';
class AppI18n extends Translations {
// Translations
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': ZhCn.values,
'en_US': EnUS.values,
};
//
void changeLanguage(String languageCode, String countryCode) {
var locale = Locale(languageCode, countryCode);
Get.updateLocale(locale);
}
}

View File

@ -0,0 +1,5 @@
class EnUS {
static const Map<String, String> values = {
"路由": "Routes",
};
}

View File

@ -0,0 +1,5 @@
class ZhCn{
static const Map<String, String> values = {
"路由": "路由",
};
}

View File

@ -1,69 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/base/app_initialization.dart';
import 'package:starwork_flutter/i18n/app_i18n.dart';
import 'package:starwork_flutter/routes/app_pages.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'package:starwork_flutter/views/login/login_view.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
Future<void> main() async {
//
AppInitialization.initializeApp();
runApp(
ScreenUtilInit(
designSize: Size(360, 690),
minTextAdapt: true,
splitScreenMode: true,
builder: (_, child) {
return GetMaterialApp(
enableLog: true,
title: '路由'.tr,
translations: AppI18n(),
locale: const Locale('zh', 'CN'),
//
fallbackLocale: const Locale('zh', 'CN'),
// fallback 使
getPages: AppPages.pages,
initialRoute: AppRoutes.login,
//
debugShowCheckedModeBanner: false,
);
},
),
);
}

43
lib/routes/app_pages.dart Normal file
View File

@ -0,0 +1,43 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'package:starwork_flutter/views/home/home_binding.dart';
import 'package:starwork_flutter/views/home/home_view.dart';
import 'package:starwork_flutter/views/login/login_binding.dart';
import 'package:starwork_flutter/views/login/login_view.dart';
import 'package:starwork_flutter/views/main/main_binding.dart';
import 'package:starwork_flutter/views/main/main_view.dart';
import 'package:starwork_flutter/views/messages/messages_binding.dart';
import 'package:starwork_flutter/views/messages/messages_view.dart';
import 'package:starwork_flutter/views/mine/mine_binding.dart';
import 'package:starwork_flutter/views/mine/mine_view.dart';
class AppPages {
//
static final pages = [
GetPage(
name: AppRoutes.login,
page: () => const LoginView(),
binding: LoginBinding(),
),
GetPage(
name: AppRoutes.home,
page: () => const HomeView(),
binding: HomeBinding(),
),
GetPage(
name: AppRoutes.main,
page: () => const MainView(),
binding: MainBinding(),
),
GetPage(
name: AppRoutes.messages,
page: () => const MessagesView(),
binding: MessagesBinding(),
),
GetPage(
name: AppRoutes.mine,
page: () => const MineView(),
binding: MineBinding(),
),
];
}

View File

@ -0,0 +1,8 @@
class AppRoutes{
//
static const String login = '/login';
static const String home = '/home';
static const String main = '/main';
static const String messages = '/messages';
static const String mine = '/mine';
}

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/views/home/home_controller.dart';
import 'package:starwork_flutter/views/login/login_controller.dart';
class HomeBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<HomeController>(() => HomeController());
}
}

View File

@ -0,0 +1,5 @@
import 'package:starwork_flutter/base/base_controller.dart';
class HomeController extends BaseController {
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'home_controller.dart';
class HomeView extends GetView<HomeController> {
const HomeView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomeView'),
centerTitle: true,
),
body: Center(
child: ElevatedButton(
onPressed: () {
if (Get.locale?.languageCode == 'zh') {
Get.updateLocale(const Locale('en', 'US'));
} else {
Get.updateLocale(const Locale('zh', 'CN'));
}
},
child: Text('切换成英语${'路由'.tr}')),
),
);
}
}

View File

@ -0,0 +1,9 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/views/login/login_controller.dart';
class LoginBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<LoginController>(() => LoginController());
}
}

View File

@ -0,0 +1,5 @@
import 'package:starwork_flutter/base/base_controller.dart';
class LoginController extends BaseController {
}

View File

@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'login_controller.dart';
class LoginView extends GetView<LoginController> {
const LoginView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: _buildBody(),
),
);
}
Widget _buildBody() {
return Container(
margin: EdgeInsets.symmetric(vertical: 48.h),
padding: EdgeInsets.symmetric(horizontal: 32.w),
child: Column(
children: [
_buildTitle(),
SizedBox(height: 32.h,),
_buildPhoneInput(),
],
),
);
}
Widget _buildTitle() {
return SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'欢迎使用斯凯签勤'.tr,
style: TextStyle(
fontSize: 22.sp,
fontWeight: FontWeight.w500,
),
),
SizedBox(
height: 4.h,
),
Text(
'未注册手机号验证后将自动创建账号'.tr,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: Colors.grey,
),
),
],
),
);
}
_buildPhoneInput() {
return TextField(
keyboardType: TextInputType.phone,
maxLength: 11,
decoration: InputDecoration(
counterText: '',
hintText: '请输入手机号'.tr,
border: const UnderlineInputBorder(),
//
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue), // 🔥
),
),
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/views/login/login_controller.dart';
import 'package:starwork_flutter/views/main/main_controller.dart';
class MainBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<MainController>(() => MainController());
}
}

View File

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/views/home/home_view.dart';
import 'package:starwork_flutter/views/messages/messages_view.dart';
import 'package:starwork_flutter/views/mine/mine_view.dart';
class MainController extends BaseController {
//
final List<BottomNavigationBarItem> bottomNavItems = [
const BottomNavigationBarItem(
icon: Icon(Icons.home_rounded),
label: '首页',
),
const BottomNavigationBarItem(
icon: Icon(Icons.messenger_outline_rounded),
label: '消息',
),
const BottomNavigationBarItem(
icon: Icon(Icons.person),
label: '我的',
),
];
//
var currentIndex = 0.obs;
//
final pages = [
HomeView(),
MessagesView(),
MineView(),
];
//
void changeIndex(int index) {
currentIndex.value = index;
}
}

View File

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'main_controller.dart';
class MainView extends GetView<MainController> {
const MainView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// 使 Obx currentIndex
body: Obx(
() => IndexedStack(
index: controller.currentIndex.value,
children: controller.pages,
),
),
bottomNavigationBar: Obx(
() => BottomNavigationBar(
currentIndex: controller.currentIndex.value,
onTap: (index) => controller.changeIndex(index),
items: controller.bottomNavItems,
type: BottomNavigationBarType.fixed,
// 3 fixed
selectedFontSize: 12.sp,
unselectedFontSize: 12.sp,
),
),
);
}
}

View File

@ -0,0 +1,11 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/views/home/home_controller.dart';
import 'package:starwork_flutter/views/login/login_controller.dart';
import 'package:starwork_flutter/views/messages/messages_controller.dart';
class MessagesBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<MessagesController>(() => MessagesController());
}
}

View File

@ -0,0 +1,5 @@
import 'package:starwork_flutter/base/base_controller.dart';
class MessagesController extends BaseController {
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'messages_controller.dart';
class MessagesView extends GetView<MessagesController> {
const MessagesView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MessagesView'),
centerTitle: true,
),
body: const Center(
child: Text(
'MessagesView is working',
style: TextStyle(fontSize: 20),
),
),
);
}
}

View File

@ -0,0 +1,9 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/views/mine/mine_controller.dart';
class MineBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<MineController>(() => MineController());
}
}

View File

@ -0,0 +1,5 @@
import 'package:starwork_flutter/base/base_controller.dart';
class MineController extends BaseController {
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'mine_controller.dart';
class MineView extends GetView<MineController> {
const MineView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MineView'),
centerTitle: true,
),
body: const Center(
child: Text(
'MineView is working',
style: TextStyle(fontSize: 20),
),
),
);
}
}

View File

@ -57,6 +57,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
flutter:
dependency: "direct main"
description: flutter
@ -70,11 +86,24 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
flutter_screenutil:
dependency: "direct main"
description:
name: flutter_screenutil
sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.9.3"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
get:
dependency: "direct main"
description:
@ -147,6 +176,150 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.0"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
url: "https://pub.flutter-io.cn"
source: hosted
version: "11.3.1"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "71bbecfee799e65aff7c744761a57e817e73b738fedf62ab7afd5593da21f9f1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "12.0.13"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.4.7"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.3+5"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.2.3"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.6"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.8"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.2"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.5.3"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
@ -224,6 +397,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
sdks:
dart: ">=3.3.4 <4.0.0"
flutter: ">=3.13.0"
flutter: ">=3.19.0"

View File

@ -1,7 +1,7 @@
name: starwork_flutter
description: "星勤移动客户端."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
publish_to: 'none'
version: 1.0.0+1
@ -16,7 +16,12 @@ dependencies:
get: ^4.7.2
# 权限申请
permission_handler: ^11.3.1
# 内置的官方图标库
cupertino_icons: ^1.0.6
# 缓存
shared_preferences: ^2.2.3
# 屏幕适配
flutter_screenutil: ^5.9.3
dev_dependencies:
flutter_test:
@ -25,3 +30,4 @@ dev_dependencies:
flutter:
uses-material-design: true

View File

@ -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:starwork_flutter/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);
});
}