Начальный коммит

This commit is contained in:
2026-01-30 21:54:00 +07:00
parent 51de113db5
commit 3881248187
81 changed files with 5424 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
// lib/controllers/auth_controller.dart
import 'package:Stocky/services/api/api_service.dart';
import 'package:Stocky/services/local/StorageService.dart';
import 'package:get/get.dart';
class AuthController extends GetxController {
// Состояния
final _state = 'inputPhone'.obs;
final ApiService apicontr = Get.find<ApiService>();
Rx<String> phoneNumber = ''.obs;
Rx<String> verificationCode = ''.obs;
// Получаем текущее состояние
String get state => _state.value;
// Меняем состояние
void setState(String newState) {
_state.value = newState;
}
// Ввод номера
void phoneNumberInput(String value) {
phoneNumber.value = value;
}
// Проверка номера
bool get isPhoneNumberValid {
final clean = phoneNumber.value.replaceAll(RegExp(r'[^0-9]'), '');
return clean.length == 11 && clean.startsWith('7'); // или 10, если без +7
}
// Получить "чистый" номер (для отправки на сервер)
String get phoneNumberClean {
return phoneNumber.value.replaceAll(RegExp(r'[^0-9]'), '');
}
// Ввод кода
void verificationCodeInput(String value) {
verificationCode.value = value;
}
Future<void> sendCode() async {
if (phoneNumber.value.isEmpty) {
Get.snackbar('Ошибка', 'Введите номер телефона');
return;
}
if (!isPhoneNumberValid) {
Get.snackbar('Ошибка', 'Неверный номер телефона');
return;
}
await Future.delayed(const Duration(seconds: 1));
setState('inputCode');
await apicontr.registerByPhone(phoneNumberClean);
}
// Подтвердить код
Future<void> submit() async {
if (verificationCode.value.isEmpty) {
Get.snackbar('Ошибка', 'Введите код подтверждения');
return;
}
await Future.delayed(const Duration(seconds: 1));
final reg = await apicontr.loginByPhone(
phoneNumber.value,
verificationCode.value,
);
if (reg) {
Get.find<LocalStorageService>().putNumber(phoneNumber.value);
Get.snackbar('Успешно', 'Вы вошли!');
Get.offAllNamed('/home');
}
}
}

View File

