Untitled

 avatar
unknown
plain_text
2 months ago
8.0 kB
5
Indexable
import 'package:flutter/material.dart';

import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'package:family_tree/app/modules/family_tree/controllers/tree_controller.dart';
import 'package:family_tree/app/modules/family_tree/model/family_model.dart';
import 'package:family_tree/app/modules/profile/controllers/profile_controller.dart';
import 'package:family_tree/app/modules/session/controllers/session_controller.dart';
import 'package:family_tree/constant/shared_preference_key.dart';
import 'package:family_tree/constant/url.dart';
import 'package:family_tree/library/dio_client.dart';
import 'package:family_tree/mgwidgets/loading_widget.dart';

class FamilyTreeController extends GetxController with GetTickerProviderStateMixin {
  // Dependencies
  final sessionController = Get.put(SessionController());
  final dio = DioClient(withLog: false);

  // UI Controllers
  late TabController tabController;

  // Observable State
  final isOpenFindPerson = false.obs;
  final family = <FamilyModel>[].obs;
  final index = 0.obs;
  final loading = false.obs;
  final listTreeController = <TreeController>[].obs;

  // Internal State
  final scrollKey = GlobalKey();
  int activeTreeId = 0;
  int treeId = 0;
  bool isRefresh = false;

  // Find a tree by its ID
  FamilyModel? getTreeById(int treeId) {
    for (var data in family) {
      if (data.tree.treeId == treeId) {
        return data;
      }
    }
    return null;
  }

  @override
  void onInit() async {
    // Initialize tab controller with zero length initially
    tabController = TabController(
      vsync: this,
      length: 0,
    );

    // Check if we need to focus on a specific tree
    if (Get.arguments != null && Get.arguments.containsKey('tree_id')) {
      activeTreeId = Get.arguments['tree_id'];
    }

    // Fetch data to populate the trees
    await fetchDataTree(refreshTab: true);
    super.onInit();
  }

  // Pull-to-refresh handler
  Future<void> onRefresh() async {
    Get.put(LoadingWidget()).show();
    await fetchDataTree();
    Get.put(LoadingWidget()).close();
  }

  // Fake refresh for testing purposes
  Future<void> onRefreshFake() async {
    Get.put(LoadingWidget()).show();
    Get.put(LoadingWidget()).close();
  }

  // Fetch tree data from API
  Future<void> fetchDataTree({
    bool refreshTab = true,
    bool toLastFamily = false,
  }) async {
    try {
      // If we're refreshing tabs, reset the tab controller
      if (refreshTab == true) {
        tabController = TabController(length: 0, vsync: this);
      }

      loading(true);

      // Get authentication token
      final prefs = await SharedPreferences.getInstance();
      var token = prefs.getString(SharedPreferenceKey.token);
      dio.baseOptions.headers['Authorization'] = 'Bearer $token';

      // Clear existing data
      family.clear();

      // Fetch tree data from API
      var response = await dio.requestGet(getTreePath, {});
      var result = response!.data;
      var json = List<Map<String, dynamic>>.from(result['data']);

      // Process each family tree
      List<TreeController> listTreeControllerTemp = [];
      for (var a in json) {
        // Create family model
        FamilyModel temp = FamilyModel.fromJson(a);
        family.add(temp);

        // Create and configure a tree controller for this family
        TreeController tempTreeController = Get.put(
          TreeController(),
          tag: temp.treeId.toString(),
        );

        // Initialize controller collections
        List<ScrollController> listScrollFamily = [];
        List<List<GlobalKey>> listKeyFamily = [];
        List<GlobalKey> listKeyGeneration = [];
        List<List<bool>> listChildBlink = [];
        List<List<bool>> listSpouseBlink = [];

        // Process each generation in the family
        for (var j in temp.generations) {
          List<GlobalKey> listKeyFamilyGeneration = [];
          List<bool> childBlink = [];
          List<bool> spouseBlink = [];

          // Set up keys and blink states for each child
          for (int k = 0; k < j.children.length; k++) {
            listKeyFamilyGeneration.add(GlobalKey());
            childBlink.add(false);
            spouseBlink.add(false);
          }

          // Add collections to their respective controllers
          listChildBlink.add(childBlink);
          listSpouseBlink.add(spouseBlink);
          listScrollFamily.add(ScrollController());
          listKeyFamily.add(listKeyFamilyGeneration);
          listKeyGeneration.add(GlobalKey());
        }

        // Assign collections to the tree controller
        tempTreeController.listChildBlink.value = listChildBlink;
        tempTreeController.listSpouseBlink.value = listSpouseBlink;
        tempTreeController.listFamilyKeyGeneration.value = listKeyGeneration;
        tempTreeController.listFamilyScrollGeneration.value = listScrollFamily;
        tempTreeController.listFamilyKeyChild.value = listKeyFamily;

        // Refresh controller state
        tempTreeController.listFamilyScrollGeneration.refresh();
        tempTreeController.listFamilyKeyChild.refresh();

        // Add to the main list of tree controllers
        listTreeControllerTemp.add(tempTreeController);
      }

      // Update the main list of tree controllers
      listTreeController.value = listTreeControllerTemp;
      listTreeController.refresh();

      // Update tab controller if needed
      if (refreshTab == true) {
        tabController = TabController(
          vsync: this,
          length: family.length,
        );
      }

      // Set up tab selection listener
      tabController.addListener(() {
        index.value = tabController.index;
      });

      // Set active tab based on tree ID if specified
      for (var i = 0; i < family.length; i++) {
        if (family[i].treeId == treeId) {
          tabController.index = i;
          index.value = i;
          treeId = 0;
        }
      }

      // Ensure tab index is set
      tabController.index = index.value;

      // Update UI state
      loading(false);
      family.refresh();
      return;
    } catch (e) {
      // Handle errors silently
      print("Error fetching tree data: $e");
    }
    return null;
  }

  // Remove tree data (for cleanup)
  Future<void> removeTree({
    bool refreshTab = true,
    bool toLastFamily = false,
  }) async {
    try {
      family.clear();
      family.refresh();
      print(family.length);
    } catch (e) {
      // Handle errors silently
    }
    return null;
  }

  // API call to unmerge photos for two persons
  Future<void> postUnmergePhoto({
    required int personId1,
    required int personId2,
  }) async {
    // Prepare request parameters
    var param = {
      'person_id1': personId1,
      'person_id2': personId2,
    };

    // Show loading indicator
    Get.put(LoadingWidget()).show();

    try {
      // Get authentication token
      final prefs = await SharedPreferences.getInstance();
      var token = prefs.getString(SharedPreferenceKey.token);

      // Make API request
      var response = await dio.requestPost(
        unmergePhoto,
        param,
        options: Options(
          headers: {
            'authorization': 'Bearer $token',
          },
        ),
      );

      // Handle response
      if (response == null) {
        Get.back();
        return null;
      }

      // Refresh data after successful unmerge
      await fetchDataTree(refreshTab: false);
      await Get.put(ProfileController()).loadData();
    } catch (e) {
      print("Error unmerging photos: $e");
    } finally {
      // Close loading indicator
      Get.put(LoadingWidget()).close();
    }
  }

  // Set active tree by ID
  void setActiveTreeId(int treeId) {
    int activeIndex = family.indexWhere((e) => e.treeId == treeId);
    if (activeIndex >= 0) {
      tabController.animateTo(activeIndex);
    }
  }
}
Editor is loading...
Leave a Comment