Gedion Daniel 1 год назад
Родитель
Сommit
b7c015e60b
13 измененных файлов: 361 добавлений и 142 удалений
  1. +7
    -0
      .env
  2. +1
    -1
      .flutter-plugins-dependencies
  3. +2
    -1
      .gitignore
  4. +11
    -0
      kotlin/CalculatorTest.kt
  5. +6
    -3
      lib/main.dart
  6. +1
    -1
      lib/presentation/abilita_disabilita_classe_screen/abilita_disabilita_classe_screen.dart
  7. +112
    -123
      lib/presentation/camera_page/camera_page.dart
  8. +42
    -0
      lib/presentation/login_screen/controller/string_controller.dart
  9. +100
    -13
      lib/presentation/login_screen/login_screen.dart
  10. +0
    -0
      lib/presentation/login_screen/models/app_strings.dart
  11. +77
    -0
      lib/presentation/login_screen/recording_details.dart
  12. +1
    -0
      lib/presentation/splash_screen_one_screen/splash_screen_one_screen.dart
  13. +1
    -0
      pubspec.yaml

+ 7
- 0
.env Просмотреть файл

@@ -0,0 +1,7 @@
SERVER_URL=https://192.168.60.230:5050
USERNAME=admin
PASSWORD=Pwdadmin1!

IP_CAMERA_BASE_URL=HTTP://10.1.1.66:2000
IP_CAMERA_USERNAME=admin
IP_CAMERA_PASSWORD=Adminadmin1

+ 1
- 1
.flutter-plugins-dependencies
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 2
- 1
.gitignore Просмотреть файл

@@ -6,4 +6,5 @@
!/.packages
!/.flutter-plugins-dependencies
!/.flutter-plugins
.env
#uncomment the following line if you want to keep your .env file
#*.env

+ 11
- 0
kotlin/CalculatorTest.kt Просмотреть файл

@@ -0,0 +1,11 @@
import org.junit.Assert.assertEquals
import org.junit.Test

class CalculatorTest {

@Test
fun addition_isCorrect() {
val calculator = Calculator()
assertEquals(4, calculator.add(2, 2))
}
}

+ 6
- 3
lib/main.dart Просмотреть файл

@@ -3,11 +3,14 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'core/app_export.dart';

import 'package:flutter_dotenv/flutter_dotenv.dart';

void main() {
import 'presentation/login_screen/models/app_strings.dart';


void main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env");
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]).then((value){
@@ -34,4 +37,4 @@ class MyApp extends StatelessWidget {
getPages: AppRoutes.pages,
);
}
}
}

+ 1
- 1
lib/presentation/abilita_disabilita_classe_screen/abilita_disabilita_classe_screen.dart Просмотреть файл

@@ -103,7 +103,7 @@ class AbilitaDisabilitaClasseScreen
textAlign:
TextAlign
.right,
style: AppStyle
style: AppStyle
.txtRobotoRomanSemiBold19Lime600))
]))
])),


+ 112
- 123
lib/presentation/camera_page/camera_page.dart Просмотреть файл

@@ -3,10 +3,11 @@ import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:io';
import 'package:http/io_client.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