@@ -0,0 +1,233 @@
import 'package:Stocky/models/task_adapter.dart';
import 'package:Stocky/models/Documents.dart';
import 'package:Stocky/services/api/api_service.dart';
import 'package:Stocky/services/api/push_notification_service.dart';
import 'package:Stocky/services/local/StorageService.dart';
import 'package:get/get.dart';
class MainController extends GetxController {
final username = ''.obs;
final tasks = <Task>[].obs;
final documents = <Document>[].obs;
final RxBool isLoading = false.obs;
final RxBool isTask = true.obs;
final RxBool isProj = true.obs;
bool _isSyncingTasks = false;
Future<void> getSettings() async {
username.value = await Get.find<LocalStorageService>().getUsername();
}
Future<void> fetchTasks() async {
if (_isSyncingTasks) return;
_isSyncingTasks = true;
try {
isLoading.value = true;
final localTasks = Get.find<LocalStorageService>().getTasks();
if (localTasks.isEmpty) {
await _fetchTasksFromServer();
} else {
await _syncTasksWithServer(localTasks);
}
final activeTasks = await Get.find<LocalStorageService>()
.getCompletedTasks();
tasks.assignAll(activeTasks);
} catch (e) {
print('Ошибка при синхронизации задач: $e');
} finally {
_isSyncingTasks = false;
isLoading.value = false;
}
}
Future<void> _syncTasksWithServer(List<Task> localTasks) async {
try {
// Шаг 1: Обрабатываем все несинхронизированные задачи
final unsyncedTasks = localTasks.where((t) => !t.isSynced).toList();
for (final task in unsyncedTasks) {
if (task.isDeletedLocally == true) {
// Удаление: пытаемся удалить на сервере
final deleted = await Get.find<ApiService>().deleteTask(
task.id.toString(),
);
if (deleted) {
Get.find<LocalStorageService>().removeTask(task.id);
} else {
// Не удалось — оставляем помеченной, попробуем позже
continue;
}
} else {
// Создание или обновление
final syncedTask = await Get.find<ApiService>().upsertTask(task);
if (syncedTask != null) {
syncedTask.isSynced = true;
syncedTask.isDeletedLocally = false;
Get.find<LocalStorageService>().updateTask(syncedTask);
}
// Если не удалось — остаётся с isSynced = false
}
}
// Шаг 2: Получаем актуальный список с сервера
final serverTasks = await Get.find<ApiService>().fetchTasks();
await Get.find<LocalStorageService>().saveTasks(serverTasks);
} catch (e) {
print('Ошибка синхронизации: $e');
// В случае ошибки — восстанавливаем локальный список
tasks.assignAll(localTasks);
}
}
Future<void> _fetchTasksFromServer() async {
try {
final serverTasks = await Get.find<ApiService>().fetchTasks();
await Get.find<LocalStorageService>().saveTasks(serverTasks);
tasks.assignAll(serverTasks);
} catch (e) {
print('Ошибка загрузки задач с сервера: $e');
// Остаёмся с пустым списком
}
}
Future<void> assignTaskToCurrentUser(Task task) async {
task.executor = username.value;
task.isSynced = false;
updateTask(task);
}
Future<void> completeTask(Task task) async {
task.isCompleted = true;
task.endTime = DateTime.now();
task.isSynced = false;
updateTask(task);
final activeTasks = await Get.find<LocalStorageService>()
.getCompletedTasks();
tasks.assignAll(activeTasks);
}
Future<void> addTask(Task task) async {
task.isSynced = false;
task.isDeletedLocally = false;
Get.find<LocalStorageService>().addTask(task);
tasks.add(task);
_syncTaskToServer(task);
}
Future<void> updateTask(Task updatedTask) async {
final index = tasks.indexWhere((t) => t.id == updatedTask.id);
if (index == -1) return;
updatedTask.isSynced = false;
updatedTask.isDeletedLocally = false;
Get.find<LocalStorageService>().updateTask(updatedTask);
tasks[index] = updatedTask;
_syncTaskToServer(updatedTask);
}
Future<void> deleteTask(Task task) async {
final index = tasks.indexWhere((t) => t.id == task.id);
if (index == -1) return;
try {
final success = await Get.find<ApiService>().deleteTask(
task.id.toString(),
);
if (success) {
Get.find<LocalStorageService>().removeTask(task.id);
tasks.removeAt(index);
} else {
// Нет связи — помечаем для отложенного удаления
_markTaskForDeletion(task);
}
} catch (e) {
print('Ошибка при удалении задачи: $e');
_markTaskForDeletion(task);
}
}
void _markTaskForDeletion(Task task) {
task.isDeletedLocally = true;
task.isSynced = false;
Get.find<LocalStorageService>().updateTask(task);
}
Future<void> _syncTaskToServer(Task task) async {
final storage = Get.find<LocalStorageService>();
if (task.isDeletedLocally == true) {
final success = await Get.find<ApiService>().deleteTask(
task.id.toString(),
);
if (success) {
storage.removeTask(task.id);
tasks.removeWhere((t) => t.id == task.id);
} else {
// Оставить помеченной — будет обработано при полной синхронизации
}
return;
}
try {
final syncedTask = await Get.find<ApiService>().upsertTask(task);
if (syncedTask == null) return;
if (syncedTask.id != task.id) {
syncedTask.isSynced = true;
syncedTask.isDeletedLocally = false;
await storage.replaceTask(task.id, syncedTask);
} else {
task.isSynced = true;
task.isDeletedLocally = false;
await storage.updateTask(syncedTask);
}
final index = tasks.indexWhere((t) => t.id == task.id);
if (index != -1) {
if (syncedTask.id != task.id) {
tasks.removeAt(index);
tasks.add(syncedTask);
} else {
tasks[index] = syncedTask;
}
}
} catch (e) {
print('Ошибка синхронизации: $e');
}
}
Task? openTask(String taskId) {
return tasks.firstWhereOrNull((task) => task.id == taskId);
}
@override
void onInit() async {
super.onInit();
Get.find<PushNotificationService>().foregroundMessageStream.listen((
message,
) {
// _handleMessageAction(message); // тот же метод, что и выше
});
getSettings();
fetchTasks();
}
void openTaskFromNotification(String taskId) {
Get.toNamed('/task', arguments: {'id': taskId});
}
}

View File

@@ -0,0 +1,32 @@
import 'package:Stocky/services/local/StorageService.dart';
import 'package:get/get.dart';
class SplashScreenController extends GetxController {
late Future<bool> _authCheck;
@override
void onInit() {
super.onInit();
_authCheck = _checkAuthentication();
}
Future<bool> _checkAuthentication() async {
final LocalStorageService settings = Get.find<LocalStorageService>();
final accessToken = settings.getAccessToken();
if (accessToken != null && accessToken.isNotEmpty) {
return true;
}
return false;
}
Future<void> navigateBasedOnAuth() async {
final isAuthenticated = await _authCheck;
if (isAuthenticated) {
Get.offAllNamed('/home');
} else {
Get.offAllNamed('/login');
}
}
}