본문 바로가기

Flutter-플러터/플러터 공부

Flutter - LinkedHasMap- 원하는 값 필터리스트로 만들기

반응형

 

 

 

Map을 2중으로도 사용가능하다. 

나같은 경우에는 

 

아래처럼 사용했다.  Map<String, Map<String ,List>>

 

Map<월, Map<일자,데이터리스트>>

요렇게 생각하면 좋다. 

 

Future<Map<String, Map<String, List<ExpenseRecordItem>>>>
      groupExpensesByMonthAndDate(List<ExpenseRecordItem> expenses) async {
    final Map<String, Map<String, List<ExpenseRecordItem>>>
        groupedExpensesByMonth = {};

    for (final expense in expenses) {
      final month =
          DateFormat('yyyy-MM').format(DateTime.parse(expense.createdTime));
      final date =
          DateFormat('yyyy-MM-dd').format(DateTime.parse(expense.createdTime));

      if (!groupedExpensesByMonth.containsKey(month)) {
        groupedExpensesByMonth[month] = {};
      }

      if (groupedExpensesByMonth[month]!.containsKey(date)) {
        groupedExpensesByMonth[month]![date]!.add(expense);
      } else {
        groupedExpensesByMonth[month]![date] = [expense];
      }
    }

    // 각 월에 대해 내부의 날짜를 내림차순으로 정렬
    groupedExpensesByMonth.forEach((month, expensesByDate) {
      final sortedDates = expensesByDate.keys.toList()
        ..sort((a, b) => DateTime.parse(b).compareTo(DateTime.parse(a)));
      groupedExpensesByMonth[month] = LinkedHashMap.fromIterable(
        sortedDates,
        key: (key) => key,
        value: (key) => expensesByDate[key]!,
      );
    });

    return groupedExpensesByMonth;
  }

 

 

이렇게 진행하다가 내가 원하는 월에만 해당하는 일자의 데이터 리스트만 보고 싶다. 

 

다음과 같이 코드를 생성했다. 

fiterExpensesByMonth 함수는 init 함수에 넣어서 화면이 초기화 될 때 바로 실행 되도록 만들었다. 

 

void filterExpensesByMonth(String selectedMonth) {
    filteredExpenses.clear(); // 기존 데이터를 비워줍니다.

    filteredExpenses.assignAll(expenseRecords.where((expense) {
      final month =
          DateFormat('yyyy-MM').format(DateTime.parse(expense.createdTime));
      return month == selectedMonth;
    }).toList());

    update();
  }

// 이전달로 이동하는 함수
  void moveToPreviousMonth() {
    update();
    final currentMonth = DateTime.parse(selectedMonth.value + '-01');
    final previousMonth = DateTime(currentMonth.year, currentMonth.month - 1);

    if (previousMonth.isBefore(DateTime(2000))) {
      return; // 2000년 이전으로 이동하지 못하게 처리
    }

    selectedMonth.value = DateFormat('yyyy-MM').format(previousMonth);
    filterExpensesByMonth(selectedMonth.value);
  }

  void moveToNextMonth() {
    update();
    final currentMonth = DateTime.parse(selectedMonth.value + '-01');
    final nextMonth = DateTime(currentMonth.year, currentMonth.month + 1);

    if (nextMonth.isAfter(DateTime(2100))) {
      return; // 2100년 이후로 이동하지 못하게 처리
    }

    selectedMonth.value = DateFormat('yyyy-MM').format(nextMonth);
    filterExpensesByMonth(selectedMonth.value);
  }

 

 

 

다음은 ui코드 

 

  Widget buildExpensesList(BuildContext context) {
    return FutureBuilder<Map<String, Map<String, List<ExpenseRecordItem>>>>(
      future: controller.groupExpensesByMonthAndDate(controller.expenseRecords),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else if (snapshot.hasError) {
          return Center(child: Text('데이터 로드 중 오류가 발생했습니다. 😔'));
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          return Center(child: Text('꾸준히 기록해보세요 🙂'));
        }

        Map<String, Map<String, List<ExpenseRecordItem>>> groupedExpenses =
            snapshot.data!;

        // 월 단위로 데이터 필터링

        return Obx(
          () {
            final filteredMonthExpenses =
                groupedExpenses[controller.selectedMonth.value] ?? {};

            return ListView(
              shrinkWrap: true,
              physics: NeverScrollableScrollPhysics(),
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    IconButton(
                      onPressed: () {
                        controller.moveToPreviousMonth();
                      },
                      icon: Icon(CupertinoIcons.arrow_left_circle),
                    ),
                    Text(
                      controller.selectedMonth.value,
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    IconButton(
                      onPressed: () {
                        controller.moveToNextMonth();
                      },
                      icon: Icon(CupertinoIcons.arrow_right_circle),
                    ),
                  ],
                ),
                ...filteredMonthExpenses.entries.expand((dailyEntry) {
                  return [
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 8.0),
                      child: Text(
                        DateFormat('dd 일')
                            .format(DateTime.parse(dailyEntry.key)),
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w500,
                        ),
                      ),
                    ),
                    ...dailyEntry.value.map((expenseRecord) {
                      return InkWell(
                        onTap: () {
                          showEditExpenseDialog(context, expenseRecord.id);
                        },
                        child: ListTile(
                          title: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              Text(expenseRecord.name),
                              Text(
                                '${controller.formatNumberWithCommas(expenseRecord.money)} 원',
                                style: TextStyle(
                                  fontSize: 15.0,
                                  fontWeight: FontWeight.w400,
                                  color: expenseRecord.isIncome
                                      ? Colors.red[300]
                                      : Colors.green,
                                ),
                              ),
                            ],
                          ),
                          trailing: IconButton(
                            onPressed: () {
                              controller.deleteExpense(expenseRecord.id);
                            },
                            icon: const Icon(Icons.delete),
                          ),
                        ),
                      );
                    }).toList(),
                  ];
                }).toList(),
              ],
            );
          },
        );
      },
    );
  }

 

 

완료

 

728x90
반응형