mirror of
https://github.com/chaos-zhu/easynode.git
synced 2026-10-07 14:48:03 +08:00
feat: 版本号展示&Android端构建配置
This commit is contained in:
@@ -43,3 +43,8 @@ app.*.map.json
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
# Android signing — never commit keystores or their passwords.
|
||||
/android/key.properties
|
||||
/android/*.jks
|
||||
/android/*.keystore
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import java.util.Properties
|
||||
import java.io.FileInputStream
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
@@ -5,8 +8,15 @@ plugins {
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
val keystoreProperties = Properties().apply {
|
||||
val file = rootProject.file("key.properties")
|
||||
if (file.exists()) {
|
||||
load(FileInputStream(file))
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.mobile"
|
||||
namespace = "io.github.chaoszhu.easynode"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
@@ -20,21 +30,36 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.example.mobile"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
applicationId = "io.github.chaoszhu.easynode"
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
val storeFilePath = keystoreProperties["storeFile"] as String?
|
||||
if (storeFilePath != null) {
|
||||
storeFile = rootProject.file(storeFilePath)
|
||||
storePassword = keystoreProperties["storePassword"] as String?
|
||||
keyAlias = keystoreProperties["keyAlias"] as String?
|
||||
keyPassword = keystoreProperties["keyPassword"] as String?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
// Fall back to the debug keystore if key.properties is missing so
|
||||
// `flutter run --release` keeps working locally for contributors
|
||||
// who haven't set up signing yet. Real release builds REQUIRE the
|
||||
// key.properties file to be present.
|
||||
signingConfig = if (keystoreProperties.isEmpty) {
|
||||
signingConfigs.getByName("debug")
|
||||
} else {
|
||||
signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.mobile
|
||||
package io.github.chaoszhu.easynode
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
storePassword=<your-store-password>
|
||||
keyPassword=<your-key-password>
|
||||
keyAlias=easynode
|
||||
storeFile=easynode-release.jks
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../core/ui/palette.dart';
|
||||
import '../../core/utils/jwt_expiry.dart';
|
||||
import '../../core/utils/validators.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../../state/package_info_provider.dart';
|
||||
import 'auth_session.dart';
|
||||
import 'login_controller.dart';
|
||||
|
||||
@@ -145,7 +147,6 @@ class _LoginPageState extends State<LoginPage> {
|
||||
children: [
|
||||
_LoginHero(
|
||||
title: l.tr('app.title'),
|
||||
subtitle: l.tr('app.subtitle'),
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
_LoginFormCard(
|
||||
@@ -441,15 +442,18 @@ class _LoginBottomBar extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _LoginHero extends StatelessWidget {
|
||||
const _LoginHero({required this.title, required this.subtitle});
|
||||
class _LoginHero extends ConsumerWidget {
|
||||
const _LoginHero({required this.title});
|
||||
|
||||
final String title;
|
||||
final String subtitle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
final info = ref.watch(packageInfoProvider).valueOrNull;
|
||||
final versionLabel = info == null
|
||||
? ''
|
||||
: 'v${info.version} (${info.buildNumber})';
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -476,7 +480,7 @@ class _LoginHero extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
subtitle,
|
||||
versionLabel,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: AppPalette.softMuted,
|
||||
|
||||
@@ -7,6 +7,7 @@ import '../../state/auth_notifier.dart';
|
||||
import '../../state/credential_list_notifier.dart';
|
||||
import '../../state/host_list_notifier.dart';
|
||||
import '../../state/locale_notifier.dart';
|
||||
import '../../state/package_info_provider.dart';
|
||||
import '../../state/plus_discount_notifier.dart';
|
||||
import '../../state/plus_info_notifier.dart';
|
||||
import '../../state/script_list_notifier.dart';
|
||||
@@ -207,6 +208,10 @@ class SettingsTab extends ConsumerWidget {
|
||||
final discount = ref.watch(plusDiscountProvider).valueOrNull ??
|
||||
const PlusDiscount(discount: false, content: '');
|
||||
final hasDiscount = discount.discount && discount.content.isNotEmpty;
|
||||
final packageInfo = ref.watch(packageInfoProvider).valueOrNull;
|
||||
final versionLabel = packageInfo == null
|
||||
? ''
|
||||
: 'v${packageInfo.version} (${packageInfo.buildNumber})';
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppPalette.canvas,
|
||||
@@ -221,6 +226,19 @@ class SettingsTab extends ConsumerWidget {
|
||||
child: TabHeader(
|
||||
title: l.tr('settings.title'),
|
||||
actions: [
|
||||
if (versionLabel.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Text(
|
||||
versionLabel,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppPalette.softMuted,
|
||||
letterSpacing: 0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!plusActive)
|
||||
_SettingsBellButton(
|
||||
hasDiscount: hasDiscount,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
/// Resolves the running app's version / build number from the platform's
|
||||
/// PackageInfo so UI surfaces don't hardcode strings that drift from
|
||||
/// `pubspec.yaml`. Cached for the lifetime of the process — package info
|
||||
/// never changes after install.
|
||||
final packageInfoProvider = FutureProvider<PackageInfo>((ref) async {
|
||||
return PackageInfo.fromPlatform();
|
||||
});
|
||||
+5
-5
@@ -486,13 +486,13 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
package_info_plus:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20"
|
||||
sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.1"
|
||||
version: "8.3.1"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -966,10 +966,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_plus
|
||||
sha256: ddf3db70eaa10c37558ff817519b85d527dbd21034fd5d8e1c2e85f31588f1c1
|
||||
sha256: "61713aa82b7f85c21c9f4cd0a148abd75f38a74ec645fcb1e446f882c82fd09b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
version: "1.3.3"
|
||||
wakelock_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
name: mobile
|
||||
description: "EasyNode mobile app."
|
||||
publish_to: 'none'
|
||||
version: 0.1.0+1
|
||||
version: 0.1.0-beta.1+2
|
||||
|
||||
environment:
|
||||
sdk: ^3.11.5
|
||||
@@ -34,6 +34,7 @@ dependencies:
|
||||
video_player: ^2.9.2
|
||||
chewie: ^1.8.5
|
||||
url_launcher: ^6.3.1
|
||||
package_info_plus: ^8.1.0
|
||||
|
||||
dependency_overrides:
|
||||
# video_player_android 2.9.x has a known Pigeon channel-error regression on
|
||||
|
||||
Reference in New Issue
Block a user