현 프로젝트 준비단계

18. 필터 기능 및 provider 생성 / 마이페이지 수정하기 제작

깡 딱 2025. 2. 16. 22:10
728x90
소요시간

2025년 2월 16일 - 4시간

 

 

 

느낀 점

 

오늘 프로바이더를 진짜 심오 깊게 공부해 봤는데 개인적으로 내가 똑바로 못쓰고 있다는 생각이 났다.

분명 main에서 먼저 써야 된다고 ai에게 들었는데 ai가 실수를 많이 해서 직접 연결했었는데

내가 모르니까 질문을 똑바로 못했다고 생각한다. 앞으로는 먼저 선공부후 진입 해야겠다.

 

 

 

필터 provider 제작

 

main 화면에 상태전달.

ChangeNotifierProvider(create: (_) => FilterProvider()),
///필터 상태

 

 

_selectedFilters에 버튼들을 담았습니다. 밑에 사진을 보시면 이해가 빠르실 겁니다.

 

밑에는 특정필터를 제거 추가 하는 코드 

notifyListeners()를 넣어서 여러 화면에 바로바로 전달 되게 만들었습니다.

class FilterProvider extends ChangeNotifier {
  final List<String> _selectedFilters = [];

  List<String> get selectedFilters => _selectedFilters;

  /// 필터 토글 (이미 선택되어 있으면 제거, 없으면 추가)
  void toggleFilter(String filter) {
    if (_selectedFilters.contains(filter)) {
      _selectedFilters.remove(filter);
    } else {
      _selectedFilters.add(filter);
    }
    notifyListeners();
  }

  /// 특정 필터 제거
  void removeFilter(String filter) {
    _selectedFilters.remove(filter);
    notifyListeners();
  }
}

 

 

 

 

필터 카테고리 버튼 UI

 

버튼 위젯인데 여기서 text와 bool문을 전달받아서 버튼에 넣어주면 

Widget casualButton(String text, {bool isSelected = false}) {
  return Container(
    width: 68.w,
    height: 36.h,
    decoration: ShapeDecoration(
      color: isSelected ? const Color(0xFF05FFF7).withOpacity(0.2) : Colors.transparent,
      shape: RoundedRectangleBorder(
        side: BorderSide(
          width: 1,
          color: isSelected ? const Color(0xFF05FFF7) : const Color(0xFF3D3D3D),
        ),
        borderRadius: BorderRadius.circular(100),
      ),
    ),
    child: Center(
      child: Text(
        text,
        textAlign: TextAlign.center,
        style: const TextStyle(
          color: Colors.white,
          fontSize: 14,
          fontFamily: 'Pretendard',
          fontWeight: FontWeight.w500,
          height: 1.40,
          letterSpacing: -0.35,
        ),
      ),
    ),
  );
}

 

 

 

이런 형태로 버튼을 만들 수 있습니다.

GestureDetector(
  onTap: () => filterProvider.toggleFilter("캐주얼"),
  child: casualButton("캐주얼", isSelected: filterProvider.selectedFilters.contains("캐주얼")),
),

 

 

꼭 버튼을 만들기 전에 필터 프로바이더를 가져와서  상태관리가 되게 만듭니다.

final filterProvider = Provider.of<FilterProvider>(context);

 

 

필터 넣은 목록 영역

 

 

앞서 만든 정필터를 제거 추가 하는 코드를 이용해서 리스트뷰를 하나 만들어 줬습니다. 

코드는 AI와 함께 만들어서 저의 형식과 달라서 마지막에 리팩토링이 필요할 거 같습니다.

Container(
  width: 360.w,
  height: 56.h,
  color: const Color(0xFF1A1A1A),
  padding: const EdgeInsets.symmetric(horizontal: 8),
  child: Align(
    alignment: Alignment.centerLeft,
    child: filterProvider.selectedFilters.isEmpty
        ? const Text(
      "선택된 필터가 없습니다.",
      style: TextStyle(color: Colors.white),
    )
        : ListView(
      scrollDirection: Axis.horizontal,
      children: filterProvider.selectedFilters.map((filter) {
        return Padding(
          padding: const EdgeInsets.only(right: 12),
          child: Chip(
            label: Text(filter),
            backgroundColor: const Color(0xFF242424),
            labelStyle: const TextStyle(color: Colors.white),
            deleteIcon: const Icon(
              Icons.close,
              size: 16,
              color: Colors.white,
            ),
            onDeleted: () {
              filterProvider.toggleFilter(filter);
            },
          ),
        );
      }).toList(),
    ),
  ),
),

 

이걸 똑같이 다른 곳에 넣어도 프로바이더 덕분에 잘 전달됩니다! 

 

 

 

 

마이페이지 화면 edit 만들기

 

이전에 만들었던 ui가 맘에 안 들어서 패딩값과 크기를 수정 그런 후

 

 

닉네임을 불러오는 메서드 추가

 

이 코드는 supabase에 저장된 userinfo라는 테이블을 가져와서 사용자의 닉네임을 띄우기 위한 메서드입니다.

 

 

Future<void> fetchUserInfo() async {
  isLoading = true;
  errorMessage = null;
  notifyListeners();

  try {
    final currentUser = supabase.auth.currentUser;
    if (currentUser == null) {
      errorMessage = "로그인된 사용자가 없습니다.";
      userList = [];
      return;
    }

    // 쿼리 실행 시 에러 발생 시 예외가 throw됩니다.
    final response = await supabase
        .from('userinfo')
        .select()
        .eq('id', currentUser.id);

    // 정상적으로 데이터를 반환하면 response는 List<dynamic> 타입입니다.
    userList = response as List<dynamic>;
  } catch (e) {
    errorMessage = e.toString();
    userList = [];
  } finally {
    isLoading = false;
    notifyListeners();
  }
}

 

또한 닉네임을 수정도 할 수 있어야 되기 때문에 update 코드도 제작하였습니다.

이건 userinfo에 있는 username을 newUsername에 저장하는 코드입니다.

 

한마디로 텍스트필드에 username을 불러와서 여기서 수정을 한내용을

newUsername에 저장을 해서 저장하는 방식입니다.

 

Future<void> updateUsername(String newUsername) async {
  final currentUser = supabase.auth.currentUser;
  if (currentUser == null) {
    errorMessage = "로그인된 사용자가 없습니다.";
    notifyListeners();
    return;
  }

  try {
    isLoading = true;
    notifyListeners();

    final response = await supabase
        .from('userinfo')
        .update({'username': newUsername})
        .eq('id', currentUser.id);

    // 업데이트된 행이 있는지 확인 (예: response가 List 형태로 반환됨)
    if (response is List && response.isEmpty) {
      errorMessage = "업데이트된 행이 없습니다. RLS 정책이나 레코드 존재 여부를 확인하세요.";
    } else {
      // 업데이트 성공 시 최신 데이터를 다시 가져옵니다.
      await fetchUserInfo();
    }
  } catch (e) {
    errorMessage = e.toString();
  } finally {
    isLoading = false;
    notifyListeners();
  }
}

 

 

사진을 보면 이해하기 쉬울 거 같습니다! 

 

supabase에 저장된 데이터값을 닉네임 필드로 불러와서 

여기서 수정을 거치고 수정버튼을 누르면 데이터베이스 값이 바뀝니다!

728x90