다양한 색으로 자신만의 연락처를 커스텀 해보세요!👨🎨
페이지 상세 설명
인트로
·
메인 페이지
·
연락처
·
즐겨찾기
·
상세 페이지
심규상, 심수빈, 이상오, 최영정
Color Contacts
🎨 다채로운 색의 연락처📕 라는 뜻으로
다양한 태그와⭐, 다양한 색을🌈 고르고 커스텀 할 수 있는 앱 입니다
연락처의 인물들을 다양한 태그로 분류하고, 자신이 원하는대로 커스텀 하는것
24/01/15 ~ 24/01/20
자유롭게 아이디어 브레인 스토밍을 하고 어느정도 아이디어를 나눈뒤 Figma를 가지고 기본적인 레이아웃을 디자인하고 거기서 아이디어가 추가되며 컨셉과,래퍼런스를 확실하게 틀을 잡았다
심규상 : 실제 폰에 있는 연락처 불러오기, ItemViewType 변경, Swipe-to-Action,RecyclerView.ItemAnimator, MotionLayout으로특수 효과 활용, View 색상 커스텀, 연락처 “ㄱ,ㄴ,ㄷ,ㄹ” 헤더 추가, 배경 설정으로 연락처 배경 이미지 추가
심수빈 : TabLayout 와 ViewPager, 검색 기능, 다양한 태그의 즐겨찾기 추가, 상세 화면&수정화면에서 즐겨찾기 태그 추가 및 정보 업데이트, 다이얼 패드로 이동
이상오 : 연락처 추가 (AddContactDialog or AddContactDialogFragment), Event 시간에 맞춰 Notification 표시, 다이얼로그로 유저 추가시, 연락처에 업데이트
최영정 : 상세 정보 (ContactDetailFragment) & 마이 페이지 (MyPageFragment), 상세 정보 수정, 인물 정보 삭제
공통 : Readme 작성, 버그 수정, 코드 수정
연락처에서 스와이프하며 통화하는걸
사람들이 움직이는 애니메이션으로 표현
화면 터치를 하면 애니메이션을 스킵하고 바로 메인 액티비티로 이동이 가능하다
애니메이션이 표기되기전에 연락처와 통화 퍼미션 요청을 하고
요청이 완료되면 사용자의 연락처 데이터를 갱신한다
뷰페이저를 이용해서 프래그먼트를 스와이프 하면서 이동할 수 있게 구현했다.앱은 기본적으로 리니어 타입인데
우측 상단의 창문모양 아이콘을 클릭하면 연락처 화면을 그리드 형태로 배치할 수 있다
또한 검색창이 있는데, 즐겨찾기 기본 연락처 탭에서 사용가능하며
유저의 이름을 검색해 빠르게 찾을 수 있다
레이아웃 타입변경 아이콘 옆에 팔레트 모양의 아이콘은 앱의 테마색을 변경 할 수 있다
다이얼로그로 항목을 정해주고, 그 항목을 선택하면 컬러피커가 나와서 사용자가 원하는대로 색깔을 커스텀 할수 있게 만들었다
우측 하단의 플로팅 버튼을 클릭하면 다이얼로그가 뜨면서 유저를 추가 할 수 있다유효성 검사와, 휴대폰 번호를 입력시 숫자만 눌러도 010-0000-0000 형식으로 입력하게 되고
이벤트로 알림을 울릴 수 있다
여기서 연락처를 추가하면 실제 연락처에도 연락처가 등록된다
자신과, 'ㄱ','ㄴ','ㄷ' 순으로 구분한 헤더, 그리고 연락처 목록으로 구성했다
화면 옆에보면 핸들이 있는데, 이를 이용해서 빠르게 연락처를 스와이프해 이동할 수 있다.
왼쪽에서 오른쪽으로 스와이프를하면 상대방과 통화가 가능하다
또한 우측 버튼을 클릭시 즐겨찾기가 추가가 가능하다
즐겨찾기 태그를 여럿으로 태그별로 나눠, 연락처의 지인들을 관계별로 정렬해 볼 수 있다
상단의 어댑터로 태그 목록을 좌우로 스와이프하며 볼 수 있으며 태그를 추가할수 있다.
멤버는 상세 페이지로가면 추가할 수 있다.
상세페이지에선 유저의 정보를 수정할 수 있다
인물의 태그, 이벤트, 메모, 프로필사진, 배경화면, 이름, 연락처 등등을 수정 할 수 있고
인물을 나타내는 키값은 고정이기 때문에 자유롭게 수정이 가능하다
배경화면을 선택하면 연락처 목록의 리스트가 배경으로 등록된다
처음부터 자세하게 기능 역할 분담을 하지 않아서 나중에 보니 같은 기능을 서로 다른 페이지에 추가하려고하는 문제가 발생했다.
-> 해결: 기본적인 틀을 잡아두고(디테일 페이지 UI), 추가로 들어가는 기능(알림설정, 즐겨찾기 태그 추가 등)는 담당하는 인원이 맡게해서 진행
뷰모델을 사용해서 구현 했는데, 문제가 생겨서 뷰모델 제거후 데이터 갱신이 안됨
-> 해결: 인터페이스로 리스너를 만들어 해결
-> 해결: 처음에 만들때 adapter에서 포지션을 받고 그걸로 유저데이터 리스트에서 즐겨찾기를 수정했는데 후에 뷰타입을 늘리면서 리사이클러뷰에 연락처 데이터 외에 다른 데이터가 들어가게됨 반환값에 유저의 key값을 반환하게 해서 key로 구별하고 데이터를 변경
-> 해결: 자동 완성으로 보여주는 코드들을 조사한뒤 setTransitionDuration으로 애니메이션 시간만큼 조정해주면 원하는대로 애니메이션이 실행됨
-> 이미지 타입을 URI -> File로 바꾸고 coil.load로 불러오게 변경한 이후, 기본이미지는 drawable이라 설정 하지 못했는데 데이터에 File이 null이면 기본이미지를 setImageReseource로 drawble로 넣고 null이 아닐시 load하게 만들어 해결
-> 문제
갤러리에서 이미지의 uri를 가지고 온 후에 앱 내에서 uri를 재사용하여 사용하는 경우 ImageView에 이미지가 안 뜨고 아래와 같은 에러가 발생하는 문제
class com.bumptech.glide.load.engine.GlideException: Failed to load resource There was 1 root cause: java.lang.SecurityException(Permission Denial: opening provider
-> 원인
우리 앱은 갤러리에서 이미지의 uri를 가져와서 앱 내에 uri를 저장하여 재사용하는 방식으로 구현했었다. 처음은 uri를 가져오는 데 문제가 없지만 그 다음부터는 경로를 제어를 못 해서 구글에서 재사용할 수 없게 막아 놓는 것으로 보여진다.
-> 해결
uri를 재사용하지 않고 갤러리에서 이미지를 가져올 때 디바이스에 있는 파일의 직접 경로를 찾아 uri가 아닌 경로를 저장한 후 해당 실제 경로를 가지고 뷰에 세팅 하는 방식으로 해결하였다.
내 기기의 번호는 일반 연락처 정보가 아닌 민감한 개인정보로 분류되기 때문에 따로 권한요청을 해야 하고 그 방법은 별로 권장되지는 않는다
→ 그냥 프로필을 작성하는 것처럼 마이페이지에서 사용자가 직접 입력하게 하는 방식을 선택했다
-> 마이페이지에 대한 클릭은 프래그먼트 코드에서 감지해서 인텐트로 타입을 보내고 나머지 연락처 리스트 각각에 대한 클릭은 리사이클러뷰의 어댑터에서 처리하도록 했었다 데이터가 한 리스트에 있지 않고 따로 있어서인지nullPointException이나 초기화 에러가 자꾸 발생했다 → 아예 액티비티를 따로 만들어야 할지 고민했는데 규상님이 리사이클러뷰 뷰 타입으로 다시 만들고 key값만 따로 해서 구분되게 해결을 해 주셨다
알림을 설정하고 그대로 있거나 페이지를 나가기만 할 때는 정상적으로 알림이 오는데 설정하고 나갔다가 시간이 지나기 전에 다시 해당 연락처의 상세 페이지로 들어가면 설정한 알림이 다시 x로 초기화되는 문제가 있었다
→ 알림 설정 완료 시간으로 계산해서 알림이 울릴 시간을 따로 변수에 저장해두고 그 시간과 현재 시간을 비교해서 이벤트 값을 초기화하는 조건문을 만들면 해결될 것 같다
한 페이지 내에서 나뉘는 경우의 수가 많아서 각 경우에 알맞은 값이 제대로 들어와야 의도한 화면이 나오는데 코드만으로는 이게 되어야 하는데 왜 안 되지 싶은 것들이 있었다.
→ 해당 변수에 대해 로그를 찍어서 어디에서 잘못 들어왔는지 바로 확인하는 것을 습관화하자
이미지 처리 방식을 변경해서 pull을 했는데 프로젝트 clean을 해도 import가 제대로 되지 않았다
→안드로이드 스튜디오 설정에서 gradle JDK 버전을 바꿨더니 해결되었다
-> 해결 : 상속받은 클래스를 dialog에서 dialogFragment 으로 변경
반면, dialog 는 종속되지 않아 별개의 생명주기로 인해 더 복잡해짐
-> 해결 : DataUpdateListener 인터페이스를 정의하고,
MainActivity, 해당 프래그먼트(ContactsListFragment)에 상속하여
기능(onDataUpdate())을 재정의 하여 처리함
-
AddContactDialogFragment() : 인터페이스 인스턴스 생성후 확인 버튼을 누르면 메소드 실행
-
mainActivity : Viewpager2 에 보이는 프래그먼트를 찾아서 메소드 실행
-
ContactsListFragment : setList()을 실행
-> 해결 : permission 등록하는 함수를 인자값을 Activitiy로 바꿈
-> 해결 : pending Intent 의 인자 flags 값을 바꿔줌
PendingIntent.FLAG_IMMUTABLE ->
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
심규상 : 시작전에 준비를 많이 했는데 팀원분들이 잘 따라줘서 고마웠고, 미처 생각하지못한 부족한부분을 채울 수 있어서 좋았습니다
이상오 : 이번 프로젝트에서 역할 분담을 하고 데드라인을 정하면서 하니까 더 체계적인 프로젝트를 할 수 있었던것 같습니다. 막힌 부분이 있으면 각각 피드백해주시고 의사소통도 열심히 해주기도하시고, 프로젝트 진행에 있어서 열정적이라 많은 자극받고 갑니다.
최영정 : 열심히 하시고 잘 하시는 분들을 보면서 많이 배웠고 도움도 많이 받을 수 있었습니다. 별 생각 없이 쓰던 기능을 직접 만들어 보려니까 생각보다 쉽지 않다는 걸 느꼈습니다. 협업을 할 때 전체적인 프로젝트 구조에 맞게 우선순위를 잘 정하는 게 중요하다는 것을 알았습니다.
심수빈 : 역할 분담이나 깃 사용에 있어서 프로젝트 시작부터 규칙을 정하여 진행하다보니 프로젝트를 진행하며 큰 어려움이 없었던 것 같아 만족스러웠다. 다만, 이미지 관련 권한 문제와 같은 예상치 못 했던 문제를 겪으면서 기능면에서 추가하고 싶은 부분이 많았는데 문제를 해결하는데 시간이 생각보다 많이 걸리다보니 아쉬움이 있었다. 팀원들 모두 열심히 최선을 다하여 진행한 만큼 만족스러운 결과를 낼 수 있었고 프로젝트를 진행하며 많이 배우고 앞으로 더 열심히 해야겠다는 생각이 들었다.