친구_지도_보기 - boostcampwm-2024/and04-Nature-Album GitHub Wiki

✅ 진행한 기능

  • 로그인 된 유저의 경우 친구 선택을 위한 버튼 추가
  • 다이얼로그에서 친구 선택기능
  • 선택된 친구들의 사진을 각각의 클러스터로 표시
  • roomDB, firebase로부터의 dto를 uiItem으로 매핑

💡문제 해결 과정 기록

  1. 버튼 추가

    1. UserManager로 로그인 상태를 확인해서 로그인 된 상태일때만 버튼 표시

    ❓ 버튼이 보이지 않아요

    ⇒ Box에서는 컴포저블의 순서대로 그려서 덮어씌워진 문제!
    지도를 먼저 그리고 버튼을 추가

  2. 다이얼로그 제작

    1. 어떤 컴포저블을 사용할까?

      1. AlertDialog는 타이틀과 텍스트를 넣을 수 있고, 버튼 두개를 자동으로 그려준다

        But, 현재 UI에서는 타이틀, 다이얼로그에서의 동작 정보, 스크롤 가능한 content를 넣어야한다. + Deprecated

      2. BasicAlterDialog는 content를 넣을수 있어 커스텀할 수 있지만 실험실 기능이라 다른 방법을 찾아보려고 한다.

      3. Dialog는 BasicAlterDialog에서 사용하는 컴포저블로 조금 더 자유로은 커스텀이 가능하다.

      4. Dialog를 사용하지 않더라도 Box등을 통해 직접 제작할 수 도 있지만, dismiss 이벤트 처리가 추가로 필요하다

      ⇒ dismiss처리가 편리하고 커스텀이 충분히 자유로운 Dialog에 Card로 컨텐츠를 추가하고 UI를 배치하기로 결정

    2. 다이얼로그의 on/off는 어떻게?

      1. 뷰 시스템에서의 동작이 익숙해 처음에는 버튼의 클릭 리스너로 다이얼로그를 실행하는 코드를 추가하려 했다.
      2. 하지만 컴포즈에서 Dialog는 실행 가능한 객체가 아니라 컴포저블 함수이고, 리스너 블럭 안에 추가할 수 없고 실행한다는 개념으로 사용하는게 아니었다.
      3. 다이얼로그를 보이게 할지 정하는 Boolean을 상태로 관리하고, 친구선택 버튼을 눌렀을때 true로 설정, dismiss 혹은 다이얼로그의 버튼을 눌렀을때 false로 설정
    3. 친구 선택하기

      1. 버튼 클릭시에 친구 리스트를 불러오고 다이얼로그에 표시

      2. 기존에 선택되어있던 유저들을 저장하고 기존 유저들로 현재 다이얼로그 선택 상태 초기화

        ⇒ remember로 다이얼로그가 선택한 유저를 저장하고 있기때문에 불필요한 로직

            FriendDialog(
                isOpen = openDialog,
                friends = friends,
                // prevSelectedFriends = showFriends,
                onDismiss = { openDialog.value = false },
                onConfirm = { selectedFriends ->
                    viewModel.fetchFriendsPhotos(selectedFriends.map { it.user.uid })
                    // showFriends = selectedFriends
                    openDialog.value = false
                }
            )
        }
        
        @Composable
        fun FriendDialog(
            isOpen: State<Boolean> = remember { mutableStateOf(true) },
            friends: State<List<FirebaseFriend>> = remember { mutableStateOf(emptyList()) },
            // prevSelectedFriends: List<FirebaseFriend> = emptyList(),
            modifier: Modifier = Modifier,
            onDismiss: () -> Unit = {},
            onConfirm: (List<FirebaseFriend>) -> Unit = {}
        ) {
            val screenHeight = LocalConfiguration.current.screenHeightDp.dp
            // var selectedFriends by remember { mutableStateOf(prevSelectedFriends) }
            var selectedFriends by remember { mutableStateOfList<FirebaseFriend>(emptyList()) }
      3. LazyColumn에 각 친구들의 정보 와 체크박스 표시

        체크박스의 상태는 체크박스에 그릴 유저가 선택된 유저 리스트에 있는지로 확인,

        체크박스 클릭시 선택상태에서는 list의 필터로 아이템을 제거하고 선택되지 않았을때는 최대 선택 갯수보다 작을때만 리스트 추가

  3. 클러스터 관리

    1. 사용자 본인과 여러 친구들의 사진을 하나의 지도에서 보여주기

      1. 하나의 클러스터에서 태그로 관리하기

      2. 사용자별로 클러스터를 관리하기

        → 태그는 클러스터에 키를 추가할때 추가로 설정할 수 있지만 삭제할때는 태그가 아닌 키로만 삭제할 수 있어서 모든 유저의 사진들을 매번 업데이트 해야함

        각 클러스터 마커 선택시 동작을 정의하기 위해서 태그에 유저 정보가 아닌 노드에 포함된 키들을 리스트로 관리할 필요가 있음

        ⇒ 사용자별 별개의 클러스터로 관리하기! 각 클러스터에서 사용할 colorTint도 각각 관리할 수 있다.

    2. 클러스터 매니저로 분리

      컴포저블에 있을 필요가 없는 코드이기도 하고 클러스터 설정에 필요한 함수들이 있는데 컴포저블 외부에서 함수로 정의하고 가져와 사용하는것보다 하나의 클래스에서 묶어서 관리하는게 한눈에 보기 편하다고 판단해 별도의 클래스로 분리했다.

  4. ui element?

    현재 프로젝트의 아키텍쳐에서 별도의 데이터 소스를 두지 않고 레포지토리를 데이터 소스처럼 사용하고 있다…

    해서 레포지토리에서 뷰모델로 dto를 그대로 전달하고 뷰모델에서 가공후 ui로 넘겨줘야하는 구조이다.

    (아키텍쳐에 대해 팀원들과 논의 필요)

    클러스터에서 사용할 PhotoKey가 존재하고, 각각의 레포지토리에서 반환하는 객체의 프로퍼티가 제각각이므로 각각의 매퍼를 추가해 동일한 타입으로 수정 후 PhotoKey로 전환(Key는 클러스터에서만 사용하는 타입이라 범용성이 떨어지고, UI에서 편하게 관리하기 위함. 원래는 레포지토리에서 수행했어야 할 로직)

    ❓ 동일한 signature

    e: file:///home/jinhwan/AndroidStudioProjects/and04-Nature-Album/app/src/main/java/com/and04/naturealbum/ui/maps/PhotoKey.kt:40:1 Platform declaration clash: The following declarations have the same JVM signature (toPhotoItems(Ljava/util/List;Ljava/util/List;)Ljava/util/List;):
        fun List<FirebasePhotoInfoResponse>.toPhotoItems(labels: List<FirebaseLabelResponse>): List<PhotoItem> defined in com.and04.naturealbum.ui.maps
        fun List<PhotoDetail>.toPhotoItems(labels: List<Label>): List<PhotoItem> defined in com.and04.naturealbum.ui.maps

    IDE 상에서는 List의 제네릭타입이 다르면 다른 타입으로 인식하는것 같지만 빌드시에는 동일하게 List 타입이라고만 인식하면서 문제가 생겼다.

    하나의 함수에서 타입별로 분기를 나눠서 처리할 수도 있지만 유효한 타입인지 확인하고, 동일한 소스로부터 온 타입인지 확인하는 과정이 추가로 필요해 그냥 함수명을 구분하기로 했다.

    (이것도 레포지토리를 데이터소스처럼 써서 생기는 문제로 보인다…)

⚠️ **GitHub.com Fallback** ⚠️