import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:surface_tension_calculator/models/stc_output.dart'; import '../res/assets.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { PlatformFile? _imageFile; STCOutput out = STCOutput.clearOutput(); static const String scriptPath = 'scripts/img_V01.exe'; Future _pickImage() async { try { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.image, ); if (result == null) return; setState(() { _imageFile = result.files.first; }); } catch (e) {} } Future _computeSTC() async { final List args = [ '-img', _imageFile!.path ?? '', '-out', 'water-drop', '-proc', '8', ]; await Process.run(scriptPath, args); out = STCOutput( negCoordFile: 'negCoordFile', posCoordFile: 'posCoordFile', syringeWidth: 0.123, radiusCurvRange: 'asd', shapeFactorRange: 'asd', initXCoordRange: 'asd', initAngleRange: 'asd', paramCombinations: 123, numProcessors: 123, juza: 12.09, bestOutput: [0.123, 12.213], lowestRMSD: 0.123, surfaceTension: 0.123, bestRadiusOfCurvature: 0.123, bestShapeFactor: 0.123, bestInitialXCoordinate: 123.123, bestInitialAngle: 234.123, elapsedTime: 12.12345, ); } @override Widget build(BuildContext context) { return Scaffold( body: SizedBox.expand( child: Container( padding: const EdgeInsets.only(top: 35.0, left: 25, right: 25), color: Color(0xFF7B1113), child: Column( children: [ buildHeader(), const SizedBox(height: 20), Container( padding: const EdgeInsets.all(25), decoration: BoxDecoration( color: Colors.grey.shade300, borderRadius: BorderRadius.circular(30), ), child: IntrinsicHeight( child: Row( children: [ buildLeftImage(), const SizedBox(width: 20), const VerticalDivider(width: 20), const SizedBox(width: 20), buildRightResults(), ], ), ), ), const SizedBox(height: 20), buildFooter(), ], ), ), ), ); } Widget buildFooter() { return Center( child: Text( '\u00a9 2025 UP Intelligent Systems Center', style: TextStyle(color: Colors.white), ), ); } Widget buildHeader() { return IntrinsicHeight( child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox(width: 20), Image.asset(Assets.logo, height: 70), const SizedBox(width: 10), const VerticalDivider(), const SizedBox(width: 10), Text( 'SURFACE TENSION CALCULATOR', style: TextStyle( fontSize: 45, fontWeight: FontWeight.w500, color: Colors.white, ), ), ], ), ); } Column buildLeftImage() { return Column( children: [ if (_imageFile == null) Container( height: 400, width: 500, decoration: BoxDecoration( color: Colors.grey.shade500, borderRadius: BorderRadius.circular(30), ), child: Center(child: Text('No image uploaded')), ), if (_imageFile != null) Container( height: 400, width: 500, decoration: BoxDecoration( color: Colors.grey.shade500, borderRadius: BorderRadius.circular(30), ), child: Image.memory(Uint8List.fromList(_imageFile!.bytes!)), ), const SizedBox(height: 15), Row( children: [ ElevatedButton( onPressed: _pickImage, child: Text('Upload Droplet Image'), ), const SizedBox(width: 10), ElevatedButton( onPressed: _imageFile == null ? null : _computeSTC, child: Text('Compute Surface Tension'), ), ], ), ], ); } Widget buildRightResults() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Results:', style: TextStyle(fontSize: 30, fontWeight: FontWeight.w600), ), const SizedBox(height: 10), SingleChildScrollView(child: buildResults()), // Text(out), ], ); } Widget buildResults() { return Row( children: [ buildOutputFields(), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(out.posCoordFile), Text(out.posCoordFile), Text(out.syringeWidth.toString()), Text(out.radiusCurvRange), Text(out.shapeFactorRange), Text(out.initXCoordRange), Text(out.initAngleRange), Text(out.paramCombinations.toString()), Text(out.numProcessors.toString()), Text(out.juza.toString()), Text(''), Text(''), Text(out.bestOutput.toString()), Text(''), Text(out.lowestRMSD.toString()), Text(out.surfaceTension.toString()), Text(out.bestRadiusOfCurvature.toString()), Text(out.bestShapeFactor.toString()), Text(out.bestInitialXCoordinate.toString()), Text(out.bestInitialAngle.toString()), Text(out.elapsedTime.toString()), ], ), ], ); //Text(Strings.sampleOut); } Column buildOutputFields() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Negative Coordinate File: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Positive Coordinate File: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Syringe Width (millimeter): ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Radius of Curvature: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Shape Factor Range: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Initial X Coordinate: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Initial Angle Range: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Parameter Combinations: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Number of Process: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Juza 5-Plane (1/H) Std.Dev: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text(''), Text( 'minimization success', style: TextStyle(fontWeight: FontWeight.w600), ), Text('best output: ', style: TextStyle(fontWeight: FontWeight.w600)), Text('', style: TextStyle(fontWeight: FontWeight.w600)), Text('Lowest RMSD: ', style: TextStyle(fontWeight: FontWeight.w600)), Text( 'Computed Surface Tension: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Best Radius of Curvature: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Best Shape Factor: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Best Initial X Coordinate: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Best Initial Angle: ', style: TextStyle(fontWeight: FontWeight.w600), ), Text( 'Lapsed Time (seconds): ', style: TextStyle(fontWeight: FontWeight.w600), ), ], ); } }