class CameraPage extends StatelessWidget {
final String loginUrl = 'https://192.168.60.230:5050/auth/login';
final String moveCameraUrl = 'https://192.168.60.230:5050/move-camera';
final String loginUrl = dotenv.env['SERVER_URL']! + '/auth/login';
final String moveCameraUrl = dotenv.env['SERVER_URL']! + '/move-camera';

Future<http.Client> createHttpClient() async {
final ioc = HttpClient()
@@ -17,7 +18,10 @@ class CameraPage extends StatelessWidget {

Future<String> loginAndGetToken(http.Client client) async {
var url = Uri.parse(loginUrl);
var data = {'username': 'admin', 'password': 'Pwdadmin1!'};
var data = {
'username': dotenv.env['USERNAME']!,
'password': dotenv.env['PASSWORD']!,
};

var body = data.keys
.map((key) =>
@@ -75,167 +79,152 @@ class CameraPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double screenHeight = MediaQuery.of(context).size.height;

return Scaffold(
body: OrientationBuilder(
builder: (context, orientation) => Stack(
children: [
Column(
children: [
Expanded(
child: Builder(
builder: (context) => GestureDetector(
builder: (context, orientation) {
return Stack(
children: [
Column(
children: [
Expanded(
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 1
});
},
child: Stack(
children: [
Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img1.png',
fit: BoxFit.cover,
),
),
child: Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img1.png',
fit: BoxFit.cover,
),
],
),
),
),
),
),
Expanded(
child: Builder(
builder: (context) => GestureDetector(
Expanded(
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 3
});
},
child: Stack(
children: [
Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img2.png',
fit: BoxFit.cover,
),
),
child: Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img2.png',
fit: BoxFit.cover,
),
],
),
),
),
),
),
Expanded(
child: Builder(
builder: (context) => GestureDetector(
Expanded(
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 2
});
},
child: Stack(
children: [
Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img3.png',
fit: BoxFit.cover,
),
),
child: Container(
color: Colors.transparent,
child: Transform.rotate(
angle: 3.14 / 2,
child: Image.asset(
'assets/images/img3.png',
fit: BoxFit.cover,
),
],
),
),
),
),
),
],
),
Positioned(
top: 110.0,
right: 350.0,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"preset": 5
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
],
),
Positioned(
top: screenHeight * 0.15,
left: screenWidth * 0.05,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 5
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
),
),
),
),
Positioned(
top: 350.0,
right: 350.0,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"preset": 4
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
Positioned(
top: screenHeight * 0.35,
left: screenWidth * 0.05,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 4
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
),
),
),
),
Positioned(
top: 700.0,
right: 350.0,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": "HTTP://10.1.1.66:2000",
"username": "admin",
"password": "Adminadmin1",
"preset": 6
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
Positioned(
top: screenHeight * 0.7,
left: screenWidth * 0.05,
child: GestureDetector(
onTap: () async {
final client = await createHttpClient();
String token = await loginAndGetToken(client);
await sendPostRequestMoveCamera(context, token, {
"baseUrl": dotenv.env['IP_CAMERA_BASE_URL']!,
"username": dotenv.env['IP_CAMERA_USERNAME']!,
"password": dotenv.env['IP_CAMERA_PASSWORD']!,
"preset": 6
});
},
child: Transform.rotate(
angle: 3.14 / 2, // Rotating 90 degrees (PI / 2 radians)
child: FaceSymbol(),
),
),
),
),
],
),
],
);
},
),
);
}
@@ -250,4 +239,4 @@ class FaceSymbol extends StatelessWidget {
color: Colors.blue,
);
}
}
}

+ 42
- 0
lib/presentation/login_screen/controller/string_controller.dart Просмотреть файл

@@ -0,0 +1,42 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';


class StringService {
final String url = dotenv.env['SERVER_URL']! + 'getStrings';

Future<Map<String, String>> fetchStrings() async {
final response = await http.get(Uri.parse(url));

if (response.statusCode == 200) {
Map<String, dynamic> jsonResponse = json.decode(response.body);
return jsonResponse.map((key, value) => MapEntry(key, value.toString()));
} else {
throw Exception('Failed to load strings');
}
}
}


class StringController extends GetxController {
var strings = <String, String>{}.obs;
var isLoading = true.obs;

@override
void onInit() {
fetchStrings();
super.onInit();
}

void fetchStrings() async {
try {
isLoading(true);
var fetchedStrings = await StringService().fetchStrings();
strings.value = fetchedStrings;
} finally {
isLoading(false);
}
}
}

+ 100
- 13
lib/presentation/login_screen/login_screen.dart Просмотреть файл

@@ -11,6 +11,7 @@ import 'package:http/http.dart' as http;
import 'package:michele_s_application8/presentation/camera_page/camera_page.dart';

