diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index d7a642c..99e9da6 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -5,29 +5,29 @@ plugins { id("dev.flutter.flutter-gradle-plugin") } +extra["code"] = 1 +extra["name"] = "1.0.0" + + android { namespace = "com.example.cpu_z_copy" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion + compileSdk = 35 + ndkVersion = "25.2.9519653" compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.example.cpu_z_copy" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName + minSdk = 25 + targetSdk = 35 + versionCode = extra["code"] as Int + versionName = extra["name"] as String } buildTypes { @@ -37,6 +37,9 @@ android { signingConfig = signingConfigs.getByName("debug") } } + kotlinOptions { + jvmTarget = "17" + } } flutter { diff --git a/android/app/src/main/kotlin/com/example/cpu_z_copy/Battery.kt b/android/app/src/main/kotlin/com/example/cpu_z_copy/Battery.kt new file mode 100644 index 0000000..536d7fb --- /dev/null +++ b/android/app/src/main/kotlin/com/example/cpu_z_copy/Battery.kt @@ -0,0 +1,87 @@ +package com.example.cpu_z_copy + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.BatteryManager +import io.flutter.plugin.common.EventChannel + +class Battery(context: Context) { + + val batteryHandler = object : EventChannel.StreamHandler { + lateinit var receiver: BroadcastReceiver + val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + + override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent == null || events == null) return + val health = getHealth(intent.getIntExtra(BatteryManager.EXTRA_HEALTH, -1)) + val status = getStatus(intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)) + val level = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + val temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) / 10 + val powerSource = getPowerSource(intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)) + val voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) + val technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY) ?: "error" + + val result = mapOf( + "type" to "battery", + "health" to health, + "status" to status, + "level" to level, + "technology" to technology, + "temperature" to temperature, + "powerSource" to powerSource, + "voltage" to voltage + ) + events.success(result) + } + } + context.registerReceiver(receiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + } + + override fun onCancel(arguments: Any?) { + receiver.let { context.unregisterReceiver(it) } + } + + } + + + fun getHealth(health: Int): String { + return when (health) { + BatteryManager.BATTERY_HEALTH_GOOD -> "Good" + BatteryManager.BATTERY_HEALTH_OVERHEAT -> "Over heat" + BatteryManager.BATTERY_HEALTH_COLD -> "Cold" + BatteryManager.BATTERY_HEALTH_DEAD -> "Dead" + BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE -> "Over voltage" + BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE -> "Unspecified failure" + BatteryManager.BATTERY_HEALTH_UNKNOWN -> "Unknown" + else -> "Error" + } + } + + fun getStatus(status: Int): String { + return when (status) { + BatteryManager.BATTERY_STATUS_CHARGING -> "Charging" + BatteryManager.BATTERY_STATUS_FULL -> "Full" + BatteryManager.BATTERY_STATUS_DISCHARGING -> "Discharging" + BatteryManager.BATTERY_STATUS_NOT_CHARGING -> "Not charging" + BatteryManager.BATTERY_STATUS_UNKNOWN -> "Unknown" + else -> "Error" + } + } + + fun getPowerSource(status: Int): String { + return when (status) { + BatteryManager.BATTERY_PLUGGED_AC -> "Ac" + BatteryManager.BATTERY_PLUGGED_USB -> "Usb" + BatteryManager.BATTERY_PLUGGED_DOCK -> "Dock" + BatteryManager.BATTERY_PLUGGED_WIRELESS -> "Wireless" + else -> "Battery" + } + } + + +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/cpu_z_copy/Device.kt b/android/app/src/main/kotlin/com/example/cpu_z_copy/Device.kt new file mode 100644 index 0000000..272bb04 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/cpu_z_copy/Device.kt @@ -0,0 +1,71 @@ +package com.example.cpu_z_copy + +import android.content.Context +import android.content.res.Resources +import android.os.Build +import android.os.StatFs +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import kotlin.math.pow +import kotlin.math.sqrt + +class Device(context: Context) { + + val storageStat = StatFs(context.filesDir.path) + val runtime = Runtime.getRuntime() + val metrics = Resources.getSystem().displayMetrics + + val handler = object : MethodChannel.MethodCallHandler { + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + val resultData = mapOf( + "type" to "device", + "content" to when (call.method) { + DeviceRequest.MANUFACTURER.title -> Build.MANUFACTURER + DeviceRequest.HARDWARE.title -> Build.HARDWARE + DeviceRequest.BOARD.title -> Build.BOARD + DeviceRequest.MODEL.title -> Build.MODEL + DeviceRequest.SCREEN.title -> { + val wInch = metrics.widthPixels / metrics.xdpi + val hInch = metrics.heightPixels / metrics.ydpi + val size = sqrt(wInch.pow(2) + hInch.pow(2)) + mapOf( + "size" to size, + "resolution" to "${metrics.heightPixels} x ${metrics.widthPixels} pixels", + "density" to metrics.densityDpi, + ) + } + + DeviceRequest.RAM.title -> mapOf( + "total" to runtime.totalMemory(), + "available" to runtime.freeMemory() + ) + + DeviceRequest.STORAGE.title -> { + var size = storageStat.blockSizeLong + var total = size * storageStat.blockCountLong + mapOf( + "total" to total, + "available" to total - (size * storageStat.availableBlocksLong) + ) + } + + else -> { + result.notImplemented() + return + } + } + ) + + result.success(resultData) + } + } + +} + + +enum class DeviceRequest(val title: String) { + MODEL("model"), MANUFACTURER("manufacturer"), BOARD("board"), HARDWARE("hardware"), SCREEN("screen"), RAM( + "ram" + ), + STORAGE("storage"); +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/cpu_z_copy/MainActivity.kt b/android/app/src/main/kotlin/com/example/cpu_z_copy/MainActivity.kt index 8a1016a..3c22588 100644 --- a/android/app/src/main/kotlin/com/example/cpu_z_copy/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/cpu_z_copy/MainActivity.kt @@ -2,48 +2,50 @@ package com.example.cpu_z_copy import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.EventChannel import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { + lateinit var _eventChannel: EventChannel + lateinit var _methodChannel: MethodChannel override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) -/* - MethodChannel( + EventChannel( flutterEngine.dartExecutor.binaryMessenger, - Define.METHOD_CHANNEL_NAME - ).setMethodCallHandler { call, result -> { - - if(call.method == "") { - - - result.success(); - } + Channel.EVENT_CHANNEL_NAME.title + RequestApp.BATTERY.title + ).setStreamHandler(Battery(context).batteryHandler) + EventChannel( + flutterEngine.dartExecutor.binaryMessenger, + Channel.EVENT_CHANNEL_NAME.title + RequestApp.SENSOR.title + ).setStreamHandler(Sensor(context).sensorHandler) + MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, + Channel.METHOD_CHANNEL_NAME.title + RequestApp.DEVICE.title + ).setMethodCallHandler(Device(context).handler) - } } - */ + MethodChannel( + flutterEngine.dartExecutor.binaryMessenger, + Channel.METHOD_CHANNEL_NAME.title + RequestApp.SYSTEM.title + ).setMethodCallHandler(System(context).handler) } - /* - - fun getBattery (): Int { - - + enum class RequestApp(val title: String) { + BATTERY("_battery"), THERMAL("_thermal"), SENSOR("_sensor"), SYSTEM("_system"), SOC("_soc"), DEVICE( + "_device" + ); } - */ - - object Define { - - const val METHOD_CHANNEL_NAME: String = "com.example.spu_z_copy_method_channel" - const val EVENT_CHANNEL_NAME: String = "com.example.spu_z_copy_event_channel" + enum class Channel(val title: String) { + METHOD_CHANNEL_NAME("com.example.spu_z_copy_method_channel"), + EVENT_CHANNEL_NAME("com.example.spu_z_copy_event_channel"); } } diff --git a/android/app/src/main/kotlin/com/example/cpu_z_copy/Sensor.kt b/android/app/src/main/kotlin/com/example/cpu_z_copy/Sensor.kt new file mode 100644 index 0000000..afe7791 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/cpu_z_copy/Sensor.kt @@ -0,0 +1,104 @@ +package com.example.cpu_z_copy + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import io.flutter.plugin.common.EventChannel + + +class Sensor(context: Context) { + val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + lateinit var listener: SensorEventListener + + val sensorHandler = object : EventChannel.StreamHandler { + + override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + if (events == null) return + + listener = object : SensorEventListener { + override fun onSensorChanged(event: SensorEvent?) { + if (event == null) return + val result = mapOf( + "type" to "sensor", + "sensor_type" to event.sensor.stringType, + "id" to event.sensor.id, + "name" to event.sensor.name, + "content" to getValue(event) + ) + events.success(result) + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} + } + sensorList.forEach { type -> + sensorManager.registerListener( + listener, sensorManager.getDefaultSensor(type), + SensorManager.SENSOR_DELAY_NORMAL + ) + } + } + + override fun onCancel(arguments: Any?) { + sensorManager.unregisterListener(listener) + } + + val sensorList = listOf( + Sensor.TYPE_ACCELEROMETER, + Sensor.TYPE_GYROSCOPE_UNCALIBRATED, + Sensor.TYPE_GYROSCOPE, + Sensor.TYPE_PRESSURE, + Sensor.TYPE_GRAVITY, + Sensor.TYPE_ROTATION_VECTOR, + Sensor.TYPE_PROXIMITY, + Sensor.TYPE_MAGNETIC_FIELD, + Sensor.TYPE_LIGHT, + Sensor.TYPE_AMBIENT_TEMPERATURE + ) + } + + fun getValue(event: SensorEvent): Map { + val sensor = event.sensor + return when (sensor.type) { + Sensor.TYPE_LIGHT -> mapOf( + "lux" to event.values[0] + ) + Sensor.TYPE_GRAVITY, Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_MAGNETIC_FIELD, Sensor.TYPE_GYROSCOPE, Sensor.TYPE_ROTATION_VECTOR -> mapOf( + "x=" to event.values[0], + "y=" to event.values[1], + "z=" to event.values[2], + "unit" to when (sensor.type) { + Sensor.TYPE_GRAVITY, Sensor.TYPE_ACCELEROMETER -> "m/s²" + Sensor.TYPE_MAGNETIC_FIELD -> "μT" + Sensor.TYPE_GYROSCOPE -> "rad/s" + Sensor.TYPE_ROTATION_VECTOR -> "" + else -> "error" + } + ) + Sensor.TYPE_AMBIENT_TEMPERATURE -> mapOf( + "°C" to event.values[0] + ) + Sensor.TYPE_PRESSURE -> mapOf( + "hPa" to event.values[0] + ) + Sensor.TYPE_PROXIMITY -> mapOf( + "cm" to event.values[0] + ) + else -> mapOf() + } + } + + fun getSensorList(): Map { + val sensorList = sensorManager.getSensorList(SensorManager.SENSOR_ALL) + if (sensorList == null) return mapOf("type" to "error") + var result: Map + result = mapOf( + "type" to "sensor", + "content" to sensorList.map { sensor -> sensor.name } + ) + return result + } + + +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/cpu_z_copy/System.kt b/android/app/src/main/kotlin/com/example/cpu_z_copy/System.kt new file mode 100644 index 0000000..b9014e5 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/cpu_z_copy/System.kt @@ -0,0 +1,56 @@ +package com.example.cpu_z_copy + +import android.app.ActivityManager +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.os.SystemClock +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import java.io.File +import java.lang.System +import kotlin.concurrent.thread + +class System(context: Context) { + + val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + + val handler = object : MethodChannel.MethodCallHandler { + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + + val resultData = mapOf( + "type" to "system", + "content" to when (call.method) { + "android_version" -> Build.VERSION.RELEASE + "api_version" -> Build.VERSION.SDK_INT + "spl" -> Build.VERSION.SECURITY_PATCH + "boot_loader" -> Build.BOOTLOADER + "build_id" -> Build.ID + "java_vm" -> System.getProperty("java.vm.version") + "openGL_version" -> activityManager.deviceConfigurationInfo.glEsVersion + "kernel_arch" -> System.getProperty("os.arch") + "kernel_version" -> try {File("/proc/version").readText()} catch (e: Exception) {"Not Found"} + "root_access" -> File("/system/bin/su").exists() || File("/system/xbin/su").exists() + "gps" -> try { + context.packageManager.getPackageInfo( + "com.google.android.gms", + 0 + ).packageName + } catch (e: PackageManager.NameNotFoundException) { + "not install googlePlayService" + } + "uptime" -> SystemClock.elapsedRealtimeNanos() + else -> { + result.notImplemented() + return + } + } + ) + + result.success(resultData) + } + + + } + +} \ No newline at end of file diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index ca7fe06..7368634 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.11.1" apply false + id("com.android.application") version "8.13.2" apply false id("org.jetbrains.kotlin.android") version "2.2.20" apply false } diff --git a/lib/controller/android_controller.dart b/lib/controller/android_controller.dart deleted file mode 100644 index 25b63e0..0000000 --- a/lib/controller/android_controller.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/services.dart'; - -class AndroidController { - static final _eventChannelName = 'com.example.spu_z_copy_event_channel'; - static final _methodCannelName = 'com.example.spu_z_copy_event_channel'; - - static final _eventPlatform = EventChannel(_eventChannelName); - static final _methodPlatform = MethodChannel(_methodCannelName); - - Stream getBattery() async* { - _eventPlatform.receiveBroadcastStream().listen((event) { - StateController.battery.value = event as int; - }); - } -} - - - -class StateController { - - static ValueNotifier battery = ValueNotifier(0); - - -} \ No newline at end of file diff --git a/lib/controller/base_controller.dart b/lib/controller/base_controller.dart new file mode 100644 index 0000000..cb7e6aa --- /dev/null +++ b/lib/controller/base_controller.dart @@ -0,0 +1,27 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; + +abstract class BaseController { + ValueNotifier updateCount = ValueNotifier(0); + + void updateScreen() => updateCount.value = updateCount.value + 1; + + Map asMap (Map map) { + return Map.from(map); + } + + +} + + +mixin Channel { + + final String _baseEventChannelName = "com.example.spu_z_copy_event_channel"; + final String _baseMethodChannelName = "com.example.spu_z_copy_method_channel"; + + late final batteryEventPlatform = EventChannel(_baseEventChannelName + '_battery'); + late final sensorEventPlatform = EventChannel(_baseEventChannelName + '_sensor'); + late final deviceMethodPlatform = MethodChannel(_baseMethodChannelName + '_device'); + late final systemMethodPlatform = MethodChannel(_baseMethodChannelName + '_system'); + +} \ No newline at end of file diff --git a/lib/controller/battery_controller.dart b/lib/controller/battery_controller.dart new file mode 100644 index 0000000..943962a --- /dev/null +++ b/lib/controller/battery_controller.dart @@ -0,0 +1,44 @@ +import 'dart:async'; + +import 'package:cpu_z_copy/controller/base_controller.dart'; + +class BatteryController extends BaseController with Channel { + int level = 0; + String health = ''; + String PowerSource = ''; + String status = ''; + String Technology = ''; + int Temperature = 0; + int Voltage = 0; + + late StreamSubscription? sub; + + + Stream> batteryStream() { + return batteryEventPlatform.receiveBroadcastStream().where( + (event) { print(event); return event != null && event['type']?.toString() == 'battery';}, + ).map((event) => Map.from(event),); + } + + BatteryController() { + subscribe(); + } + + void dispose () { + sub?.cancel(); + } + + void subscribe() { + final stream = batteryStream(); + sub = stream.listen((data) { + level = data['level']; + health = data['health']; + PowerSource = data['powerSource']; + Technology = data['technology']; + status = data['status']; + Temperature = data['temperature']; + Voltage = data['voltage']; + updateScreen(); + }); + } +} diff --git a/lib/controller/device_controller.dart b/lib/controller/device_controller.dart new file mode 100644 index 0000000..60df246 --- /dev/null +++ b/lib/controller/device_controller.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:cpu_z_copy/controller/base_controller.dart'; + +class DeviceController extends BaseController with Channel { + String model = ""; + String manufacturer = ""; + String board = ""; + String hardware = ""; + double screenSize = 0; + String screenResolution = ""; + int screenDensity = 0; + int totalRam = 0; + int availableRam = 0; + int internalStorage = 0; + int availableStorage = 0; + + Future init() async { + await loadStatic(); + loadDynamic(); + } + + void dispose() { + _timer?.cancel(); + } + + Future loadStatic() async { + model = asMap(await deviceMethodPlatform.invokeMethod('model'))['content']; + manufacturer = asMap( + await deviceMethodPlatform.invokeMethod('manufacturer'), + )['content']; + board = asMap(await deviceMethodPlatform.invokeMethod('board'))['content']; + hardware = asMap( + await deviceMethodPlatform.invokeMethod('hardware'), + )['content']; + await deviceMethodPlatform.invokeMethod('screen').then((value) { + screenSize = asMap(asMap(value)['content'])['size']; + screenResolution = asMap(asMap(value)['content'])['resolution']; + screenDensity = asMap(asMap(value)['content'])['density']; + }); + await deviceMethodPlatform.invokeMethod('ram').then((value) { + totalRam = asMap(asMap(value)['content'])['total']; + availableRam = asMap(asMap(value)['content'])['available']; + }); + await deviceMethodPlatform.invokeMethod('storage').then((value) { + internalStorage = asMap(asMap(value)['content'])['total']; + availableStorage = asMap(asMap(value)['content'])['available']; + }); + updateScreen(); + } + + Timer? _timer; + + void loadDynamic() { + _timer = Timer.periodic(Duration(seconds: 1), (_) async { + await deviceMethodPlatform.invokeMethod('ram').then((value) { + totalRam = asMap(asMap(value)['content'])['total']; + availableRam = asMap(asMap(value)['content'])['available']; + }); + await deviceMethodPlatform.invokeMethod('storage').then((value) { + internalStorage = asMap(asMap(value)['content'])['total']; + availableStorage = asMap(asMap(value)['content'])['available']; + }); + updateScreen(); + }); + } +} diff --git a/lib/controller/sensor_contollrer.dart b/lib/controller/sensor_contollrer.dart new file mode 100644 index 0000000..528aff3 --- /dev/null +++ b/lib/controller/sensor_contollrer.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:cpu_z_copy/controller/base_controller.dart'; +import 'package:cpu_z_copy/model/sensor_model.dart'; + +class SensorController extends BaseController with Channel { + List sensorList = []; + + late StreamSubscription? sub; + + Stream> sensorStream() { + return sensorEventPlatform.receiveBroadcastStream().where( + (event) => event != null && event['type']?.toString() == 'sensor', + ).map((event) => Map.from(event),); + } + + + SensorController() { + subscribe(); + } + + void dispose () { + sub?.cancel(); + } + + + void subscribe() { + final stream = sensorStream(); + sub = stream.listen((data) { + final matchSensor = sensorList + .where((sensor) => sensor.type == data['sensor_type']) + .firstOrNull; + + if (matchSensor != null) sensorList.remove(matchSensor); + sensorList.add(SensorModel.fromJson(data)); + sensorList.sort((a, b) => a.type.compareTo(b.type)); + updateScreen(); + }); + } + + static String getSensorInfo(SensorModel sensor) { + bool reverse = false; + sensor.content.keys.forEach( + (unit) => !reverse ? reverse = unit.contains('=') : null, + ); + + if (reverse) { + return sensor.content.entries + .map( + (content) => !content.key.contains('unit') + ? "${content.key} ${content.value.toStringAsFixed(6)} ${sensor.content['unit']}" + : "", + ) + .join(" "); + } + return sensor.content.entries + .map((content) => "${content.value.toStringAsFixed(6)} ${content.key}") + .join(" "); + } +} diff --git a/lib/controller/system_controller.dart b/lib/controller/system_controller.dart new file mode 100644 index 0000000..973dd5f --- /dev/null +++ b/lib/controller/system_controller.dart @@ -0,0 +1,80 @@ +import 'dart:async'; + +import 'package:cpu_z_copy/controller/base_controller.dart'; + +class SystemController extends BaseController with Channel { + String androidVersion = ""; + int apiVersion = 0; + String spl = ""; + String bootLoader = ""; + String buildId = ""; + String javaVm = ""; + String openGLVersion = ""; + String kernelArch = ""; + String kernelVersion = ""; + bool rootAccess = false; + String gps = ""; + Duration uptime = Duration(milliseconds: 0); + + Timer? _timer; + + Future init() async { + loadStatic(); + loadDynamic(); + } + + void dispose () { + _timer?.cancel(); + _timer = null; + } + + Future loadStatic() async { + print("affer"); + androidVersion = asMap( + await systemMethodPlatform.invokeMethod("android_version"), + )["content"]; + apiVersion = asMap( + await systemMethodPlatform.invokeMethod("api_version"), + )["content"]; + spl = asMap(await systemMethodPlatform.invokeMethod("spl"))["content"]; + bootLoader = asMap( + await systemMethodPlatform.invokeMethod("boot_loader"), + )["content"]; + buildId = asMap( + await systemMethodPlatform.invokeMethod("build_id"), + )["content"]; + javaVm = asMap( + await systemMethodPlatform.invokeMethod("java_vm"), + )["content"]; + openGLVersion = asMap( + await systemMethodPlatform.invokeMethod("openGL_version"), + )["content"]; + kernelArch = asMap( + await systemMethodPlatform.invokeMethod("kernel_arch"), + )["content"]; + kernelVersion = asMap( + await systemMethodPlatform.invokeMethod("kernel_version"), + )["content"]; + rootAccess = asMap( + await systemMethodPlatform.invokeMethod("root_access"), + )["content"]; + gps = asMap(await systemMethodPlatform.invokeMethod("gps"))["content"]; + uptime = Duration( + milliseconds: asMap( + await systemMethodPlatform.invokeMethod("uptime"), + )["content"], + ); + updateScreen(); + } + + void loadDynamic() { + _timer = Timer.periodic(Duration(seconds: 1), (timer) async { + uptime = Duration( + milliseconds: asMap( + await systemMethodPlatform.invokeMethod("uptime"), + )["content"], + ); + updateScreen(); + }); + } +} diff --git a/lib/main.dart b/lib/main.dart index c02b2d3..2eedfd4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:cpu_z_copy/screen/base_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; void main() { runApp(MaterialApp(debugShowCheckedModeBanner: false, home: BaseScreen())); @@ -15,4 +16,6 @@ class Global { static Color lightGrey = Colors.grey.shade200; static Color linkBlue = Colors.indigo; + static NumberFormat floatDot2 = NumberFormat('#.##'); + } \ No newline at end of file diff --git a/lib/model/sensor_model.dart b/lib/model/sensor_model.dart new file mode 100644 index 0000000..d593547 --- /dev/null +++ b/lib/model/sensor_model.dart @@ -0,0 +1,22 @@ +class SensorModel { + final int id; + final String name; + final String type; + final Map content; + + SensorModel({ + required this.id, + required this.name, + required this.type, + required this.content, + }); + + static SensorModel fromJson(Map json) { + return SensorModel( + id: json['id'], + name: json['name'], + type: json['sensor_type'], + content: (json['content'] as Map).map((key, value) => MapEntry(key.toString(), value),), + ); + } +} diff --git a/lib/screen/base_screen.dart b/lib/screen/base_screen.dart index a58a22f..97aa5ef 100644 --- a/lib/screen/base_screen.dart +++ b/lib/screen/base_screen.dart @@ -5,9 +5,14 @@ import 'package:cpu_z_copy/widget/top_bar.dart'; import 'package:flutter/material.dart'; @immutable -class BaseScreen extends StatelessWidget { +class BaseScreen extends StatefulWidget { BaseScreen({super.key}); + @override + State createState() => _BaseScreenState(); +} + +class _BaseScreenState extends State { final List keyList = [ 'SOC', 'DEVICE', @@ -19,73 +24,110 @@ class BaseScreen extends StatelessWidget { ]; final List pageList = [ - SOC(key: Key('SOC'),), - Device(key: Key('DEVICE'),), - System(key: Key('SYSTEM')), - Battery(key: Key('BATTERY')), - Thermal(key: Key('THERMAL')), - Sensors(key: Key('SENSORS')), - About(key: Key('ABOUT')), + SOC(), + Device(), + System(), + Battery(), + Thermal(), + Sensors(), + About(), ]; - final ValueNotifier _curIndex = ValueNotifier(0); + final ScrollController _scrollController = ScrollController(); + final PageController _pageController = PageController(); + final GlobalKey _tapListKey = GlobalKey(); - void moveTo(int value) { _curIndex.value = value;} + final double _tapWidth = 84; - double? screen; + Future moveTo(int index) async { + final halfWidth = MediaQuery.of(context).size.width / 2; + final curWidth = _tapWidth * index; + _curIndex.value = index; + await _pageController.animateToPage( + index, + duration: Duration(milliseconds: 300), + curve: Curves.ease, + ); + + await _scrollController.animateTo( + curWidth + curWidth > halfWidth ? halfWidth : 0, + duration: Duration(milliseconds: 300), + curve: Curves.ease, + ); + } + + double? screen; @override Widget build(BuildContext context) { screen = MediaQuery.of(context).size.height; - return DefaultLayout(appBar: TopBar(), child: Column(children: [ - - tapList(), - - Expanded( - child: PageView.builder( - controller: _pageController, - onPageChanged: moveTo, - itemBuilder: (_, index) => pageList[index], - itemCount: pageList.length, - ), + return DefaultLayout( + appBar: TopBar(), + child: Column( + children: [ + _tapList(), + + Expanded( + child: PageView.builder( + controller: _pageController, + onPageChanged: moveTo, + itemBuilder: (_, index) => pageList[index], + itemCount: pageList.length, + ), + ), + ], ), - - - ],), ); } - - Widget tapList () { - return SingleChildScrollView(scrollDirection:.horizontal, controller: _scrollController, - child: ValueListenableBuilder(valueListenable: _curIndex, - builder: (_, value, _) => Row(key: _tapListKey, children: List.generate(keyList.length, - (index) => tap(keyList[index], index)),) - )); + Widget _tapList() { + return SingleChildScrollView( + scrollDirection: .horizontal, + controller: _scrollController, + child: ValueListenableBuilder( + valueListenable: _curIndex, + builder: (_, value, _) => Row( + key: _tapListKey, + children: List.generate( + keyList.length, + (index) => _tap(keyList[index], index), + ), + ), + ), + ); } - - Widget tap (String text, int index) { + Widget _tap(String text, int index) { final bool isCurIndex = _curIndex.value == index; return InkWell( - onTap: () {moveTo(index);}, + onTap: () async { + await moveTo(index); + }, child: Container( - padding: EdgeInsets.symmetric(horizontal: 11, vertical: 8), + width: _tapWidth, + height: 48, + alignment: .center, decoration: BoxDecoration( - border: isCurIndex ? BoxBorder.fromLTRB(bottom: BorderSide(color: Global.mainColor, width: 5)) : null, + border: isCurIndex + ? BoxBorder.fromLTRB( + bottom: BorderSide(color: Global.mainColor, width: 5), + ) + : null, ), - child: Text(text, style: TextStyle(color: isCurIndex ? Global.mainColor : Global.grey, fontWeight: .w600, fontSize: 15),)), + child: Text( + text, + style: TextStyle( + color: isCurIndex ? Global.mainColor : Global.grey, + fontWeight: .w600, + fontSize: 16, + ), + ), + ), ); } - - } - - - - diff --git a/lib/screen/pages.dart b/lib/screen/pages.dart index a0fe506..42526db 100644 --- a/lib/screen/pages.dart +++ b/lib/screen/pages.dart @@ -1,8 +1,11 @@ -import 'dart:io'; - +import 'package:cpu_z_copy/controller/battery_controller.dart'; +import 'package:cpu_z_copy/controller/device_controller.dart'; +import 'package:cpu_z_copy/controller/sensor_contollrer.dart'; +import 'package:cpu_z_copy/controller/system_controller.dart'; import 'package:cpu_z_copy/main.dart'; import 'package:cpu_z_copy/widget/info_item.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; class SOC extends StatelessWidget { SOC({super.key}); @@ -10,77 +13,262 @@ class SOC extends StatelessWidget { @override Widget build(BuildContext context) { return SingleChildScrollView( - child: Column(children: [ - InfoItem(title: 'Model', infos: ['dfagdsfg',]), - InfoItem(title: 'Cores', infos: ['dfagdsfg']), - InfoItem(title: 'big.LITTLE', infos: ['sadfasfds']), - InfoItem(title: 'Topology', infos: ['dfagdsfg',]), - InfoItem(title: 'Revision', infos: ['dfagdsfg',]), - InfoItem(title: 'Clock Speed', infos: ['dfagdsfg',]), - ...List.generate(8, (index) => Padding(padding: const EdgeInsets.only(left: 12), child: InfoItem(title: 'CPU $index', infos: ['ddfg']),),), - InfoItem(title: 'GPU Load', infos: ['%']), - InfoItem(title: 'Scaling Governor', infos: ['dfsgdf']), - ]), + child: Column( + children: [ + InfoItem(title: 'Model', infos: ['dfagdsfg']), + InfoItem(title: 'Cores', infos: ['dfagdsfg']), + InfoItem(title: 'big.LITTLE', infos: ['sadfasfds']), + InfoItem(title: 'Topology', infos: ['dfagdsfg']), + InfoItem(title: 'Revision', infos: ['dfagdsfg']), + InfoItem(title: 'Clock Speed', infos: ['dfagdsfg']), + ...List.generate( + 8, + (index) => Padding( + padding: const EdgeInsets.only(left: 12), + child: InfoItem(title: 'CPU $index', infos: ['ddfg']), + ), + ), + InfoItem(title: 'GPU Load', infos: ['%']), + InfoItem(title: 'Scaling Governor', infos: ['dfsgdf']), + ], + ), ); } } -class Device extends StatelessWidget { +class Device extends StatefulWidget { const Device({super.key}); + @override + State createState() => _DeviceState(); +} + +class _DeviceState extends State { + late DeviceController _deviceController; + + @override + void initState() { + _deviceController = DeviceController(); + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + _deviceController.init(); + }); + } + + @override + void dispose() { + _deviceController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return Column(children: [ - InfoItem(title: 'Model', infos: ['dd']), - InfoItem(title: 'Manufacturer', infos: ['dd']), - InfoItem(title: 'Board', infos: ['dd']), - InfoItem(title: 'Hardware', infos: ['dd']), - InfoItem(title: 'Screen Size', infos: ['dd']), - InfoItem(title: 'Screen Resolution', infos: ['dd']), - InfoItem(title: 'Screen Density', infos: ['dd']), - InfoItem(title: 'Total RAM', infos: ['dd']), - InfoItem(title: 'Available', infos: ['dd']), - InfoItem(title: 'Internal Storage', infos: ['dd']), - InfoItem(title: 'Available Storage', infos: ['dd']), - ]); + return ValueListenableBuilder( + valueListenable: _deviceController.updateCount, + builder: (context, value, child) { + return Column( + children: [ + InfoItem(title: 'Model', infos: [_deviceController.model]), + InfoItem( + title: 'Manufacturer', + infos: [_deviceController.manufacturer], + ), + InfoItem(title: 'Board', infos: [_deviceController.board]), + InfoItem(title: 'Hardware', infos: [_deviceController.hardware]), + InfoItem( + title: 'Screen Size', + infos: [ + Global.floatDot2.format(_deviceController.screenSize) + + " inches", + ], + ), + InfoItem( + title: 'Screen Resolution', + infos: [_deviceController.screenResolution], + ), + InfoItem( + title: 'Screen Density', + infos: ["${_deviceController.screenDensity}" + " dpi"], + ), + InfoItem( + title: 'Total RAM', + infos: [ + Global.floatDot2.format(_deviceController.totalRam / 1e6) + + " MB", + ], + ), + InfoItem( + title: 'Available', + infos: [ + Global.floatDot2.format(_deviceController.availableRam / 1e6) + + " MB", + ], + ), + InfoItem( + title: 'Internal Storage', + infos: [ + Global.floatDot2.format( + _deviceController.internalStorage / 1e6, + ) + + " MB", + ], + ), + InfoItem( + title: 'Available Storage', + infos: [ + Global.floatDot2.format( + _deviceController.availableStorage / 1e9, + ) + + " GB", + ], + ), + ], + ); + }, + ); } } -class System extends StatelessWidget { +class System extends StatefulWidget { const System({super.key}); + @override + State createState() => _SystemState(); +} + +class _SystemState extends State { + late SystemController _systemController; + + @override + void initState() { + _systemController = SystemController(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + _systemController.init(); + }); + super.initState(); + } + + String durationFormat(Duration d) { + final days = d.inDays; + final hours = d.inHours % 24; + final minutes = d.inMinutes % 60; + final seconds = d.inSeconds % 60; + + return '${days.toString()}. ' + '${hours.toString()}:' + '${minutes.toString()}:' + '${seconds.toString()}'; + } + @override Widget build(BuildContext context) { - return Column(children: [ - InfoItem(title: 'Android Version', infos: ['']), - InfoItem(title: 'API Level', infos: ['']), - InfoItem(title: 'Security Patch Level', infos: ['']), - InfoItem(title: 'Bootloader', infos: ['']), - InfoItem(title: 'Build ID', infos: ['']), - InfoItem(title: 'Java VM', infos: ['']), - InfoItem(title: 'Kernel Architecture', infos: ['']), - InfoItem(title: 'Kernel Version', infos: ['']), - InfoItem(title: 'Root Access', infos: ['']), - InfoItem(title: 'Google Play Services', infos: ['']), - InfoItem(title: 'System Uptime', infos: ['']), - ]); + return ValueListenableBuilder( + valueListenable: _systemController.updateCount, + builder: (context, value, child) { + return Column( + children: [ + InfoItem( + title: 'Android Version', + infos: [_systemController.androidVersion], + ), + InfoItem( + title: 'API Level', + infos: ["${_systemController.apiVersion}"], + ), + InfoItem( + title: 'Security Patch Level', + infos: [_systemController.spl], + ), + InfoItem( + title: 'Bootloader', + infos: [_systemController.bootLoader], + ), + InfoItem(title: 'Build ID', infos: [_systemController.buildId]), + InfoItem(title: 'Java VM', infos: [_systemController.javaVm]), + InfoItem( + title: 'OpenGL Version', + infos: [_systemController.openGLVersion], + ), + InfoItem( + title: 'Kernel Architecture', + infos: [_systemController.kernelArch], + ), + InfoItem( + title: 'Kernel Version', + infos: [_systemController.kernelVersion], + ), + InfoItem( + title: 'Root Access', + infos: [_systemController.rootAccess ? "Yes" : "No"], + ), + InfoItem( + title: 'Google Play Services', + infos: [_systemController.gps], + ), + InfoItem( + title: 'System Uptime', + infos: [durationFormat(_systemController.uptime)], + ), + ], + ); + }, + ); } } -class Battery extends StatelessWidget { +class Battery extends StatefulWidget { const Battery({super.key}); @override - Widget build(BuildContext context) { - return Column(children: [ - InfoItem(title: 'Health', infos: []), - InfoItem(title: 'Level', infos: []), - InfoItem(title: 'Power Source', infos: []), - InfoItem(title: 'Technology', infos: []), - InfoItem(title: 'Temperature', infos: []), - InfoItem(title: 'Voltage', infos: []), + State createState() => _BatteryState(); +} - ]); +class _BatteryState extends State { + late BatteryController _batteryController; + + @override + void initState() { + _batteryController = BatteryController(); + super.initState(); + } + + @override + void dispose() { + _batteryController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: _batteryController.updateCount, + builder: (context, value, child) { + return Column( + children: [ + InfoItem(title: 'Health', infos: [_batteryController.health]), + InfoItem(title: 'Level', infos: ['${_batteryController.level} %']), + InfoItem( + title: 'Power Source', + infos: [_batteryController.PowerSource], + ), + InfoItem(title: 'Status', infos: [_batteryController.status]), + InfoItem( + title: 'Technology', + infos: [_batteryController.Technology], + ), + InfoItem( + title: 'Temperature', + infos: ['${_batteryController.Temperature} °C'], + ), + InfoItem( + title: 'Voltage', + infos: ['${_batteryController.Voltage} mV'], + ), + ], + ); + }, + ); } } @@ -89,64 +277,61 @@ class Thermal extends StatelessWidget { @override Widget build(BuildContext context) { - return Column(children: [ - InfoItem(title: 'Battery', infos: ['C']), - InfoItem(title: 'ac', infos: ['C']), - InfoItem(title: 'battery', infos: ['C']), - ]); + return Column( + children: [ + InfoItem(title: 'Battery', infos: ['C']), + InfoItem(title: 'ac', infos: ['C']), + InfoItem(title: 'battery', infos: ['C']), + ], + ); } } -class Sensors extends StatelessWidget { +class Sensors extends StatefulWidget { const Sensors({super.key}); + @override + State createState() => _SensorsState(); +} + +class _SensorsState extends State { + late SensorController _sensorController; + + @override + void initState() { + _sensorController = SensorController(); + super.initState(); + } + + @override + void dispose() { + _sensorController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return SingleChildScrollView( - child: Column(children: [ - SensorItem(title: 'LSM6DSO Accelerometer', info: ''), - SensorItem(title: 'AK09918 Magnetometer', info: ''), - SensorItem(title: 'LSM6DSO Gyroscope', info: ''), - SensorItem(title: 'TMD4907 Light Ambient Light Sensor Non-wakeup', info: ''), - SensorItem(title: 'Ips22hh Pressure Sensor Non-wakeup', info: ''), - SensorItem(title: 'gravity Non-wakeup', info: ''), - SensorItem(title: 'linear_acceleration', info: ''), - SensorItem(title: 'Rotation Vector Non-wakeup', info: ''), - SensorItem(title: 'AL09918 Magnetometer', info: ''), - SensorItem(title: 'Game Rotation Vector Non-wakeup', info: ''), - SensorItem(title: 'Rotation Vector Non-wakeup', info: ''), - SensorItem(title: 'LSM6DSO Gyroscope-Uncalibrated', info: ''), - SensorItem(title: 'sdm Wakeup', info: ''), - SensorItem(title: 'step_detector Non-wakeup', info: ''), - SensorItem(title: 'step_counter Non-wakeup', info: ''), - SensorItem(title: 'Tilt Detector Wakeup', info: ''), - SensorItem(title: 'Pick Up Gesture Wakeup', info: ''), - SensorItem(title: 'Screen Orientation Sensor', info: ''), - SensorItem(title: 'motion_detect', info: ''), - SensorItem(title: 'LSM6DSO Accelerometer_Uncalibrated', info: ''), - SensorItem(title: 'WideIR ALS', info: ''), - SensorItem(title: 'interrupt_gyro Non-wakeup', info: ''), - SensorItem(title: 'Proximity strm', info: ''), - SensorItem(title: 'SensorHub type', info: ''), - SensorItem(title: 'TMD4907 Light CCT Non-wakeup', info: ''), - SensorItem(title: 'Wake Up Motion Wakeup', info: ''), - SensorItem(title: 'TMD4907 Proximity Proximity Sensor Wakeup', info: ''), - SensorItem(title: 'call_gesture Wakeup', info: ''), - SensorItem(title: 'TMD4907 Light Auto Brightness Non-wakeup', info: ''), - SensorItem(title: 'Pocket mode Wakeup', info: ''), - SensorItem(title: 'Led Cover Event Wakeup', info: ''), - SensorItem(title: 'Shake to Share Wakeup', info: ''), - SensorItem(title: 'Sar BackOff Motion Wakeup', info: ''), - SensorItem(title: 'Pocket Position Mode Wakeup', info: ''), - SensorItem(title: 'SX9360 Grip sensor', info: ''), - SensorItem(title: 'Touch Proximity Sensor', info: ''), - SensorItem(title: 'Hall IC', info: ''), - SensorItem(title: 'TCS3407 Rear ALS', info: ''), - SensorItem(title: 'Palm Proximity Sensor version 2', info: ''), - SensorItem(title: 'Motion Sensor', info: ''), - SensorItem(title: 'Orientation Sensor', info: ''), - //Wake Up Motion WakeUp - ]), + return ValueListenableBuilder( + valueListenable: _sensorController.updateCount, + builder: (context, value, child) { + return SingleChildScrollView( + child: Column( + children: [ + ...List.generate( + _sensorController.sensorList.length, + (index) => SensorItem( + title: _sensorController.sensorList[index].name, + info: SensorController.getSensorInfo( + _sensorController.sensorList[index], + ), + ), + ), + + SizedBox(height: 100), + ], + ), + ); + }, ); } } @@ -156,74 +341,90 @@ class About extends StatelessWidget { @override Widget build(BuildContext context) { - return Column(children: [ - - SizedBox(height: 24,), - - Text('CPU-Z', style: TextStyle(color: Global.mainColorDark, fontSize: 26, fontWeight: .w700),), - _subTip('for Android'), - _subTip('Version 1.54'), - Padding(padding: const EdgeInsets.symmetric(vertical: 8), - child: _subSubTip('CPUID DPU-Z is a free software.')), - - - Padding( - padding: EdgeInsets.symmetric(horizontal: 74, vertical: 54), - child: Column(spacing: 12, children: [ - _button(() {}, 'ONLINE VALIDATION'), - _button(() {}, 'CPU-Z SETTINGS'), - _button(() {}, 'HELP AND FAQ'), - _button(() {}, 'REMOVE ADS'), - ],), - ), + return Column( + children: [ + SizedBox(height: 24), + + Text( + 'CPU-Z', + style: TextStyle( + color: Global.mainColorDark, + fontSize: 26, + fontWeight: .w700, + ), + ), + _subTip('for Android'), + _subTip('Version 1.54'), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: _subSubTip('CPUID DPU-Z is a free software.'), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 74, vertical: 54), + child: Column( + spacing: 12, + children: [ + _button(() {}, 'ONLINE VALIDATION'), + _button(() {}, 'CPU-Z SETTINGS'), + _button(() {}, 'HELP AND FAQ'), + _button(() {}, 'REMOVE ADS'), + ], + ), + ), Spacer(), - Column(children: [ - - _link('CPUID Web Page'), - _link('Validation Web Page'), - SizedBox(height: 6,), - _subSubTip('Copyright 2025 - CPUID - All Rights Reserved'), - - ],), - - - ]); + Column( + children: [ + _link('CPUID Web Page'), + _link('Validation Web Page'), + SizedBox(height: 6), + _subSubTip('Copyright 2025 - CPUID - All Rights Reserved'), + ], + ), + ], + ); } - Widget _subTip (String text) { - return Text(text, style: TextStyle(color: Global.grey, fontWeight: .w600),); + Widget _subTip(String text) { + return Text( + text, + style: TextStyle(color: Global.grey, fontWeight: .w600), + ); } - Widget _subSubTip (String text) { - return Text(text, style: TextStyle(fontWeight: .w400, color: Global.grey),); + Widget _subSubTip(String text) { + return Text( + text, + style: TextStyle(fontWeight: .w400, color: Global.grey), + ); } - - Widget _button (VoidCallback onTap, String text) { + Widget _button(VoidCallback onTap, String text) { return SizedBox( height: 34, width: double.infinity, child: TextButton( onPressed: onTap, - child: Text(text, style: TextStyle(color: Colors.white),), + child: Text(text, style: TextStyle(color: Colors.white)), style: TextButton.styleFrom( - backgroundColor: Global.mainColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + backgroundColor: Global.mainColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ), ); } - - Widget _link (String text) { - return Text(text, - style: TextStyle(color: Global.linkBlue, - decoration: TextDecoration.underline, decorationThickness: 1, decorationColor: Global.linkBlue - ),); + Widget _link(String text) { + return Text( + text, + style: TextStyle( + color: Global.linkBlue, + decoration: TextDecoration.underline, + decorationThickness: 1, + decorationColor: Global.linkBlue, + ), + ); } - - } diff --git a/pubspec.lock b/pubspec.lock index 688d871..9410375 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -75,6 +75,14 @@ packages: description: flutter source: sdk version: "0.0.0" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" leak_tracker: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fb92d46..e30bb65 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 + intl: ^0.20.2 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index a4b190f..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -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:cpu_z_copy/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); - }); -}