a bunch of flutter updates

This commit is contained in:
Wowieee4
2026-05-08 20:27:57 +07:00
parent 53e612e221
commit 22ebbb7db0
44 changed files with 3351 additions and 1240 deletions
@@ -1,184 +1 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:dio/dio.dart';
import '../../../../core/constants/app_constants.dart';
import '../../../../injection_container.dart';
import '../../../../core/network/api_client.dart';
class ServerConnectScreen extends StatefulWidget {
const ServerConnectScreen({super.key});
@override
State<ServerConnectScreen> createState() => _ServerConnectScreenState();
}
class _ServerConnectScreenState extends State<ServerConnectScreen> {
final _urlCtrl = TextEditingController(text: 'http://202.46.28.160:8080');
bool _testing = false;
bool _connected = false;
String? _errorMsg;
String? _serverInfo;
Future<void> _testConnection() async {
final url = _urlCtrl.text.trim();
if (url.isEmpty) return;
setState(() { _testing = true; _connected = false; _errorMsg = null; _serverInfo = null; });
try {
final tempDio = Dio(BaseOptions(
connectTimeout: AppConstants.pingTimeout,
receiveTimeout: AppConstants.pingTimeout,
));
final res = await tempDio.get('$url/api/v1/auth/ping');
if (res.statusCode == 200 && res.data['success'] == true) {
setState(() {
_connected = true;
_serverInfo = 'Server aktif — ${res.data['message'] ?? 'OK'}';
});
} else {
setState(() => _errorMsg = 'Server merespons tapi tidak valid. Cek URL.');
}
} on DioException catch (e) {
String msg;
if (e.type == DioExceptionType.connectionTimeout ||
e.type == DioExceptionType.receiveTimeout) {
msg = 'Koneksi timeout. Pastikan server berjalan dan URL benar.';
} else if (e.type == DioExceptionType.connectionError) {
msg = 'Tidak bisa terhubung. Cek URL dan pastikan HP di jaringan yang sama dengan server.';
} else {
msg = 'Error: ${e.message}';
}
setState(() => _errorMsg = msg);
} catch (e) {
setState(() => _errorMsg = 'Error tidak dikenal: $e');
} finally {
setState(() => _testing = false);
}
}
Future<void> _continueToApp() async {
final url = _urlCtrl.text.trim();
await AppConstants.setServerUrl(url);
await sl<ApiClient>().init(url);
if (mounted) context.go('/splash');
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF1F5F9),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Container(
constraints: const BoxConstraints(maxWidth: 440),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.08), blurRadius: 40, offset: const Offset(0, 16))],
),
padding: const EdgeInsets.all(32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Logo
Row(children: [
Container(
width: 40, height: 40,
decoration: BoxDecoration(color: const Color(0xFF1A56DB), borderRadius: BorderRadius.circular(10)),
child: const Icon(Icons.navigation_rounded, color: Colors.white, size: 22),
),
const SizedBox(width: 10),
Text('WalkGuide', style: GoogleFonts.outfit(fontSize: 20, fontWeight: FontWeight.w700, color: const Color(0xFF0F172A))),
]),
const SizedBox(height: 28),
Text('Connect to Server', style: GoogleFonts.outfit(fontSize: 26, fontWeight: FontWeight.w700, color: const Color(0xFF0F172A))),
const SizedBox(height: 6),
Text('Masukkan URL server yang diberikan oleh dosen/instructor.', style: GoogleFonts.inter(fontSize: 13, color: const Color(0xFF64748B))),
const SizedBox(height: 24),
// URL Input
Text('Server URL', style: GoogleFonts.inter(fontSize: 12, fontWeight: FontWeight.w500, color: const Color(0xFF64748B))),
const SizedBox(height: 6),
TextField(
controller: _urlCtrl,
keyboardType: TextInputType.url,
style: GoogleFonts.inter(fontSize: 14, color: const Color(0xFF0F172A)),
decoration: InputDecoration(
hintText: 'http://202.46.28.160:8080',
hintStyle: GoogleFonts.inter(color: const Color(0xFFCBD5E1)),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFE2E8F0))),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFE2E8F0))),
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFF1A56DB), width: 2)),
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
),
onChanged: (_) => setState(() { _connected = false; _errorMsg = null; }),
),
const SizedBox(height: 16),
// Status
if (_errorMsg != null)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: const Color(0xFFFEF2F2), borderRadius: BorderRadius.circular(8)),
child: Row(children: [
const Icon(Icons.error_outline, color: Color(0xFFDC2626), size: 18),
const SizedBox(width: 8),
Expanded(child: Text(_errorMsg!, style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFFDC2626)))),
]),
),
if (_connected && _serverInfo != null)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: const Color(0xFFF0FDF4), borderRadius: BorderRadius.circular(8)),
child: Row(children: [
const Icon(Icons.check_circle_outline, color: Color(0xFF16A34A), size: 18),
const SizedBox(width: 8),
Expanded(child: Text(_serverInfo!, style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFF16A34A)))),
]),
),
const SizedBox(height: 20),
// Test button
SizedBox(
width: double.infinity, height: 44,
child: OutlinedButton(
onPressed: _testing ? null : _testConnection,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Color(0xFF1A56DB)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
child: _testing
? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2))
: Text('Test Connection', style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w500, color: const Color(0xFF1A56DB))),
),
),
const SizedBox(height: 10),
// Continue button (only after successful test)
if (_connected)
SizedBox(
width: double.infinity, height: 44,
child: ElevatedButton(
onPressed: _continueToApp,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1A56DB),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
child: Text('Continue to App', style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)),
),
),
const SizedBox(height: 24),
Center(child: Text('v1.0.0 · For Testing Purposes', style: GoogleFonts.inter(fontSize: 11, color: const Color(0xFFCBD5E1)))),
],
),
),
),
),
);
}
}
export '../screens.dart';