Flatlogic Bot 18b6dbc27d V1
2025-10-26 23:03:53 +00:00

282 lines
8.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'src/calendar_screen.dart';
import 'src/education_screen.dart';
import 'src/resume_screen.dart';
import 'src/settings_screen.dart';
void main() {
runApp(const MyApp());
}
// Color Palette
const Color darkJungleGreen = Color(0xFF000505);
const Color englishViolet = Color(0xFF3B3355);
const Color slateGray = Color(0xFF5D5D81);
const Color lightSteelBlue = Color(0xFFBFCDE0);
const Color ghostWhite = Color(0xFFFEFCFD);
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isDarkMode = false;
void _toggleTheme(bool isDark) {
setState(() {
_isDarkMode = isDark;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Connect',
theme: ThemeData(
brightness: Brightness.light,
primaryColor: englishViolet,
scaffoldBackgroundColor: ghostWhite,
colorScheme: const ColorScheme.light(
primary: englishViolet,
secondary: slateGray,
surface: ghostWhite,
background: ghostWhite,
onPrimary: ghostWhite,
onSecondary: darkJungleGreen,
onSurface: darkJungleGreen,
onBackground: darkJungleGreen,
error: Colors.red,
onError: ghostWhite,
),
appBarTheme: const AppBarTheme(
backgroundColor: englishViolet,
foregroundColor: ghostWhite,
titleTextStyle: TextStyle(fontFamily: 'Poppins', fontSize: 20, fontWeight: FontWeight.bold),
),
textTheme: const TextTheme(
bodyLarge: TextStyle(color: darkJungleGreen),
titleLarge: TextStyle(color: darkJungleGreen, fontWeight: FontWeight.bold),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: englishViolet,
foregroundColor: ghostWhite,
),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
primaryColor: lightSteelBlue,
scaffoldBackgroundColor: darkJungleGreen,
colorScheme: const ColorScheme.dark(
primary: lightSteelBlue,
secondary: slateGray,
surface: darkJungleGreen,
background: darkJungleGreen,
onPrimary: darkJungleGreen,
onSecondary: ghostWhite,
onSurface: ghostWhite,
onBackground: ghostWhite,
error: Colors.red,
onError: ghostWhite,
),
appBarTheme: const AppBarTheme(
backgroundColor: slateGray,
foregroundColor: ghostWhite,
titleTextStyle: TextStyle(fontFamily: 'Poppins', fontSize: 20, fontWeight: FontWeight.bold),
),
textTheme: const TextTheme(
bodyLarge: TextStyle(color: ghostWhite),
titleLarge: TextStyle(color: ghostWhite, fontWeight: FontWeight.bold),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: lightSteelBlue,
foregroundColor: darkJungleGreen,
),
),
themeMode: _isDarkMode ? ThemeMode.dark : ThemeMode.light,
home: JobListingScreen(isDarkMode: _isDarkMode, onThemeChanged: _toggleTheme),
);
}
}
class JobListingScreen extends StatefulWidget {
final bool isDarkMode;
final ValueChanged<bool> onThemeChanged;
const JobListingScreen({
Key? key,
required this.isDarkMode,
required this.onThemeChanged,
}) : super(key: key);
@override
_JobListingScreenState createState() => _JobListingScreenState();
}
class _JobListingScreenState extends State<JobListingScreen> {
List<dynamic> jobs = [];
bool isLoading = true;
String? error;
@override
void initState() {
super.initState();
fetchJobs();
}
Future<void> fetchJobs() async {
// IMPORTANT: Replace with your actual IP/domain in a real environment.
// 10.0.2.2 is the special alias for the host machine's localhost in the Android emulator.
const String apiUrl = 'http://10.0.2.2/api.php';
try {
final response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
final result = json.decode(response.body);
if (result['success'] == true) {
setState(() {
jobs = result['data'];
isLoading = false;
});
} else {
setState(() {
error = result['error'] ?? 'An unknown error occurred.';
isLoading = false;
});
}
} else {
setState(() {
error = 'Failed to load jobs. Status code: ${response.statusCode}';
isLoading = false;
});
}
} catch (e) {
setState(() {
error = 'Failed to connect to the server. Please check your network connection and the API endpoint. Details: $e';
isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Connect'),
),
drawer: Drawer( // Vertical navigation drawer
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: englishViolet,
),
child: Text(
'Connect',
style: TextStyle(color: Colors.white, fontSize: 24),
),
),
ListTile(
leading: const Icon(Icons.school),
title: const Text('Education/Information'),
onTap: () {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => const EducationScreen()));
},
),
ListTile(
leading: const Icon(Icons.description),
title: const Text('Resume/Job Letter'),
onTap: () {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => const ResumeScreen()));
},
),
ListTile(
leading: const Icon(Icons.calendar_today),
title: const Text('Calendar'),
onTap: () {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => const CalendarScreen()));
},
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('Settings'),
onTap: () {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => SettingsScreen(
isDarkMode: widget.isDarkMode,
onThemeChanged: widget.onThemeChanged,
)));
},
),
],
),
),
body: buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
// AI Chatbot action
},
child: const Icon(Icons.chat),
),
);
}
Widget buildBody() {
if (isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (error != null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Error: $error',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.red, fontSize: 16),
),
),
);
}
if (jobs.isEmpty) {
return const Center(child: Text('No jobs found.'));
}
return ListView.builder(
itemCount: jobs.length,
itemBuilder: (context, index) {
final job = jobs[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: ListTile(
title: Text(job['title'] ?? 'No Title', style: Theme.of(context).textTheme.titleLarge),
subtitle: Text(
'${job['company'] ?? 'No Company'} - ${job['location'] ?? 'No Location'}',
style: Theme.of(context).textTheme.bodyLarge,
),
trailing: Text(
job['salary_range'] ?? '',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
onTap: () {
// Show job details
},
),
);
},
);
}
}