import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoginScreen extends StatefulWidget {
@override
@@ -33,12 +34,69 @@ class _LoginScreenState extends State<LoginScreen> {

Timer? _recordingTimer;

List<String> _defaultTimes = [];
String mainTitle = '';
String selectDuration = '';
String enterCustomDuration = '';
String insertTitle = '';
String insertPresenterName = '';
String startRecording = '';
String recordingDetails = '';
String goToCamera = '';

@override
void initState() {
super.initState();
String deviceLanguage = ui.window.locale.languageCode;
String language = (deviceLanguage == 'en') ? 'EN' : (deviceLanguage == 'it') ? 'IT' : 'IT';
_languageController = TextEditingController(text: language);
fetchStringsFromServer();
}

Future<void> fetchStringsFromServer() async {
try {
String token = await loginAndGetToken(); // Get the token first
HttpClient httpClient = new HttpClient()
..badCertificateCallback =
((X509Certificate cert, String host, int port) => true);

var request = await httpClient.getUrl(Uri.parse(dotenv.env['SERVER_URL']! + '/get-strings'))
..headers.add('Authorization', 'Bearer $token');
var response = await request.close();
var responseBody = await response.transform(utf8.decoder).join();

if (response.statusCode == 200) {
final data = jsonDecode(responseBody);
setState(() {
_defaultTimes = List<String>.from(data['durations']);
selectDuration = data['select_duration'];
enterCustomDuration = data['enter_custom_duration'];
insertTitle = data['insert_title'];
insertPresenterName = data['insert_presenter_name'];
startRecording = data['start_recording'];
recordingDetails = data['recording_details'];
goToCamera = data['go_to_camera'];
mainTitle = data['main_title'];
});
} else {
print('Failed to load strings with status code: ${response.statusCode}');
throw Exception('Failed to load strings');
}
} catch (e) {
print('Error fetching strings: $e'); // Debug: Print error message
setState(() {
isError = true;
_defaultTimes = ["00:05:00", "01:00:00", "01:30:00", "02:00:00"];
mainTitle = 'CookingLab';
selectDuration = 'seleziona Durata';
enterCustomDuration = 'Oppure inserisci una durata personalizzata';
insertTitle = 'Inserisci il titolo';
insertPresenterName = 'Inserisci il nome del relatore';
startRecording = 'Inizia a Registrare';
recordingDetails = 'Dettagli di registrazione';
goToCamera = 'Vai a Fotocamera';
});
}
}

@override
@@ -68,7 +126,7 @@ class _LoginScreenState extends State<LoginScreen> {
children: [
if (!isRecording || showStartRecordingButton)
Text(
'CookingLab',
mainTitle,
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
),
if (!isRecording || showStartRecordingButton)
@@ -80,6 +138,32 @@ class _LoginScreenState extends State<LoginScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DropdownButtonFormField<String>(
value: null,
hint: Text(selectDuration),
icon: Icon(Icons.timer),
decoration: InputDecoration(
border: OutlineInputBorder(),
),
items: _defaultTimes.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (newValue) {
setState(() {
_timeController1.text = newValue!;
});
},
validator: (value) {
if (_timeController1.text.isEmpty || !isTime(_timeController1.text)) {
return "Inserisci un'ora valida (HH:MM:SS)";
}
return null;
},
),
SizedBox(height: 12),
GestureDetector(
onTap: () async {
await showDialog(
@@ -93,7 +177,7 @@ class _LoginScreenState extends State<LoginScreen> {
onTimerDurationChanged: (Duration duration) {
_timeController1.text = "${duration.inHours.toString().padLeft(2, '0')}:${duration.inMinutes.remainder(60).toString().padLeft(2, '0')}:${duration.inSeconds.remainder(60).toString().padLeft(2, '0')}";
},
initialTimerDuration: Duration(hours: DateTime.now().hour, minutes: DateTime.now().minute, seconds: DateTime.now().second),
initialTimerDuration: Duration(hours: 0, minutes: 0, seconds: 0),
),
),
);
@@ -104,7 +188,7 @@ class _LoginScreenState extends State<LoginScreen> {
child: CustomTextFormField(
controller: _timeController1,
prefixIcon: Icon(Icons.timer),
hintText: "Inserisci la durata",
hintText: enterCustomDuration,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
@@ -121,7 +205,7 @@ class _LoginScreenState extends State<LoginScreen> {
CustomTextFormField(
controller: _titleController,
prefixIcon: Icon(Icons.title),
hintText: "Inserisci il titolo",
hintText: insertTitle,
margin: EdgeInsets.fromLTRB(5, 12, 10, 0),
validator: (value) {
if (value != null && !isText(value)) {
@@ -133,7 +217,7 @@ class _LoginScreenState extends State<LoginScreen> {
CustomTextFormField(
controller: _presenterNameController,
prefixIcon: Icon(Icons.person),
hintText: "Inserisci il nome del relatore",
hintText: insertPresenterName,
margin: EdgeInsets.fromLTRB(5, 12, 10, 0),
validator: (value) {
if (value != null && !isText(value)) {
@@ -148,7 +232,7 @@ class _LoginScreenState extends State<LoginScreen> {
),
if (!isRecording || showStartRecordingButton)
CustomButton(
text: "Inizia a Registrare",
text: startRecording,
margin: EdgeInsets.fromLTRB(50, 30, 50, 10),
variant: ButtonVariant.OutlineBlack9003f,
padding: ButtonPadding.PaddingAll9,
@@ -224,7 +308,7 @@ class _LoginScreenState extends State<LoginScreen> {
child: Column(
children: [
Text(
'Dettagli di registrazione',
recordingDetails,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black),
),
SizedBox(height: 10),
@@ -284,7 +368,7 @@ class _LoginScreenState extends State<LoginScreen> {
child: isLoading
? SizedBox() // Hide the button when isLoading is true
: CustomButton(
text: "Vai a Fotocamera",
text: goToCamera,
// prefixIcon: Icon(Icons.camera_alt),
margin: EdgeInsets.symmetric(horizontal: 50, vertical: 30),
variant: ButtonVariant.OutlineBlack9003f,
@@ -310,8 +394,11 @@ class _LoginScreenState extends State<LoginScreen> {
}

Future<String> loginAndGetToken() async {
var url = Uri.parse('https://192.168.60.230:5050/auth/login');
var data = {'username': 'admin', 'password': 'Pwdadmin1!'};
var url = Uri.parse(dotenv.env['SERVER_URL']! + '/auth/login');
var data = {
'username': dotenv.env['USERNAME']!,
'password': dotenv.env['PASSWORD']!,
};

var body = data.keys.map((key) => "${Uri.encodeComponent(key)}=${Uri.encodeComponent(data[key] ?? '')}").join("&");

@@ -337,7 +424,7 @@ class _LoginScreenState extends State<LoginScreen> {


Future<void> sendPostRequestStart(String token, Map<String, dynamic> data, String time, String camNumber) async {
var url = Uri.parse('https://192.168.60.230:5050/start-recording');
var url = Uri.parse(dotenv.env['SERVER_URL']! + '/start-recording');
List<String> timeParts = time.split(':');
int durationInSeconds = int.parse(timeParts[0]) * 3600 + int.parse(timeParts[1]) * 60 + int.parse(timeParts[2]);
durationInSeconds += 10;
@@ -385,7 +472,7 @@ class _LoginScreenState extends State<LoginScreen> {


Future<void> sendPostRequestStop(String token, String camNumber) async {
var url = Uri.parse('https://192.168.60.230:5050/stop-recording');
var url = Uri.parse(dotenv.env['SERVER_URL']! + '/stop-recording');

var requestData = {
"camera_name": int.parse(camNumber),
@@ -443,4 +530,4 @@ class _LoginScreenState extends State<LoginScreen> {
bool isText(String? value) {
return value != null && value.isNotEmpty;
}
}
}

+ 0
- 0
lib/presentation/login_screen/models/app_strings.dart Просмотреть файл


+ 77
- 0
lib/presentation/login_screen/recording_details.dart Просмотреть файл

@@ -0,0 +1,77 @@
// recording_details.dart
import 'package:flutter/material.dart';
import 'package:michele_s_application8/widgets/custom_button.dart';

class RecordingDetails extends StatelessWidget {
final String recordingDetails;
final String duration;
final String title;
final String presenterName;
final VoidCallback onStop;

RecordingDetails({
required this.recordingDetails,
required this.duration,
required this.title,
required this.presenterName,
required this.onStop,
});

@override
Widget build(BuildContext context) {
return Expanded(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min, // Minimize the column size to its content
children: [
Container(
padding: EdgeInsets.all(40), // Increase the padding to increase the size of the Container
decoration: BoxDecoration(
color: Colors.white, // Change this to your preferred color
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
children: [
Text(
recordingDetails,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.black),
),
SizedBox(height: 10),
Text(
'Durata: $duration',
style: TextStyle(fontSize: 20, color: Colors.black),
),
SizedBox(height: 10),
Text(
'Titolo: $title',
style: TextStyle(fontSize: 20, color: Colors.black),
),
SizedBox(height: 10),
Text(
'Nome del relatore: $presenterName',
style: TextStyle(fontSize: 20, color: Colors.black),
),
],
),
),
CustomButton(
text: "Interrompi la registrazione",
margin: EdgeInsets.fromLTRB(80, 10, 80, 10),
variant: ButtonVariant.OutlineBlack9003f,
padding: ButtonPadding.PaddingAll15,
onTap: onStop,
),
],
),
),
);
}
}

+ 1
- 0
lib/presentation/splash_screen_one_screen/splash_screen_one_screen.dart Просмотреть файл

@@ -58,6 +58,7 @@ class _SplashScreenOneScreenState extends State<SplashScreenOneScreen> with Auto

@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
body: Stack(
children: [


+ 1
- 0
pubspec.yaml Просмотреть файл

@@ -35,6 +35,7 @@ flutter:
- assets/images/lab1.jpg
- assets/images/lab2.jpg
- assets/images/lab3.jpg
- .env
fonts:
- family: Roboto
fonts:


Загрузка…
Отмена
Сохранить