전체 글 (138) 썸네일형 리스트형 7편: 가로로 돌리면 경계선이 사라집니다 — clamp 한 줄이 만든 버그 증상테스트하다가 화면을 가로로 돌렸더니 지도가 이상했습니다.시군구·시도 경계선이 하나도 보이지 않습니다색칠과 사진은 정상적으로 그려집니다지도 가장자리가 들쭉날쭉합니다세로로 되돌리면 멀쩡합니다처음엔 "가로에서 지도가 안 그려진다"고 생각했는데, 캡쳐를 자세히 보니 그려지긴 하는데 선만 없는 상태였습니다. 이 구분이 나중에 중요해집니다.가설 1: 선 굵기가 0에 수렴한다선 굵기는 화면상 굵기를 일정하게 유지하려고 배율로 나눠서 씁니다. 배율이 비정상적으로 크면 굵기가 0에 가까워져 선이 사라질 수 있습니다. 색칠은 굵기와 무관하니 증상과도 맞습니다.로그를 찍어 봤습니다. painter borders scaleUsed=1.0 strokeW=0.4 / 1.2sidoBounds=Rect.fromLTRB(297.6.. 6편: 사진을 지역 모양대로 잘라 지도에 그리기 색칠 대신 사진지역을 단색으로 칠하는 것까지는 금방 됐습니다. 그런데 색만 칠해 두니 "다녀왔다"는 사실만 남고 무엇을 봤는지가 안 남았습니다.그래서 사진이 있는 지역은 대표 사진(촬영순 첫 장)을 그 지역 모양대로 잘라서 그리기로 했습니다. 사진이 없는 방문 지역만 단색입니다.구현은 간단합니다.지역의 Path로 clipPath그 안에 drawImageRect로 사진을 그림경계선은 그 위에 그대로 덧그림지도를 확대하면 사진도 같이 커져야 하므로, 지역의 화면상 사각형(dst)에 맞춰 매 프레임 BoxFit.cover처럼 계산합니다.디코딩 파이프라인을 맞춰야 합니다사진을 매번 원본으로 디코딩할 수는 없어서, 320px로 줄여서 캐시합니다. 지역이 바뀌거나 사진이 바뀐 것만 다시 디코딩하고, 빠진 것은 di.. 5편: EXIF GPS로 지역 자동 판정, 안드로이드에서 막힌 지점 사진은 복사하고, DB에는 파일 이름만사진을 고르면 앱 문서 디렉터리 아래 photos/로 복사합니다. DB에는 파일 이름만 저장합니다.절대 경로를 저장하면 안 됩니다. iOS는 앱을 업데이트할 때 앱 디렉터리의 절대 경로가 바뀝니다. 경로를 저장해 두면 업데이트 후 모든 사진이 깨집니다. 읽을 때마다 문서 디렉터리를 구해서 파일 이름을 붙이는 게 맞습니다.목록에 사진을 띄울 때는 두 가지를 꼭 챙깁니다.cacheWidth 지정 — 원본 해상도로 디코딩하면 메모리가 순식간에 올라갑니다errorBuilder 지정 — 파일이 없을 때 앱이 죽지 않게EXIF 촬영일시native_exif로 촬영일시를 읽습니다. EXIF 날짜는 yyyy:MM:dd HH:mm:ss 형식이라 그대로 파싱하면 실패합니다. 날짜 부분의.. 4편: 공유를 염두에 둔 DB 설계, 그리고 구조를 갈아엎은 이야기 로컬 DB인데 동기화를 먼저 생각했습니다지금은 전부 기기 안에 저장합니다. sqflite를 쓰는 평범한 구조입니다. 그런데 나중에 공유 기능을 붙이면 서버와 동기화를 해야 합니다. 그때 가서 스키마를 바꾸면 이미 쓰고 있는 사용자 데이터를 건드려야 하니, 처음부터 세 가지를 넣어 뒀습니다.uuid — 로컬 id는 기기마다 다르니, 전역 식별자를 따로 둡니다updated_at — 어느 쪽이 최신인지 판단할 기준deleted_at — 소프트 삭제. 진짜 지우면 "삭제됐다"는 사실을 서버에 전달할 수 없습니다조회는 전부 deleted_at IS NULL 조건이 붙습니다. 여행을 삭제해도 하위 데이터를 연쇄 삭제하지 않고, 조회 쿼리에서 상위 여행의 삭제 여부까지 확인하는 방식으로 처리합니다. sqlSELECT.. 3편: CustomPainter로 지도 그리기, 그리고 900배 확대 그리는 구조구조는 단순합니다.CustomPainter가 시군구 250개의 Path를 그립니다그 위에 시도 경계선을 더 굵게 덧그립니다전체를 InteractiveViewer로 감싸서 핀치 줌과 이동을 처리합니다위경도를 화면 좌표로 바꾸는 투영은 직접 만들었습니다. 우리나라 정도 범위라면 복잡한 투영이 필요 없고, 경도에 cos(기준위도)를 곱해서 가로를 보정하는 정도면 충분합니다. 기준 위도는 35.9도로 잡았습니다. lonMin 124.6 / lonMax 131.0 / latMin 33.1 / latMax 38.7 / latRef 35.9scale = min(width / rawW, height / rawH)처음에 밟은 지뢰들선 굵기가 같이 커집니다. 확대하면 경계선도 같이 두꺼워져서 금방 지저분해집니다.. 2편: 시군구 250개 지도 데이터, 확대하면 틈이 벌어졌습니다 지도 SDK 대신 GeoJSON지도 SDK를 붙이면 타일 이미지가 깔립니다. 하지만 제가 원한 건 도로도 건물도 없는, 지역 모양만 있는 지도였습니다. 지역이 색으로 채워지는 게 전부인 화면이라 타일은 오히려 방해였습니다.그래서 공개 데이터를 썼습니다.출처: southkorea/southkorea-maps (통계청 2018 시군구 경계)시도 17개로 시작했다가 시군구 250개로 세분화했습니다. 시도 단위는 한 번 여행하면 금방 칠해져서 재미가 없습니다원본은 18MB라 저장소에는 넣지 않고 변환 결과만 커밋했습니다경계 데이터는 그대로 쓰기엔 너무 무겁습니다. 점 개수를 줄이는 단순화(simplify)가 필요합니다.그런데 확대하면 틈이 생겼습니다부산 중구와 부산진구 사이에 흰 선 같은 틈이 보였습니다. 처음.. 1편: 여행 기록을 지도에 채우는 앱, 기획부터 법규 검토까지 시작은 대동여지도였습니다여행을 다녀와도 사진은 갤러리에 묻히고, 어디를 갔었는지는 금방 흐려집니다. 그래서 다녀온 지역이 지도에 하나씩 채워지는 앱을 만들기로 했습니다. 지도를 채워 나간다는 감각이 핵심이고, 사진은 그 지역을 설명하는 재료입니다.기술 스택은 Flutter(안드로이드 + iOS)로 정했습니다. 지도는 구글 맵 같은 지도 SDK를 쓰지 않고, GeoJSON을 직접 그리는 방식을 택했습니다. 이유는 2편에서 자세히 다루겠습니다.제품 원칙을 먼저 못 박았습니다개발하면서 계속 흔들리는 지점이 생기기 때문에, 처음에 원칙을 정해 두었습니다.여행이 중심이다. 사용자가 여행(제목 + 기간)을 먼저 만들고, 그 안에 지역과 사진을 채운다사진은 여행 안에서만 추가한다. 지도에서 지역을 눌렀을 때 뜨는 시.. [쪽지 기능 2편] 운영자, 백그라운드 탭, 관리자 화면 — 만들면서 걸린 것들 1편에서는 쪽지를 누구에게 열어줄지, 게스트가 사라지면 대화를 어떻게 할지 같은 정책을 정리했습니다. 이번 편은 그걸 실제로 만들면서 걸린 세 가지입니다.운영자는 players에 없다쪽지 테이블의 from_key/to_key는 players 테이블을 외래 키로 참조합니다. 1편에서 말한 CASCADE 정리가 이 구조 덕분에 돌아가요.그런데 운영자 쪽지를 넣으려니 구멍이 하나 보였습니다. 운영자는 players에 행이 없어요. 관리자 대시보드(썬더박스)는 별도 인증을 쓰니까요. 운영자가 보내는 쪽지에는 넣을 보낸 사람 키가 없고, 사용자가 운영자에게 답장하면 넣을 받는 사람 키가 없습니다.운영자용 가짜 players 행을 하나 만드는 방법도 있었지만, 그러면 랭킹이나 친구 조회 같은 곳에서 그 행을 매번 .. 이전 1 2 3 4 ··· 18 다음