Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 29 additions & 40 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_genius_scan/flutter_genius_scan.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'screens/home_screen.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv;
import 'components/care_view.dart';
import 'components/center_next_button.dart';
import 'components/mood_diary_vew.dart';
import 'components/relax_view.dart';
import 'components/splash_view.dart';
import 'components/top_back_skip_view.dart';
import 'components/welcome_view.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv;

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DotEnv.dotenv.load(fileName: ".env");
runApp(MyApp());
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();

final prefs = await SharedPreferences.getInstance();
final bool isFirstRun = prefs.getBool('isFirstRun') ?? true;

runApp(MyApp(isFirstRun: isFirstRun));
}

class _MyAppState extends State<MyApp> {
class MyApp extends StatelessWidget {
final bool isFirstRun;

const MyApp({Key? key, required this.isFirstRun}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: IntroductionAnimationScreen()),
title: 'Paper',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: isFirstRun ? IntroductionAnimationScreen() : HomeScreen(),
);
}
}

class IntroductionAnimationScreen extends StatefulWidget {
const IntroductionAnimationScreen({Key? key}) : super(key: key);

Expand Down Expand Up @@ -60,7 +71,6 @@ class _IntroductionAnimationScreenState

@override
Widget build(BuildContext context) {
print(_animationController?.value);
return Scaffold(
backgroundColor: Color(0xffF7EBE1),
body: ClipRect(
Expand Down Expand Up @@ -132,37 +142,16 @@ class _IntroductionAnimationScreenState
_animationController?.animateTo(0.8);
} else if (_animationController!.value > 0.6 &&
_animationController!.value <= 0.8) {
_signUpClick();
_finishOnboarding();
}
}

void _signUpClick() {
Navigator.pop(context);
void _finishOnboarding() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isFirstRun', false);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
}
}

// class MyScaffoldBody extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// return Center(
// child: ElevatedButton(
// onPressed: () {
// FlutterGeniusScan.scanWithConfiguration({
// 'source': 'camera',
// 'multiPage': true,
// }).then((result) {
// String pdfUrl = result['pdfUrl'];
// OpenFile.open(pdfUrl.replaceAll("file://", '')).then(
// (result) => debugPrint(result.message),
// onError: (error) => displayError(context, error));
// }, onError: (error) => displayError(context, error));
// },
// child: Text("Scan a doc"),
// ));
// }
//
// void displayError(BuildContext context, PlatformException error) {
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error.message!)));
// }
// }

42 changes: 42 additions & 0 deletions lib/models/scanned_document.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:convert';

class ScannedDocument {
final String id;
final String name;
final String filePath;
final String thumbnailPath;
final DateTime dateTime;

ScannedDocument({
required this.id,
required this.name,
required this.filePath,
required this.thumbnailPath,
required this.dateTime,
});

Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'filePath': filePath,
'thumbnailPath': thumbnailPath,
'dateTime': dateTime.toIso8601String(),
};
}

factory ScannedDocument.fromMap(Map<String, dynamic> map) {
return ScannedDocument(
id: map['id'],
name: map['name'],
filePath: map['filePath'],
thumbnailPath: map['thumbnailPath'],
dateTime: DateTime.parse(map['dateTime']),
);
}

String toJson() => json.encode(toMap());

factory ScannedDocument.fromJson(String source) =>
ScannedDocument.fromMap(json.decode(source));
}
170 changes: 170 additions & 0 deletions lib/screens/home_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_genius_scan/flutter_genius_scan.dart';
import 'package:open_file/open_file.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:path_provider/path_provider.dart';
import '../models/scanned_document.dart';
import 'dart:convert';

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
List<ScannedDocument> _documents = [];

@override
void initState() {
super.initState();
_loadDocuments();
}

Future<void> _loadDocuments() async {
final prefs = await SharedPreferences.getInstance();
final String? docsJson = prefs.getString('scanned_documents');
if (docsJson != null) {
final List<dynamic> decoded = json.decode(docsJson);
setState(() {
_documents = decoded.map((item) => ScannedDocument.fromMap(item)).toList();
// Sort by date descending
_documents.sort((a, b) => b.dateTime.compareTo(a.dateTime));
});
}
}

Future<void> _saveDocuments() async {
final prefs = await SharedPreferences.getInstance();
final String encoded = json.encode(_documents.map((doc) => doc.toMap()).toList());
await prefs.setString('scanned_documents', encoded);
}

void _startScan() async {
try {
final result = await FlutterGeniusScan.scanWithConfiguration({
'source': 'camera',
'multiPage': true,
});

final String pdfUrl = result['pdfUrl'];
final String filePath = pdfUrl.replaceAll("file://", "");

// For simplicity in this feature, we'll use the PDF itself or a placeholder as thumbnail
// Real implementation would extract a thumbnail image.
final newDoc = ScannedDocument(
id: DateTime.now().millisecondsSinceEpoch.toString(),
name: "Scan ${DateTime.now().toString().split('.')[0]}",
filePath: filePath,
thumbnailPath: filePath, // Placeholder
dateTime: DateTime.now(),
);

setState(() {
_documents.insert(0, newDoc);
});
_saveDocuments();

OpenFile.open(filePath);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Scan failed: $e")),
);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My Documents", style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold)),
backgroundColor: Colors.white,
elevation: 0,
centerTitle: true,
),
backgroundColor: Colors.white,
body: _documents.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.description_outlined, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text("No scans yet", style: TextStyle(color: Colors.grey, fontSize: 18)),
],
),
)
: Padding(
padding: const EdgeInsets.all(16.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.8,
),
itemCount: _documents.length,
itemBuilder: (context, index) {
final doc = _documents[index];
return GestureDetector(
onTap: () => OpenFile.open(doc.filePath),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 5,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
child: Center(
child: Icon(Icons.picture_as_pdf, size: 48, color: Colors.red[400]),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
doc.name,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
"${doc.dateTime.day}/${doc.dateTime.month}/${doc.dateTime.year}",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
),
],
),
),
);
},
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: _startScan,
label: Text("Scan"),
icon: Icon(Icons.camera_alt),
backgroundColor: Colors.black,
),
);
}
}
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies:
font_awesome_flutter: ^9.0.0
flutter_rating_bar: ^4.0.0
intl: ^0.17.0
shared_preferences: ^2.0.12
path_provider: ^2.0.8


dev_dependencies:
Expand Down