feat: change ui
This commit is contained in:
parent
357bdfe60d
commit
77fc37ee52
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '12.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:harvest_guard_app/routes/app_routes.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({super.key});
|
||||
|
@ -9,81 +10,193 @@ class SplashScreen extends StatefulWidget {
|
|||
State<SplashScreen> createState() => _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
class _SplashScreenState extends State<SplashScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _rotationAnimation;
|
||||
late Animation<double> _scaleAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Tunggu selama 3 detik kemudian navigasi ke Dashboard dengan AppRoutes
|
||||
|
||||
// Animation controller
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 3),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
// Rotation animation
|
||||
_rotationAnimation = Tween<double>(
|
||||
begin: 0,
|
||||
end: 2 * math.pi,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
|
||||
// Scale animation
|
||||
_scaleAnimation = Tween<double>(
|
||||
begin: 0.8,
|
||||
end: 1.0,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.elasticOut,
|
||||
));
|
||||
|
||||
// Start animation
|
||||
_controller.forward();
|
||||
|
||||
// Navigate to intro screen after 3 seconds
|
||||
Future.delayed(const Duration(seconds: 3), () {
|
||||
Get.offNamed(
|
||||
AppRoutes.dashboard); // Menggunakan konstanta route dari AppRoutes
|
||||
Get.offNamed(AppRoutes.intro); // Change to intro route
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// Spacer untuk menjaga tampilan di tengah
|
||||
const Spacer(flex: 2),
|
||||
|
||||
// Logo tanaman menggunakan Image.asset
|
||||
Center(
|
||||
body: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Colors.green.shade100,
|
||||
Colors.green.shade300,
|
||||
Colors.green.shade500,
|
||||
],
|
||||
stops: [0.0, 0.5 + _controller.value * 0.2, 1.0],
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/plant.png',
|
||||
height: 60,
|
||||
width: 60,
|
||||
const Spacer(flex: 2),
|
||||
|
||||
// Logo dengan animasi
|
||||
Center(
|
||||
child: Column(
|
||||
children: [
|
||||
ScaleTransition(
|
||||
scale: _scaleAnimation,
|
||||
child: RotationTransition(
|
||||
turns: _rotationAnimation,
|
||||
child: Container(
|
||||
height: 80,
|
||||
width: 80,
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.eco_rounded,
|
||||
size: 50,
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
|
||||
// Teks Harvest - Guard dengan animasi
|
||||
AnimatedOpacity(
|
||||
opacity: _controller.value,
|
||||
duration: const Duration(milliseconds: 800),
|
||||
child: const Text(
|
||||
'Harvest - Guard',
|
||||
style: TextStyle(
|
||||
fontSize: 26,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
letterSpacing: 1.2,
|
||||
shadows: [
|
||||
Shadow(
|
||||
color: Colors.black26,
|
||||
offset: Offset(1, 1),
|
||||
blurRadius: 3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Sub text
|
||||
FadeTransition(
|
||||
opacity: _controller,
|
||||
child: const Text(
|
||||
'Proteksi Tanaman Padi Anda',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
const Spacer(flex: 3),
|
||||
|
||||
// Teks Harvest - Guard
|
||||
const Text(
|
||||
'Harvest - Guard',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
// Teks "Developed by" dengan animasi
|
||||
FadeTransition(
|
||||
opacity: _controller,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
'Developed by',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white70,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Nama developer dengan animasi
|
||||
FadeTransition(
|
||||
opacity: _controller,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(bottom: 32.0),
|
||||
child: Text(
|
||||
'Bahrudin Ayub',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Spacer untuk mendorong "Developed by" ke bagian bawah
|
||||
const Spacer(flex: 3),
|
||||
|
||||
// Teks "Developed by"
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
'Developed by',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Nama developer
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 32.0),
|
||||
child: Text(
|
||||
'Bahrudin Ayub',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,34 +1,109 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:harvest_guard_app/periksa/model_controller.dart';
|
||||
import 'package:harvest_guard_app/routes/app_routes.dart';
|
||||
|
||||
|
||||
class DashboardController extends GetxController {
|
||||
class DashboardController extends GetxController
|
||||
with GetSingleTickerProviderStateMixin {
|
||||
// User name state
|
||||
var userName = "Petani".obs;
|
||||
|
||||
|
||||
// Reference to ModelController for scan history
|
||||
late final ModelController modelController;
|
||||
|
||||
|
||||
// Animation controller
|
||||
late AnimationController animationController;
|
||||
|
||||
// Animation status
|
||||
var animationCompleted = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
|
||||
// Get ModelController instance
|
||||
if (!Get.isRegistered<ModelController>()) {
|
||||
Get.put(ModelController());
|
||||
}
|
||||
modelController = Get.find<ModelController>();
|
||||
|
||||
// Initialize animation controller - hanya jalankan sekali
|
||||
animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 2000), // Durasi total animasi
|
||||
);
|
||||
|
||||
// Tambahkan listener untuk memastikan nilai dalam batas
|
||||
animationController.addListener(() {
|
||||
// Pastikan nilai animasi selalu dalam rentang 0.0 - 1.0
|
||||
if (animationController.value < 0.0 || animationController.value > 1.0) {
|
||||
animationController.value = animationController.value.clamp(0.0, 1.0);
|
||||
}
|
||||
});
|
||||
|
||||
// Mulai animasi sekali ketika halaman dimuat
|
||||
// Pastikan animasi hanya jalan sekali dan tidak repeat
|
||||
animationController.forward().then((_) {
|
||||
animationCompleted.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
animationController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
// Fungsi untuk memulai pemindaian dan navigasi ke PeriksaScreen
|
||||
void startScanning() {
|
||||
// Navigasi ke PeriksaScreen menggunakan AppRoutes
|
||||
Get.toNamed(AppRoutes.periksa);
|
||||
// Haptic feedback
|
||||
HapticFeedback.mediumImpact();
|
||||
|
||||
// Animasi transisi custom
|
||||
Get.toNamed(
|
||||
AppRoutes.periksa,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Navigate to scan history detail screen
|
||||
void navigateToScanHistoryDetail() {
|
||||
Get.toNamed(AppRoutes.scanHistory);
|
||||
// Haptic feedback
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
Get.toNamed(
|
||||
AppRoutes.scanHistory,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Open history item detail
|
||||
void openHistoryDetail(dynamic historyItem) {
|
||||
// Haptic feedback
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
// Implement detail view navigation
|
||||
Get.toNamed(
|
||||
'${AppRoutes.scanHistory}/${historyItem.id}',
|
||||
arguments: historyItem,
|
||||
);
|
||||
}
|
||||
|
||||
// Switch user profile
|
||||
void switchUserProfile() {
|
||||
// Haptic feedback
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
// Placeholder untuk fitur profil multiple
|
||||
final profiles = ["Petani", "Ahmad", "Budi", "Citra"];
|
||||
final currentIndex = profiles.indexOf(userName.value);
|
||||
final nextIndex = (currentIndex + 1) % profiles.length;
|
||||
|
||||
userName.value = profiles[nextIndex];
|
||||
}
|
||||
|
||||
// Reset animasi ketika halaman muncul kembali
|
||||
void resetAnimation() {
|
||||
animationController.reset();
|
||||
animationController.forward();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,282 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:harvest_guard_app/routes/app_routes.dart';
|
||||
|
||||
class IntroScreen extends StatefulWidget {
|
||||
const IntroScreen({super.key});
|
||||
|
||||
@override
|
||||
State<IntroScreen> createState() => _IntroScreenState();
|
||||
}
|
||||
|
||||
class _IntroScreenState extends State<IntroScreen> {
|
||||
final PageController _pageController = PageController();
|
||||
int _currentPage = 0;
|
||||
|
||||
final List<IntroPage> _introPages = [
|
||||
IntroPage(
|
||||
title: 'Pilih Varietas Padi',
|
||||
description:
|
||||
'Pilih jenis padi yang ingin Anda periksa dari daftar varietas yang tersedia',
|
||||
icon: Icons.grass_rounded,
|
||||
color: Colors.green.shade400,
|
||||
),
|
||||
IntroPage(
|
||||
title: 'Scan Tanaman Padi',
|
||||
description:
|
||||
'Arahkan kamera ponsel Anda ke bagian tanaman padi yang ingin diperiksa',
|
||||
icon: Icons.document_scanner_rounded,
|
||||
color: Colors.blue.shade400,
|
||||
),
|
||||
IntroPage(
|
||||
title: 'Cek Hasil Diagnosis',
|
||||
description:
|
||||
'Dapatkan hasil diagnosis penyakit dan rekomendasi penanganannya',
|
||||
icon: Icons.checklist_rounded,
|
||||
color: Colors.orange.shade400,
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// Background animasi bergerak
|
||||
AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
top: -100 + (_currentPage * 50),
|
||||
right: -100 + (_currentPage * 40),
|
||||
child: Container(
|
||||
height: 300,
|
||||
width: 300,
|
||||
decoration: BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
_introPages[_currentPage].color.withOpacity(0.7),
|
||||
_introPages[_currentPage].color.withOpacity(0.0),
|
||||
],
|
||||
stops: const [0.1, 1.0],
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
AnimatedPositioned(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
bottom: -80 + (_currentPage * 30),
|
||||
left: -50 + (_currentPage * 20),
|
||||
child: Container(
|
||||
height: 250,
|
||||
width: 250,
|
||||
decoration: BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
_introPages[_currentPage].color.withOpacity(0.5),
|
||||
_introPages[_currentPage].color.withOpacity(0.0),
|
||||
],
|
||||
stops: const [0.1, 1.0],
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Content
|
||||
Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: PageView.builder(
|
||||
controller: _pageController,
|
||||
itemCount: _introPages.length,
|
||||
onPageChanged: (int page) {
|
||||
setState(() {
|
||||
_currentPage = page;
|
||||
});
|
||||
},
|
||||
itemBuilder: (context, index) {
|
||||
return _buildIntroPage(_introPages[index]);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// Pagination indicator
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 30),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: List.generate(
|
||||
_introPages.length,
|
||||
(index) => _buildDotIndicator(index),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Bottom buttons
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Next/Finish button
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_currentPage < _introPages.length - 1) {
|
||||
_pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
} else {
|
||||
Get.offNamed(AppRoutes.dashboard);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: _introPages[_currentPage].color,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 30, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
_currentPage < _introPages.length - 1
|
||||
? 'Lanjut'
|
||||
: 'Mulai',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildIntroPage(IntroPage page) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Icon with animated container
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 600),
|
||||
builder: (context, value, child) {
|
||||
return Transform.scale(
|
||||
scale: value,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(25),
|
||||
decoration: BoxDecoration(
|
||||
color: page.color.withOpacity(0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
page.icon,
|
||||
size: 80,
|
||||
color: page.color,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Title
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 800),
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - value)),
|
||||
child: Text(
|
||||
page.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Description
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
builder: (context, value, child) {
|
||||
return Opacity(
|
||||
opacity: value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 30 * (1 - value)),
|
||||
child: Text(
|
||||
page.description,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black54,
|
||||
height: 1.5,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDotIndicator(int index) {
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 5),
|
||||
height: 8,
|
||||
width: _currentPage == index ? 24 : 8,
|
||||
decoration: BoxDecoration(
|
||||
color: _currentPage == index
|
||||
? _introPages[_currentPage].color
|
||||
: Colors.grey.shade300,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class IntroPage {
|
||||
final String title;
|
||||
final String description;
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
|
||||
IntroPage({
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.icon,
|
||||
required this.color,
|
||||
});
|
||||
}
|
|
@ -8,17 +8,14 @@ import 'package:hive_flutter/adapters.dart';
|
|||
Future<void> main() async {
|
||||
runApp(const MainApp());
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
|
||||
// Initialize Hive
|
||||
await Hive.initFlutter();
|
||||
|
||||
|
||||
// Register adapters
|
||||
Hive.registerAdapter(ScanHistoryAdapter());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class MainApp extends StatelessWidget {
|
||||
const MainApp({super.key});
|
||||
|
||||
|
|
|
@ -1,129 +1,756 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:harvest_guard_app/periksa/periksa_controller.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
|
||||
class PeriksaScreen extends StatelessWidget {
|
||||
class PeriksaScreen extends StatefulWidget {
|
||||
const PeriksaScreen({super.key});
|
||||
|
||||
@override
|
||||
State<PeriksaScreen> createState() => _PeriksaScreenState();
|
||||
}
|
||||
|
||||
class _PeriksaScreenState extends State<PeriksaScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final PeriksaController controller;
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _fadeInAnimation;
|
||||
late Animation<double> _slideAnimation;
|
||||
late Animation<double> _scaleAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Inisialisasi controller
|
||||
controller = Get.put(PeriksaController());
|
||||
|
||||
// Setup animasi
|
||||
_animationController = AnimationController(
|
||||
duration: const Duration(milliseconds: 1200),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_fadeInAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.6, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
|
||||
_slideAnimation = Tween<double>(begin: 50.0, end: 0.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.0, 0.6, curve: Curves.easeOut),
|
||||
),
|
||||
);
|
||||
|
||||
_scaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: const Interval(0.2, 0.8, curve: Curves.elasticOut),
|
||||
),
|
||||
);
|
||||
|
||||
// Mulai animasi
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final PeriksaController controller = Get.put(PeriksaController());
|
||||
final Size size = MediaQuery.of(context).size;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Periksa Kesehatan Padi'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
// Background dengan efek gradient dan elemen dekoratif
|
||||
_buildAnimatedBackground(),
|
||||
|
||||
// Konten utama
|
||||
SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// App Bar custom
|
||||
_buildCustomAppBar(),
|
||||
|
||||
// Konten utama dengan scroll
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
|
||||
// Judul utama dengan animasi
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
return Opacity(
|
||||
opacity: _fadeInAnimation.value,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, _slideAnimation.value),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.green.shade400,
|
||||
Colors.green.shade600,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.green.shade200.withOpacity(0.5),
|
||||
blurRadius: 15,
|
||||
offset: const Offset(0, 5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Text(
|
||||
'Periksa Kesehatan Padimu',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Ilustrasi
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
return Transform.scale(
|
||||
scale: _scaleAnimation.value,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.shade50,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.eco_rounded,
|
||||
size: 120,
|
||||
color: Colors.green.shade300,
|
||||
),
|
||||
Positioned(
|
||||
top: 50,
|
||||
right: 45,
|
||||
child: Icon(
|
||||
Icons.search,
|
||||
size: 60,
|
||||
color: Colors.green.shade700
|
||||
.withOpacity(0.8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Subtitle
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
final delayedOpacity =
|
||||
_animationController.value > 0.3
|
||||
? (((_animationController.value - 0.3) /
|
||||
0.7) *
|
||||
1.0)
|
||||
.clamp(0.0, 1.0)
|
||||
: 0.0;
|
||||
|
||||
return Opacity(
|
||||
opacity: delayedOpacity,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - delayedOpacity)),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.06),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 3),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 20,
|
||||
color: Colors.green.shade700,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Panduan Scanning',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Pastikan foto dengan jelas di bagian daun padi untuk hasil deteksi optimal',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black54,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Tombol Ambil Foto
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
final delayedOpacity =
|
||||
_animationController.value > 0.4
|
||||
? (((_animationController.value - 0.4) /
|
||||
0.6) *
|
||||
1.0)
|
||||
.clamp(0.0, 1.0)
|
||||
: 0.0;
|
||||
|
||||
return Opacity(
|
||||
opacity: delayedOpacity,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 30 * (1 - delayedOpacity)),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () => controller.takePhoto(),
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 150,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.green.shade500,
|
||||
Colors.green.shade700,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.green.shade300
|
||||
.withOpacity(0.5),
|
||||
blurRadius: 15,
|
||||
spreadRadius: 5,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.camera_alt_rounded,
|
||||
color: Colors.white,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Ambil Foto',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// Divider dengan "atau"
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
final delayedOpacity =
|
||||
_animationController.value > 0.5
|
||||
? (((_animationController.value - 0.5) /
|
||||
0.5) *
|
||||
1.0)
|
||||
.clamp(0.0, 1.0)
|
||||
: 0.0;
|
||||
|
||||
return Opacity(
|
||||
opacity: delayedOpacity,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Colors.grey.shade300,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.shade50,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: const Text(
|
||||
'atau',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.green,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Colors.grey.shade300,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// Tombol Pilih dari Galeri
|
||||
AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
final delayedOpacity =
|
||||
_animationController.value > 0.6
|
||||
? (((_animationController.value - 0.6) /
|
||||
0.4) *
|
||||
1.0)
|
||||
.clamp(0.0, 1.0)
|
||||
: 0.0;
|
||||
|
||||
return Opacity(
|
||||
opacity: delayedOpacity,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, 20 * (1 - delayedOpacity)),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () => controller.pickFromGallery(),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
spreadRadius: 1,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
border: Border.all(
|
||||
color: Colors.green.shade200,
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.shade50,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.photo_library_rounded,
|
||||
size: 24,
|
||||
color: Colors.green.shade600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'Pilih dari Galeri',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Format: JPG, JPEG, PNG',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 16,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 40),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
);
|
||||
}
|
||||
|
||||
// Custom App Bar dengan efek transparan
|
||||
Widget _buildCustomAppBar() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
// Back button dengan efek glassmorphism
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.03),
|
||||
blurRadius: 5,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () => Get.back(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
size: 20,
|
||||
color: Colors.green.shade700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const Spacer(),
|
||||
|
||||
// Info icon dengan efek glassmorphism
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.03),
|
||||
blurRadius: 5,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onTap: () {
|
||||
_showInfoDialog();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
Icons.help_outline_rounded,
|
||||
size: 20,
|
||||
color: Colors.green.shade700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Animated Background dengan elemen dekoratif
|
||||
Widget _buildAnimatedBackground() {
|
||||
return Stack(
|
||||
children: [
|
||||
// Gradient background
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.green.shade50,
|
||||
Colors.white,
|
||||
Colors.white,
|
||||
],
|
||||
stops: const [0.0, 0.3, 1.0],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Decorative top blob
|
||||
Positioned(
|
||||
top: -80,
|
||||
right: -50,
|
||||
child: Container(
|
||||
height: 200,
|
||||
width: 200,
|
||||
decoration: BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
Colors.green.shade200.withOpacity(0.6),
|
||||
Colors.green.shade200.withOpacity(0.0),
|
||||
],
|
||||
stops: const [0.2, 1.0],
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Decorative bottom blob
|
||||
Positioned(
|
||||
bottom: 100,
|
||||
left: -30,
|
||||
child: Container(
|
||||
height: 150,
|
||||
width: 150,
|
||||
decoration: BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
colors: [
|
||||
Colors.green.shade200.withOpacity(0.4),
|
||||
Colors.green.shade200.withOpacity(0.0),
|
||||
],
|
||||
stops: const [0.2, 1.0],
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Decorative elements
|
||||
for (int i = 0; i < 5; i++)
|
||||
Positioned(
|
||||
top: 150 + (i * 120),
|
||||
left: (i % 2 == 0) ? 20 : null,
|
||||
right: (i % 2 == 0) ? null : 20,
|
||||
child: AnimatedBuilder(
|
||||
animation: _animationController,
|
||||
builder: (context, child) {
|
||||
final delayedStart = 0.1 * i;
|
||||
final localProgress =
|
||||
((_animationController.value - delayedStart) /
|
||||
(1 - delayedStart))
|
||||
.clamp(0.0, 1.0);
|
||||
|
||||
return Opacity(
|
||||
opacity: localProgress * 0.3,
|
||||
child: Transform.translate(
|
||||
offset: Offset(
|
||||
0,
|
||||
20 * (1 - localProgress),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.eco,
|
||||
size: 20 + (i * 2),
|
||||
color: Colors.green.shade300.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showInfoDialog() {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
// Judul utama
|
||||
const Center(
|
||||
child: Text(
|
||||
'Periksa Kesehatan\nPadimu Sekarang',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.shade100,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.tips_and_updates_rounded,
|
||||
color: Colors.green.shade700,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
|
||||
// Subtitle
|
||||
const Center(
|
||||
child: Text(
|
||||
'Foto di bagian daun padi',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Tombol Ambil Foto (lingkaran hijau)
|
||||
GestureDetector(
|
||||
onTap: () => controller.takePhoto(),
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 150,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.green,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Ikon kamera dengan border putih
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: const Icon(
|
||||
Icons.center_focus_strong_outlined,
|
||||
color: Colors.white,
|
||||
size: 40,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'Tips Foto yang Baik',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
const Text(
|
||||
'Ambil Foto',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
const Text(
|
||||
'atau',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Tombol Pilih dari Galeri
|
||||
GestureDetector(
|
||||
onTap: () => controller.pickFromGallery(),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
_buildTipItem(
|
||||
Icons.brightness_5_rounded,
|
||||
'Foto dengan pencahayaan yang cukup',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildTipItem(
|
||||
Icons.center_focus_strong_rounded,
|
||||
'Fokus pada bagian daun yang menunjukkan gejala',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildTipItem(
|
||||
Icons.crop_rounded,
|
||||
'Hindari bayangan atau jari di foto',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildTipItem(
|
||||
Icons.filter_rounded,
|
||||
'Jangan menggunakan filter kamera',
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () => Get.back(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green.shade600,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Pilih dari Galeri\n*JPG, JPEG, PNG',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.insert_drive_file_outlined,
|
||||
size: 30,
|
||||
color: Colors.black87,
|
||||
),
|
||||
],
|
||||
),
|
||||
minimumSize: const Size(double.infinity, 45),
|
||||
),
|
||||
child: const Text(
|
||||
'Mengerti',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -133,4 +760,26 @@ class PeriksaScreen extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTipItem(IconData icon, String text) {
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 18,
|
||||
color: Colors.green.shade600,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade700,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:harvest_guard_app/components/scan_history_screen.dart';
|
|||
import 'package:harvest_guard_app/components/splashscreen.dart';
|
||||
import 'package:harvest_guard_app/dashboard/dashboard_binding.dart';
|
||||
import 'package:harvest_guard_app/dashboard/dashboard_page.dart';
|
||||
import 'package:harvest_guard_app/intro/page_intro.dart';
|
||||
import 'package:harvest_guard_app/periksa/periksa_binding.dart';
|
||||
import 'package:harvest_guard_app/periksa/periksa_controller.dart';
|
||||
import 'package:harvest_guard_app/periksa/periksa_page.dart';
|
||||
|
@ -18,9 +19,14 @@ class AppRoutes {
|
|||
static const String dashboard = '/dashboard';
|
||||
static const String periksa = '/periksa';
|
||||
static const String scanHistory = '/scan-history';
|
||||
static const String intro = '/intro';
|
||||
|
||||
// Daftar route aplikasi
|
||||
static final List<GetPage> pages = [
|
||||
GetPage(
|
||||
name: intro,
|
||||
page: () => const IntroScreen(),
|
||||
),
|
||||
GetPage(
|
||||
name: splash,
|
||||
page: () => const SplashScreen(),
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
platform :osx, '10.14'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_macos_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_macos_build_settings(target)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
PODS:
|
||||
- file_selector_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- tflite_flutter (0.0.1):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- tflite_flutter (from `Flutter/ephemeral/.symlinks/plugins/tflite_flutter/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
file_selector_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
path_provider_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
tflite_flutter:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/tflite_flutter/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
tflite_flutter: d1496f2e968aa5a142fb282da8f5d754fcee5613
|
||||
|
||||
PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
|
||||
|
||||
COCOAPODS: 1.16.2
|
|
@ -21,12 +21,14 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
20B381EA337542C3DD4070EA /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F97A4A17003EFDF1E242E694 /* Pods_RunnerTests.framework */; };
|
||||
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
|
||||
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
|
||||
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
|
||||
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||
6B879622470369E8A2157860 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AA04D75EBF536695C72D258 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -60,11 +62,14 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1B9D8C324CD0CFDF976861A8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
1CF9B9D9A8593095E96C87F7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
2E0747B455219D8FC5CEB350 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
||||
33CC10ED2044A3C60003C045 /* harvest_guard_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "harvest_guard_app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
33CC10ED2044A3C60003C045 /* harvest_guard_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = harvest_guard_app.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
||||
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
|
@ -76,8 +81,13 @@
|
|||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||
4148578F2DB7C29BE1987901 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
7AA04D75EBF536695C72D258 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||
91A000F3F01E65B9710933E2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
EFB6CD8707FA4682E67D3D53 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F97A4A17003EFDF1E242E694 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -85,6 +95,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
20B381EA337542C3DD4070EA /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -92,6 +103,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6B879622470369E8A2157860 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -125,6 +137,7 @@
|
|||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||
33CC10EE2044A3C60003C045 /* Products */,
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||
B682B58076B3E8A496768CE4 /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
@ -172,9 +185,25 @@
|
|||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B682B58076B3E8A496768CE4 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EFB6CD8707FA4682E67D3D53 /* Pods-Runner.debug.xcconfig */,
|
||||
1CF9B9D9A8593095E96C87F7 /* Pods-Runner.release.xcconfig */,
|
||||
1B9D8C324CD0CFDF976861A8 /* Pods-Runner.profile.xcconfig */,
|
||||
2E0747B455219D8FC5CEB350 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
91A000F3F01E65B9710933E2 /* Pods-RunnerTests.release.xcconfig */,
|
||||
4148578F2DB7C29BE1987901 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AA04D75EBF536695C72D258 /* Pods_Runner.framework */,
|
||||
F97A4A17003EFDF1E242E694 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -186,6 +215,7 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
F0F4B0455EC8BDC1BB981526 /* [CP] Check Pods Manifest.lock */,
|
||||
331C80D1294CF70F00263BE5 /* Sources */,
|
||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||
331C80D3294CF70F00263BE5 /* Resources */,
|
||||
|
@ -204,11 +234,13 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
82D07F52A88D609488332DD1 /* [CP] Check Pods Manifest.lock */,
|
||||
33CC10E92044A3C60003C045 /* Sources */,
|
||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||
33CC10EB2044A3C60003C045 /* Resources */,
|
||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||
569AD5714DA21E30963986D5 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -329,6 +361,67 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||
};
|
||||
569AD5714DA21E30963986D5 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
82D07F52A88D609488332DD1 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F0F4B0455EC8BDC1BB981526 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -380,6 +473,7 @@
|
|||
/* Begin XCBuildConfiguration section */
|
||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 2E0747B455219D8FC5CEB350 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
@ -394,6 +488,7 @@
|
|||
};
|
||||
331C80DC294CF71000263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 91A000F3F01E65B9710933E2 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
@ -408,6 +503,7 @@
|
|||
};
|
||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 4148578F2DB7C29BE1987901 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
|
|
@ -4,4 +4,7 @@
|
|||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
|
@ -798,10 +798,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: tflite_flutter
|
||||
sha256: ffb8651fdb116ab0131d6dc47ff73883e0f634ad1ab12bb2852eef1bbeab4a6a
|
||||
sha256: "48e6fde2ad97162bb66a16a142f4c4698add9e8cd397ce9d1cc7451b55537ac1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.4"
|
||||
version: "0.11.0"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
|||
get: ^4.7.2
|
||||
image_cropper: ^9.0.0
|
||||
image_picker: ^1.1.2
|
||||
tflite_flutter: ^0.10.0
|
||||
tflite_flutter: ^0.11.0
|
||||
path_provider: ^2.1.0
|
||||
image: ^4.1.0
|
||||
hive_flutter: ^1.1.0
|
||||
|
|
Loading…
Reference in New Issue