From a66d984b84ca8ffda3e3bd371c5bf3304bdeb97e Mon Sep 17 00:00:00 2001 From: linirini <101927543+linirini@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:38:05 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EC=9D=B4=EC=8A=88=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EC=9E=91=EC=84=B1=20(#543)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * docs: 서비스 소개글 작성 (#127) * build: develop-an의 CI 테스트 자동화 추가 및 데모 APK 추출 #78 (#92) * build: test 자동화 Job 추가 * build: local.properties 생성 시점 변경 * build: 디버그 APK를 빌드하여 업로드하는 workflow 작성 * fix: test Job과 APK build Job에 local.properties 생성 동작 추가 * build: read 전용 권한 제거 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * build: Firebase Analytics, Crashlytics 설정 #136 (#143) * build: Firebase Analytics, Crashlytics 의존성 추가 * chore: google-service.json ignore * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * feat: 특정 여행 상세 수정 api 연결 #109 (#146) * feat: 여행 수정 api service 구현 * feat: 여행 수정 data source 구현 * feat: 여행 수정 repository 구현 * feat: 여행 수정 화면 현재 데이터 로딩 기능 구현 * refactor: 컨벤션 따라 여행 api service의 수정 메서드명 변경 - 이전: updateTravel - 이후: putTravel * feat: 특정 여행 상세 수정 api 연결 * refactor: memberImage 타입 변경 및 기본 인자 설정 * refactor: MembersDto 삭제 * refactor: TravelCreationUiModel.kt 삭제 * refactor: TravelCreation 이름 변경 - 이전: TravelCreation - 이후: NewTravel * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * refactor: api 명세서 변경에 따른 도메인 모델 수정 및 여행 코드 리팩터링 #151 (#152) * refactor: nickName 변수명 변경 - 이전: nickName - 이후: nickname * ui: 여행 수정 화면 이미지 속성 수정 - glide -> coil 이용 - scaleType : fitXY -> centerCrop * style: import 정렬 * feat: 여행 상세 -> 방문 상세로 이동 시 여행 id 전달 * feat: 방문기록 조회 dto 수정 - 방문기록 조회 도메인 변경으로 인해 방문 기록이 조회되지 않음 - 따라서 api 명세서와 일치하도록 dto 수정하여 오류 해결 * refactor: 여행 생성을 위한 viewModel 메서드 분리 * refactor: 여행 조회를 위한 viewModel 메서드 분리 * feat: 여행 수정 handler 구현 * refactor: 여행 default id 변경 - 이전: -1L - 이후: 0L * refactor: TravelHandler 구현 위치 변경 - 이전: TravelViewModel - 이후: TravelFragment * style: 컨벤션에 맞게 TravelFragment의 메서드 순서 수정 * refactor: TravelFragment의 travelId 초기화 방식 변경 * feat: 여행 생성 및 수정 error toast 구현 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: 방문 생성 화면, 방문 수정 화면에서 갤러리 사진 불러오기 구현 #150 (#155) * feat: PhotoAttachFragment에 PhotoAttachHandler 연결 * feat: PhotoAttachFragment 앨범 접근 권한 관련 로직 구현 - API level 33 이상 : READ_MEDIA_IMAGES - API level 33 이하 : READ_EXTERNAL_STORAGE - ActivityResultLauncher를 이용한 권한 요청 - 권한 거부 시, 설정으로 이동하는 스낵바 띄우기 * feat: PhotoAttachFragment 앨범에서 불러온 이미지의 URI 추출하기 * feat: 불러온 이미지의 URI를 호스트 Activity로 전달 - OnUrisSelectedListener 인터페이스 추가 * feat: Uri를 File로 변환하는 메서드 파일 추가 * refactor: pr 리뷰 반영 * refactor: pr 리뷰 반영2 * build: develop-an의 android-ci 수정 #115 (#160) - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: android-ci 환경변수 생성 위치 조정 (#164) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * build: bash 쉘에 맞는 명령어 활용 #115 (#165) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * fix: bash 쉘에 적합한 명령어 형식으로 변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 특정 여행 상세 삭제 api 연결 #153 (#167) * feat: 특정 여행 삭제 api service 구현 * feat: 특정 여행 삭제 data source 구현 * feat: 특정 여행 삭제 repository 구현 * feat: 특정 여행 삭제 기능 api 연결 * feat: error handling 방식 수정 - 서버에서 들어오는 error body의 status와 message를 활용하는 방식으로 변경 * refactor: DialogHandler를 독립적으로 관리 * refactor: api path 상수 활용 * refactor: BuildConfig에 token 정의 * refactor: DEFAULT_VALUE 상수 제거 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * docs: PR 템플릿 오타 수정 (#154) - 오타 수정 및 개행 조정 - Issue Number 태그 형식 추가 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: 여행 생성 기능 api 수정 #169 (#178) * feat: onUrisSelected 매개변수 가변인자로 변경 * feat: 여행 생성 화면 갤러리 이미지 로딩 기능 구현 * refactor: 이미지 선택 리스너 초기화 메서드명 오타 수정 * refactor: 스낵바 액션 설정 코드 간소화 * feat: TravelRequest 의 여행 썸네일 필드 제거 * refactor: 여행 썸네일 이미지 변수명 수정 * feat: 이미지 전송 기능 구현 * refactor: image url 변수명 변경 - 변수 끝에 url이 오도록 * feat: 여행 생성 progressBar 구현 * ui: 사진 첨부 아이콘 가시성 설정 * feat: 여행 상세 수정 기능 api 변경 및 여행 리팩터링 #180 (#181) * feat: 여행 수정 화면 갤러리 이미지 로딩 기능 구현 * feat: URL 및 URI 기반 이미지 로딩 BindingAdapter 구현 * feat: 이미지 전송 기능 구현 * feat: 여행 수정 progressBar 구현 * fix: 삭제 불가능한 여행 삭제 시도 관련 에러 토스트 문제 해결 삭제 불가능한 여행을 삭제하려고 시도 -> 방문 조회 -> 뒤로 가기 버튼 클릭 -> 삭제 불가능 에러 토스트가 다시 뜨는 문제가 발생해 이를 해결 * refactor: TravelCreationViewModel의 imageUrl 변수 제거 * ui: 여행 상세 내 방문 기록 이미지 scaleType 속성 설정 * ui: 여행 생성 썸네일 이미지 scaleType 속성 설정 * fix: 여행 소개 미입력 시 여행이 생성 되지 않는 오류 해결 * refactor: 타임라인 화면 리팩터링 #162 (#179) * ui: 타임라인 RecyclerView의 크기 조정 및 여백 수정 * feat: Activity와 Fragment 간 데이터를 공유하는 공유 ViewModel 생성 * feat: 공유 ViewModel을 이용하여 타임라인 업데이트 여부를 공유 * refactor: RecyclerView.Adapter에서 ListAdapter로 변환 * refactor: 처음 타임라인을 불러오는 동작을 ViewModel 초기화 시에 수행 * fix: ListAdapter 수정 - 불필요한 travels 프로퍼티와 getItemCounts 메서드 제거 - currentList를 사용하는 것으로 변경 * refactor: 에러 핸들링 방식 수정 및 ViewModel 수정 - TimelineDefaultRepository로 네이밍 변경 - ApiResponseHandler와 ResponseResult를 이용하여 에러 핸들링 처리 - TimelineViewModel 에러 메시지 LiveData 사용 - 그 외 repository, dataSource 프로퍼티 이름 수정하여 통일 * refactor: MutableLiveData의 값 업데이트를 setValue로 변경 및 메서드 분리 * style: ktlint 적용 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * feat: 3차 스프린트에서 수정된 방문 기록 상세 API 연결 #163 (#183) * feat: 방문 상세 생성 API 연결 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 방문 기록 생성 및 수정 시 로딩과 토스트 추가 * feat: 닉네임을 활용한 로그인 기능 구현 #124 (#172) * ui: 로그인 화면 구성 - 로그인 화면에서 사용되는 텍스트를 strings에 추가 - 로그인 버튼 스타일에 대한 style 생성 - xml 임시로 작성 * ui: 앱 로고 삽입 및 margin 조정 - 임시 로고 이미지 저장 - 로고 크기 및 마진 조정 * feat: 로그인 API Service 작성 및 Retrofit 객체 생성 * feat: 로그인 DataSource 작성 * feat: 로그인 Repository 생성 * feat: 사용자 정보를 저장하는 SharedPreferences Manager 생성 - 토큰 값 불러오기 및 저장 - 추후 사용자 닉네임, 사용자 프로필 이미지 등의 정보 저장 가능 * feat: Application 생성 및 사용자 정보 Preferences Manager 캐싱 * ui: Splash Screen 화면 구성을 위한 테마 생성 * feat: Preferences 로부터 사용자 토큰 값을 가져와 헤더에 추가하도록 변경 * refactor: Repository 네이밍 통일 * refactor: DataSource 기본 인자 추가 * feat: LoginViewModel 및 Handler 작성 * feat: LoginViewModel 을 생성하는 ViewModel Factory 작성 * feat: LoginActivity 작성 및 양방향 데이터 바인딩 적용 * feat: StaccatoApplication과 LoginActivity 설정 및 LoginActivity를 시작 화면으로 변경 * style: 불필요한 namespace 제거 및 lint 확인 * refactor: LoginViewModel과 Factory를 viewmodel 패키지로 분리 * refactor: TimelineViewModel과 Factory를 viewmodel 패키지로 분리 * style: ktlint 적용 * fix: 불필요한 ConverterFactory 제거 - 더 이상 사용하지 않는 text/plain 변환용 ScalarsConverterFactory 제거 * feat: 닉네임 로그인 요청 및 응답에 대한 DTO 작성 * refactor: 로그인 요청, 응답 시 DTO 활용 * fix: 토큰 값을 불러오고 및 저장하는 동작의 비동기 처리 및 화면 전환 개선 * refactor: 토큰 값을 캐싱하여 저장하는 TokenManager 생성 및 적용 - 매번 runBlocking을 통해 Preference에 저장된 토큰 값을 불러오는 것은 네트워크 성능을 저하시킨다. - 따라서, token 값을 캐싱하여 저장하는 TokenManager를 활용한다. - 첫 네트워크 요청 시에만 토큰을 불러오는 작업을 동기적으로 처리하기 위해 Main Thread가 Blocking 된다. - TokenManager가 Preference로부터 가져온 토큰을 캐싱하여 저장한다. - 이후 요청부터는 캐시된 토큰을 가져오므로 Main Thread가 Blocking 되지 않는다. * style: ktlint 적용 * feat: Night 모드 비활성화 * refactor: 여행 기간 날짜 형식 변환을 BindingAdapter에서 수행 - TimelineTravelUiModel 프로퍼티 수정 - UiModel의 여행기간 날짜를 LocalDate로 갖도록 통일 - 추후 날짜 관련 UI가 변경되었을 때 확장성 고려 - BindingAdapters에 날짜 형식 변환해주는 메서드 작성 * chore: 주석 처리된 Log 코드 삭제 * style: xml View의 ID 네이밍 컨벤션 적용 * ui: 앱 심볼 로고 추가 및 스플래시 스크린에 적용 * feat: 방문 상세 생성 API 연결 * ui: 배경 색을 흰 색으로 지정 * feat: 키보드 활성화 상태에서 화면 터치 시 키보드를 내리는 기능 추가 * style: ktlint 적용 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * fix: merge 과정에서 발생한 id값 네이밍 충돌 해결 * build: 앱 version code와 version name 수정 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 스플래시 스크린 시간 조정 및 데모 시연용 토큰 활성화 * fix: 동일한 사진이 여러 장 업로드되는 버그 수정 * feat: 기존 로그인 기능으로 롤백 --------- Co-authored-by: somin * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * fix: 테스트 배포를 위한 버그 수정 #198 (#219) * style: formatting * fix: 무한 로딩 오류 수정 * fix: 여행 생성 오류 수정 * add: 앱 아이콘 변경 * ui: timeline empty view 추가 * feat: timeline empty view 가시성 설정 * ui: 여행 내 방문 기록 empty view 추가 및 가시성 설정 * ui: 방문 기록 내 로그 미지원 기능 view 추가 * feat: 사진 첨부 카메라 미지원 기능 알림 추가 * ui: 필수값 표기 style 정의 * ui: 여행 생성 및 수정 필수값 표기 추가 * ui: 방문 기록 생성 및 수정 필수값 표기 추가 * feat: 생성, 수정, 로그인 시 다중 요청 전송을 막기 위한 화면 터치 제한 * feat: 장소 생성의 사진 첨부 리사이클러뷰 구현 - 사진 추가 & 삭제 구현 - GridLayout으로 변경 - 사진 중복 없이 최대 5장으로 제한 - 새로 추가된 사진이 기존 사진 뒤에 더해지도록 구현 * chore: 방문 생성 화면 rv_photo_attach로 xml id 수정 * ui: app icon 및 splash icon 변경 * refactor: xml ID 네이밍 컨벤션 적용 --------- Co-authored-by: somin Co-authored-by: Junyoung-WON * refactor: 도메인명 변경에 따라 travel을 memory로 수정 #217 (#231) * refactor: 패키지명 travel -> memory로 수정 * refactor: dto의 TravelMapper 를 MemoryMapper 로 네이밍 변경 * refactor: 여행(현 추억) 생성 response dto 네이밍 변경 - TravelCreationResponse -> MemoryCreationResponse * refactor: 여행(현 추억) request dto 네이밍 변경 - TravelRequest -> MemoryRequest * refactor: 여행(현 추억) 조회 response dto 네이밍 변경 - TravelResponse -> MemoryResponse * refactor: 여행(현 추억) 수정 request dto 네이밍 변경 - TravelUpdateRequest -> MemoryUpdateRequest * refactor: 여행(현 추억) 내 방문 dto 네이밍 변경 - TravelVisitDto -> MemoryVisitDto * refactor: 타임라인 여행(현 추억) item의 dto 네이밍 변경 - TimelineTravelDto -> TimelineMemoryDto * refactor: 여행(현 추억) ApiService 네이밍 변경 - TravelApiService -> MemoryApiService * refactor: 여행(현 추억) DataSource 네이밍 변경 - TravelDataSource -> MemoryDataSource - TravelRemoteDataSource -> MemoryRemoteDataSource * refactor: 여행(현 추억) Repository 네이밍 변경 - TravelRepository -> MemoryRepository - TravelDefaultRepository -> MemoryDefaultRepository * style: TimelineMapper import 재정렬 * refactor: NewTravel 도메인명을 NewMemory로 변경 * refactor: Travel 도메인명을 Memory로 변경 * refactor: TravelVisit 도메인명을 MemoryVisit으로 변경 * refactor: presentation의 TravelMapper 명 변경 - TravelMapper -> MemoryMapper * refactor: 여행(현 추억) ui 모델명 변경 - TravelUiModel -> MemoryUiModel - TravelVisitUiModel -> MemoryVisitUiModel * refactor: 여행(현 추억) view model 명 변경 - TravelViewModel -> MemoryViewModel - TravelViewModelFactory -> MemoryViewModelFactory * refactor: MemoryApiService의 Path 변경 - travel을 memory로 변경 - travels을 memories로 변경 * refactor: Memory 관련 dto 변수명 변경 - travel을 memory로 변경 * refactor: Timeline Dto의 Memory 관련 변수명 변경 - travel을 memory로 변경 - travels를 memories로 변경 * refactor: Memory 관련 도메인 모델의 변수명 변경 - travel을 memory로 변경 * refactor: Memory 관련 ui 모델의 변수명 변경 - travel을 memory로 변경 * refactor: data layer의 Memory 관련 함수 및 변수명 변경 - travel을 memory로 변경 * refactor: 방문 생성 request dto의 travelId 변수명 변경 - travelId -> memoryId * refactor: 여행(현 추억) 조회 view model 및 fragment의 네이밍 변경 - travel -> memory * refactor: fragment_travel 의 리소스 네이밍 변경 - travel -> memory - strings.xml의 리소스명 변경 * refactor: TravelCreationActivity 네이밍 변경 - TravelCreationActivity -> MemoryCreationActivity * refactor: 여행(현 추억) 생성의 ViewModel 관련 네이밍 변경 - TravelCreationViewModel -> MemoryCreationViewModel - TravelCreationViewModelFactory -> MemoryCreationViewModelFactory - 관련 함수 및 변수명 변경 - travel -> memory * refactor: 여행(현 추억) 생성, 수정에 관한 xml 리소스 명 변경 - travel -> memory - strings.xml 의 관련 리소스 수정 * refactor: 여행(현 추억) 수정 Activity, Handler 의 네이밍 변경 - travel -> memory * refactor: 여행(현 추억) 수정 ViewModel 의 네이밍 변경 - 관련 함수 및 변수 명 변경 - travel -> memory - Factory 클래스명 변경 * refactor: 여행(현 추억) 생성, 수정에서의 파일 변환 메서드명 변경 - travel -> memory - 자식 파일 명 상수화 * refactor: Timeline 의 UI 모델 및 Travel ID Key 의 리네이밍 - travel -> memory 로 일괄 변경 * refactor: presentation/timeline 내 travel 도메인명 변경 - travel -> memory - TimelineMapper 내 domain model -> ui model 변환 메서드명 변경 * refactor: dto/MemoryMapper 내 domain 변환 메서드명 변경 - dto/MemoryMapper 내 domain model을 dto로 변환하는 메서드명 변경 - travel -> memory * refactor: dummyTravel 을 dummyMemory 로 변경 * refactor: MainActivity 내 travel을 memory로 변경 * refactor: activity_main 내 travel을 memory로 변경 * refactor: TimeLineApiService 내 GET 메서드 path 수정 - travels -> memories * refactor: MemoryFragment 내 travel 을 memory 로 변경 - MemoryFragment, fragment_memory 내 travel 을 memory 로 변경 * refactor: MemoryViewModel 내 error message 변수명 변경 - TRAVEL_ERROR_MESSAGE -> MEMORY_ERROR_MESSAGE * refactor: navigation graph 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 extra 키 값 수정 - TRAVEL_ID_KEY -> MEMORY_ID_KEY - TRAVEL_TITLE_KEY -> MEMORY_TITLE_KEY * refactor: VisitFragment 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 travel을 memory로 변경 * refactor: VisitUpdateViewModel 내 travel을 memory로 변경 * refactor: VisitTravelUiModel을 VisitMemoryUiModel로 변경 * refactor: 방문 수정 xml의 travel을 memory로 변경 * refactor: 여행(현 추억) 선택 xml 내 travel을 memory로 변경 * refactor: 여행 선택 바텀 시트 내 travel을 memory로 변경 - TravelSelectionFragment -> MemorySelectionFragment 로 수정 - TravelSelectionHandler -> MemorySelectionHandler 로 수정 - TravelSelectionFragment 내 메서드명 수정 - TravelSelectionHandler 내 매개변수명 수정 * refactor: VisitRepository와 구현체의 메서드 내 매개변수명 통일 * refactor: VisitsViewHolder 내 travel을 memory로 변경 * refactor: VisitCreationActivity 내 travel을 memory로 변경 * refactor: VisitCreationViewModel 내 travel을 memory로 변경 * refactor: 방문 생성 xml 내 travel을 memory로 변경 * refactor: BindingAdapters 내 travel을 memory로 변경 * refactor: strings 내 travel을 memory로 변경 - strings 내 '여행'을 '추억'으로 수정 Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * refactor: visit, visit log 도메인명 수정 #218 (#237) * refactor: VisitApiService 내 visit을 moment 로 변경 - 파일명 수정 - path 수정 - 메서드명 수정 - 매개변수명 수정 * refactor: data/visit 패키지명을 moment로 변경 * refactor: data/dto/visit 패키지명을 moment로 변경 * refactor: VisitCreationRequest 네이밍 변경 - 이전: VisitCreationRequest - 이후: MomentCreationRequest * style: StaccatoClient import 재정렬 * refactor: VisitCreationResponse 네이밍 변경 - 이전: VisitCreationResponse - 이후: MomentCreationResponse - 필드명 변경 : visitId -> momentId * refactor: VisitResponse 네이밍 변경 - 이전: VisitResponse - 이후: MomentResponse - VisitResponse 필드 내 visit을 moment로 변경 - VisitResponse 필드 내 visitLogs SerialName을 comments로 변경 * refactor: VisitUpdateRequest 네이밍 변경 - 이전: VisitUpdateRequest - 이후: MomentUpdateRequest - VisitUpdateRequest 필드 내 visit을 moment로 변경 * refactor: VisitLogDto 내 SerialName 변경 - visitLogId를 commentId로 변경 * refactor: MemoryResponse 내 visits SerialName 변경 - visits를 moments로 변경 * refactor: VisitCreationViewModel 내 FORM_DATA_NAME 변경 - 이전: visitImageFiles - 이후: momentImageFiles * refactor: MemoryVisitDto 내 visit를 moment로 변경 - MemoryVisitDto -> MemoryMomentDto로 변경 - visitId -> momentId로 변경 - visitImageUrl -> momentImageUrl로 변경 * refactor: VisitRemoteDataSource 내 visit을 moment로 변경 - VisitRemoteDataSource -> MomentRemoteDataSource로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: MomentRepository 및 구현체 내 visit을 moment로 변경 - VisitRepository -> MomentRepository로 변경 - VisitDefaultRepository -> MomentDefaultRepository로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: Visit 도메인 모델명 및 변수명 변경 - Visit -> Moment로 변경 - visitLogs -> comments로 변경 * refactor: Memory 도에인 모델의 visits을 moments로 변경 * refactor: MemoryVisit 도메인 모델 내 visit을 moment로 변경 * refactor: MemoryResponse의 visits 필드명을 moments로 변경 * refactor: dto/mapper/VisitMapper를 MomentMapper로 변경 * refactor: presentation/visit 패키지명을 moment로 변경 * refactor: VisitViewHolderType 네이밍 변경 - VisitViewHolderType -> MomentViewHolderType - enum 상수명 변경 - VISIT_DEFAULT -> MOMENT_DEFAULT - MY_VISIT_LOG -> MY_COMMENTS * refactor: VisitViewHolder 네이밍 변경 - VisitViewHolder -> MomentViewHolder - VisitDefaultViewHolder -> MomentDefaultViewHolder - MyVisitLogViewHolder -> MyCommentViewHolder * refactor: VisitAdapter 내 visit을 moment로 변경 - VisitAdapter -> MomentAdapter 로 변경 - visit -> moment 로 변경 * refactor: MomentAdapter 내 visit log를 comments로 변경 * refactor: VisitDetailUiModel 내 visit을 moment로 변경 - VisitDetailUiModel -> MomentDetailUiModel - VisitDefaultUiModel -> MomentDefaultUiModel - visitImageUrls -> momentImageUrls * refactor: VisitLogUiModel을 CommentsUiModel로 변경 * refactor: VISIT_ID_KEY extra key id 네이밍 변경 - VISIT_ID_KEY -> MOMENT_ID_KEY * refactor: VisitFragment 내 visit을 moment로 변경 * refactor: VisitViewModel 내 visit을 moment로 변경 - VisitViewModel -> MomentViewModel로 변경 - VisitViewModelFactory -> MomentViewModelFactory로 변경 * refactor: VisitMemoryUiModel 네이밍 변경 - VisitMemoryUiModel -> MomentMemoryUiModel로 변경 * refactor: presentation/visitcreation 패키지명 momentcreation으로 변경 * refactor: VisitCreationActivity 내 visit을 moment로 변경 - VisitCreationActivity -> MomentCreationActivity로 변경 * refactor: VisitCreationHandler 네이밍 변경 - VisitCreationHandler -> MomentCreationHandler로 변경 * refactor: VisitCreationViewModel 내 visit을 moment로 변경 - VisitCreationViewModel -> MomentCreationViewModel로 변경 - 메서드 및 변수명 변경 * refactor: 여행 -> 추억, 방문 기록 -> 스타카토로 도메인명 변경 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: s3 api 연결 #239 (#241) * feat: ImageResponse, ImageApiService 구현 * feat: ImageRepository 및 구현체 구현 Co-authored-by: s6m1n * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * fix: 추억 기능 버그 수정 #246 (#252) * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * fix: 일부 EditText 개행 불가 처리 및 키보드 숨김 처리 #247 (#249) * ui: 닉네임과 추억 생성, 수정 제목 입력 시 줄바꿈 제한 * fix: 키보드 활성화 상태에서 빈 화면 터치로 키보드 숨김 처리 - 메서드 명 변경: setHideKeyboardAction -> setHidingKeyboardAction * style: 클래스 내 override 메서드의 순서 변경 - 팀 코드 컨벤션에 맞게 순서 재정렬 - override 메서드를 상단에 둔다. * style: ktlint 적용 * fix: root뷰 터치 시 클릭 이벤트가 발생하지 않는 오류 수정 - 원인 분석: ConstraintLayout 내부 Toolbar 및 ScrollView, 그리고 그 자식 View들이 클릭 이벤트를 가로채기 때문에, 바인딩 된 최상단 root 뷰인 ConstraintLayout의 클릭 이벤트가 동작하지 않는다. - 해결 방법: 여러 클릭 이벤트를 가로채는 dispatchTouchEvent 메서드를 오버라이드하여, 터치된 부분이 현재 포커스가 되지 않은 View(키보드 바깥 화면) 범위라면, 키보드를 숨기는 동작을 추가하였다. * refactor: 키보드 숨김 동작을 handler 바인딩으로 적용 - LoginHandler 에 화면 터치에 대한 동작을 추가, 화면 터치 시 키보드를 숨김 처리하는 동작을 바인딩으로 설정 - InputMethodManager 인스턴스를 지연초기화하여 저장 * refactor: InputMethodManager 인스턴스를 lazy로 지연 초기화 * fix: 닉네임, 제목 입력 칸의 키보드 액션 버튼 변경 - 키보드의 액션 타입을 Search에서 Done으로 변경 * style: ktlint 적용 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * refactor: 타임라인 리팩터링 #232 (#263) * refactor: TimelineViewModelFactory의 생성자 파라미터 추가 - 내부 프로퍼티에 속해있던 TimelineRepository를 생성자 프로퍼티로 변경 * fix: 추억 목록 아이템이 하나일 때의 View 수정 - 아이템 개수가 하나일 때는 타임라인의 선이 나타나지 않도록 변경 * chore: 코루틴 예외 처리 로그에context 출력 * refactor: 메서드 분리 및 순서 재정렬 - 코드 컨벤션: override 메서드는 상단에 위치한다 * refactor: TimelineViewModel 생성 팩토리 메서드 활용 * style: ktlint 적용 * ui: 화면 전환에 사용될 twin animation 효과 생성 * ui: animation 효과 활용하여 화면 전환 애니메이션 적용 * ui: Main 화면의 배경 색을 하얀색(#FFFFFF)으로 지정 * style: ktlint 적용 * feat: 기분 선택 기능 구현 및 스타카토 조회 화면 구조 변경 #191 (#289) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * style: ktlint 적용 * feat: 추억 API 변경사항 반영 및 리팩터링 #259 (#265) * ui: 추억 생성 화면 사진 로드 시 coil 라이브러리 사용 * ui: 삭제 버튼 아이콘 추가 * ui: 추억 생성 화면 사진 삭제 버튼 추가 * feat: 추억 생성 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 생성 화면 사진 삭제 구현 * feat: 추억 수정 화면 사진 첨부 icon 가시성 설정 * ui: 추억 수정 화면 사진 삭제 버튼 추가 * feat: 추억 수정 화면 사진 삭제 버튼 가시성 설정 * feat: 추억 수정 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 수정 화면 사진 삭제 구현 * fix: 추억 생성 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * fix: 추억 수정 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * feat: MemoryRequest dto에 썸네일 사진 url 필드 추가 * feat: 추억 생성 메서드의 시그니처 변경 - MemoryApiService 내 추억 생성 메서드의 시그니처 변경 - 위 변경에 따른 DataSource, Repository, ViewModel의 추억 생성 관련 메서드 시그니처 변경 * feat: 추억 생성 view model 주 생성자로 ImageRepository 주입 * feat: 추억 생성 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 생성 화면) - 추억 생성 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 생성 시 썸네일 사진 url 추가 * refactor: MemoryRequest의 추억 썸네일 사진 기본 인자 값 null로 설정 * feat: 추억 수정 메서드의 시그니처 변경 * feat: 추억 수정 view model 주 생성자로 ImageRepository 주입 * feat: 추억 수정 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 수정 화면) - 추억 수정 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 수정 시 썸네일 사진 url 추가 * refactor: 불필요한 MemoryUpdateRequest 제거 * ui: empty view 캐릭터 이미지 추가 * ui: 추억 설명글 유무에 따른 가시성 설정 * ui: 함께 한 사람들 가시성 gone 으로 설정 - 4차 스프린트 범위에서 제외됨 * feat: 이미지 선택 옵션 추가 (단일 선택 및 다중 선택 지원) * ui: TextInputLayout, TextInputEditText Style 정의 * ui: 추억 생성 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 수정 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 조회 화면 썸네일 사진 유무에 따른 가시성 설정 * ui: empty view 캐릭터 이미지 크기 변경 * ui: 앱 이름 Staccato_AN -> Staccato 로 수정 * refactor: 추억 생성 및 수정 화면 메서드 순서 정리 * ui: 제목용 TextInputEditTextStyle 정의 및 적용 * ui: 추억 생성 및 수정 화면 썸네일 coilPlaceHolder 변경 - 이전: shape_place_holder_rectangle - 이후: shape_all_gray1_8dp * refactor: 삭제 다이얼로그 show 메서드 호출 방식 변경 - apply를 사용하지 않는 방식으로 변경 * ui: 코멘트 미지원 안내 view 추가 * feat: 스타카토 생성, 수정 화면 사진 및 완료 버튼 개선 #242 (#291) * feat: (스타카토 생성 화면) 사진 드래그로 순서 변경 기능 구현 * refactor: data 패키지에 S3 이미지 API 분리 적용 * refactor: AttachedPhotoUiModel 및 프로그래스바 추가 * feat: recyclerView에서 지워진 사진의 job cancel 처리 * refactor: editText를 TextInputLayout로 수정 * feat: (스타카토 수정 화면) 사진 드래그로 순서 변경 / 로딩 구현 * refactor: 프로퍼티 네임 변경 및 visitedAt LocalDateTime으로 수정 * style: ktlint 적용 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * build: 구글 맵 API 사용에 따른 CI 수정 #296 (#297) * build: 구글 맵 api key를 저장하는 파일을 설정하는 명령어 작성 * refactor: defaults 에 설정된 shell 설정에 따라 추가적인 shell 설정 삭제 * feat: Google Map 연결, 스타카토 목록 조회 API 연결 #54 (#295) * build: google map 의존성 추가 * build: 구글맵 관련 properties ignore 추가 * build: 구글맵 api key 설정 * feat: Google Map 연결 * feat: MainActivity Handler 구현 * ui: 추억 및 스타카토 생성 메뉴 추가 * ui: popup menu style 정의 * feat: 추억 생성 및 수정 menu 연결 - handler 연결 - 메서드 분리 * feat: 위치 권한 요청 구현 - ACCESS_FINE_LOCATION 권한 요청 - ACCESS_COARSE_LOCATION 권한 요청 * feat: 현 위치 표시 * style: MainActivity formatting * feat: locationPermissions 타입 변경 - 이전: List - 이후: Array * feat: MomentLocationDto, MomentLocationResponse 추가 * feat: 스타카토 목록 조회 api service 구현 * feat: 스타카토 목록 조회 data source 구현 * feat: MomentLocation 도메인 모델 구현 * feat: MomentLocationDto를 도메인 모델로 변환하는 mapper 구현 * feat: 스타카토 목록 조회 repository 구현 * feat: 스타카토 목록 조회 view model 구현 * feat: 스타카토 목록을 marker로 표시 * refactor: home 패키지명을 maps로 변경 * feat: 마커 클릭 시 스타카토 상세로 이동 기능 구현 * feat: 스타카토 조회 추억 id, 제목 필드 추가 * feat: 마지막 위치 위경도 찾기 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * refactor: 안드로이드 1차 QA 반영 #299 (#301) * refactor: 안드로이드 1차 QA 반영 * refactor: 안드로이드 1차 QA 반영2 * refactor: 안드로이드 1차 QA 반영3 * refactor: 삭제 메시지 변경 * fix: 스타카토 조회 화면 스택 관리 및 ui 수정 #304 (#306) * feat: 지도 화면에서 스타카토 조회 화면으로 이동 시 스택 관리 * feat: 타임라인 화면에서 추억이 존재하지 않을 때 추억 생성 버튼 추가 * ui: 스타카토 조회 화면 툴바 위치 고정 * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * build: Android CD 적용 #300 (#308) * build: CD 워크플로우 yml 파일 작성 * build: keystore 접근을 위한 build.gradle.kts 파일 설정 * build: 기존 apk 추출 ci 파일 수정 - demo 버전의 apk를 추출 및 배포하는 목적에 맞게 파일 명 수정 - apk 빌드 후 테스트를 수행하는 job 추가 - firebase 앱 배포에 아티팩트 업로드하는 job 추가 * fix: ci 파일에도 keystore 생성 job 추가 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: ci 파일에 키스토어 관련 설정 적용 * fix: 키스토어 관련 명령어 일부 수정 * fix: build.gradle.kts 불필요한 괄호 제거 * fix: keystore.properties 로 부터 프로퍼티를 가져오는 형식 변경 * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 * deploy: 스타카토 v1.0.0 #312 (#313) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 --------- Co-authored-by: devhoya97 Co-authored-by: somin Co-authored-by: BurningFalls Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * build: CI 적용 브랜치 추가 * fix: upload-artifact step에서 빌드 파일의 upload 경로 수정 (#316) upload-artifact 는 defaults 설정의 working-directory 경로가 적용되지 않음 * fix: android cd 재수정 (2차) #317 (#319) * fix: upload-artifact 빌드 파일의 upload 경로 3차 수정 * fix: 배포 시 빌드 파일의 경로 수정 * fix: 빌드 파일의 upload 경로 수정 및 파일이 없는 경우 에러 처리 * fix: 빌드 파일의 upload 경로 4차 수정 * fix: 빌드 파일의 upload 경로 5차 수정 * fix: 빌드 파일의 upload 경로 6차 수정 - 디렉터리 경로 생성 후 upload 실행 * fix: 빌드 파일의 upload 경로 7차 수정 github의 workspace 환경변수(절대경로) 활용 * fix: clean test 제거 및 디버그용 파일 경로 탐색 명령어 추가 * fix: 디버그용 파일 경로 검색 명령어 수정 * fix: 디버그용 파일 경로 검색 명령어 삭제 * fix: 디버그용 파일 검색 명령어 삭제 및 업로드 파일 경로명 수정 * hotfix: QA #322 (#323) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 * chore: QA 위한 트리거 수정 * chore: 배포 트리거 세팅 * docs: pr 템플릿 수정 --------- Co-authored-by: devhoya97 Co-authored-by: somin Co-authored-by: BurningFalls Co-authored-by: YoonJuHo Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 기능 구현 #314 (#324) * feat: MainActivity에서 주소를 가져오는 로직 삭제 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 로직 구현 * refactor: 메서드 순서 정렬 * refactor: 스타카토 조회 화면 ViewPager2 적용 및 UI 아이콘 개선 #318 (#320) * refactor: 아이콘 추가 및 UI 개선 * feat: 스타카토 상세 사진 Viewpager 적용 * feat: 스타카토 상세 사진 Viewpager에 dot indicator 추가 * style: ktLint Format * feat: 메인 지도 화면에서 스타카토 생성하는 플로우 구현 #321 (#327) * feat: 날짜로 추억 목록 불러오는 getMemories API 추가 * feat: 메인에서 스타카토 생성 시 추억 목록 선택 가능 * feat: 스타카토 생성 시 역지오코딩과 추억 선택 연동 * build: debug와 release로 buildTypes 분리 (#329) - appName, appId, baseUrl 분리 - release에 난독화 적용 * build: debug 와 release 배포 분기에 따른 CD 수정 - CD에 대한 트리거 재설정 : main 브랜치에 대한 push 및 pr * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 #326 (#330) * refactor: 지도 화면 onResume에서 스타카토 목록 load * refactor: 스타카토 목록 로드 메서드명 변경 - 이전: loadMoments - 이후: loadStaccatos * feat: 공유 view model에 스타카토 목록 업데이트 상태 추가 * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 * feat: 지도 로드 시 현위치로 이동하도록 구현 * build: ci 및 cd 파일 수정 ci - 불필요한 gradle 빌드 및 테스트 제거 cd - 타겟 브랜치 develop 제거 * feat: 댓글 조회, 생성, 삭제 기능 구현 #290 (#331) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * ui: xml 컨벤션에 맞추어진 타 사용자의 댓글 ui 구성 * feat: 댓글 API의 DTO 작성 * feat: 댓글 API Service 작성 * feat: 댓글 CRUD DataSource 작성 * refactor: CommentApiService 각 메서드의 반환 값을 Response로 변경 * feat: CommentApiService 를 create * feat: CommentDataSource 구현체 생성 * refactor: 댓글 Dto 클래스 네이밍 변경 - VisitLogDto -> CommentDto * refactor: CommentDto 의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * refactor: VisitLog 도메인 모델 클래스의 네이밍 변경 - VisitLog -> Comment * refactor: Comment 도메인 모델의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * feat: 새로운 댓글 도메인 모델 생성 * feat: CommentRepository 작성 * feat: Domain 모델과 DTO 모델을 변환해주는 Mapper 작성 - CommentDto를 Comment로 변환하는 메서드를 CommentMapper.kt로 이동 * feat: CommentRepository의 기본 구현체 작성 * feat: 댓글 ViewModel, Factory 작성 및 Comment 불러오기 구현 * ui: ViewModel 데이터바인딩 및 빈 댓글 문구에 대한 strings 설정 * feat: CommentsViewModel 활용 및 옵저빙 * feat: 댓글 조회, 생성, 삭제 기능 구현 * chore: ktlint 적용 * feat: 추억 생성 및 수정 이미지 로딩 중 표시 및 저장 버튼 비활성화 #332 (#334) * feat: 추억 생성 이미지 로딩 중 표시 * feat: 추억 수정 이미지 로딩 중 표시 * feat: 추억 생성 및 수정 이미지 로딩 중 저장 버튼 비활성화 * style: formatting * deploy: 스타카토 v1.0.0 #310 (#311) * build: 프로젝트 생성 및 의존성 추가 * chore: 사용자 기능 및 권한 추가 * chore: gitignore 재설정 * chore: gitigonre .idea/ 추가 * build: develop-an 브랜치의 CI 설정 #3 (#10) * build: android-ci.yml 파일 생성 * chore: 오타 및 개행 수정 * chore: working-directory 수정 * build: ktLint 적용 및 format * ui: 디자인 시스템 구현 #11 (#44) * ui: color 정의 * ui: shape, selector 추가 * ui: icon 추가 * ui: font family 추가 - pretendard regular, medium, semibold, bold 추가 * ui: typography 정의 * ui: strings 정의 * ui: bottom sheet drag handle drawable 추가 * ui: styles 정의 * ui: detail toolbar 구현 - 상세 화면에서 사용 * ui: dialog, bottom sheet 구현 - 여행 및 방문 기록 삭제 dialog - 사진 등록 bottom sheet * ui: 사진 첨부 layout 구현 * feat: 삭제 다이얼로그, 사진 첨부 바텀 시트 fragment 추가 * ui: 세로모드로 고정 * build: data binding 의존성 추가 * style: strings resource 순서 정렬 * style: formatting * ui: plus icon 추가 * feat: jetpack navigation 및 바텀시트 프래그먼트 추가 #12 (#15) * build: androidx.navigation 및 dataBinding 의존성 추가 * feat: Binding 화면 클래스 및 bottomSheetNavigation 추가 * feat: TimelineFragment 임시 화면 추가 * feat: TravelFragment 임시 화면 추가 * feat: TravelCreationFragment 임시 화면 추가 * feat: VisitFragment 임시 화면 추가 * feat: VisitCreationFragment 임시 화면 추가 * feat: (여행, 방문 기록) 수정 화면 추가 * feat: (여행, 방문 기록) 생성 화면 이동 구현 * feat: BottomSheetController 설정 및 Navigation 이동 구현 * feat: 뒤로가기 버튼 클릭 시 BottomSheet, Toast 작동 구현 * feat: 여행, 방문 기록 생성을 위한 액티비티 추가 및 이동 구현 * feat: 여행, 방문 기록 수정을 위한 액티비티 추가 및 이동 구현 * build: 중복된 dataBinding 제거 * feat: 공통 이미지 로딩 BindingAdapter 설정 #33 (#41) * build: dataBinding 사용 설정 * feat: 이미지 로딩 바인딩 어댑터 설정 - Glide, Coil 바인딩 어댑터를 각각 작성 - placeholder 설정 * style: ktlint check - import 순서 조정 * fix: attribute 개수에 맞추어 BindingAdapter의 value 재설정 * style: 마지막 줄 개행 추가 * feat: placeHolder를 필수 속성으로 변경 및 coil 이미지 로딩 코드 수정 - placeHolder를 ImageView의 필수 속성으로 지정 - Coil BindingAdapter에서 url이 null인 경우에도 이미지를 로드하는 동작이 수행되도록 수정 * ui: 상단바 색상 변경 * build: develop-an의 CI 설정 수정 #38 (#39) - Git Action에 Secret으로 저장된 LOCAL_PROPERTIES_API_KEY를 변수로 가져온다. - 가져온 변수를 echo를 활용하여 local.properties에 설정한다. * build: develop-an 브랜치의 CI 파일 문법 오류 수정 #45 (#46) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: android-ci.yml 파일의 명령어 수정 #47 (#48) LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 * fix: develop-an 브랜치의 CI 파일 명령어 재수정 #47 (#49) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> * fix: 문자열 임을 명시하고 환경변수 설정 위치 조정 * fix: local.properties 생성 시점 수정 * feat: 데이터 패키지 설정 #13 (#35) * build: 서버 base url의 local.properties 사용 설정 및 BuildConfig 설정 * feat: Retrofit Client 작성 * fix: Merge Conflict 해결 - build.gradle.kts(project, app)의 ktlint 의존성 충돌 해결 - 버전 카탈로그 플러그인 충돌 해결 * feat: DTO 클래스 작성 * style: ktlint check - 불필요한 import 제거 - 개행 조정 - 콤마 추가 * feat: SerialName 어노테이션의 값을 camelCase로 수정 * refactor: DTO 클래스의 이름 수정 - API 요청으로 직접 보내거나 들어오는 JSON의 경우 DTO 클래스명 뒤에 Request/Response 를 붙이도록 설정 - JSON 안에 속성 값으로 들어가는 JSON은 DTO 클래스명 뒤에 Dto를 붙이도록 설정 * feat: 누락된 Dto 클래스 추가 TimelineResponse.kt - 타임라인 조회 시 여행 상세 목록을 불러올 때 사용되는 DTO 클래스 - TimelineTravelDto 리스트를 갖는다 * style: ktlint check * fix: const 키워드 제거 --------- Co-authored-by: hxeyexn * feat: 둥근 모서리의 이미지를 로드하는 BindingAdapters 추가 #58 (#59) * feat: 둥근 모서리로 이미지를 로딩하는 Glide 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - glideRoundedCornerImageUrl: 출력하고자 하는 이미지 url - glidePlaceHolder: placeHolder의 url - glideRoundingRadius: 모서리의 둥근 정도를 Int로 설정 * feat: 둥근 모서리로 이미지를 로딩하는 Coil 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - coilRoundedCornerImageUrl: 출력하고자 하는 이미지 url - coilPlaceHolder: placeHolder의 url - coilRoundingRadius: 모서리의 둥근 정도를 Float으로 설정 * fix: centerCrop 설정을 BindingAdapter 에 위임 - xml 속성으로 centerCrop을 주게 되면 Round Corner가 제대로 적용되지 않는 현상 발생 - Glide의 api로 제공되는 centerCrop() 메서드를 활용 * ui: 타임라인 프래그먼트(BottomSheet) 구현 #55 (#71) * ui: 타임라인 View xml 파일 작성 - 타임라인에 나타날 여행 상세 아이템 xml 작성 - 썸네일 사진 유무에 따라 뷰를 구분 - 타임라인이 나타날 fragment xml 작성 * feat: 타임라인 여행 상세 아이템 UI 모델 생성 * ui: 썸네일이 없는 여행상세 아이템의 margin 조정 * ui: Timeline RecyclerView의 layoutManager 설정 * ui: xml에서의 UiModel 데이터 바인딩 설정 * feat: ViewHolder 작성 - 썸네일 사진 유무에 따라 다른 ViewHolder로 구분 - 공통된 속성을 정의한 TimelineViewHolder 추상클래스 생성 * feat: TimelineRepository Interface 생성 * feat: 임시 TimelineRepository 구현체 생성 * feat: TimelineViewModel 및 Factory 생성 * feat: TimelineViewType 작성 * feat: TimelineAdapter 작성 * feat: TimelineFragment에 ViewModel과 Adapter 구현 * feat: 이미지 로딩 PlaceHolder drawable 추가 및 적용 * feat: 임시 데이터 연결 * ui: Timeline fragment 의 세부 설정 조정 * ui: Timeline의 Item xml 변경 - 뷰 타입을 3개로 분할: 첫 번째 아이템, 중간 아이템, 마지막 아이템 - 이에 따라 xml 파일 추가 및 view 수정 * feat: ViewType 변경에 따른 Adapter 및 ViewHolder 수정 * refactor: 불필요한 View 및 ViewHolder 제거 * feat: 여행 click 에 대한 event handler 생성 및 설정 * refactor: drawable 이름을 네이밍 컨벤션에 맞게 수정 * ui: RecyclerView의 마진 속성을 패딩 속성으로 변경 * feat: 바텀 시트 디자인 변경 및 툴바와의 상호작용 구현 * ui: 타임라인 글귀 추가 * style: ktlint check * ui: 둥근 모서리의 이미지로 변경 * ui: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 구현 #52 (#74) * ui: typography.body textSize 1sp 씩 증가 * feat: DeleteDialogFragment에 Handler 추가 * feat: 툴바의 수정, 삭제 버튼 제어를 위한 ToolbarHandler 추가 * feat: 방문 상세 화면을 위한 VisitDetailUiModel 추가 * ui: PlaceHolder를 위한 xml 파일 추가 * feat: 방문 기록 상세 화면을 위한 VisitAdapter 및 VisitViewHolder 구현 * feat: 임시 VisitViewModel와 VisitViewModelFactory 추가 * feat: VisitFragment 화면 구현 * feat: 방문 기록에 해당하는 여행 선택을 위한 TravelSelectionFragment 구현 * feat: 방문 기록에 해당하는 날짜 선택을 위한 VisitedAtSelectionFragment 구현 * feat: 방문 기록 생성을 위한 VisitCreationActivity 구현 * feat: 방문 기록 수정을 위한 VisitUpdateActivity 구현 * refactor: DialogHandler를 DeleteDialogFragment의 생성자에서 받도록 수정 * refactor: initVisitUpdateDoneButton 중복 로직 제거 * refactor: VisitViewHolderType 메서드 명 변경 of -> from * refactor: tv_place_name_title을 xml id convention에 맞게 수정 * ui: 여행 화면 구현 #51 (#75) * ui: 함께 간 사람들 item 구현 * ui: 방문 기록 item 구현 * ui: 여행 상세 화면 구현 * ui: 여행 생성 화면 구현 * ui: 여행 수정 화면 구현 * ui: placeholder에 사용할 drawable 추가 * ui: 여행 삭제 완료 string 추가 * feat: 둥근 모서리 이미지 BindingAdapter 구현 * feat: 함께 간 사람들 adapter 구현 * ui: 여행 상세 화면 NestedScrollView로 변경 - 이전: ScrollView - 이후: NestedScrollView * feat: 방문 기록 adapter 구현 * feat: 여행 상세 view 연결 * feat: 함께 간 사람들, 방문 기록 adapter 연결 * feat: 삭제 다이얼로그 handler 구현 * feat: 여행 상세 화면 toolbar handler 구현 - 뒤로가기 - 여행 수정 화면으로 이동 - 삭제 다이얼로그 show * feat: 여행 -> 방문 기록 화면 이동 구현 * ui: DatePickerStyle 추가 - DatePickerStyle, CustomMaterialCalendarStyle 추가 - staccato_blue 투명도 30 추가 * feat: 여행 저장 버튼, 여행 기간 BindingAdapter 추가 * feat: 여행 생성 view 연결 * feat: 여행 수정 view 연결 * style: formatting - Exceeded max line length 해결 - 임시 이미지 URL 변경 * refactor: 기간 선택 로직 메서드 분리 * feat: 타임라인의 API 적용 및 MainActivity의 Toolbar 제거 #81 (#93) * refactor: UI Model의 패키지 경로 변경 * refactor: API 명세 변경에 따른 TimelineTravelDto 수정 * refactor: repository 메서드 수정 - 서버 요청을 비동기적으로 처리하기 위해 suspend 키워드 삽입 - 기존의 임시 데이터 요청 코드를 위해 load 메서드 분리 * feat: Timeline의 API Service 작성 * feat: DataSource 인터페이스 작성 * feat: TimelineDataSource 구현체 생성 * refactor: 년도에 대한 default parameter 설정 * refactor: DataSource의 요청 메서드 네이밍 수정 * feat: http 통신이 가능하도록 Cleartext Traffic 허용 설정 * feat: Authorization Header를 삽입하기 위한 Interceptor 생성 * feat: Client에 HeaderInterceptor 추가 * refactor: errorBody의 message 속성 이름 변경 * feat: 도메인 모델 작성 * feat: Response(dto)에서 도메인 모델로 변환하는 확장함수 구현 * feat: 도메인 모델에서 UI 모델로 변환하는 확장함수 구현 * feat: Repository 수정 및 ViewModel 데이터 연결 * ui: MainActivity의 상단 툴바 제거 * refactor: ViewType에 viewType 속성 추가 및 when에서의 enum 활용 * refactor: Timeline의 공통 ViewHolder를 sealed class로 변경 * style: ktlint check 수행 * fix: Response 데이터의 nullable 속성에 맞추어 DTO 수정 및 누락된 DTO 추가 * fix: 데이터가 비어있는 경우(초기)에만 새로운 여행상세 목록을 받도록 수정 * refactor: lazy 로 지연 초기화 및 timelineService가 하나의 인스턴스로 관리되도록 수정 * fix: Travel의 description에 nullable 속성 추가 API 명세서 잘 좀 보자 제발 * refactor: create 메서드를 private으로 변경 Client 클래스에서 Service를 create 하여 제공 및 캐싱하기 때문에, 불필요한 인스턴스를 생성하지 않도록 create를 public으로 두지 않는 것이 좋다. * refactor: LocalDateConverters의 패키지 경로 수정 * refactor: 파일의 이름 수정 * style: ktlint check * refactor: 에러 메시지 상수화 * feat: 특정 여행 상세 조회 api 연결 #82 (#97) * feat: 특정 여행 상세 조회 api service 구현 * feat: 썸네일, 소개 타입 변경 및 기본 인자 설정 - 변경 data class : TravelResponse, TravelUiModel - 이전: String - 이후: String? * refactor: MatesUiModel 네이밍 변경 MatesUiModel이 공통적으로 사용될 예정이므로 MemberUiModel로 변경 - 이전: MatesUiModel - 이후: MemberUiModel * refactor: VisitUiModel 네이밍 변경 - 여행 상세 방문 기록에 사용되는 UiModel 이름을 명시적으로 변경 - 이전: VisitUiModel - 이후: TravelVisitUiModel * feat: 특정 여행 상세 조회에 사용할 domain model 추가 * feat: Api 응답 핸들링 로직 구현 * feat: 특정 여행 상세 조회 data source 구현 * feat: 특정 여행 상세 조회 repository 구현 * feat: 특정 여행 상세 조회 api 연결 * feat: 특정 여행 상세 조회 로직 매개변수 추가 - 타임라인에서 선택된 여행 id를 매개변수로 받도록 변경 * refactor: ApiResponseHandler 이름 오타 수정 * refactor: 에러 메세지 상수화 * feat: 특정 여행 상세 조회 시그니처 변경 - HeaderInterceptor 적용으로 authorization 매개변수 제거 * style: formatting * feat: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 API 연결 #79 (#99) * feat: VisitApiService 인터페이스 및 관련 data class 추가 * feat: VisitRepository, RemoteVisitDataSource 및 관련 class 추가 * feat: 각 Visit 화면들의 ViewModelFactory 구현 * feat: 각 Visit 화면들의 UiModel 클래스 및 Mapper 추가 * feat: 여행 선택 및 방문 날짜 선택을 위한 BottomSheetDialogFragment 수정 * feat: VisitFragment API 연결 * feat: VisitCreationActivity API 연결 * feat: VisitUpdateActivity API 연결 준비 * refactor: visitApiService를 StaccatoClient object로 이동 * refactor: TravelVisit 클래스의 visitImage 변수 nullable하게 수정 * refactor: VisitApiService의 중복된 @Header 제거 * refactor: 방문 생성 성공 시 created id를 가져오도록 리팩터링 * chore: 변수명 visitImage로 수정 및 ktLint 적용 * refactor: 여행 수정 완료 동작 구현 및 VisitUpdateActivity 함수 분리 * feat: 여행 생성 api 연결 #98 (#104) * feat: 여행 생성 api service 구현 * feat: 여행 생성 data source 구현 * feat: 방문 기록 썸네일 타입 변경 및 기본 인자 설정 - 변경 data class :  TravelVisitDto, TravelVisit, TravelVisitUiModel - 이전: String - 이후: String? * build: converter scalars 의존성 추가 * feat: 여행 생성 ApiService 반환값 및 DataSource 시그니처 변경 - 여행 생성 ApiService 반환값 변경 - DataSource 시그니처 변경 - TravelCreation DomainModel 구현 - TravelCreation Dto 변환 Mapper 구현 * feat: Client에 ScalarsConvert 추가 - Header 값을 읽어오기 위해 ScalarsConvert 추가 * feat: 여행 생성 repository 구현 * feat: 여행 생성 api 연결 * feat: TravelViewModel 생성자 변경 - 이전: travelId를 TravelViewModel 생성자로 넣어줌 - 이후: travelId를 loadTravel()의 매개변수로 넣어줌 * ui: map 화면 변경 * refactor: 컨벤션 통일 및 패키지 정리 #112 (#118) * refactor: bind 네임스페이스 적용 * refactor: BindingAdapters 메서드명 변경 * refactor: 컨벤션 맞게 xml 파일 이름 변경 * refactor: data 패키지 구조 정리 * refactor: RemoteVisitDataSource 컨벤션 따라 네이밍 변경 * refactor: 네트워킹 관련 메서드 이름 변경 - api service, data source, repository * refactor: presentation 패키지 구조 정리 * refactor: message utils 생성 및 적용 Co-authored-by: s6m1n Co-authored-by: Junyoung-WON * build: develop-an의 CI 테스트 자동화 추가 및 데모 APK 추출 #78 (#92) * build: test 자동화 Job 추가 * build: local.properties 생성 시점 변경 * build: 디버그 APK를 빌드하여 업로드하는 workflow 작성 * fix: test Job과 APK build Job에 local.properties 생성 동작 추가 * build: read 전용 권한 제거 * build: Firebase Analytics, Crashlytics 설정 #136 (#143) * build: Firebase Analytics, Crashlytics 의존성 추가 * chore: google-service.json ignore * feat: 특정 여행 상세 수정 api 연결 #109 (#146) * feat: 여행 수정 api service 구현 * feat: 여행 수정 data source 구현 * feat: 여행 수정 repository 구현 * feat: 여행 수정 화면 현재 데이터 로딩 기능 구현 * refactor: 컨벤션 따라 여행 api service의 수정 메서드명 변경 - 이전: updateTravel - 이후: putTravel * feat: 특정 여행 상세 수정 api 연결 * refactor: memberImage 타입 변경 및 기본 인자 설정 * refactor: MembersDto 삭제 * refactor: TravelCreationUiModel.kt 삭제 * refactor: TravelCreation 이름 변경 - 이전: TravelCreation - 이후: NewTravel * refactor: api 명세서 변경에 따른 도메인 모델 수정 및 여행 코드 리팩터링 #151 (#152) * refactor: nickName 변수명 변경 - 이전: nickName - 이후: nickname * ui: 여행 수정 화면 이미지 속성 수정 - glide -> coil 이용 - scaleType : fitXY -> centerCrop * style: import 정렬 * feat: 여행 상세 -> 방문 상세로 이동 시 여행 id 전달 * feat: 방문기록 조회 dto 수정 - 방문기록 조회 도메인 변경으로 인해 방문 기록이 조회되지 않음 - 따라서 api 명세서와 일치하도록 dto 수정하여 오류 해결 * refactor: 여행 생성을 위한 viewModel 메서드 분리 * refactor: 여행 조회를 위한 viewModel 메서드 분리 * feat: 여행 수정 handler 구현 * refactor: 여행 default id 변경 - 이전: -1L - 이후: 0L * refactor: TravelHandler 구현 위치 변경 - 이전: TravelViewModel - 이후: TravelFragment * style: 컨벤션에 맞게 TravelFragment의 메서드 순서 수정 * refactor: TravelFragment의 travelId 초기화 방식 변경 * feat: 여행 생성 및 수정 error toast 구현 * feat: 방문 생성 화면, 방문 수정 화면에서 갤러리 사진 불러오기 구현 #150 (#155) * feat: PhotoAttachFragment에 PhotoAttachHandler 연결 * feat: PhotoAttachFragment 앨범 접근 권한 관련 로직 구현 - API level 33 이상 : READ_MEDIA_IMAGES - API level 33 이하 : READ_EXTERNAL_STORAGE - ActivityResultLauncher를 이용한 권한 요청 - 권한 거부 시, 설정으로 이동하는 스낵바 띄우기 * feat: PhotoAttachFragment 앨범에서 불러온 이미지의 URI 추출하기 * feat: 불러온 이미지의 URI를 호스트 Activity로 전달 - OnUrisSelectedListener 인터페이스 추가 * feat: Uri를 File로 변환하는 메서드 파일 추가 * refactor: pr 리뷰 반영 * refactor: pr 리뷰 반영2 * build: develop-an의 android-ci 수정 #115 (#160) - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: android-ci 환경변수 생성 위치 조정 (#164) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * build: bash 쉘에 맞는 명령어 활용 #115 (#165) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * fix: bash 쉘에 적합한 명령어 형식으로 변경 * feat: 특정 여행 상세 삭제 api 연결 #153 (#167) * feat: 특정 여행 삭제 api service 구현 * feat: 특정 여행 삭제 data source 구현 * feat: 특정 여행 삭제 repository 구현 * feat: 특정 여행 삭제 기능 api 연결 * feat: error handling 방식 수정 - 서버에서 들어오는 error body의 status와 message를 활용하는 방식으로 변경 * refactor: DialogHandler를 독립적으로 관리 * refactor: api path 상수 활용 * refactor: BuildConfig에 token 정의 * refactor: DEFAULT_VALUE 상수 제거 * feat: 여행 생성 기능 api 수정 #169 (#178) * feat: onUrisSelected 매개변수 가변인자로 변경 * feat: 여행 생성 화면 갤러리 이미지 로딩 기능 구현 * refactor: 이미지 선택 리스너 초기화 메서드명 오타 수정 * refactor: 스낵바 액션 설정 코드 간소화 * feat: TravelRequest 의 여행 썸네일 필드 제거 * refactor: 여행 썸네일 이미지 변수명 수정 * feat: 이미지 전송 기능 구현 * refactor: image url 변수명 변경 - 변수 끝에 url이 오도록 * feat: 여행 생성 progressBar 구현 * ui: 사진 첨부 아이콘 가시성 설정 * feat: 여행 상세 수정 기능 api 변경 및 여행 리팩터링 #180 (#181) * feat: 여행 수정 화면 갤러리 이미지 로딩 기능 구현 * feat: URL 및 URI 기반 이미지 로딩 BindingAdapter 구현 * feat: 이미지 전송 기능 구현 * feat: 여행 수정 progressBar 구현 * fix: 삭제 불가능한 여행 삭제 시도 관련 에러 토스트 문제 해결 삭제 불가능한 여행을 삭제하려고 시도 -> 방문 조회 -> 뒤로 가기 버튼 클릭 -> 삭제 불가능 에러 토스트가 다시 뜨는 문제가 발생해 이를 해결 * refactor: TravelCreationViewModel의 imageUrl 변수 제거 * ui: 여행 상세 내 방문 기록 이미지 scaleType 속성 설정 * ui: 여행 생성 썸네일 이미지 scaleType 속성 설정 * fix: 여행 소개 미입력 시 여행이 생성 되지 않는 오류 해결 * refactor: 타임라인 화면 리팩터링 #162 (#179) * ui: 타임라인 RecyclerView의 크기 조정 및 여백 수정 * feat: Activity와 Fragment 간 데이터를 공유하는 공유 ViewModel 생성 * feat: 공유 ViewModel을 이용하여 타임라인 업데이트 여부를 공유 * refactor: RecyclerView.Adapter에서 ListAdapter로 변환 * refactor: 처음 타임라인을 불러오는 동작을 ViewModel 초기화 시에 수행 * fix: ListAdapter 수정 - 불필요한 travels 프로퍼티와 getItemCounts 메서드 제거 - currentList를 사용하는 것으로 변경 * refactor: 에러 핸들링 방식 수정 및 ViewModel 수정 - TimelineDefaultRepository로 네이밍 변경 - ApiResponseHandler와 ResponseResult를 이용하여 에러 핸들링 처리 - TimelineViewModel 에러 메시지 LiveData 사용 - 그 외 repository, dataSource 프로퍼티 이름 수정하여 통일 * refactor: MutableLiveData의 값 업데이트를 setValue로 변경 및 메서드 분리 * style: ktlint 적용 * feat: 3차 스프린트에서 수정된 방문 기록 상세 API 연결 #163 (#183) * feat: 방문 상세 생성 API 연결 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 방문 기록 생성 및 수정 시 로딩과 토스트 추가 * feat: 닉네임을 활용한 로그인 기능 구현 #124 (#172) * ui: 로그인 화면 구성 - 로그인 화면에서 사용되는 텍스트를 strings에 추가 - 로그인 버튼 스타일에 대한 style 생성 - xml 임시로 작성 * ui: 앱 로고 삽입 및 margin 조정 - 임시 로고 이미지 저장 - 로고 크기 및 마진 조정 * feat: 로그인 API Service 작성 및 Retrofit 객체 생성 * feat: 로그인 DataSource 작성 * feat: 로그인 Repository 생성 * feat: 사용자 정보를 저장하는 SharedPreferences Manager 생성 - 토큰 값 불러오기 및 저장 - 추후 사용자 닉네임, 사용자 프로필 이미지 등의 정보 저장 가능 * feat: Application 생성 및 사용자 정보 Preferences Manager 캐싱 * ui: Splash Screen 화면 구성을 위한 테마 생성 * feat: Preferences 로부터 사용자 토큰 값을 가져와 헤더에 추가하도록 변경 * refactor: Repository 네이밍 통일 * refactor: DataSource 기본 인자 추가 * feat: LoginViewModel 및 Handler 작성 * feat: LoginViewModel 을 생성하는 ViewModel Factory 작성 * feat: LoginActivity 작성 및 양방향 데이터 바인딩 적용 * feat: StaccatoApplication과 LoginActivity 설정 및 LoginActivity를 시작 화면으로 변경 * style: 불필요한 namespace 제거 및 lint 확인 * refactor: LoginViewModel과 Factory를 viewmodel 패키지로 분리 * refactor: TimelineViewModel과 Factory를 viewmodel 패키지로 분리 * style: ktlint 적용 * fix: 불필요한 ConverterFactory 제거 - 더 이상 사용하지 않는 text/plain 변환용 ScalarsConverterFactory 제거 * feat: 닉네임 로그인 요청 및 응답에 대한 DTO 작성 * refactor: 로그인 요청, 응답 시 DTO 활용 * fix: 토큰 값을 불러오고 및 저장하는 동작의 비동기 처리 및 화면 전환 개선 * refactor: 토큰 값을 캐싱하여 저장하는 TokenManager 생성 및 적용 - 매번 runBlocking을 통해 Preference에 저장된 토큰 값을 불러오는 것은 네트워크 성능을 저하시킨다. - 따라서, token 값을 캐싱하여 저장하는 TokenManager를 활용한다. - 첫 네트워크 요청 시에만 토큰을 불러오는 작업을 동기적으로 처리하기 위해 Main Thread가 Blocking 된다. - TokenManager가 Preference로부터 가져온 토큰을 캐싱하여 저장한다. - 이후 요청부터는 캐시된 토큰을 가져오므로 Main Thread가 Blocking 되지 않는다. * style: ktlint 적용 * feat: Night 모드 비활성화 * refactor: 여행 기간 날짜 형식 변환을 BindingAdapter에서 수행 - TimelineTravelUiModel 프로퍼티 수정 - UiModel의 여행기간 날짜를 LocalDate로 갖도록 통일 - 추후 날짜 관련 UI가 변경되었을 때 확장성 고려 - BindingAdapters에 날짜 형식 변환해주는 메서드 작성 * chore: 주석 처리된 Log 코드 삭제 * style: xml View의 ID 네이밍 컨벤션 적용 * ui: 앱 심볼 로고 추가 및 스플래시 스크린에 적용 * feat: 방문 상세 생성 API 연결 * ui: 배경 색을 흰 색으로 지정 * feat: 키보드 활성화 상태에서 화면 터치 시 키보드를 내리는 기능 추가 * style: ktlint 적용 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * fix: merge 과정에서 발생한 id값 네이밍 충돌 해결 * build: 앱 version code와 version name 수정 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 스플래시 스크린 시간 조정 및 데모 시연용 토큰 활성화 * fix: 동일한 사진이 여러 장 업로드되는 버그 수정 * feat: 기존 로그인 기능으로 롤백 --------- Co-authored-by: somin * fix: 테스트 배포를 위한 버그 수정 #198 (#219) * style: formatting * fix: 무한 로딩 오류 수정 * fix: 여행 생성 오류 수정 * add: 앱 아이콘 변경 * ui: timeline empty view 추가 * feat: timeline empty view 가시성 설정 * ui: 여행 내 방문 기록 empty view 추가 및 가시성 설정 * ui: 방문 기록 내 로그 미지원 기능 view 추가 * feat: 사진 첨부 카메라 미지원 기능 알림 추가 * ui: 필수값 표기 style 정의 * ui: 여행 생성 및 수정 필수값 표기 추가 * ui: 방문 기록 생성 및 수정 필수값 표기 추가 * feat: 생성, 수정, 로그인 시 다중 요청 전송을 막기 위한 화면 터치 제한 * feat: 장소 생성의 사진 첨부 리사이클러뷰 구현 - 사진 추가 & 삭제 구현 - GridLayout으로 변경 - 사진 중복 없이 최대 5장으로 제한 - 새로 추가된 사진이 기존 사진 뒤에 더해지도록 구현 * chore: 방문 생성 화면 rv_photo_attach로 xml id 수정 * ui: app icon 및 splash icon 변경 * refactor: xml ID 네이밍 컨벤션 적용 --------- Co-authored-by: somin Co-authored-by: Junyoung-WON * refactor: 도메인명 변경에 따라 travel을 memory로 수정 #217 (#231) * refactor: 패키지명 travel -> memory로 수정 * refactor: dto의 TravelMapper 를 MemoryMapper 로 네이밍 변경 * refactor: 여행(현 추억) 생성 response dto 네이밍 변경 - TravelCreationResponse -> MemoryCreationResponse * refactor: 여행(현 추억) request dto 네이밍 변경 - TravelRequest -> MemoryRequest * refactor: 여행(현 추억) 조회 response dto 네이밍 변경 - TravelResponse -> MemoryResponse * refactor: 여행(현 추억) 수정 request dto 네이밍 변경 - TravelUpdateRequest -> MemoryUpdateRequest * refactor: 여행(현 추억) 내 방문 dto 네이밍 변경 - TravelVisitDto -> MemoryVisitDto * refactor: 타임라인 여행(현 추억) item의 dto 네이밍 변경 - TimelineTravelDto -> TimelineMemoryDto * refactor: 여행(현 추억) ApiService 네이밍 변경 - TravelApiService -> MemoryApiService * refactor: 여행(현 추억) DataSource 네이밍 변경 - TravelDataSource -> MemoryDataSource - TravelRemoteDataSource -> MemoryRemoteDataSource * refactor: 여행(현 추억) Repository 네이밍 변경 - TravelRepository -> MemoryRepository - TravelDefaultRepository -> MemoryDefaultRepository * style: TimelineMapper import 재정렬 * refactor: NewTravel 도메인명을 NewMemory로 변경 * refactor: Travel 도메인명을 Memory로 변경 * refactor: TravelVisit 도메인명을 MemoryVisit으로 변경 * refactor: presentation의 TravelMapper 명 변경 - TravelMapper -> MemoryMapper * refactor: 여행(현 추억) ui 모델명 변경 - TravelUiModel -> MemoryUiModel - TravelVisitUiModel -> MemoryVisitUiModel * refactor: 여행(현 추억) view model 명 변경 - TravelViewModel -> MemoryViewModel - TravelViewModelFactory -> MemoryViewModelFactory * refactor: MemoryApiService의 Path 변경 - travel을 memory로 변경 - travels을 memories로 변경 * refactor: Memory 관련 dto 변수명 변경 - travel을 memory로 변경 * refactor: Timeline Dto의 Memory 관련 변수명 변경 - travel을 memory로 변경 - travels를 memories로 변경 * refactor: Memory 관련 도메인 모델의 변수명 변경 - travel을 memory로 변경 * refactor: Memory 관련 ui 모델의 변수명 변경 - travel을 memory로 변경 * refactor: data layer의 Memory 관련 함수 및 변수명 변경 - travel을 memory로 변경 * refactor: 방문 생성 request dto의 travelId 변수명 변경 - travelId -> memoryId * refactor: 여행(현 추억) 조회 view model 및 fragment의 네이밍 변경 - travel -> memory * refactor: fragment_travel 의 리소스 네이밍 변경 - travel -> memory - strings.xml의 리소스명 변경 * refactor: TravelCreationActivity 네이밍 변경 - TravelCreationActivity -> MemoryCreationActivity * refactor: 여행(현 추억) 생성의 ViewModel 관련 네이밍 변경 - TravelCreationViewModel -> MemoryCreationViewModel - TravelCreationViewModelFactory -> MemoryCreationViewModelFactory - 관련 함수 및 변수명 변경 - travel -> memory * refactor: 여행(현 추억) 생성, 수정에 관한 xml 리소스 명 변경 - travel -> memory - strings.xml 의 관련 리소스 수정 * refactor: 여행(현 추억) 수정 Activity, Handler 의 네이밍 변경 - travel -> memory * refactor: 여행(현 추억) 수정 ViewModel 의 네이밍 변경 - 관련 함수 및 변수 명 변경 - travel -> memory - Factory 클래스명 변경 * refactor: 여행(현 추억) 생성, 수정에서의 파일 변환 메서드명 변경 - travel -> memory - 자식 파일 명 상수화 * refactor: Timeline 의 UI 모델 및 Travel ID Key 의 리네이밍 - travel -> memory 로 일괄 변경 * refactor: presentation/timeline 내 travel 도메인명 변경 - travel -> memory - TimelineMapper 내 domain model -> ui model 변환 메서드명 변경 * refactor: dto/MemoryMapper 내 domain 변환 메서드명 변경 - dto/MemoryMapper 내 domain model을 dto로 변환하는 메서드명 변경 - travel -> memory * refactor: dummyTravel 을 dummyMemory 로 변경 * refactor: MainActivity 내 travel을 memory로 변경 * refactor: activity_main 내 travel을 memory로 변경 * refactor: TimeLineApiService 내 GET 메서드 path 수정 - travels -> memories * refactor: MemoryFragment 내 travel 을 memory 로 변경 - MemoryFragment, fragment_memory 내 travel 을 memory 로 변경 * refactor: MemoryViewModel 내 error message 변수명 변경 - TRAVEL_ERROR_MESSAGE -> MEMORY_ERROR_MESSAGE * refactor: navigation graph 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 extra 키 값 수정 - TRAVEL_ID_KEY -> MEMORY_ID_KEY - TRAVEL_TITLE_KEY -> MEMORY_TITLE_KEY * refactor: VisitFragment 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 travel을 memory로 변경 * refactor: VisitUpdateViewModel 내 travel을 memory로 변경 * refactor: VisitTravelUiModel을 VisitMemoryUiModel로 변경 * refactor: 방문 수정 xml의 travel을 memory로 변경 * refactor: 여행(현 추억) 선택 xml 내 travel을 memory로 변경 * refactor: 여행 선택 바텀 시트 내 travel을 memory로 변경 - TravelSelectionFragment -> MemorySelectionFragment 로 수정 - TravelSelectionHandler -> MemorySelectionHandler 로 수정 - TravelSelectionFragment 내 메서드명 수정 - TravelSelectionHandler 내 매개변수명 수정 * refactor: VisitRepository와 구현체의 메서드 내 매개변수명 통일 * refactor: VisitsViewHolder 내 travel을 memory로 변경 * refactor: VisitCreationActivity 내 travel을 memory로 변경 * refactor: VisitCreationViewModel 내 travel을 memory로 변경 * refactor: 방문 생성 xml 내 travel을 memory로 변경 * refactor: BindingAdapters 내 travel을 memory로 변경 * refactor: strings 내 travel을 memory로 변경 - strings 내 '여행'을 '추억'으로 수정 Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * refactor: visit, visit log 도메인명 수정 #218 (#237) * refactor: VisitApiService 내 visit을 moment 로 변경 - 파일명 수정 - path 수정 - 메서드명 수정 - 매개변수명 수정 * refactor: data/visit 패키지명을 moment로 변경 * refactor: data/dto/visit 패키지명을 moment로 변경 * refactor: VisitCreationRequest 네이밍 변경 - 이전: VisitCreationRequest - 이후: MomentCreationRequest * style: StaccatoClient import 재정렬 * refactor: VisitCreationResponse 네이밍 변경 - 이전: VisitCreationResponse - 이후: MomentCreationResponse - 필드명 변경 : visitId -> momentId * refactor: VisitResponse 네이밍 변경 - 이전: VisitResponse - 이후: MomentResponse - VisitResponse 필드 내 visit을 moment로 변경 - VisitResponse 필드 내 visitLogs SerialName을 comments로 변경 * refactor: VisitUpdateRequest 네이밍 변경 - 이전: VisitUpdateRequest - 이후: MomentUpdateRequest - VisitUpdateRequest 필드 내 visit을 moment로 변경 * refactor: VisitLogDto 내 SerialName 변경 - visitLogId를 commentId로 변경 * refactor: MemoryResponse 내 visits SerialName 변경 - visits를 moments로 변경 * refactor: VisitCreationViewModel 내 FORM_DATA_NAME 변경 - 이전: visitImageFiles - 이후: momentImageFiles * refactor: MemoryVisitDto 내 visit를 moment로 변경 - MemoryVisitDto -> MemoryMomentDto로 변경 - visitId -> momentId로 변경 - visitImageUrl -> momentImageUrl로 변경 * refactor: VisitRemoteDataSource 내 visit을 moment로 변경 - VisitRemoteDataSource -> MomentRemoteDataSource로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: MomentRepository 및 구현체 내 visit을 moment로 변경 - VisitRepository -> MomentRepository로 변경 - VisitDefaultRepository -> MomentDefaultRepository로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: Visit 도메인 모델명 및 변수명 변경 - Visit -> Moment로 변경 - visitLogs -> comments로 변경 * refactor: Memory 도에인 모델의 visits을 moments로 변경 * refactor: MemoryVisit 도메인 모델 내 visit을 moment로 변경 * refactor: MemoryResponse의 visits 필드명을 moments로 변경 * refactor: dto/mapper/VisitMapper를 MomentMapper로 변경 * refactor: presentation/visit 패키지명을 moment로 변경 * refactor: VisitViewHolderType 네이밍 변경 - VisitViewHolderType -> MomentViewHolderType - enum 상수명 변경 - VISIT_DEFAULT -> MOMENT_DEFAULT - MY_VISIT_LOG -> MY_COMMENTS * refactor: VisitViewHolder 네이밍 변경 - VisitViewHolder -> MomentViewHolder - VisitDefaultViewHolder -> MomentDefaultViewHolder - MyVisitLogViewHolder -> MyCommentViewHolder * refactor: VisitAdapter 내 visit을 moment로 변경 - VisitAdapter -> MomentAdapter 로 변경 - visit -> moment 로 변경 * refactor: MomentAdapter 내 visit log를 comments로 변경 * refactor: VisitDetailUiModel 내 visit을 moment로 변경 - VisitDetailUiModel -> MomentDetailUiModel - VisitDefaultUiModel -> MomentDefaultUiModel - visitImageUrls -> momentImageUrls * refactor: VisitLogUiModel을 CommentsUiModel로 변경 * refactor: VISIT_ID_KEY extra key id 네이밍 변경 - VISIT_ID_KEY -> MOMENT_ID_KEY * refactor: VisitFragment 내 visit을 moment로 변경 * refactor: VisitViewModel 내 visit을 moment로 변경 - VisitViewModel -> MomentViewModel로 변경 - VisitViewModelFactory -> MomentViewModelFactory로 변경 * refactor: VisitMemoryUiModel 네이밍 변경 - VisitMemoryUiModel -> MomentMemoryUiModel로 변경 * refactor: presentation/visitcreation 패키지명 momentcreation으로 변경 * refactor: VisitCreationActivity 내 visit을 moment로 변경 - VisitCreationActivity -> MomentCreationActivity로 변경 * refactor: VisitCreationHandler 네이밍 변경 - VisitCreationHandler -> MomentCreationHandler로 변경 * refactor: VisitCreationViewModel 내 visit을 moment로 변경 - VisitCreationViewModel -> MomentCreationViewModel로 변경 - 메서드 및 변수명 변경 * refactor: 여행 -> 추억, 방문 기록 -> 스타카토로 도메인명 변경 * feat: s3 api 연결 #239 (#241) * feat: ImageResponse, ImageApiService 구현 * feat: ImageRepository 및 구현체 구현 Co-authored-by: s6m1n * fix: 추억 기능 버그 수정 #246 (#252) * fix: 일부 EditText 개행 불가 처리 및 키보드 숨김 처리 #247 (#249) * ui: 닉네임과 추억 생성, 수정 제목 입력 시 줄바꿈 제한 * fix: 키보드 활성화 상태에서 빈 화면 터치로 키보드 숨김 처리 - 메서드 명 변경: setHideKeyboardAction -> setHidingKeyboardAction * style: 클래스 내 override 메서드의 순서 변경 - 팀 코드 컨벤션에 맞게 순서 재정렬 - override 메서드를 상단에 둔다. * style: ktlint 적용 * fix: root뷰 터치 시 클릭 이벤트가 발생하지 않는 오류 수정 - 원인 분석: ConstraintLayout 내부 Toolbar 및 ScrollView, 그리고 그 자식 View들이 클릭 이벤트를 가로채기 때문에, 바인딩 된 최상단 root 뷰인 ConstraintLayout의 클릭 이벤트가 동작하지 않는다. - 해결 방법: 여러 클릭 이벤트를 가로채는 dispatchTouchEvent 메서드를 오버라이드하여, 터치된 부분이 현재 포커스가 되지 않은 View(키보드 바깥 화면) 범위라면, 키보드를 숨기는 동작을 추가하였다. * refactor: 키보드 숨김 동작을 handler 바인딩으로 적용 - LoginHandler 에 화면 터치에 대한 동작을 추가, 화면 터치 시 키보드를 숨김 처리하는 동작을 바인딩으로 설정 - InputMethodManager 인스턴스를 지연초기화하여 저장 * refactor: InputMethodManager 인스턴스를 lazy로 지연 초기화 * fix: 닉네임, 제목 입력 칸의 키보드 액션 버튼 변경 - 키보드의 액션 타입을 Search에서 Done으로 변경 * style: ktlint 적용 * refactor: 타임라인 리팩터링 #232 (#263) * refactor: TimelineViewModelFactory의 생성자 파라미터 추가 - 내부 프로퍼티에 속해있던 TimelineRepository를 생성자 프로퍼티로 변경 * fix: 추억 목록 아이템이 하나일 때의 View 수정 - 아이템 개수가 하나일 때는 타임라인의 선이 나타나지 않도록 변경 * chore: 코루틴 예외 처리 로그에context 출력 * refactor: 메서드 분리 및 순서 재정렬 - 코드 컨벤션: override 메서드는 상단에 위치한다 * refactor: TimelineViewModel 생성 팩토리 메서드 활용 * style: ktlint 적용 * ui: 화면 전환에 사용될 twin animation 효과 생성 * ui: animation 효과 활용하여 화면 전환 애니메이션 적용 * ui: Main 화면의 배경 색을 하얀색(#FFFFFF)으로 지정 * style: ktlint 적용 * feat: 기분 선택 기능 구현 및 스타카토 조회 화면 구조 변경 #191 (#289) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * style: ktlint 적용 * feat: 추억 API 변경사항 반영 및 리팩터링 #259 (#265) * ui: 추억 생성 화면 사진 로드 시 coil 라이브러리 사용 * ui: 삭제 버튼 아이콘 추가 * ui: 추억 생성 화면 사진 삭제 버튼 추가 * feat: 추억 생성 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 생성 화면 사진 삭제 구현 * feat: 추억 수정 화면 사진 첨부 icon 가시성 설정 * ui: 추억 수정 화면 사진 삭제 버튼 추가 * feat: 추억 수정 화면 사진 삭제 버튼 가시성 설정 * feat: 추억 수정 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 수정 화면 사진 삭제 구현 * fix: 추억 생성 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * fix: 추억 수정 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * feat: MemoryRequest dto에 썸네일 사진 url 필드 추가 * feat: 추억 생성 메서드의 시그니처 변경 - MemoryApiService 내 추억 생성 메서드의 시그니처 변경 - 위 변경에 따른 DataSource, Repository, ViewModel의 추억 생성 관련 메서드 시그니처 변경 * feat: 추억 생성 view model 주 생성자로 ImageRepository 주입 * feat: 추억 생성 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 생성 화면) - 추억 생성 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 생성 시 썸네일 사진 url 추가 * refactor: MemoryRequest의 추억 썸네일 사진 기본 인자 값 null로 설정 * feat: 추억 수정 메서드의 시그니처 변경 * feat: 추억 수정 view model 주 생성자로 ImageRepository 주입 * feat: 추억 수정 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 수정 화면) - 추억 수정 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 수정 시 썸네일 사진 url 추가 * refactor: 불필요한 MemoryUpdateRequest 제거 * ui: empty view 캐릭터 이미지 추가 * ui: 추억 설명글 유무에 따른 가시성 설정 * ui: 함께 한 사람들 가시성 gone 으로 설정 - 4차 스프린트 범위에서 제외됨 * feat: 이미지 선택 옵션 추가 (단일 선택 및 다중 선택 지원) * ui: TextInputLayout, TextInputEditText Style 정의 * ui: 추억 생성 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 수정 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 조회 화면 썸네일 사진 유무에 따른 가시성 설정 * ui: empty view 캐릭터 이미지 크기 변경 * ui: 앱 이름 Staccato_AN -> Staccato 로 수정 * refactor: 추억 생성 및 수정 화면 메서드 순서 정리 * ui: 제목용 TextInputEditTextStyle 정의 및 적용 * ui: 추억 생성 및 수정 화면 썸네일 coilPlaceHolder 변경 - 이전: shape_place_holder_rectangle - 이후: shape_all_gray1_8dp * refactor: 삭제 다이얼로그 show 메서드 호출 방식 변경 - apply를 사용하지 않는 방식으로 변경 * ui: 코멘트 미지원 안내 view 추가 * feat: 스타카토 생성, 수정 화면 사진 및 완료 버튼 개선 #242 (#291) * feat: (스타카토 생성 화면) 사진 드래그로 순서 변경 기능 구현 * refactor: data 패키지에 S3 이미지 API 분리 적용 * refactor: AttachedPhotoUiModel 및 프로그래스바 추가 * feat: recyclerView에서 지워진 사진의 job cancel 처리 * refactor: editText를 TextInputLayout로 수정 * feat: (스타카토 수정 화면) 사진 드래그로 순서 변경 / 로딩 구현 * refactor: 프로퍼티 네임 변경 및 visitedAt LocalDateTime으로 수정 * style: ktlint 적용 * build: 구글 맵 API 사용에 따른 CI 수정 #296 (#297) * build: 구글 맵 api key를 저장하는 파일을 설정하는 명령어 작성 * refactor: defaults 에 설정된 shell 설정에 따라 추가적인 shell 설정 삭제 * feat: Google Map 연결, 스타카토 목록 조회 API 연결 #54 (#295) * build: google map 의존성 추가 * build: 구글맵 관련 properties ignore 추가 * build: 구글맵 api key 설정 * feat: Google Map 연결 * feat: MainActivity Handler 구현 * ui: 추억 및 스타카토 생성 메뉴 추가 * ui: popup menu style 정의 * feat: 추억 생성 및 수정 menu 연결 - handler 연결 - 메서드 분리 * feat: 위치 권한 요청 구현 - ACCESS_FINE_LOCATION 권한 요청 - ACCESS_COARSE_LOCATION 권한 요청 * feat: 현 위치 표시 * style: MainActivity formatting * feat: locationPermissions 타입 변경 - 이전: List - 이후: Array * feat: MomentLocationDto, MomentLocationResponse 추가 * feat: 스타카토 목록 조회 api service 구현 * feat: 스타카토 목록 조회 data source 구현 * feat: MomentLocation 도메인 모델 구현 * feat: MomentLocationDto를 도메인 모델로 변환하는 mapper 구현 * feat: 스타카토 목록 조회 repository 구현 * feat: 스타카토 목록 조회 view model 구현 * feat: 스타카토 목록을 marker로 표시 * refactor: home 패키지명을 maps로 변경 * feat: 마커 클릭 시 스타카토 상세로 이동 기능 구현 * feat: 스타카토 조회 추억 id, 제목 필드 추가 * feat: 마지막 위치 위경도 찾기 * refactor: 안드로이드 1차 QA 반영 #299 (#301) * refactor: 안드로이드 1차 QA 반영 * refactor: 안드로이드 1차 QA 반영2 * refactor: 안드로이드 1차 QA 반영3 * refactor: 삭제 메시지 변경 * fix: 스타카토 조회 화면 스택 관리 및 ui 수정 #304 (#306) * feat: 지도 화면에서 스타카토 조회 화면으로 이동 시 스택 관리 * feat: 타임라인 화면에서 추억이 존재하지 않을 때 추억 생성 버튼 추가 * ui: 스타카토 조회 화면 툴바 위치 고정 * build: Android CD 적용 #300 (#308) * build: CD 워크플로우 yml 파일 작성 * build: keystore 접근을 위한 build.gradle.kts 파일 설정 * build: 기존 apk 추출 ci 파일 수정 - demo 버전의 apk를 추출 및 배포하는 목적에 맞게 파일 명 수정 - apk 빌드 후 테스트를 수행하는 job 추가 - firebase 앱 배포에 아티팩트 업로드하는 job 추가 * fix: ci 파일에도 keystore 생성 job 추가 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: ci 파일에 키스토어 관련 설정 적용 * fix: 키스토어 관련 명령어 일부 수정 * fix: build.gradle.kts 불필요한 괄호 제거 * fix: keystore.properties 로 부터 프로퍼티를 가져오는 형식 변경 * fix: upload-artifact step에서 빌드 파일의 upload 경로 수정 (#316) upload-artifact 는 defaults 설정의 working-directory 경로가 적용되지 않음 * fix: android cd 재수정 (2차) #317 (#319) * fix: upload-artifact 빌드 파일의 upload 경로 3차 수정 * fix: 배포 시 빌드 파일의 경로 수정 * fix: 빌드 파일의 upload 경로 수정 및 파일이 없는 경우 에러 처리 * fix: 빌드 파일의 upload 경로 4차 수정 * fix: 빌드 파일의 upload 경로 5차 수정 * fix: 빌드 파일의 upload 경로 6차 수정 - 디렉터리 경로 생성 후 upload 실행 * fix: 빌드 파일의 upload 경로 7차 수정 github의 workspace 환경변수(절대경로) 활용 * fix: clean test 제거 및 디버그용 파일 경로 탐색 명령어 추가 * fix: 디버그용 파일 경로 검색 명령어 수정 * fix: 디버그용 파일 경로 검색 명령어 삭제 * fix: 디버그용 파일 검색 명령어 삭제 및 업로드 파일 경로명 수정 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 기능 구현 #314 (#324) * feat: MainActivity에서 주소를 가져오는 로직 삭제 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 로직 구현 * refactor: 메서드 순서 정렬 * refactor: 스타카토 조회 화면 ViewPager2 적용 및 UI 아이콘 개선 #318 (#320) * refactor: 아이콘 추가 및 UI 개선 * feat: 스타카토 상세 사진 Viewpager 적용 * feat: 스타카토 상세 사진 Viewpager에 dot indicator 추가 * style: ktLint Format * feat: 메인 지도 화면에서 스타카토 생성하는 플로우 구현 #321 (#327) * feat: 날짜로 추억 목록 불러오는 getMemories API 추가 * feat: 메인에서 스타카토 생성 시 추억 목록 선택 가능 * feat: 스타카토 생성 시 역지오코딩과 추억 선택 연동 * build: debug와 release로 buildTypes 분리 (#329) - appName, appId, baseUrl 분리 - release에 난독화 적용 * build: debug 와 release 배포 분기에 따른 CD 수정 - CD에 대한 트리거 재설정 : main 브랜치에 대한 push 및 pr * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 #326 (#330) * refactor: 지도 화면 onResume에서 스타카토 목록 load * refactor: 스타카토 목록 로드 메서드명 변경 - 이전: loadMoments - 이후: loadStaccatos * feat: 공유 view model에 스타카토 목록 업데이트 상태 추가 * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 * feat: 지도 로드 시 현위치로 이동하도록 구현 * build: ci 및 cd 파일 수정 ci - 불필요한 gradle 빌드 및 테스트 제거 cd - 타겟 브랜치 develop 제거 * feat: 댓글 조회, 생성, 삭제 기능 구현 #290 (#331) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * ui: xml 컨벤션에 맞추어진 타 사용자의 댓글 ui 구성 * feat: 댓글 API의 DTO 작성 * feat: 댓글 API Service 작성 * feat: 댓글 CRUD DataSource 작성 * refactor: CommentApiService 각 메서드의 반환 값을 Response로 변경 * feat: CommentApiService 를 create * feat: CommentDataSource 구현체 생성 * refactor: 댓글 Dto 클래스 네이밍 변경 - VisitLogDto -> CommentDto * refactor: CommentDto 의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * refactor: VisitLog 도메인 모델 클래스의 네이밍 변경 - VisitLog -> Comment * refactor: Comment 도메인 모델의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * feat: 새로운 댓글 도메인 모델 생성 * feat: CommentRepository 작성 * feat: Domain 모델과 DTO 모델을 변환해주는 Mapper 작성 - CommentDto를 Comment로 변환하는 메서드를 CommentMapper.kt로 이동 * feat: CommentRepository의 기본 구현체 작성 * feat: 댓글 ViewModel, Factory 작성 및 Comment 불러오기 구현 * ui: ViewModel 데이터바인딩 및 빈 댓글 문구에 대한 strings 설정 * feat: CommentsViewModel 활용 및 옵저빙 * feat: 댓글 조회, 생성, 삭제 기능 구현 * chore: ktlint 적용 * feat: 추억 생성 및 수정 이미지 로딩 중 표시 및 저장 버튼 비활성화 #332 (#334) * feat: 추억 생성 이미지 로딩 중 표시 * feat: 추억 수정 이미지 로딩 중 표시 * feat: 추억 생성 및 수정 이미지 로딩 중 저장 버튼 비활성화 * style: formatting --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * fix: 특정 기기에서 location이 null 되는 오류 수정 * refactor: 댓글 화면 개선 및 리팩터링 #333 (#335) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 * deploy: 스타카토 v1.0.0 #333 (#336) * build: 프로젝트 생성 및 의존성 추가 * chore: 사용자 기능 및 권한 추가 * chore: gitignore 재설정 * chore: gitigonre .idea/ 추가 * build: develop-an 브랜치의 CI 설정 #3 (#10) * build: android-ci.yml 파일 생성 * chore: 오타 및 개행 수정 * chore: working-directory 수정 * build: ktLint 적용 및 format * ui: 디자인 시스템 구현 #11 (#44) * ui: color 정의 * ui: shape, selector 추가 * ui: icon 추가 * ui: font family 추가 - pretendard regular, medium, semibold, bold 추가 * ui: typography 정의 * ui: strings 정의 * ui: bottom sheet drag handle drawable 추가 * ui: styles 정의 * ui: detail toolbar 구현 - 상세 화면에서 사용 * ui: dialog, bottom sheet 구현 - 여행 및 방문 기록 삭제 dialog - 사진 등록 bottom sheet * ui: 사진 첨부 layout 구현 * feat: 삭제 다이얼로그, 사진 첨부 바텀 시트 fragment 추가 * ui: 세로모드로 고정 * build: data binding 의존성 추가 * style: strings resource 순서 정렬 * style: formatting * ui: plus icon 추가 * feat: jetpack navigation 및 바텀시트 프래그먼트 추가 #12 (#15) * build: androidx.navigation 및 dataBinding 의존성 추가 * feat: Binding 화면 클래스 및 bottomSheetNavigation 추가 * feat: TimelineFragment 임시 화면 추가 * feat: TravelFragment 임시 화면 추가 * feat: TravelCreationFragment 임시 화면 추가 * feat: VisitFragment 임시 화면 추가 * feat: VisitCreationFragment 임시 화면 추가 * feat: (여행, 방문 기록) 수정 화면 추가 * feat: (여행, 방문 기록) 생성 화면 이동 구현 * feat: BottomSheetController 설정 및 Navigation 이동 구현 * feat: 뒤로가기 버튼 클릭 시 BottomSheet, Toast 작동 구현 * feat: 여행, 방문 기록 생성을 위한 액티비티 추가 및 이동 구현 * feat: 여행, 방문 기록 수정을 위한 액티비티 추가 및 이동 구현 * build: 중복된 dataBinding 제거 * feat: 공통 이미지 로딩 BindingAdapter 설정 #33 (#41) * build: dataBinding 사용 설정 * feat: 이미지 로딩 바인딩 어댑터 설정 - Glide, Coil 바인딩 어댑터를 각각 작성 - placeholder 설정 * style: ktlint check - import 순서 조정 * fix: attribute 개수에 맞추어 BindingAdapter의 value 재설정 * style: 마지막 줄 개행 추가 * feat: placeHolder를 필수 속성으로 변경 및 coil 이미지 로딩 코드 수정 - placeHolder를 ImageView의 필수 속성으로 지정 - Coil BindingAdapter에서 url이 null인 경우에도 이미지를 로드하는 동작이 수행되도록 수정 * ui: 상단바 색상 변경 * build: develop-an의 CI 설정 수정 #38 (#39) - Git Action에 Secret으로 저장된 LOCAL_PROPERTIES_API_KEY를 변수로 가져온다. - 가져온 변수를 echo를 활용하여 local.properties에 설정한다. * build: develop-an 브랜치의 CI 파일 문법 오류 수정 #45 (#46) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: android-ci.yml 파일의 명령어 수정 #47 (#48) LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 * fix: develop-an 브랜치의 CI 파일 명령어 재수정 #47 (#49) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> * fix: 문자열 임을 명시하고 환경변수 설정 위치 조정 * fix: local.properties 생성 시점 수정 * feat: 데이터 패키지 설정 #13 (#35) * build: 서버 base url의 local.properties 사용 설정 및 BuildConfig 설정 * feat: Retrofit Client 작성 * fix: Merge Conflict 해결 - build.gradle.kts(project, app)의 ktlint 의존성 충돌 해결 - 버전 카탈로그 플러그인 충돌 해결 * feat: DTO 클래스 작성 * style: ktlint check - 불필요한 import 제거 - 개행 조정 - 콤마 추가 * feat: SerialName 어노테이션의 값을 camelCase로 수정 * refactor: DTO 클래스의 이름 수정 - API 요청으로 직접 보내거나 들어오는 JSON의 경우 DTO 클래스명 뒤에 Request/Response 를 붙이도록 설정 - JSON 안에 속성 값으로 들어가는 JSON은 DTO 클래스명 뒤에 Dto를 붙이도록 설정 * feat: 누락된 Dto 클래스 추가 TimelineResponse.kt - 타임라인 조회 시 여행 상세 목록을 불러올 때 사용되는 DTO 클래스 - TimelineTravelDto 리스트를 갖는다 * style: ktlint check * fix: const 키워드 제거 --------- Co-authored-by: hxeyexn * feat: 둥근 모서리의 이미지를 로드하는 BindingAdapters 추가 #58 (#59) * feat: 둥근 모서리로 이미지를 로딩하는 Glide 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - glideRoundedCornerImageUrl: 출력하고자 하는 이미지 url - glidePlaceHolder: placeHolder의 url - glideRoundingRadius: 모서리의 둥근 정도를 Int로 설정 * feat: 둥근 모서리로 이미지를 로딩하는 Coil 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - coilRoundedCornerImageUrl: 출력하고자 하는 이미지 url - coilPlaceHolder: placeHolder의 url - coilRoundingRadius: 모서리의 둥근 정도를 Float으로 설정 * fix: centerCrop 설정을 BindingAdapter 에 위임 - xml 속성으로 centerCrop을 주게 되면 Round Corner가 제대로 적용되지 않는 현상 발생 - Glide의 api로 제공되는 centerCrop() 메서드를 활용 * ui: 타임라인 프래그먼트(BottomSheet) 구현 #55 (#71) * ui: 타임라인 View xml 파일 작성 - 타임라인에 나타날 여행 상세 아이템 xml 작성 - 썸네일 사진 유무에 따라 뷰를 구분 - 타임라인이 나타날 fragment xml 작성 * feat: 타임라인 여행 상세 아이템 UI 모델 생성 * ui: 썸네일이 없는 여행상세 아이템의 margin 조정 * ui: Timeline RecyclerView의 layoutManager 설정 * ui: xml에서의 UiModel 데이터 바인딩 설정 * feat: ViewHolder 작성 - 썸네일 사진 유무에 따라 다른 ViewHolder로 구분 - 공통된 속성을 정의한 TimelineViewHolder 추상클래스 생성 * feat: TimelineRepository Interface 생성 * feat: 임시 TimelineRepository 구현체 생성 * feat: TimelineViewModel 및 Factory 생성 * feat: TimelineViewType 작성 * feat: TimelineAdapter 작성 * feat: TimelineFragment에 ViewModel과 Adapter 구현 * feat: 이미지 로딩 PlaceHolder drawable 추가 및 적용 * feat: 임시 데이터 연결 * ui: Timeline fragment 의 세부 설정 조정 * ui: Timeline의 Item xml 변경 - 뷰 타입을 3개로 분할: 첫 번째 아이템, 중간 아이템, 마지막 아이템 - 이에 따라 xml 파일 추가 및 view 수정 * feat: ViewType 변경에 따른 Adapter 및 ViewHolder 수정 * refactor: 불필요한 View 및 ViewHolder 제거 * feat: 여행 click 에 대한 event handler 생성 및 설정 * refactor: drawable 이름을 네이밍 컨벤션에 맞게 수정 * ui: RecyclerView의 마진 속성을 패딩 속성으로 변경 * feat: 바텀 시트 디자인 변경 및 툴바와의 상호작용 구현 * ui: 타임라인 글귀 추가 * style: ktlint check * ui: 둥근 모서리의 이미지로 변경 * ui: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 구현 #52 (#74) * ui: typography.body textSize 1sp 씩 증가 * feat: DeleteDialogFragment에 Handler 추가 * feat: 툴바의 수정, 삭제 버튼 제어를 위한 ToolbarHandler 추가 * feat: 방문 상세 화면을 위한 VisitDetailUiModel 추가 * ui: PlaceHolder를 위한 xml 파일 추가 * feat: 방문 기록 상세 화면을 위한 VisitAdapter 및 VisitViewHolder 구현 * feat: 임시 VisitViewModel와 VisitViewModelFactory 추가 * feat: VisitFragment 화면 구현 * feat: 방문 기록에 해당하는 여행 선택을 위한 TravelSelectionFragment 구현 * feat: 방문 기록에 해당하는 날짜 선택을 위한 VisitedAtSelectionFragment 구현 * feat: 방문 기록 생성을 위한 VisitCreationActivity 구현 * feat: 방문 기록 수정을 위한 VisitUpdateActivity 구현 * refactor: DialogHandler를 DeleteDialogFragment의 생성자에서 받도록 수정 * refactor: initVisitUpdateDoneButton 중복 로직 제거 * refactor: VisitViewHolderType 메서드 명 변경 of -> from * refactor: tv_place_name_title을 xml id convention에 맞게 수정 * ui: 여행 화면 구현 #51 (#75) * ui: 함께 간 사람들 item 구현 * ui: 방문 기록 item 구현 * ui: 여행 상세 화면 구현 * ui: 여행 생성 화면 구현 * ui: 여행 수정 화면 구현 * ui: placeholder에 사용할 drawable 추가 * ui: 여행 삭제 완료 string 추가 * feat: 둥근 모서리 이미지 BindingAdapter 구현 * feat: 함께 간 사람들 adapter 구현 * ui: 여행 상세 화면 NestedScrollView로 변경 - 이전: ScrollView - 이후: NestedScrollView * feat: 방문 기록 adapter 구현 * feat: 여행 상세 view 연결 * feat: 함께 간 사람들, 방문 기록 adapter 연결 * feat: 삭제 다이얼로그 handler 구현 * feat: 여행 상세 화면 toolbar handler 구현 - 뒤로가기 - 여행 수정 화면으로 이동 - 삭제 다이얼로그 show * feat: 여행 -> 방문 기록 화면 이동 구현 * ui: DatePickerStyle 추가 - DatePickerStyle, CustomMaterialCalendarStyle 추가 - staccato_blue 투명도 30 추가 * feat: 여행 저장 버튼, 여행 기간 BindingAdapter 추가 * feat: 여행 생성 view 연결 * feat: 여행 수정 view 연결 * style: formatting - Exceeded max line length 해결 - 임시 이미지 URL 변경 * refactor: 기간 선택 로직 메서드 분리 * feat: 타임라인의 API 적용 및 MainActivity의 Toolbar 제거 #81 (#93) * refactor: UI Model의 패키지 경로 변경 * refactor: API 명세 변경에 따른 TimelineTravelDto 수정 * refactor: repository 메서드 수정 - 서버 요청을 비동기적으로 처리하기 위해 suspend 키워드 삽입 - 기존의 임시 데이터 요청 코드를 위해 load 메서드 분리 * feat: Timeline의 API Service 작성 * feat: DataSource 인터페이스 작성 * feat: TimelineDataSource 구현체 생성 * refactor: 년도에 대한 default parameter 설정 * refactor: DataSource의 요청 메서드 네이밍 수정 * feat: http 통신이 가능하도록 Cleartext Traffic 허용 설정 * feat: Authorization Header를 삽입하기 위한 Interceptor 생성 * feat: Client에 HeaderInterceptor 추가 * refactor: errorBody의 message 속성 이름 변경 * feat: 도메인 모델 작성 * feat: Response(dto)에서 도메인 모델로 변환하는 확장함수 구현 * feat: 도메인 모델에서 UI 모델로 변환하는 확장함수 구현 * feat: Repository 수정 및 ViewModel 데이터 연결 * ui: MainActivity의 상단 툴바 제거 * refactor: ViewType에 viewType 속성 추가 및 when에서의 enum 활용 * refactor: Timeline의 공통 ViewHolder를 sealed class로 변경 * style: ktlint check 수행 * fix: Response 데이터의 nullable 속성에 맞추어 DTO 수정 및 누락된 DTO 추가 * fix: 데이터가 비어있는 경우(초기)에만 새로운 여행상세 목록을 받도록 수정 * refactor: lazy 로 지연 초기화 및 timelineService가 하나의 인스턴스로 관리되도록 수정 * fix: Travel의 description에 nullable 속성 추가 API 명세서 잘 좀 보자 제발 * refactor: create 메서드를 private으로 변경 Client 클래스에서 Service를 create 하여 제공 및 캐싱하기 때문에, 불필요한 인스턴스를 생성하지 않도록 create를 public으로 두지 않는 것이 좋다. * refactor: LocalDateConverters의 패키지 경로 수정 * refactor: 파일의 이름 수정 * style: ktlint check * refactor: 에러 메시지 상수화 * feat: 특정 여행 상세 조회 api 연결 #82 (#97) * feat: 특정 여행 상세 조회 api service 구현 * feat: 썸네일, 소개 타입 변경 및 기본 인자 설정 - 변경 data class : TravelResponse, TravelUiModel - 이전: String - 이후: String? * refactor: MatesUiModel 네이밍 변경 MatesUiModel이 공통적으로 사용될 예정이므로 MemberUiModel로 변경 - 이전: MatesUiModel - 이후: MemberUiModel * refactor: VisitUiModel 네이밍 변경 - 여행 상세 방문 기록에 사용되는 UiModel 이름을 명시적으로 변경 - 이전: VisitUiModel - 이후: TravelVisitUiModel * feat: 특정 여행 상세 조회에 사용할 domain model 추가 * feat: Api 응답 핸들링 로직 구현 * feat: 특정 여행 상세 조회 data source 구현 * feat: 특정 여행 상세 조회 repository 구현 * feat: 특정 여행 상세 조회 api 연결 * feat: 특정 여행 상세 조회 로직 매개변수 추가 - 타임라인에서 선택된 여행 id를 매개변수로 받도록 변경 * refactor: ApiResponseHandler 이름 오타 수정 * refactor: 에러 메세지 상수화 * feat: 특정 여행 상세 조회 시그니처 변경 - HeaderInterceptor 적용으로 authorization 매개변수 제거 * style: formatting * feat: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 API 연결 #79 (#99) * feat: VisitApiService 인터페이스 및 관련 data class 추가 * feat: VisitRepository, RemoteVisitDataSource 및 관련 class 추가 * feat: 각 Visit 화면들의 ViewModelFactory 구현 * feat: 각 Visit 화면들의 UiModel 클래스 및 Mapper 추가 * feat: 여행 선택 및 방문 날짜 선택을 위한 BottomSheetDialogFragment 수정 * feat: VisitFragment API 연결 * feat: VisitCreationActivity API 연결 * feat: VisitUpdateActivity API 연결 준비 * refactor: visitApiService를 StaccatoClient object로 이동 * refactor: TravelVisit 클래스의 visitImage 변수 nullable하게 수정 * refactor: VisitApiService의 중복된 @Header 제거 * refactor: 방문 생성 성공 시 created id를 가져오도록 리팩터링 * chore: 변수명 visitImage로 수정 및 ktLint 적용 * refactor: 여행 수정 완료 동작 구현 및 VisitUpdateActivity 함수 분리 * feat: 여행 생성 api 연결 #98 (#104) * feat: 여행 생성 api service 구현 * feat: 여행 생성 data source 구현 * feat: 방문 기록 썸네일 타입 변경 및 기본 인자 설정 - 변경 data class :  TravelVisitDto, TravelVisit, TravelVisitUiModel - 이전: String - 이후: String? * build: converter scalars 의존성 추가 * feat: 여행 생성 ApiService 반환값 및 DataSource 시그니처 변경 - 여행 생성 ApiService 반환값 변경 - DataSource 시그니처 변경 - TravelCreation DomainModel 구현 - TravelCreation Dto 변환 Mapper 구현 * feat: Client에 ScalarsConvert 추가 - Header 값을 읽어오기 위해 ScalarsConvert 추가 * feat: 여행 생성 repository 구현 * feat: 여행 생성 api 연결 * feat: TravelViewModel 생성자 변경 - 이전: travelId를 TravelViewModel 생성자로 넣어줌 - 이후: travelId를 loadTravel()의 매개변수로 넣어줌 * ui: map 화면 변경 * refactor: 컨벤션 통일 및 패키지 정리 #112 (#118) * refactor: bind 네임스페이스 적용 * refactor: BindingAdapters 메서드명 변경 * refactor: 컨벤션 맞게 xml 파일 이름 변경 * refactor: data 패키지 구조 정리 * refactor: RemoteVisitDataSource 컨벤션 따라 네이밍 변경 * refactor: 네트워킹 관련 메서드 이름 변경 - api service, data source, repository * refactor: presentation 패키지 구조 정리 * refactor: message utils 생성 및 적용 Co-authored-by: s6m1n Co-authored-by: Junyoung-WON * build: develop-an의 CI 테스트 자동화 추가 및 데모 APK 추출 #78 (#92) * build: test 자동화 Job 추가 * build: local.properties 생성 시점 변경 * build: 디버그 APK를 빌드하여 업로드하는 workflow 작성 * fix: test Job과 APK build Job에 local.properties 생성 동작 추가 * build: read 전용 권한 제거 * build: Firebase Analytics, Crashlytics 설정 #136 (#143) * build: Firebase Analytics, Crashlytics 의존성 추가 * chore: google-service.json ignore * feat: 특정 여행 상세 수정 api 연결 #109 (#146) * feat: 여행 수정 api service 구현 * feat: 여행 수정 data source 구현 * feat: 여행 수정 repository 구현 * feat: 여행 수정 화면 현재 데이터 로딩 기능 구현 * refactor: 컨벤션 따라 여행 api service의 수정 메서드명 변경 - 이전: updateTravel - 이후: putTravel * feat: 특정 여행 상세 수정 api 연결 * refactor: memberImage 타입 변경 및 기본 인자 설정 * refactor: MembersDto 삭제 * refactor: TravelCreationUiModel.kt 삭제 * refactor: TravelCreation 이름 변경 - 이전: TravelCreation - 이후: NewTravel * refactor: api 명세서 변경에 따른 도메인 모델 수정 및 여행 코드 리팩터링 #151 (#152) * refactor: nickName 변수명 변경 - 이전: nickName - 이후: nickname * ui: 여행 수정 화면 이미지 속성 수정 - glide -> coil 이용 - scaleType : fitXY -> centerCrop * style: import 정렬 * feat: 여행 상세 -> 방문 상세로 이동 시 여행 id 전달 * feat: 방문기록 조회 dto 수정 - 방문기록 조회 도메인 변경으로 인해 방문 기록이 조회되지 않음 - 따라서 api 명세서와 일치하도록 dto 수정하여 오류 해결 * refactor: 여행 생성을 위한 viewModel 메서드 분리 * refactor: 여행 조회를 위한 viewModel 메서드 분리 * feat: 여행 수정 handler 구현 * refactor: 여행 default id 변경 - 이전: -1L - 이후: 0L * refactor: TravelHandler 구현 위치 변경 - 이전: TravelViewModel - 이후: TravelFragment * style: 컨벤션에 맞게 TravelFragment의 메서드 순서 수정 * refactor: TravelFragment의 travelId 초기화 방식 변경 * feat: 여행 생성 및 수정 error toast 구현 * feat: 방문 생성 화면, 방문 수정 화면에서 갤러리 사진 불러오기 구현 #150 (#155) * feat: PhotoAttachFragment에 PhotoAttachHandler 연결 * feat: PhotoAttachFragment 앨범 접근 권한 관련 로직 구현 - API level 33 이상 : READ_MEDIA_IMAGES - API level 33 이하 : READ_EXTERNAL_STORAGE - ActivityResultLauncher를 이용한 권한 요청 - 권한 거부 시, 설정으로 이동하는 스낵바 띄우기 * feat: PhotoAttachFragment 앨범에서 불러온 이미지의 URI 추출하기 * feat: 불러온 이미지의 URI를 호스트 Activity로 전달 - OnUrisSelectedListener 인터페이스 추가 * feat: Uri를 File로 변환하는 메서드 파일 추가 * refactor: pr 리뷰 반영 * refactor: pr 리뷰 반영2 * build: develop-an의 android-ci 수정 #115 (#160) - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: android-ci 환경변수 생성 위치 조정 (#164) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * build: bash 쉘에 맞는 명령어 활용 #115 (#165) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * fix: bash 쉘에 적합한 명령어 형식으로 변경 * feat: 특정 여행 상세 삭제 api 연결 #153 (#167) * feat: 특정 여행 삭제 api service 구현 * feat: 특정 여행 삭제 data source 구현 * feat: 특정 여행 삭제 repository 구현 * feat: 특정 여행 삭제 기능 api 연결 * feat: error handling 방식 수정 - 서버에서 들어오는 error body의 status와 message를 활용하는 방식으로 변경 * refactor: DialogHandler를 독립적으로 관리 * refactor: api path 상수 활용 * refactor: BuildConfig에 token 정의 * refactor: DEFAULT_VALUE 상수 제거 * feat: 여행 생성 기능 api 수정 #169 (#178) * feat: onUrisSelected 매개변수 가변인자로 변경 * feat: 여행 생성 화면 갤러리 이미지 로딩 기능 구현 * refactor: 이미지 선택 리스너 초기화 메서드명 오타 수정 * refactor: 스낵바 액션 설정 코드 간소화 * feat: TravelRequest 의 여행 썸네일 필드 제거 * refactor: 여행 썸네일 이미지 변수명 수정 * feat: 이미지 전송 기능 구현 * refactor: image url 변수명 변경 - 변수 끝에 url이 오도록 * feat: 여행 생성 progressBar 구현 * ui: 사진 첨부 아이콘 가시성 설정 * feat: 여행 상세 수정 기능 api 변경 및 여행 리팩터링 #180 (#181) * feat: 여행 수정 화면 갤러리 이미지 로딩 기능 구현 * feat: URL 및 URI 기반 이미지 로딩 BindingAdapter 구현 * feat: 이미지 전송 기능 구현 * feat: 여행 수정 progressBar 구현 * fix: 삭제 불가능한 여행 삭제 시도 관련 에러 토스트 문제 해결 삭제 불가능한 여행을 삭제하려고 시도 -> 방문 조회 -> 뒤로 가기 버튼 클릭 -> 삭제 불가능 에러 토스트가 다시 뜨는 문제가 발생해 이를 해결 * refactor: TravelCreationViewModel의 imageUrl 변수 제거 * ui: 여행 상세 내 방문 기록 이미지 scaleType 속성 설정 * ui: 여행 생성 썸네일 이미지 scaleType 속성 설정 * fix: 여행 소개 미입력 시 여행이 생성 되지 않는 오류 해결 * refactor: 타임라인 화면 리팩터링 #162 (#179) * ui: 타임라인 RecyclerView의 크기 조정 및 여백 수정 * feat: Activity와 Fragment 간 데이터를 공유하는 공유 ViewModel 생성 * feat: 공유 ViewModel을 이용하여 타임라인 업데이트 여부를 공유 * refactor: RecyclerView.Adapter에서 ListAdapter로 변환 * refactor: 처음 타임라인을 불러오는 동작을 ViewModel 초기화 시에 수행 * fix: ListAdapter 수정 - 불필요한 travels 프로퍼티와 getItemCounts 메서드 제거 - currentList를 사용하는 것으로 변경 * refactor: 에러 핸들링 방식 수정 및 ViewModel 수정 - TimelineDefaultRepository로 네이밍 변경 - ApiResponseHandler와 ResponseResult를 이용하여 에러 핸들링 처리 - TimelineViewModel 에러 메시지 LiveData 사용 - 그 외 repository, dataSource 프로퍼티 이름 수정하여 통일 * refactor: MutableLiveData의 값 업데이트를 setValue로 변경 및 메서드 분리 * style: ktlint 적용 * feat: 3차 스프린트에서 수정된 방문 기록 상세 API 연결 #163 (#183) * feat: 방문 상세 생성 API 연결 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 방문 기록 생성 및 수정 시 로딩과 토스트 추가 * feat: 닉네임을 활용한 로그인 기능 구현 #124 (#172) * ui: 로그인 화면 구성 - 로그인 화면에서 사용되는 텍스트를 strings에 추가 - 로그인 버튼 스타일에 대한 style 생성 - xml 임시로 작성 * ui: 앱 로고 삽입 및 margin 조정 - 임시 로고 이미지 저장 - 로고 크기 및 마진 조정 * feat: 로그인 API Service 작성 및 Retrofit 객체 생성 * feat: 로그인 DataSource 작성 * feat: 로그인 Repository 생성 * feat: 사용자 정보를 저장하는 SharedPreferences Manager 생성 - 토큰 값 불러오기 및 저장 - 추후 사용자 닉네임, 사용자 프로필 이미지 등의 정보 저장 가능 * feat: Application 생성 및 사용자 정보 Preferences Manager 캐싱 * ui: Splash Screen 화면 구성을 위한 테마 생성 * feat: Preferences 로부터 사용자 토큰 값을 가져와 헤더에 추가하도록 변경 * refactor: Repository 네이밍 통일 * refactor: DataSource 기본 인자 추가 * feat: LoginViewModel 및 Handler 작성 * feat: LoginViewModel 을 생성하는 ViewModel Factory 작성 * feat: LoginActivity 작성 및 양방향 데이터 바인딩 적용 * feat: StaccatoApplication과 LoginActivity 설정 및 LoginActivity를 시작 화면으로 변경 * style: 불필요한 namespace 제거 및 lint 확인 * refactor: LoginViewModel과 Factory를 viewmodel 패키지로 분리 * refactor: TimelineViewModel과 Factory를 viewmodel 패키지로 분리 * style: ktlint 적용 * fix: 불필요한 ConverterFactory 제거 - 더 이상 사용하지 않는 text/plain 변환용 ScalarsConverterFactory 제거 * feat: 닉네임 로그인 요청 및 응답에 대한 DTO 작성 * refactor: 로그인 요청, 응답 시 DTO 활용 * fix: 토큰 값을 불러오고 및 저장하는 동작의 비동기 처리 및 화면 전환 개선 * refactor: 토큰 값을 캐싱하여 저장하는 TokenManager 생성 및 적용 - 매번 runBlocking을 통해 Preference에 저장된 토큰 값을 불러오는 것은 네트워크 성능을 저하시킨다. - 따라서, token 값을 캐싱하여 저장하는 TokenManager를 활용한다. - 첫 네트워크 요청 시에만 토큰을 불러오는 작업을 동기적으로 처리하기 위해 Main Thread가 Blocking 된다. - TokenManager가 Preference로부터 가져온 토큰을 캐싱하여 저장한다. - 이후 요청부터는 캐시된 토큰을 가져오므로 Main Thread가 Blocking 되지 않는다. * style: ktlint 적용 * feat: Night 모드 비활성화 * refactor: 여행 기간 날짜 형식 변환을 BindingAdapter에서 수행 - TimelineTravelUiModel 프로퍼티 수정 - UiModel의 여행기간 날짜를 LocalDate로 갖도록 통일 - 추후 날짜 관련 UI가 변경되었을 때 확장성 고려 - BindingAdapters에 날짜 형식 변환해주는 메서드 작성 * chore: 주석 처리된 Log 코드 삭제 * style: xml View의 ID 네이밍 컨벤션 적용 * ui: 앱 심볼 로고 추가 및 스플래시 스크린에 적용 * feat: 방문 상세 생성 API 연결 * ui: 배경 색을 흰 색으로 지정 * feat: 키보드 활성화 상태에서 화면 터치 시 키보드를 내리는 기능 추가 * style: ktlint 적용 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * fix: merge 과정에서 발생한 id값 네이밍 충돌 해결 * build: 앱 version code와 version name 수정 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 스플래시 스크린 시간 조정 및 데모 시연용 토큰 활성화 * fix: 동일한 사진이 여러 장 업로드되는 버그 수정 * feat: 기존 로그인 기능으로 롤백 --------- Co-authored-by: somin * fix: 테스트 배포를 위한 버그 수정 #198 (#219) * style: formatting * fix: 무한 로딩 오류 수정 * fix: 여행 생성 오류 수정 * add: 앱 아이콘 변경 * ui: timeline empty view 추가 * feat: timeline empty view 가시성 설정 * ui: 여행 내 방문 기록 empty view 추가 및 가시성 설정 * ui: 방문 기록 내 로그 미지원 기능 view 추가 * feat: 사진 첨부 카메라 미지원 기능 알림 추가 * ui: 필수값 표기 style 정의 * ui: 여행 생성 및 수정 필수값 표기 추가 * ui: 방문 기록 생성 및 수정 필수값 표기 추가 * feat: 생성, 수정, 로그인 시 다중 요청 전송을 막기 위한 화면 터치 제한 * feat: 장소 생성의 사진 첨부 리사이클러뷰 구현 - 사진 추가 & 삭제 구현 - GridLayout으로 변경 - 사진 중복 없이 최대 5장으로 제한 - 새로 추가된 사진이 기존 사진 뒤에 더해지도록 구현 * chore: 방문 생성 화면 rv_photo_attach로 xml id 수정 * ui: app icon 및 splash icon 변경 * refactor: xml ID 네이밍 컨벤션 적용 --------- Co-authored-by: somin Co-authored-by: Junyoung-WON * refactor: 도메인명 변경에 따라 travel을 memory로 수정 #217 (#231) * refactor: 패키지명 travel -> memory로 수정 * refactor: dto의 TravelMapper 를 MemoryMapper 로 네이밍 변경 * refactor: 여행(현 추억) 생성 response dto 네이밍 변경 - TravelCreationResponse -> MemoryCreationResponse * refactor: 여행(현 추억) request dto 네이밍 변경 - TravelRequest -> MemoryRequest * refactor: 여행(현 추억) 조회 response dto 네이밍 변경 - TravelResponse -> MemoryResponse * refactor: 여행(현 추억) 수정 request dto 네이밍 변경 - TravelUpdateRequest -> MemoryUpdateRequest * refactor: 여행(현 추억) 내 방문 dto 네이밍 변경 - TravelVisitDto -> MemoryVisitDto * refactor: 타임라인 여행(현 추억) item의 dto 네이밍 변경 - TimelineTravelDto -> TimelineMemoryDto * refactor: 여행(현 추억) ApiService 네이밍 변경 - TravelApiService -> MemoryApiService * refactor: 여행(현 추억) DataSource 네이밍 변경 - TravelDataSource -> MemoryDataSource - TravelRemoteDataSource -> MemoryRemoteDataSource * refactor: 여행(현 추억) Repository 네이밍 변경 - TravelRepository -> MemoryRepository - TravelDefaultRepository -> MemoryDefaultRepository * style: TimelineMapper import 재정렬 * refactor: NewTravel 도메인명을 NewMemory로 변경 * refactor: Travel 도메인명을 Memory로 변경 * refactor: TravelVisit 도메인명을 MemoryVisit으로 변경 * refactor: presentation의 TravelMapper 명 변경 - TravelMapper -> MemoryMapper * refactor: 여행(현 추억) ui 모델명 변경 - TravelUiModel -> MemoryUiModel - TravelVisitUiModel -> MemoryVisitUiModel * refactor: 여행(현 추억) view model 명 변경 - TravelViewModel -> MemoryViewModel - TravelViewModelFactory -> MemoryViewModelFactory * refactor: MemoryApiService의 Path 변경 - travel을 memory로 변경 - travels을 memories로 변경 * refactor: Memory 관련 dto 변수명 변경 - travel을 memory로 변경 * refactor: Timeline Dto의 Memory 관련 변수명 변경 - travel을 memory로 변경 - travels를 memories로 변경 * refactor: Memory 관련 도메인 모델의 변수명 변경 - travel을 memory로 변경 * refactor: Memory 관련 ui 모델의 변수명 변경 - travel을 memory로 변경 * refactor: data layer의 Memory 관련 함수 및 변수명 변경 - travel을 memory로 변경 * refactor: 방문 생성 request dto의 travelId 변수명 변경 - travelId -> memoryId * refactor: 여행(현 추억) 조회 view model 및 fragment의 네이밍 변경 - travel -> memory * refactor: fragment_travel 의 리소스 네이밍 변경 - travel -> memory - strings.xml의 리소스명 변경 * refactor: TravelCreationActivity 네이밍 변경 - TravelCreationActivity -> MemoryCreationActivity * refactor: 여행(현 추억) 생성의 ViewModel 관련 네이밍 변경 - TravelCreationViewModel -> MemoryCreationViewModel - TravelCreationViewModelFactory -> MemoryCreationViewModelFactory - 관련 함수 및 변수명 변경 - travel -> memory * refactor: 여행(현 추억) 생성, 수정에 관한 xml 리소스 명 변경 - travel -> memory - strings.xml 의 관련 리소스 수정 * refactor: 여행(현 추억) 수정 Activity, Handler 의 네이밍 변경 - travel -> memory * refactor: 여행(현 추억) 수정 ViewModel 의 네이밍 변경 - 관련 함수 및 변수 명 변경 - travel -> memory - Factory 클래스명 변경 * refactor: 여행(현 추억) 생성, 수정에서의 파일 변환 메서드명 변경 - travel -> memory - 자식 파일 명 상수화 * refactor: Timeline 의 UI 모델 및 Travel ID Key 의 리네이밍 - travel -> memory 로 일괄 변경 * refactor: presentation/timeline 내 travel 도메인명 변경 - travel -> memory - TimelineMapper 내 domain model -> ui model 변환 메서드명 변경 * refactor: dto/MemoryMapper 내 domain 변환 메서드명 변경 - dto/MemoryMapper 내 domain model을 dto로 변환하는 메서드명 변경 - travel -> memory * refactor: dummyTravel 을 dummyMemory 로 변경 * refactor: MainActivity 내 travel을 memory로 변경 * refactor: activity_main 내 travel을 memory로 변경 * refactor: TimeLineApiService 내 GET 메서드 path 수정 - travels -> memories * refactor: MemoryFragment 내 travel 을 memory 로 변경 - MemoryFragment, fragment_memory 내 travel 을 memory 로 변경 * refactor: MemoryViewModel 내 error message 변수명 변경 - TRAVEL_ERROR_MESSAGE -> MEMORY_ERROR_MESSAGE * refactor: navigation graph 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 extra 키 값 수정 - TRAVEL_ID_KEY -> MEMORY_ID_KEY - TRAVEL_TITLE_KEY -> MEMORY_TITLE_KEY * refactor: VisitFragment 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 travel을 memory로 변경 * refactor: VisitUpdateViewModel 내 travel을 memory로 변경 * refactor: VisitTravelUiModel을 VisitMemoryUiModel로 변경 * refactor: 방문 수정 xml의 travel을 memory로 변경 * refactor: 여행(현 추억) 선택 xml 내 travel을 memory로 변경 * refactor: 여행 선택 바텀 시트 내 travel을 memory로 변경 - TravelSelectionFragment -> MemorySelectionFragment 로 수정 - TravelSelectionHandler -> MemorySelectionHandler 로 수정 - TravelSelectionFragment 내 메서드명 수정 - TravelSelectionHandler 내 매개변수명 수정 * refactor: VisitRepository와 구현체의 메서드 내 매개변수명 통일 * refactor: VisitsViewHolder 내 travel을 memory로 변경 * refactor: VisitCreationActivity 내 travel을 memory로 변경 * refactor: VisitCreationViewModel 내 travel을 memory로 변경 * refactor: 방문 생성 xml 내 travel을 memory로 변경 * refactor: BindingAdapters 내 travel을 memory로 변경 * refactor: strings 내 travel을 memory로 변경 - strings 내 '여행'을 '추억'으로 수정 Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * refactor: visit, visit log 도메인명 수정 #218 (#237) * refactor: VisitApiService 내 visit을 moment 로 변경 - 파일명 수정 - path 수정 - 메서드명 수정 - 매개변수명 수정 * refactor: data/visit 패키지명을 moment로 변경 * refactor: data/dto/visit 패키지명을 moment로 변경 * refactor: VisitCreationRequest 네이밍 변경 - 이전: VisitCreationRequest - 이후: MomentCreationRequest * style: StaccatoClient import 재정렬 * refactor: VisitCreationResponse 네이밍 변경 - 이전: VisitCreationResponse - 이후: MomentCreationResponse - 필드명 변경 : visitId -> momentId * refactor: VisitResponse 네이밍 변경 - 이전: VisitResponse - 이후: MomentResponse - VisitResponse 필드 내 visit을 moment로 변경 - VisitResponse 필드 내 visitLogs SerialName을 comments로 변경 * refactor: VisitUpdateRequest 네이밍 변경 - 이전: VisitUpdateRequest - 이후: MomentUpdateRequest - VisitUpdateRequest 필드 내 visit을 moment로 변경 * refactor: VisitLogDto 내 SerialName 변경 - visitLogId를 commentId로 변경 * refactor: MemoryResponse 내 visits SerialName 변경 - visits를 moments로 변경 * refactor: VisitCreationViewModel 내 FORM_DATA_NAME 변경 - 이전: visitImageFiles - 이후: momentImageFiles * refactor: MemoryVisitDto 내 visit를 moment로 변경 - MemoryVisitDto -> MemoryMomentDto로 변경 - visitId -> momentId로 변경 - visitImageUrl -> momentImageUrl로 변경 * refactor: VisitRemoteDataSource 내 visit을 moment로 변경 - VisitRemoteDataSource -> MomentRemoteDataSource로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: MomentRepository 및 구현체 내 visit을 moment로 변경 - VisitRepository -> MomentRepository로 변경 - VisitDefaultRepository -> MomentDefaultRepository로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: Visit 도메인 모델명 및 변수명 변경 - Visit -> Moment로 변경 - visitLogs -> comments로 변경 * refactor: Memory 도에인 모델의 visits을 moments로 변경 * refactor: MemoryVisit 도메인 모델 내 visit을 moment로 변경 * refactor: MemoryResponse의 visits 필드명을 moments로 변경 * refactor: dto/mapper/VisitMapper를 MomentMapper로 변경 * refactor: presentation/visit 패키지명을 moment로 변경 * refactor: VisitViewHolderType 네이밍 변경 - VisitViewHolderType -> MomentViewHolderType - enum 상수명 변경 - VISIT_DEFAULT -> MOMENT_DEFAULT - MY_VISIT_LOG -> MY_COMMENTS * refactor: VisitViewHolder 네이밍 변경 - VisitViewHolder -> MomentViewHolder - VisitDefaultViewHolder -> MomentDefaultViewHolder - MyVisitLogViewHolder -> MyCommentViewHolder * refactor: VisitAdapter 내 visit을 moment로 변경 - VisitAdapter -> MomentAdapter 로 변경 - visit -> moment 로 변경 * refactor: MomentAdapter 내 visit log를 comments로 변경 * refactor: VisitDetailUiModel 내 visit을 moment로 변경 - VisitDetailUiModel -> MomentDetailUiModel - VisitDefaultUiModel -> MomentDefaultUiModel - visitImageUrls -> momentImageUrls * refactor: VisitLogUiModel을 CommentsUiModel로 변경 * refactor: VISIT_ID_KEY extra key id 네이밍 변경 - VISIT_ID_KEY -> MOMENT_ID_KEY * refactor: VisitFragment 내 visit을 moment로 변경 * refactor: VisitViewModel 내 visit을 moment로 변경 - VisitViewModel -> MomentViewModel로 변경 - VisitViewModelFactory -> MomentViewModelFactory로 변경 * refactor: VisitMemoryUiModel 네이밍 변경 - VisitMemoryUiModel -> MomentMemoryUiModel로 변경 * refactor: presentation/visitcreation 패키지명 momentcreation으로 변경 * refactor: VisitCreationActivity 내 visit을 moment로 변경 - VisitCreationActivity -> MomentCreationActivity로 변경 * refactor: VisitCreationHandler 네이밍 변경 - VisitCreationHandler -> MomentCreationHandler로 변경 * refactor: VisitCreationViewModel 내 visit을 moment로 변경 - VisitCreationViewModel -> MomentCreationViewModel로 변경 - 메서드 및 변수명 변경 * refactor: 여행 -> 추억, 방문 기록 -> 스타카토로 도메인명 변경 * feat: s3 api 연결 #239 (#241) * feat: ImageResponse, ImageApiService 구현 * feat: ImageRepository 및 구현체 구현 Co-authored-by: s6m1n * fix: 추억 기능 버그 수정 #246 (#252) * fix: 일부 EditText 개행 불가 처리 및 키보드 숨김 처리 #247 (#249) * ui: 닉네임과 추억 생성, 수정 제목 입력 시 줄바꿈 제한 * fix: 키보드 활성화 상태에서 빈 화면 터치로 키보드 숨김 처리 - 메서드 명 변경: setHideKeyboardAction -> setHidingKeyboardAction * style: 클래스 내 override 메서드의 순서 변경 - 팀 코드 컨벤션에 맞게 순서 재정렬 - override 메서드를 상단에 둔다. * style: ktlint 적용 * fix: root뷰 터치 시 클릭 이벤트가 발생하지 않는 오류 수정 - 원인 분석: ConstraintLayout 내부 Toolbar 및 ScrollView, 그리고 그 자식 View들이 클릭 이벤트를 가로채기 때문에, 바인딩 된 최상단 root 뷰인 ConstraintLayout의 클릭 이벤트가 동작하지 않는다. - 해결 방법: 여러 클릭 이벤트를 가로채는 dispatchTouchEvent 메서드를 오버라이드하여, 터치된 부분이 현재 포커스가 되지 않은 View(키보드 바깥 화면) 범위라면, 키보드를 숨기는 동작을 추가하였다. * refactor: 키보드 숨김 동작을 handler 바인딩으로 적용 - LoginHandler 에 화면 터치에 대한 동작을 추가, 화면 터치 시 키보드를 숨김 처리하는 동작을 바인딩으로 설정 - InputMethodManager 인스턴스를 지연초기화하여 저장 * refactor: InputMethodManager 인스턴스를 lazy로 지연 초기화 * fix: 닉네임, 제목 입력 칸의 키보드 액션 버튼 변경 - 키보드의 액션 타입을 Search에서 Done으로 변경 * style: ktlint 적용 * refactor: 타임라인 리팩터링 #232 (#263) * refactor: TimelineViewModelFactory의 생성자 파라미터 추가 - 내부 프로퍼티에 속해있던 TimelineRepository를 생성자 프로퍼티로 변경 * fix: 추억 목록 아이템이 하나일 때의 View 수정 - 아이템 개수가 하나일 때는 타임라인의 선이 나타나지 않도록 변경 * chore: 코루틴 예외 처리 로그에context 출력 * refactor: 메서드 분리 및 순서 재정렬 - 코드 컨벤션: override 메서드는 상단에 위치한다 * refactor: TimelineViewModel 생성 팩토리 메서드 활용 * style: ktlint 적용 * ui: 화면 전환에 사용될 twin animation 효과 생성 * ui: animation 효과 활용하여 화면 전환 애니메이션 적용 * ui: Main 화면의 배경 색을 하얀색(#FFFFFF)으로 지정 * style: ktlint 적용 * feat: 기분 선택 기능 구현 및 스타카토 조회 화면 구조 변경 #191 (#289) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * style: ktlint 적용 * feat: 추억 API 변경사항 반영 및 리팩터링 #259 (#265) * ui: 추억 생성 화면 사진 로드 시 coil 라이브러리 사용 * ui: 삭제 버튼 아이콘 추가 * ui: 추억 생성 화면 사진 삭제 버튼 추가 * feat: 추억 생성 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 생성 화면 사진 삭제 구현 * feat: 추억 수정 화면 사진 첨부 icon 가시성 설정 * ui: 추억 수정 화면 사진 삭제 버튼 추가 * feat: 추억 수정 화면 사진 삭제 버튼 가시성 설정 * feat: 추억 수정 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 수정 화면 사진 삭제 구현 * fix: 추억 생성 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * fix: 추억 수정 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * feat: MemoryRequest dto에 썸네일 사진 url 필드 추가 * feat: 추억 생성 메서드의 시그니처 변경 - MemoryApiService 내 추억 생성 메서드의 시그니처 변경 - 위 변경에 따른 DataSource, Repository, ViewModel의 추억 생성 관련 메서드 시그니처 변경 * feat: 추억 생성 view model 주 생성자로 ImageRepository 주입 * feat: 추억 생성 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 생성 화면) - 추억 생성 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 생성 시 썸네일 사진 url 추가 * refactor: MemoryRequest의 추억 썸네일 사진 기본 인자 값 null로 설정 * feat: 추억 수정 메서드의 시그니처 변경 * feat: 추억 수정 view model 주 생성자로 ImageRepository 주입 * feat: 추억 수정 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 수정 화면) - 추억 수정 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 수정 시 썸네일 사진 url 추가 * refactor: 불필요한 MemoryUpdateRequest 제거 * ui: empty view 캐릭터 이미지 추가 * ui: 추억 설명글 유무에 따른 가시성 설정 * ui: 함께 한 사람들 가시성 gone 으로 설정 - 4차 스프린트 범위에서 제외됨 * feat: 이미지 선택 옵션 추가 (단일 선택 및 다중 선택 지원) * ui: TextInputLayout, TextInputEditText Style 정의 * ui: 추억 생성 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 수정 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 조회 화면 썸네일 사진 유무에 따른 가시성 설정 * ui: empty view 캐릭터 이미지 크기 변경 * ui: 앱 이름 Staccato_AN -> Staccato 로 수정 * refactor: 추억 생성 및 수정 화면 메서드 순서 정리 * ui: 제목용 TextInputEditTextStyle 정의 및 적용 * ui: 추억 생성 및 수정 화면 썸네일 coilPlaceHolder 변경 - 이전: shape_place_holder_rectangle - 이후: shape_all_gray1_8dp * refactor: 삭제 다이얼로그 show 메서드 호출 방식 변경 - apply를 사용하지 않는 방식으로 변경 * ui: 코멘트 미지원 안내 view 추가 * feat: 스타카토 생성, 수정 화면 사진 및 완료 버튼 개선 #242 (#291) * feat: (스타카토 생성 화면) 사진 드래그로 순서 변경 기능 구현 * refactor: data 패키지에 S3 이미지 API 분리 적용 * refactor: AttachedPhotoUiModel 및 프로그래스바 추가 * feat: recyclerView에서 지워진 사진의 job cancel 처리 * refactor: editText를 TextInputLayout로 수정 * feat: (스타카토 수정 화면) 사진 드래그로 순서 변경 / 로딩 구현 * refactor: 프로퍼티 네임 변경 및 visitedAt LocalDateTime으로 수정 * style: ktlint 적용 * build: 구글 맵 API 사용에 따른 CI 수정 #296 (#297) * build: 구글 맵 api key를 저장하는 파일을 설정하는 명령어 작성 * refactor: defaults 에 설정된 shell 설정에 따라 추가적인 shell 설정 삭제 * feat: Google Map 연결, 스타카토 목록 조회 API 연결 #54 (#295) * build: google map 의존성 추가 * build: 구글맵 관련 properties ignore 추가 * build: 구글맵 api key 설정 * feat: Google Map 연결 * feat: MainActivity Handler 구현 * ui: 추억 및 스타카토 생성 메뉴 추가 * ui: popup menu style 정의 * feat: 추억 생성 및 수정 menu 연결 - handler 연결 - 메서드 분리 * feat: 위치 권한 요청 구현 - ACCESS_FINE_LOCATION 권한 요청 - ACCESS_COARSE_LOCATION 권한 요청 * feat: 현 위치 표시 * style: MainActivity formatting * feat: locationPermissions 타입 변경 - 이전: List - 이후: Array * feat: MomentLocationDto, MomentLocationResponse 추가 * feat: 스타카토 목록 조회 api service 구현 * feat: 스타카토 목록 조회 data source 구현 * feat: MomentLocation 도메인 모델 구현 * feat: MomentLocationDto를 도메인 모델로 변환하는 mapper 구현 * feat: 스타카토 목록 조회 repository 구현 * feat: 스타카토 목록 조회 view model 구현 * feat: 스타카토 목록을 marker로 표시 * refactor: home 패키지명을 maps로 변경 * feat: 마커 클릭 시 스타카토 상세로 이동 기능 구현 * feat: 스타카토 조회 추억 id, 제목 필드 추가 * feat: 마지막 위치 위경도 찾기 * refactor: 안드로이드 1차 QA 반영 #299 (#301) * refactor: 안드로이드 1차 QA 반영 * refactor: 안드로이드 1차 QA 반영2 * refactor: 안드로이드 1차 QA 반영3 * refactor: 삭제 메시지 변경 * fix: 스타카토 조회 화면 스택 관리 및 ui 수정 #304 (#306) * feat: 지도 화면에서 스타카토 조회 화면으로 이동 시 스택 관리 * feat: 타임라인 화면에서 추억이 존재하지 않을 때 추억 생성 버튼 추가 * ui: 스타카토 조회 화면 툴바 위치 고정 * build: Android CD 적용 #300 (#308) * build: CD 워크플로우 yml 파일 작성 * build: keystore 접근을 위한 build.gradle.kts 파일 설정 * build: 기존 apk 추출 ci 파일 수정 - demo 버전의 apk를 추출 및 배포하는 목적에 맞게 파일 명 수정 - apk 빌드 후 테스트를 수행하는 job 추가 - firebase 앱 배포에 아티팩트 업로드하는 job 추가 * fix: ci 파일에도 keystore 생성 job 추가 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: ci 파일에 키스토어 관련 설정 적용 * fix: 키스토어 관련 명령어 일부 수정 * fix: build.gradle.kts 불필요한 괄호 제거 * fix: keystore.properties 로 부터 프로퍼티를 가져오는 형식 변경 * fix: upload-artifact step에서 빌드 파일의 upload 경로 수정 (#316) upload-artifact 는 defaults 설정의 working-directory 경로가 적용되지 않음 * fix: android cd 재수정 (2차) #317 (#319) * fix: upload-artifact 빌드 파일의 upload 경로 3차 수정 * fix: 배포 시 빌드 파일의 경로 수정 * fix: 빌드 파일의 upload 경로 수정 및 파일이 없는 경우 에러 처리 * fix: 빌드 파일의 upload 경로 4차 수정 * fix: 빌드 파일의 upload 경로 5차 수정 * fix: 빌드 파일의 upload 경로 6차 수정 - 디렉터리 경로 생성 후 upload 실행 * fix: 빌드 파일의 upload 경로 7차 수정 github의 workspace 환경변수(절대경로) 활용 * fix: clean test 제거 및 디버그용 파일 경로 탐색 명령어 추가 * fix: 디버그용 파일 경로 검색 명령어 수정 * fix: 디버그용 파일 경로 검색 명령어 삭제 * fix: 디버그용 파일 검색 명령어 삭제 및 업로드 파일 경로명 수정 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 기능 구현 #314 (#324) * feat: MainActivity에서 주소를 가져오는 로직 삭제 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 로직 구현 * refactor: 메서드 순서 정렬 * refactor: 스타카토 조회 화면 ViewPager2 적용 및 UI 아이콘 개선 #318 (#320) * refactor: 아이콘 추가 및 UI 개선 * feat: 스타카토 상세 사진 Viewpager 적용 * feat: 스타카토 상세 사진 Viewpager에 dot indicator 추가 * style: ktLint Format * feat: 메인 지도 화면에서 스타카토 생성하는 플로우 구현 #321 (#327) * feat: 날짜로 추억 목록 불러오는 getMemories API 추가 * feat: 메인에서 스타카토 생성 시 추억 목록 선택 가능 * feat: 스타카토 생성 시 역지오코딩과 추억 선택 연동 * build: debug와 release로 buildTypes 분리 (#329) - appName, appId, baseUrl 분리 - release에 난독화 적용 * build: debug 와 release 배포 분기에 따른 CD 수정 - CD에 대한 트리거 재설정 : main 브랜치에 대한 push 및 pr * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 #326 (#330) * refactor: 지도 화면 onResume에서 스타카토 목록 load * refactor: 스타카토 목록 로드 메서드명 변경 - 이전: loadMoments - 이후: loadStaccatos * feat: 공유 view model에 스타카토 목록 업데이트 상태 추가 * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 * feat: 지도 로드 시 현위치로 이동하도록 구현 * build: ci 및 cd 파일 수정 ci - 불필요한 gradle 빌드 및 테스트 제거 cd - 타겟 브랜치 develop 제거 * feat: 댓글 조회, 생성, 삭제 기능 구현 #290 (#331) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * ui: xml 컨벤션에 맞추어진 타 사용자의 댓글 ui 구성 * feat: 댓글 API의 DTO 작성 * feat: 댓글 API Service 작성 * feat: 댓글 CRUD DataSource 작성 * refactor: CommentApiService 각 메서드의 반환 값을 Response로 변경 * feat: CommentApiService 를 create * feat: CommentDataSource 구현체 생성 * refactor: 댓글 Dto 클래스 네이밍 변경 - VisitLogDto -> CommentDto * refactor: CommentDto 의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * refactor: VisitLog 도메인 모델 클래스의 네이밍 변경 - VisitLog -> Comment * refactor: Comment 도메인 모델의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * feat: 새로운 댓글 도메인 모델 생성 * feat: CommentRepository 작성 * feat: Domain 모델과 DTO 모델을 변환해주는 Mapper 작성 - CommentDto를 Comment로 변환하는 메서드를 CommentMapper.kt로 이동 * feat: CommentRepository의 기본 구현체 작성 * feat: 댓글 ViewModel, Factory 작성 및 Comment 불러오기 구현 * ui: ViewModel 데이터바인딩 및 빈 댓글 문구에 대한 strings 설정 * feat: CommentsViewModel 활용 및 옵저빙 * feat: 댓글 조회, 생성, 삭제 기능 구현 * chore: ktlint 적용 * feat: 추억 생성 및 수정 이미지 로딩 중 표시 및 저장 버튼 비활성화 #332 (#334) * feat: 추억 생성 이미지 로딩 중 표시 * feat: 추억 수정 이미지 로딩 중 표시 * feat: 추억 생성 및 수정 이미지 로딩 중 저장 버튼 비활성화 * style: formatting * refactor: 댓글 화면 개선 및 리팩터링 #333 (#335) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 --------- Co-authored-by: hxeyexn Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: s6m1n * docs: 서비스 소개 수정 * chore: main ci 트리거 수정 * fix: 구글 플레이 스토어 자동 배포 비활성화 * build: defaultConfig의 버전 코드와 이름 수정 versionCode : 2 -> 3 versionName : 1.1 -> 1.0.0 (배포 버전과 동일) * build: Android Config의 버전 코드 및 이름 변경 #338 (#339) * build: 프로젝트 생성 및 의존성 추가 * chore: 사용자 기능 및 권한 추가 * chore: gitignore 재설정 * chore: gitigonre .idea/ 추가 * build: develop-an 브랜치의 CI 설정 #3 (#10) * build: android-ci.yml 파일 생성 * chore: 오타 및 개행 수정 * chore: working-directory 수정 * build: ktLint 적용 및 format * ui: 디자인 시스템 구현 #11 (#44) * ui: color 정의 * ui: shape, selector 추가 * ui: icon 추가 * ui: font family 추가 - pretendard regular, medium, semibold, bold 추가 * ui: typography 정의 * ui: strings 정의 * ui: bottom sheet drag handle drawable 추가 * ui: styles 정의 * ui: detail toolbar 구현 - 상세 화면에서 사용 * ui: dialog, bottom sheet 구현 - 여행 및 방문 기록 삭제 dialog - 사진 등록 bottom sheet * ui: 사진 첨부 layout 구현 * feat: 삭제 다이얼로그, 사진 첨부 바텀 시트 fragment 추가 * ui: 세로모드로 고정 * build: data binding 의존성 추가 * style: strings resource 순서 정렬 * style: formatting * ui: plus icon 추가 * feat: jetpack navigation 및 바텀시트 프래그먼트 추가 #12 (#15) * build: androidx.navigation 및 dataBinding 의존성 추가 * feat: Binding 화면 클래스 및 bottomSheetNavigation 추가 * feat: TimelineFragment 임시 화면 추가 * feat: TravelFragment 임시 화면 추가 * feat: TravelCreationFragment 임시 화면 추가 * feat: VisitFragment 임시 화면 추가 * feat: VisitCreationFragment 임시 화면 추가 * feat: (여행, 방문 기록) 수정 화면 추가 * feat: (여행, 방문 기록) 생성 화면 이동 구현 * feat: BottomSheetController 설정 및 Navigation 이동 구현 * feat: 뒤로가기 버튼 클릭 시 BottomSheet, Toast 작동 구현 * feat: 여행, 방문 기록 생성을 위한 액티비티 추가 및 이동 구현 * feat: 여행, 방문 기록 수정을 위한 액티비티 추가 및 이동 구현 * build: 중복된 dataBinding 제거 * feat: 공통 이미지 로딩 BindingAdapter 설정 #33 (#41) * build: dataBinding 사용 설정 * feat: 이미지 로딩 바인딩 어댑터 설정 - Glide, Coil 바인딩 어댑터를 각각 작성 - placeholder 설정 * style: ktlint check - import 순서 조정 * fix: attribute 개수에 맞추어 BindingAdapter의 value 재설정 * style: 마지막 줄 개행 추가 * feat: placeHolder를 필수 속성으로 변경 및 coil 이미지 로딩 코드 수정 - placeHolder를 ImageView의 필수 속성으로 지정 - Coil BindingAdapter에서 url이 null인 경우에도 이미지를 로드하는 동작이 수행되도록 수정 * ui: 상단바 색상 변경 * build: develop-an의 CI 설정 수정 #38 (#39) - Git Action에 Secret으로 저장된 LOCAL_PROPERTIES_API_KEY를 변수로 가져온다. - 가져온 변수를 echo를 활용하여 local.properties에 설정한다. * build: develop-an 브랜치의 CI 파일 문법 오류 수정 #45 (#46) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: android-ci.yml 파일의 명령어 수정 #47 (#48) LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 * fix: develop-an 브랜치의 CI 파일 명령어 재수정 #47 (#49) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> * fix: 문자열 임을 명시하고 환경변수 설정 위치 조정 * fix: local.properties 생성 시점 수정 * feat: 데이터 패키지 설정 #13 (#35) * build: 서버 base url의 local.properties 사용 설정 및 BuildConfig 설정 * feat: Retrofit Client 작성 * fix: Merge Conflict 해결 - build.gradle.kts(project, app)의 ktlint 의존성 충돌 해결 - 버전 카탈로그 플러그인 충돌 해결 * feat: DTO 클래스 작성 * style: ktlint check - 불필요한 import 제거 - 개행 조정 - 콤마 추가 * feat: SerialName 어노테이션의 값을 camelCase로 수정 * refactor: DTO 클래스의 이름 수정 - API 요청으로 직접 보내거나 들어오는 JSON의 경우 DTO 클래스명 뒤에 Request/Response 를 붙이도록 설정 - JSON 안에 속성 값으로 들어가는 JSON은 DTO 클래스명 뒤에 Dto를 붙이도록 설정 * feat: 누락된 Dto 클래스 추가 TimelineResponse.kt - 타임라인 조회 시 여행 상세 목록을 불러올 때 사용되는 DTO 클래스 - TimelineTravelDto 리스트를 갖는다 * style: ktlint check * fix: const 키워드 제거 --------- Co-authored-by: hxeyexn * feat: 둥근 모서리의 이미지를 로드하는 BindingAdapters 추가 #58 (#59) * feat: 둥근 모서리로 이미지를 로딩하는 Glide 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - glideRoundedCornerImageUrl: 출력하고자 하는 이미지 url - glidePlaceHolder: placeHolder의 url - glideRoundingRadius: 모서리의 둥근 정도를 Int로 설정 * feat: 둥근 모서리로 이미지를 로딩하는 Coil 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - coilRoundedCornerImageUrl: 출력하고자 하는 이미지 url - coilPlaceHolder: placeHolder의 url - coilRoundingRadius: 모서리의 둥근 정도를 Float으로 설정 * fix: centerCrop 설정을 BindingAdapter 에 위임 - xml 속성으로 centerCrop을 주게 되면 Round Corner가 제대로 적용되지 않는 현상 발생 - Glide의 api로 제공되는 centerCrop() 메서드를 활용 * ui: 타임라인 프래그먼트(BottomSheet) 구현 #55 (#71) * ui: 타임라인 View xml 파일 작성 - 타임라인에 나타날 여행 상세 아이템 xml 작성 - 썸네일 사진 유무에 따라 뷰를 구분 - 타임라인이 나타날 fragment xml 작성 * feat: 타임라인 여행 상세 아이템 UI 모델 생성 * ui: 썸네일이 없는 여행상세 아이템의 margin 조정 * ui: Timeline RecyclerView의 layoutManager 설정 * ui: xml에서의 UiModel 데이터 바인딩 설정 * feat: ViewHolder 작성 - 썸네일 사진 유무에 따라 다른 ViewHolder로 구분 - 공통된 속성을 정의한 TimelineViewHolder 추상클래스 생성 * feat: TimelineRepository Interface 생성 * feat: 임시 TimelineRepository 구현체 생성 * feat: TimelineViewModel 및 Factory 생성 * feat: TimelineViewType 작성 * feat: TimelineAdapter 작성 * feat: TimelineFragment에 ViewModel과 Adapter 구현 * feat: 이미지 로딩 PlaceHolder drawable 추가 및 적용 * feat: 임시 데이터 연결 * ui: Timeline fragment 의 세부 설정 조정 * ui: Timeline의 Item xml 변경 - 뷰 타입을 3개로 분할: 첫 번째 아이템, 중간 아이템, 마지막 아이템 - 이에 따라 xml 파일 추가 및 view 수정 * feat: ViewType 변경에 따른 Adapter 및 ViewHolder 수정 * refactor: 불필요한 View 및 ViewHolder 제거 * feat: 여행 click 에 대한 event handler 생성 및 설정 * refactor: drawable 이름을 네이밍 컨벤션에 맞게 수정 * ui: RecyclerView의 마진 속성을 패딩 속성으로 변경 * feat: 바텀 시트 디자인 변경 및 툴바와의 상호작용 구현 * ui: 타임라인 글귀 추가 * style: ktlint check * ui: 둥근 모서리의 이미지로 변경 * ui: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 구현 #52 (#74) * ui: typography.body textSize 1sp 씩 증가 * feat: DeleteDialogFragment에 Handler 추가 * feat: 툴바의 수정, 삭제 버튼 제어를 위한 ToolbarHandler 추가 * feat: 방문 상세 화면을 위한 VisitDetailUiModel 추가 * ui: PlaceHolder를 위한 xml 파일 추가 * feat: 방문 기록 상세 화면을 위한 VisitAdapter 및 VisitViewHolder 구현 * feat: 임시 VisitViewModel와 VisitViewModelFactory 추가 * feat: VisitFragment 화면 구현 * feat: 방문 기록에 해당하는 여행 선택을 위한 TravelSelectionFragment 구현 * feat: 방문 기록에 해당하는 날짜 선택을 위한 VisitedAtSelectionFragment 구현 * feat: 방문 기록 생성을 위한 VisitCreationActivity 구현 * feat: 방문 기록 수정을 위한 VisitUpdateActivity 구현 * refactor: DialogHandler를 DeleteDialogFragment의 생성자에서 받도록 수정 * refactor: initVisitUpdateDoneButton 중복 로직 제거 * refactor: VisitViewHolderType 메서드 명 변경 of -> from * refactor: tv_place_name_title을 xml id convention에 맞게 수정 * ui: 여행 화면 구현 #51 (#75) * ui: 함께 간 사람들 item 구현 * ui: 방문 기록 item 구현 * ui: 여행 상세 화면 구현 * ui: 여행 생성 화면 구현 * ui: 여행 수정 화면 구현 * ui: placeholder에 사용할 drawable 추가 * ui: 여행 삭제 완료 string 추가 * feat: 둥근 모서리 이미지 BindingAdapter 구현 * feat: 함께 간 사람들 adapter 구현 * ui: 여행 상세 화면 NestedScrollView로 변경 - 이전: ScrollView - 이후: NestedScrollView * feat: 방문 기록 adapter 구현 * feat: 여행 상세 view 연결 * feat: 함께 간 사람들, 방문 기록 adapter 연결 * feat: 삭제 다이얼로그 handler 구현 * feat: 여행 상세 화면 toolbar handler 구현 - 뒤로가기 - 여행 수정 화면으로 이동 - 삭제 다이얼로그 show * feat: 여행 -> 방문 기록 화면 이동 구현 * ui: DatePickerStyle 추가 - DatePickerStyle, CustomMaterialCalendarStyle 추가 - staccato_blue 투명도 30 추가 * feat: 여행 저장 버튼, 여행 기간 BindingAdapter 추가 * feat: 여행 생성 view 연결 * feat: 여행 수정 view 연결 * style: formatting - Exceeded max line length 해결 - 임시 이미지 URL 변경 * refactor: 기간 선택 로직 메서드 분리 * feat: 타임라인의 API 적용 및 MainActivity의 Toolbar 제거 #81 (#93) * refactor: UI Model의 패키지 경로 변경 * refactor: API 명세 변경에 따른 TimelineTravelDto 수정 * refactor: repository 메서드 수정 - 서버 요청을 비동기적으로 처리하기 위해 suspend 키워드 삽입 - 기존의 임시 데이터 요청 코드를 위해 load 메서드 분리 * feat: Timeline의 API Service 작성 * feat: DataSource 인터페이스 작성 * feat: TimelineDataSource 구현체 생성 * refactor: 년도에 대한 default parameter 설정 * refactor: DataSource의 요청 메서드 네이밍 수정 * feat: http 통신이 가능하도록 Cleartext Traffic 허용 설정 * feat: Authorization Header를 삽입하기 위한 Interceptor 생성 * feat: Client에 HeaderInterceptor 추가 * refactor: errorBody의 message 속성 이름 변경 * feat: 도메인 모델 작성 * feat: Response(dto)에서 도메인 모델로 변환하는 확장함수 구현 * feat: 도메인 모델에서 UI 모델로 변환하는 확장함수 구현 * feat: Repository 수정 및 ViewModel 데이터 연결 * ui: MainActivity의 상단 툴바 제거 * refactor: ViewType에 viewType 속성 추가 및 when에서의 enum 활용 * refactor: Timeline의 공통 ViewHolder를 sealed class로 변경 * style: ktlint check 수행 * fix: Response 데이터의 nullable 속성에 맞추어 DTO 수정 및 누락된 DTO 추가 * fix: 데이터가 비어있는 경우(초기)에만 새로운 여행상세 목록을 받도록 수정 * refactor: lazy 로 지연 초기화 및 timelineService가 하나의 인스턴스로 관리되도록 수정 * fix: Travel의 description에 nullable 속성 추가 API 명세서 잘 좀 보자 제발 * refactor: create 메서드를 private으로 변경 Client 클래스에서 Service를 create 하여 제공 및 캐싱하기 때문에, 불필요한 인스턴스를 생성하지 않도록 create를 public으로 두지 않는 것이 좋다. * refactor: LocalDateConverters의 패키지 경로 수정 * refactor: 파일의 이름 수정 * style: ktlint check * refactor: 에러 메시지 상수화 * feat: 특정 여행 상세 조회 api 연결 #82 (#97) * feat: 특정 여행 상세 조회 api service 구현 * feat: 썸네일, 소개 타입 변경 및 기본 인자 설정 - 변경 data class : TravelResponse, TravelUiModel - 이전: String - 이후: String? * refactor: MatesUiModel 네이밍 변경 MatesUiModel이 공통적으로 사용될 예정이므로 MemberUiModel로 변경 - 이전: MatesUiModel - 이후: MemberUiModel * refactor: VisitUiModel 네이밍 변경 - 여행 상세 방문 기록에 사용되는 UiModel 이름을 명시적으로 변경 - 이전: VisitUiModel - 이후: TravelVisitUiModel * feat: 특정 여행 상세 조회에 사용할 domain model 추가 * feat: Api 응답 핸들링 로직 구현 * feat: 특정 여행 상세 조회 data source 구현 * feat: 특정 여행 상세 조회 repository 구현 * feat: 특정 여행 상세 조회 api 연결 * feat: 특정 여행 상세 조회 로직 매개변수 추가 - 타임라인에서 선택된 여행 id를 매개변수로 받도록 변경 * refactor: ApiResponseHandler 이름 오타 수정 * refactor: 에러 메세지 상수화 * feat: 특정 여행 상세 조회 시그니처 변경 - HeaderInterceptor 적용으로 authorization 매개변수 제거 * style: formatting * feat: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 API 연결 #79 (#99) * feat: VisitApiService 인터페이스 및 관련 data class 추가 * feat: VisitRepository, RemoteVisitDataSource 및 관련 class 추가 * feat: 각 Visit 화면들의 ViewModelFactory 구현 * feat: 각 Visit 화면들의 UiModel 클래스 및 Mapper 추가 * feat: 여행 선택 및 방문 날짜 선택을 위한 BottomSheetDialogFragment 수정 * feat: VisitFragment API 연결 * feat: VisitCreationActivity API 연결 * feat: VisitUpdateActivity API 연결 준비 * refactor: visitApiService를 StaccatoClient object로 이동 * refactor: TravelVisit 클래스의 visitImage 변수 nullable하게 수정 * refactor: VisitApiService의 중복된 @Header 제거 * refactor: 방문 생성 성공 시 created id를 가져오도록 리팩터링 * chore: 변수명 visitImage로 수정 및 ktLint 적용 * refactor: 여행 수정 완료 동작 구현 및 VisitUpdateActivity 함수 분리 * feat: 여행 생성 api 연결 #98 (#104) * feat: 여행 생성 api service 구현 * feat: 여행 생성 data source 구현 * feat: 방문 기록 썸네일 타입 변경 및 기본 인자 설정 - 변경 data class :  TravelVisitDto, TravelVisit, TravelVisitUiModel - 이전: String - 이후: String? * build: converter scalars 의존성 추가 * feat: 여행 생성 ApiService 반환값 및 DataSource 시그니처 변경 - 여행 생성 ApiService 반환값 변경 - DataSource 시그니처 변경 - TravelCreation DomainModel 구현 - TravelCreation Dto 변환 Mapper 구현 * feat: Client에 ScalarsConvert 추가 - Header 값을 읽어오기 위해 ScalarsConvert 추가 * feat: 여행 생성 repository 구현 * feat: 여행 생성 api 연결 * feat: TravelViewModel 생성자 변경 - 이전: travelId를 TravelViewModel 생성자로 넣어줌 - 이후: travelId를 loadTravel()의 매개변수로 넣어줌 * ui: map 화면 변경 * refactor: 컨벤션 통일 및 패키지 정리 #112 (#118) * refactor: bind 네임스페이스 적용 * refactor: BindingAdapters 메서드명 변경 * refactor: 컨벤션 맞게 xml 파일 이름 변경 * refactor: data 패키지 구조 정리 * refactor: RemoteVisitDataSource 컨벤션 따라 네이밍 변경 * refactor: 네트워킹 관련 메서드 이름 변경 - api service, data source, repository * refactor: presentation 패키지 구조 정리 * refactor: message utils 생성 및 적용 Co-authored-by: s6m1n Co-authored-by: Junyoung-WON * build: develop-an의 CI 테스트 자동화 추가 및 데모 APK 추출 #78 (#92) * build: test 자동화 Job 추가 * build: local.properties 생성 시점 변경 * build: 디버그 APK를 빌드하여 업로드하는 workflow 작성 * fix: test Job과 APK build Job에 local.properties 생성 동작 추가 * build: read 전용 권한 제거 * build: Firebase Analytics, Crashlytics 설정 #136 (#143) * build: Firebase Analytics, Crashlytics 의존성 추가 * chore: google-service.json ignore * feat: 특정 여행 상세 수정 api 연결 #109 (#146) * feat: 여행 수정 api service 구현 * feat: 여행 수정 data source 구현 * feat: 여행 수정 repository 구현 * feat: 여행 수정 화면 현재 데이터 로딩 기능 구현 * refactor: 컨벤션 따라 여행 api service의 수정 메서드명 변경 - 이전: updateTravel - 이후: putTravel * feat: 특정 여행 상세 수정 api 연결 * refactor: memberImage 타입 변경 및 기본 인자 설정 * refactor: MembersDto 삭제 * refactor: TravelCreationUiModel.kt 삭제 * refactor: TravelCreation 이름 변경 - 이전: TravelCreation - 이후: NewTravel * refactor: api 명세서 변경에 따른 도메인 모델 수정 및 여행 코드 리팩터링 #151 (#152) * refactor: nickName 변수명 변경 - 이전: nickName - 이후: nickname * ui: 여행 수정 화면 이미지 속성 수정 - glide -> coil 이용 - scaleType : fitXY -> centerCrop * style: import 정렬 * feat: 여행 상세 -> 방문 상세로 이동 시 여행 id 전달 * feat: 방문기록 조회 dto 수정 - 방문기록 조회 도메인 변경으로 인해 방문 기록이 조회되지 않음 - 따라서 api 명세서와 일치하도록 dto 수정하여 오류 해결 * refactor: 여행 생성을 위한 viewModel 메서드 분리 * refactor: 여행 조회를 위한 viewModel 메서드 분리 * feat: 여행 수정 handler 구현 * refactor: 여행 default id 변경 - 이전: -1L - 이후: 0L * refactor: TravelHandler 구현 위치 변경 - 이전: TravelViewModel - 이후: TravelFragment * style: 컨벤션에 맞게 TravelFragment의 메서드 순서 수정 * refactor: TravelFragment의 travelId 초기화 방식 변경 * feat: 여행 생성 및 수정 error toast 구현 * feat: 방문 생성 화면, 방문 수정 화면에서 갤러리 사진 불러오기 구현 #150 (#155) * feat: PhotoAttachFragment에 PhotoAttachHandler 연결 * feat: PhotoAttachFragment 앨범 접근 권한 관련 로직 구현 - API level 33 이상 : READ_MEDIA_IMAGES - API level 33 이하 : READ_EXTERNAL_STORAGE - ActivityResultLauncher를 이용한 권한 요청 - 권한 거부 시, 설정으로 이동하는 스낵바 띄우기 * feat: PhotoAttachFragment 앨범에서 불러온 이미지의 URI 추출하기 * feat: 불러온 이미지의 URI를 호스트 Activity로 전달 - OnUrisSelectedListener 인터페이스 추가 * feat: Uri를 File로 변환하는 메서드 파일 추가 * refactor: pr 리뷰 반영 * refactor: pr 리뷰 반영2 * build: develop-an의 android-ci 수정 #115 (#160) - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: android-ci 환경변수 생성 위치 조정 (#164) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * build: bash 쉘에 맞는 명령어 활용 #115 (#165) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * fix: bash 쉘에 적합한 명령어 형식으로 변경 * feat: 특정 여행 상세 삭제 api 연결 #153 (#167) * feat: 특정 여행 삭제 api service 구현 * feat: 특정 여행 삭제 data source 구현 * feat: 특정 여행 삭제 repository 구현 * feat: 특정 여행 삭제 기능 api 연결 * feat: error handling 방식 수정 - 서버에서 들어오는 error body의 status와 message를 활용하는 방식으로 변경 * refactor: DialogHandler를 독립적으로 관리 * refactor: api path 상수 활용 * refactor: BuildConfig에 token 정의 * refactor: DEFAULT_VALUE 상수 제거 * feat: 여행 생성 기능 api 수정 #169 (#178) * feat: onUrisSelected 매개변수 가변인자로 변경 * feat: 여행 생성 화면 갤러리 이미지 로딩 기능 구현 * refactor: 이미지 선택 리스너 초기화 메서드명 오타 수정 * refactor: 스낵바 액션 설정 코드 간소화 * feat: TravelRequest 의 여행 썸네일 필드 제거 * refactor: 여행 썸네일 이미지 변수명 수정 * feat: 이미지 전송 기능 구현 * refactor: image url 변수명 변경 - 변수 끝에 url이 오도록 * feat: 여행 생성 progressBar 구현 * ui: 사진 첨부 아이콘 가시성 설정 * feat: 여행 상세 수정 기능 api 변경 및 여행 리팩터링 #180 (#181) * feat: 여행 수정 화면 갤러리 이미지 로딩 기능 구현 * feat: URL 및 URI 기반 이미지 로딩 BindingAdapter 구현 * feat: 이미지 전송 기능 구현 * feat: 여행 수정 progressBar 구현 * fix: 삭제 불가능한 여행 삭제 시도 관련 에러 토스트 문제 해결 삭제 불가능한 여행을 삭제하려고 시도 -> 방문 조회 -> 뒤로 가기 버튼 클릭 -> 삭제 불가능 에러 토스트가 다시 뜨는 문제가 발생해 이를 해결 * refactor: TravelCreationViewModel의 imageUrl 변수 제거 * ui: 여행 상세 내 방문 기록 이미지 scaleType 속성 설정 * ui: 여행 생성 썸네일 이미지 scaleType 속성 설정 * fix: 여행 소개 미입력 시 여행이 생성 되지 않는 오류 해결 * refactor: 타임라인 화면 리팩터링 #162 (#179) * ui: 타임라인 RecyclerView의 크기 조정 및 여백 수정 * feat: Activity와 Fragment 간 데이터를 공유하는 공유 ViewModel 생성 * feat: 공유 ViewModel을 이용하여 타임라인 업데이트 여부를 공유 * refactor: RecyclerView.Adapter에서 ListAdapter로 변환 * refactor: 처음 타임라인을 불러오는 동작을 ViewModel 초기화 시에 수행 * fix: ListAdapter 수정 - 불필요한 travels 프로퍼티와 getItemCounts 메서드 제거 - currentList를 사용하는 것으로 변경 * refactor: 에러 핸들링 방식 수정 및 ViewModel 수정 - TimelineDefaultRepository로 네이밍 변경 - ApiResponseHandler와 ResponseResult를 이용하여 에러 핸들링 처리 - TimelineViewModel 에러 메시지 LiveData 사용 - 그 외 repository, dataSource 프로퍼티 이름 수정하여 통일 * refactor: MutableLiveData의 값 업데이트를 setValue로 변경 및 메서드 분리 * style: ktlint 적용 * feat: 3차 스프린트에서 수정된 방문 기록 상세 API 연결 #163 (#183) * feat: 방문 상세 생성 API 연결 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 방문 기록 생성 및 수정 시 로딩과 토스트 추가 * feat: 닉네임을 활용한 로그인 기능 구현 #124 (#172) * ui: 로그인 화면 구성 - 로그인 화면에서 사용되는 텍스트를 strings에 추가 - 로그인 버튼 스타일에 대한 style 생성 - xml 임시로 작성 * ui: 앱 로고 삽입 및 margin 조정 - 임시 로고 이미지 저장 - 로고 크기 및 마진 조정 * feat: 로그인 API Service 작성 및 Retrofit 객체 생성 * feat: 로그인 DataSource 작성 * feat: 로그인 Repository 생성 * feat: 사용자 정보를 저장하는 SharedPreferences Manager 생성 - 토큰 값 불러오기 및 저장 - 추후 사용자 닉네임, 사용자 프로필 이미지 등의 정보 저장 가능 * feat: Application 생성 및 사용자 정보 Preferences Manager 캐싱 * ui: Splash Screen 화면 구성을 위한 테마 생성 * feat: Preferences 로부터 사용자 토큰 값을 가져와 헤더에 추가하도록 변경 * refactor: Repository 네이밍 통일 * refactor: DataSource 기본 인자 추가 * feat: LoginViewModel 및 Handler 작성 * feat: LoginViewModel 을 생성하는 ViewModel Factory 작성 * feat: LoginActivity 작성 및 양방향 데이터 바인딩 적용 * feat: StaccatoApplication과 LoginActivity 설정 및 LoginActivity를 시작 화면으로 변경 * style: 불필요한 namespace 제거 및 lint 확인 * refactor: LoginViewModel과 Factory를 viewmodel 패키지로 분리 * refactor: TimelineViewModel과 Factory를 viewmodel 패키지로 분리 * style: ktlint 적용 * fix: 불필요한 ConverterFactory 제거 - 더 이상 사용하지 않는 text/plain 변환용 ScalarsConverterFactory 제거 * feat: 닉네임 로그인 요청 및 응답에 대한 DTO 작성 * refactor: 로그인 요청, 응답 시 DTO 활용 * fix: 토큰 값을 불러오고 및 저장하는 동작의 비동기 처리 및 화면 전환 개선 * refactor: 토큰 값을 캐싱하여 저장하는 TokenManager 생성 및 적용 - 매번 runBlocking을 통해 Preference에 저장된 토큰 값을 불러오는 것은 네트워크 성능을 저하시킨다. - 따라서, token 값을 캐싱하여 저장하는 TokenManager를 활용한다. - 첫 네트워크 요청 시에만 토큰을 불러오는 작업을 동기적으로 처리하기 위해 Main Thread가 Blocking 된다. - TokenManager가 Preference로부터 가져온 토큰을 캐싱하여 저장한다. - 이후 요청부터는 캐시된 토큰을 가져오므로 Main Thread가 Blocking 되지 않는다. * style: ktlint 적용 * feat: Night 모드 비활성화 * refactor: 여행 기간 날짜 형식 변환을 BindingAdapter에서 수행 - TimelineTravelUiModel 프로퍼티 수정 - UiModel의 여행기간 날짜를 LocalDate로 갖도록 통일 - 추후 날짜 관련 UI가 변경되었을 때 확장성 고려 - BindingAdapters에 날짜 형식 변환해주는 메서드 작성 * chore: 주석 처리된 Log 코드 삭제 * style: xml View의 ID 네이밍 컨벤션 적용 * ui: 앱 심볼 로고 추가 및 스플래시 스크린에 적용 * feat: 방문 상세 생성 API 연결 * ui: 배경 색을 흰 색으로 지정 * feat: 키보드 활성화 상태에서 화면 터치 시 키보드를 내리는 기능 추가 * style: ktlint 적용 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * fix: merge 과정에서 발생한 id값 네이밍 충돌 해결 * build: 앱 version code와 version name 수정 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 스플래시 스크린 시간 조정 및 데모 시연용 토큰 활성화 * fix: 동일한 사진이 여러 장 업로드되는 버그 수정 * feat: 기존 로그인 기능으로 롤백 --------- Co-authored-by: somin * fix: 테스트 배포를 위한 버그 수정 #198 (#219) * style: formatting * fix: 무한 로딩 오류 수정 * fix: 여행 생성 오류 수정 * add: 앱 아이콘 변경 * ui: timeline empty view 추가 * feat: timeline empty view 가시성 설정 * ui: 여행 내 방문 기록 empty view 추가 및 가시성 설정 * ui: 방문 기록 내 로그 미지원 기능 view 추가 * feat: 사진 첨부 카메라 미지원 기능 알림 추가 * ui: 필수값 표기 style 정의 * ui: 여행 생성 및 수정 필수값 표기 추가 * ui: 방문 기록 생성 및 수정 필수값 표기 추가 * feat: 생성, 수정, 로그인 시 다중 요청 전송을 막기 위한 화면 터치 제한 * feat: 장소 생성의 사진 첨부 리사이클러뷰 구현 - 사진 추가 & 삭제 구현 - GridLayout으로 변경 - 사진 중복 없이 최대 5장으로 제한 - 새로 추가된 사진이 기존 사진 뒤에 더해지도록 구현 * chore: 방문 생성 화면 rv_photo_attach로 xml id 수정 * ui: app icon 및 splash icon 변경 * refactor: xml ID 네이밍 컨벤션 적용 --------- Co-authored-by: somin Co-authored-by: Junyoung-WON * refactor: 도메인명 변경에 따라 travel을 memory로 수정 #217 (#231) * refactor: 패키지명 travel -> memory로 수정 * refactor: dto의 TravelMapper 를 MemoryMapper 로 네이밍 변경 * refactor: 여행(현 추억) 생성 response dto 네이밍 변경 - TravelCreationResponse -> MemoryCreationResponse * refactor: 여행(현 추억) request dto 네이밍 변경 - TravelRequest -> MemoryRequest * refactor: 여행(현 추억) 조회 response dto 네이밍 변경 - TravelResponse -> MemoryResponse * refactor: 여행(현 추억) 수정 request dto 네이밍 변경 - TravelUpdateRequest -> MemoryUpdateRequest * refactor: 여행(현 추억) 내 방문 dto 네이밍 변경 - TravelVisitDto -> MemoryVisitDto * refactor: 타임라인 여행(현 추억) item의 dto 네이밍 변경 - TimelineTravelDto -> TimelineMemoryDto * refactor: 여행(현 추억) ApiService 네이밍 변경 - TravelApiService -> MemoryApiService * refactor: 여행(현 추억) DataSource 네이밍 변경 - TravelDataSource -> MemoryDataSource - TravelRemoteDataSource -> MemoryRemoteDataSource * refactor: 여행(현 추억) Repository 네이밍 변경 - TravelRepository -> MemoryRepository - TravelDefaultRepository -> MemoryDefaultRepository * style: TimelineMapper import 재정렬 * refactor: NewTravel 도메인명을 NewMemory로 변경 * refactor: Travel 도메인명을 Memory로 변경 * refactor: TravelVisit 도메인명을 MemoryVisit으로 변경 * refactor: presentation의 TravelMapper 명 변경 - TravelMapper -> MemoryMapper * refactor: 여행(현 추억) ui 모델명 변경 - TravelUiModel -> MemoryUiModel - TravelVisitUiModel -> MemoryVisitUiModel * refactor: 여행(현 추억) view model 명 변경 - TravelViewModel -> MemoryViewModel - TravelViewModelFactory -> MemoryViewModelFactory * refactor: MemoryApiService의 Path 변경 - travel을 memory로 변경 - travels을 memories로 변경 * refactor: Memory 관련 dto 변수명 변경 - travel을 memory로 변경 * refactor: Timeline Dto의 Memory 관련 변수명 변경 - travel을 memory로 변경 - travels를 memories로 변경 * refactor: Memory 관련 도메인 모델의 변수명 변경 - travel을 memory로 변경 * refactor: Memory 관련 ui 모델의 변수명 변경 - travel을 memory로 변경 * refactor: data layer의 Memory 관련 함수 및 변수명 변경 - travel을 memory로 변경 * refactor: 방문 생성 request dto의 travelId 변수명 변경 - travelId -> memoryId * refactor: 여행(현 추억) 조회 view model 및 fragment의 네이밍 변경 - travel -> memory * refactor: fragment_travel 의 리소스 네이밍 변경 - travel -> memory - strings.xml의 리소스명 변경 * refactor: TravelCreationActivity 네이밍 변경 - TravelCreationActivity -> MemoryCreationActivity * refactor: 여행(현 추억) 생성의 ViewModel 관련 네이밍 변경 - TravelCreationViewModel -> MemoryCreationViewModel - TravelCreationViewModelFactory -> MemoryCreationViewModelFactory - 관련 함수 및 변수명 변경 - travel -> memory * refactor: 여행(현 추억) 생성, 수정에 관한 xml 리소스 명 변경 - travel -> memory - strings.xml 의 관련 리소스 수정 * refactor: 여행(현 추억) 수정 Activity, Handler 의 네이밍 변경 - travel -> memory * refactor: 여행(현 추억) 수정 ViewModel 의 네이밍 변경 - 관련 함수 및 변수 명 변경 - travel -> memory - Factory 클래스명 변경 * refactor: 여행(현 추억) 생성, 수정에서의 파일 변환 메서드명 변경 - travel -> memory - 자식 파일 명 상수화 * refactor: Timeline 의 UI 모델 및 Travel ID Key 의 리네이밍 - travel -> memory 로 일괄 변경 * refactor: presentation/timeline 내 travel 도메인명 변경 - travel -> memory - TimelineMapper 내 domain model -> ui model 변환 메서드명 변경 * refactor: dto/MemoryMapper 내 domain 변환 메서드명 변경 - dto/MemoryMapper 내 domain model을 dto로 변환하는 메서드명 변경 - travel -> memory * refactor: dummyTravel 을 dummyMemory 로 변경 * refactor: MainActivity 내 travel을 memory로 변경 * refactor: activity_main 내 travel을 memory로 변경 * refactor: TimeLineApiService 내 GET 메서드 path 수정 - travels -> memories * refactor: MemoryFragment 내 travel 을 memory 로 변경 - MemoryFragment, fragment_memory 내 travel 을 memory 로 변경 * refactor: MemoryViewModel 내 error message 변수명 변경 - TRAVEL_ERROR_MESSAGE -> MEMORY_ERROR_MESSAGE * refactor: navigation graph 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 extra 키 값 수정 - TRAVEL_ID_KEY -> MEMORY_ID_KEY - TRAVEL_TITLE_KEY -> MEMORY_TITLE_KEY * refactor: VisitFragment 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 travel을 memory로 변경 * refactor: VisitUpdateViewModel 내 travel을 memory로 변경 * refactor: VisitTravelUiModel을 VisitMemoryUiModel로 변경 * refactor: 방문 수정 xml의 travel을 memory로 변경 * refactor: 여행(현 추억) 선택 xml 내 travel을 memory로 변경 * refactor: 여행 선택 바텀 시트 내 travel을 memory로 변경 - TravelSelectionFragment -> MemorySelectionFragment 로 수정 - TravelSelectionHandler -> MemorySelectionHandler 로 수정 - TravelSelectionFragment 내 메서드명 수정 - TravelSelectionHandler 내 매개변수명 수정 * refactor: VisitRepository와 구현체의 메서드 내 매개변수명 통일 * refactor: VisitsViewHolder 내 travel을 memory로 변경 * refactor: VisitCreationActivity 내 travel을 memory로 변경 * refactor: VisitCreationViewModel 내 travel을 memory로 변경 * refactor: 방문 생성 xml 내 travel을 memory로 변경 * refactor: BindingAdapters 내 travel을 memory로 변경 * refactor: strings 내 travel을 memory로 변경 - strings 내 '여행'을 '추억'으로 수정 Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * refactor: visit, visit log 도메인명 수정 #218 (#237) * refactor: VisitApiService 내 visit을 moment 로 변경 - 파일명 수정 - path 수정 - 메서드명 수정 - 매개변수명 수정 * refactor: data/visit 패키지명을 moment로 변경 * refactor: data/dto/visit 패키지명을 moment로 변경 * refactor: VisitCreationRequest 네이밍 변경 - 이전: VisitCreationRequest - 이후: MomentCreationRequest * style: StaccatoClient import 재정렬 * refactor: VisitCreationResponse 네이밍 변경 - 이전: VisitCreationResponse - 이후: MomentCreationResponse - 필드명 변경 : visitId -> momentId * refactor: VisitResponse 네이밍 변경 - 이전: VisitResponse - 이후: MomentResponse - VisitResponse 필드 내 visit을 moment로 변경 - VisitResponse 필드 내 visitLogs SerialName을 comments로 변경 * refactor: VisitUpdateRequest 네이밍 변경 - 이전: VisitUpdateRequest - 이후: MomentUpdateRequest - VisitUpdateRequest 필드 내 visit을 moment로 변경 * refactor: VisitLogDto 내 SerialName 변경 - visitLogId를 commentId로 변경 * refactor: MemoryResponse 내 visits SerialName 변경 - visits를 moments로 변경 * refactor: VisitCreationViewModel 내 FORM_DATA_NAME 변경 - 이전: visitImageFiles - 이후: momentImageFiles * refactor: MemoryVisitDto 내 visit를 moment로 변경 - MemoryVisitDto -> MemoryMomentDto로 변경 - visitId -> momentId로 변경 - visitImageUrl -> momentImageUrl로 변경 * refactor: VisitRemoteDataSource 내 visit을 moment로 변경 - VisitRemoteDataSource -> MomentRemoteDataSource로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: MomentRepository 및 구현체 내 visit을 moment로 변경 - VisitRepository -> MomentRepository로 변경 - VisitDefaultRepository -> MomentDefaultRepository로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: Visit 도메인 모델명 및 변수명 변경 - Visit -> Moment로 변경 - visitLogs -> comments로 변경 * refactor: Memory 도에인 모델의 visits을 moments로 변경 * refactor: MemoryVisit 도메인 모델 내 visit을 moment로 변경 * refactor: MemoryResponse의 visits 필드명을 moments로 변경 * refactor: dto/mapper/VisitMapper를 MomentMapper로 변경 * refactor: presentation/visit 패키지명을 moment로 변경 * refactor: VisitViewHolderType 네이밍 변경 - VisitViewHolderType -> MomentViewHolderType - enum 상수명 변경 - VISIT_DEFAULT -> MOMENT_DEFAULT - MY_VISIT_LOG -> MY_COMMENTS * refactor: VisitViewHolder 네이밍 변경 - VisitViewHolder -> MomentViewHolder - VisitDefaultViewHolder -> MomentDefaultViewHolder - MyVisitLogViewHolder -> MyCommentViewHolder * refactor: VisitAdapter 내 visit을 moment로 변경 - VisitAdapter -> MomentAdapter 로 변경 - visit -> moment 로 변경 * refactor: MomentAdapter 내 visit log를 comments로 변경 * refactor: VisitDetailUiModel 내 visit을 moment로 변경 - VisitDetailUiModel -> MomentDetailUiModel - VisitDefaultUiModel -> MomentDefaultUiModel - visitImageUrls -> momentImageUrls * refactor: VisitLogUiModel을 CommentsUiModel로 변경 * refactor: VISIT_ID_KEY extra key id 네이밍 변경 - VISIT_ID_KEY -> MOMENT_ID_KEY * refactor: VisitFragment 내 visit을 moment로 변경 * refactor: VisitViewModel 내 visit을 moment로 변경 - VisitViewModel -> MomentViewModel로 변경 - VisitViewModelFactory -> MomentViewModelFactory로 변경 * refactor: VisitMemoryUiModel 네이밍 변경 - VisitMemoryUiModel -> MomentMemoryUiModel로 변경 * refactor: presentation/visitcreation 패키지명 momentcreation으로 변경 * refactor: VisitCreationActivity 내 visit을 moment로 변경 - VisitCreationActivity -> MomentCreationActivity로 변경 * refactor: VisitCreationHandler 네이밍 변경 - VisitCreationHandler -> MomentCreationHandler로 변경 * refactor: VisitCreationViewModel 내 visit을 moment로 변경 - VisitCreationViewModel -> MomentCreationViewModel로 변경 - 메서드 및 변수명 변경 * refactor: 여행 -> 추억, 방문 기록 -> 스타카토로 도메인명 변경 * feat: s3 api 연결 #239 (#241) * feat: ImageResponse, ImageApiService 구현 * feat: ImageRepository 및 구현체 구현 Co-authored-by: s6m1n * fix: 추억 기능 버그 수정 #246 (#252) * fix: 일부 EditText 개행 불가 처리 및 키보드 숨김 처리 #247 (#249) * ui: 닉네임과 추억 생성, 수정 제목 입력 시 줄바꿈 제한 * fix: 키보드 활성화 상태에서 빈 화면 터치로 키보드 숨김 처리 - 메서드 명 변경: setHideKeyboardAction -> setHidingKeyboardAction * style: 클래스 내 override 메서드의 순서 변경 - 팀 코드 컨벤션에 맞게 순서 재정렬 - override 메서드를 상단에 둔다. * style: ktlint 적용 * fix: root뷰 터치 시 클릭 이벤트가 발생하지 않는 오류 수정 - 원인 분석: ConstraintLayout 내부 Toolbar 및 ScrollView, 그리고 그 자식 View들이 클릭 이벤트를 가로채기 때문에, 바인딩 된 최상단 root 뷰인 ConstraintLayout의 클릭 이벤트가 동작하지 않는다. - 해결 방법: 여러 클릭 이벤트를 가로채는 dispatchTouchEvent 메서드를 오버라이드하여, 터치된 부분이 현재 포커스가 되지 않은 View(키보드 바깥 화면) 범위라면, 키보드를 숨기는 동작을 추가하였다. * refactor: 키보드 숨김 동작을 handler 바인딩으로 적용 - LoginHandler 에 화면 터치에 대한 동작을 추가, 화면 터치 시 키보드를 숨김 처리하는 동작을 바인딩으로 설정 - InputMethodManager 인스턴스를 지연초기화하여 저장 * refactor: InputMethodManager 인스턴스를 lazy로 지연 초기화 * fix: 닉네임, 제목 입력 칸의 키보드 액션 버튼 변경 - 키보드의 액션 타입을 Search에서 Done으로 변경 * style: ktlint 적용 * refactor: 타임라인 리팩터링 #232 (#263) * refactor: TimelineViewModelFactory의 생성자 파라미터 추가 - 내부 프로퍼티에 속해있던 TimelineRepository를 생성자 프로퍼티로 변경 * fix: 추억 목록 아이템이 하나일 때의 View 수정 - 아이템 개수가 하나일 때는 타임라인의 선이 나타나지 않도록 변경 * chore: 코루틴 예외 처리 로그에context 출력 * refactor: 메서드 분리 및 순서 재정렬 - 코드 컨벤션: override 메서드는 상단에 위치한다 * refactor: TimelineViewModel 생성 팩토리 메서드 활용 * style: ktlint 적용 * ui: 화면 전환에 사용될 twin animation 효과 생성 * ui: animation 효과 활용하여 화면 전환 애니메이션 적용 * ui: Main 화면의 배경 색을 하얀색(#FFFFFF)으로 지정 * style: ktlint 적용 * feat: 기분 선택 기능 구현 및 스타카토 조회 화면 구조 변경 #191 (#289) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * style: ktlint 적용 * feat: 추억 API 변경사항 반영 및 리팩터링 #259 (#265) * ui: 추억 생성 화면 사진 로드 시 coil 라이브러리 사용 * ui: 삭제 버튼 아이콘 추가 * ui: 추억 생성 화면 사진 삭제 버튼 추가 * feat: 추억 생성 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 생성 화면 사진 삭제 구현 * feat: 추억 수정 화면 사진 첨부 icon 가시성 설정 * ui: 추억 수정 화면 사진 삭제 버튼 추가 * feat: 추억 수정 화면 사진 삭제 버튼 가시성 설정 * feat: 추억 수정 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 수정 화면 사진 삭제 구현 * fix: 추억 생성 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * fix: 추억 수정 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * feat: MemoryRequest dto에 썸네일 사진 url 필드 추가 * feat: 추억 생성 메서드의 시그니처 변경 - MemoryApiService 내 추억 생성 메서드의 시그니처 변경 - 위 변경에 따른 DataSource, Repository, ViewModel의 추억 생성 관련 메서드 시그니처 변경 * feat: 추억 생성 view model 주 생성자로 ImageRepository 주입 * feat: 추억 생성 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 생성 화면) - 추억 생성 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 생성 시 썸네일 사진 url 추가 * refactor: MemoryRequest의 추억 썸네일 사진 기본 인자 값 null로 설정 * feat: 추억 수정 메서드의 시그니처 변경 * feat: 추억 수정 view model 주 생성자로 ImageRepository 주입 * feat: 추억 수정 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 수정 화면) - 추억 수정 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 수정 시 썸네일 사진 url 추가 * refactor: 불필요한 MemoryUpdateRequest 제거 * ui: empty view 캐릭터 이미지 추가 * ui: 추억 설명글 유무에 따른 가시성 설정 * ui: 함께 한 사람들 가시성 gone 으로 설정 - 4차 스프린트 범위에서 제외됨 * feat: 이미지 선택 옵션 추가 (단일 선택 및 다중 선택 지원) * ui: TextInputLayout, TextInputEditText Style 정의 * ui: 추억 생성 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 수정 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 조회 화면 썸네일 사진 유무에 따른 가시성 설정 * ui: empty view 캐릭터 이미지 크기 변경 * ui: 앱 이름 Staccato_AN -> Staccato 로 수정 * refactor: 추억 생성 및 수정 화면 메서드 순서 정리 * ui: 제목용 TextInputEditTextStyle 정의 및 적용 * ui: 추억 생성 및 수정 화면 썸네일 coilPlaceHolder 변경 - 이전: shape_place_holder_rectangle - 이후: shape_all_gray1_8dp * refactor: 삭제 다이얼로그 show 메서드 호출 방식 변경 - apply를 사용하지 않는 방식으로 변경 * ui: 코멘트 미지원 안내 view 추가 * feat: 스타카토 생성, 수정 화면 사진 및 완료 버튼 개선 #242 (#291) * feat: (스타카토 생성 화면) 사진 드래그로 순서 변경 기능 구현 * refactor: data 패키지에 S3 이미지 API 분리 적용 * refactor: AttachedPhotoUiModel 및 프로그래스바 추가 * feat: recyclerView에서 지워진 사진의 job cancel 처리 * refactor: editText를 TextInputLayout로 수정 * feat: (스타카토 수정 화면) 사진 드래그로 순서 변경 / 로딩 구현 * refactor: 프로퍼티 네임 변경 및 visitedAt LocalDateTime으로 수정 * style: ktlint 적용 * build: 구글 맵 API 사용에 따른 CI 수정 #296 (#297) * build: 구글 맵 api key를 저장하는 파일을 설정하는 명령어 작성 * refactor: defaults 에 설정된 shell 설정에 따라 추가적인 shell 설정 삭제 * feat: Google Map 연결, 스타카토 목록 조회 API 연결 #54 (#295) * build: google map 의존성 추가 * build: 구글맵 관련 properties ignore 추가 * build: 구글맵 api key 설정 * feat: Google Map 연결 * feat: MainActivity Handler 구현 * ui: 추억 및 스타카토 생성 메뉴 추가 * ui: popup menu style 정의 * feat: 추억 생성 및 수정 menu 연결 - handler 연결 - 메서드 분리 * feat: 위치 권한 요청 구현 - ACCESS_FINE_LOCATION 권한 요청 - ACCESS_COARSE_LOCATION 권한 요청 * feat: 현 위치 표시 * style: MainActivity formatting * feat: locationPermissions 타입 변경 - 이전: List - 이후: Array * feat: MomentLocationDto, MomentLocationResponse 추가 * feat: 스타카토 목록 조회 api service 구현 * feat: 스타카토 목록 조회 data source 구현 * feat: MomentLocation 도메인 모델 구현 * feat: MomentLocationDto를 도메인 모델로 변환하는 mapper 구현 * feat: 스타카토 목록 조회 repository 구현 * feat: 스타카토 목록 조회 view model 구현 * feat: 스타카토 목록을 marker로 표시 * refactor: home 패키지명을 maps로 변경 * feat: 마커 클릭 시 스타카토 상세로 이동 기능 구현 * feat: 스타카토 조회 추억 id, 제목 필드 추가 * feat: 마지막 위치 위경도 찾기 * refactor: 안드로이드 1차 QA 반영 #299 (#301) * refactor: 안드로이드 1차 QA 반영 * refactor: 안드로이드 1차 QA 반영2 * refactor: 안드로이드 1차 QA 반영3 * refactor: 삭제 메시지 변경 * fix: 스타카토 조회 화면 스택 관리 및 ui 수정 #304 (#306) * feat: 지도 화면에서 스타카토 조회 화면으로 이동 시 스택 관리 * feat: 타임라인 화면에서 추억이 존재하지 않을 때 추억 생성 버튼 추가 * ui: 스타카토 조회 화면 툴바 위치 고정 * build: Android CD 적용 #300 (#308) * build: CD 워크플로우 yml 파일 작성 * build: keystore 접근을 위한 build.gradle.kts 파일 설정 * build: 기존 apk 추출 ci 파일 수정 - demo 버전의 apk를 추출 및 배포하는 목적에 맞게 파일 명 수정 - apk 빌드 후 테스트를 수행하는 job 추가 - firebase 앱 배포에 아티팩트 업로드하는 job 추가 * fix: ci 파일에도 keystore 생성 job 추가 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: ci 파일에 키스토어 관련 설정 적용 * fix: 키스토어 관련 명령어 일부 수정 * fix: build.gradle.kts 불필요한 괄호 제거 * fix: keystore.properties 로 부터 프로퍼티를 가져오는 형식 변경 * fix: upload-artifact step에서 빌드 파일의 upload 경로 수정 (#316) upload-artifact 는 defaults 설정의 working-directory 경로가 적용되지 않음 * fix: android cd 재수정 (2차) #317 (#319) * fix: upload-artifact 빌드 파일의 upload 경로 3차 수정 * fix: 배포 시 빌드 파일의 경로 수정 * fix: 빌드 파일의 upload 경로 수정 및 파일이 없는 경우 에러 처리 * fix: 빌드 파일의 upload 경로 4차 수정 * fix: 빌드 파일의 upload 경로 5차 수정 * fix: 빌드 파일의 upload 경로 6차 수정 - 디렉터리 경로 생성 후 upload 실행 * fix: 빌드 파일의 upload 경로 7차 수정 github의 workspace 환경변수(절대경로) 활용 * fix: clean test 제거 및 디버그용 파일 경로 탐색 명령어 추가 * fix: 디버그용 파일 경로 검색 명령어 수정 * fix: 디버그용 파일 경로 검색 명령어 삭제 * fix: 디버그용 파일 검색 명령어 삭제 및 업로드 파일 경로명 수정 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 기능 구현 #314 (#324) * feat: MainActivity에서 주소를 가져오는 로직 삭제 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 로직 구현 * refactor: 메서드 순서 정렬 * refactor: 스타카토 조회 화면 ViewPager2 적용 및 UI 아이콘 개선 #318 (#320) * refactor: 아이콘 추가 및 UI 개선 * feat: 스타카토 상세 사진 Viewpager 적용 * feat: 스타카토 상세 사진 Viewpager에 dot indicator 추가 * style: ktLint Format * feat: 메인 지도 화면에서 스타카토 생성하는 플로우 구현 #321 (#327) * feat: 날짜로 추억 목록 불러오는 getMemories API 추가 * feat: 메인에서 스타카토 생성 시 추억 목록 선택 가능 * feat: 스타카토 생성 시 역지오코딩과 추억 선택 연동 * build: debug와 release로 buildTypes 분리 (#329) - appName, appId, baseUrl 분리 - release에 난독화 적용 * build: debug 와 release 배포 분기에 따른 CD 수정 - CD에 대한 트리거 재설정 : main 브랜치에 대한 push 및 pr * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 #326 (#330) * refactor: 지도 화면 onResume에서 스타카토 목록 load * refactor: 스타카토 목록 로드 메서드명 변경 - 이전: loadMoments - 이후: loadStaccatos * feat: 공유 view model에 스타카토 목록 업데이트 상태 추가 * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 * feat: 지도 로드 시 현위치로 이동하도록 구현 * build: ci 및 cd 파일 수정 ci - 불필요한 gradle 빌드 및 테스트 제거 cd - 타겟 브랜치 develop 제거 * feat: 댓글 조회, 생성, 삭제 기능 구현 #290 (#331) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * ui: xml 컨벤션에 맞추어진 타 사용자의 댓글 ui 구성 * feat: 댓글 API의 DTO 작성 * feat: 댓글 API Service 작성 * feat: 댓글 CRUD DataSource 작성 * refactor: CommentApiService 각 메서드의 반환 값을 Response로 변경 * feat: CommentApiService 를 create * feat: CommentDataSource 구현체 생성 * refactor: 댓글 Dto 클래스 네이밍 변경 - VisitLogDto -> CommentDto * refactor: CommentDto 의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * refactor: VisitLog 도메인 모델 클래스의 네이밍 변경 - VisitLog -> Comment * refactor: Comment 도메인 모델의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * feat: 새로운 댓글 도메인 모델 생성 * feat: CommentRepository 작성 * feat: Domain 모델과 DTO 모델을 변환해주는 Mapper 작성 - CommentDto를 Comment로 변환하는 메서드를 CommentMapper.kt로 이동 * feat: CommentRepository의 기본 구현체 작성 * feat: 댓글 ViewModel, Factory 작성 및 Comment 불러오기 구현 * ui: ViewModel 데이터바인딩 및 빈 댓글 문구에 대한 strings 설정 * feat: CommentsViewModel 활용 및 옵저빙 * feat: 댓글 조회, 생성, 삭제 기능 구현 * chore: ktlint 적용 * feat: 추억 생성 및 수정 이미지 로딩 중 표시 및 저장 버튼 비활성화 #332 (#334) * feat: 추억 생성 이미지 로딩 중 표시 * feat: 추억 수정 이미지 로딩 중 표시 * feat: 추억 생성 및 수정 이미지 로딩 중 저장 버튼 비활성화 * style: formatting * refactor: 댓글 화면 개선 및 리팩터링 #333 (#335) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 * build: defaultConfig의 버전 코드와 이름 수정 versionCode : 2 -> 3 versionName : 1.1 -> 1.0.0 (배포 버전과 동일) --------- Co-authored-by: hxeyexn Co-authored-by: s6m1n * refactor: 패키지명 변경 #342 (#343) - 5차 스프린트 요구사항 만족을 위해 패키지명 변경 - 이전: com.woowacourse.staccato - 이후: com.on.staccato * build: CI 적용 브랜치 추가 * hotfix: QA #322 (#323) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 * chore: QA 위한 트리거 수정 * chore: 배포 트리거 세팅 * docs: pr 템플릿 수정 --------- Co-authored-by: devhoya97 Co-authored-by: somin Co-authored-by: BurningFalls Co-authored-by: YoonJuHo Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * docs: 서비스 소개 수정 * chore: main ci 트리거 수정 * ui: 타임라인 화면 디자인 수정 #347 (#348) * layout: 타임라인 디자인 수정 및 STATE_HALF_EXPANDED 구현 * chore: 불필요한 파일 삭제 * chore: 수정된 패키지명 반영 * layout: empty 추억 view 높이 조절 * layout: 기분 선택 여부 컬러/흑백 처리 * ui: 추억 화면 디자인 수정 및 추억 생성 플로우 변경 #346 (#355) * ui: 추억 썸네일 이미지용 gradient drawable 구현 * ui: 스타카토 썸네일 이미지용 gradient drawable 구현 * ui: 추억 조회 화면 ui 수정 - 추억 상세 내용 ui 수정 - 스타카토 목록 ui 수정 * ui: 스타카토 추가 버튼 수정 * feat: 홈 화면의 추억 생성 플로우 제거 - 홈 화면에서는 스타카토 생성만 가능하게 변경 * ui: 추억 생성 및 수정 화면 toolbar 제목 추가 * ui: 스타카토 생성 및 수정 화면 toolbar 제목 추가 * ui: 타임라인 화면 추억 추가 및 정렬 버튼 추가 * style: formatting * refactor: 댓글 화면 개선 #333 (#354) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 * ui: 댓글 구성요소의 UI 개선 RecyclerView - 아이템 변화 시 애니메이션 효과 제거 - 스크롤 시 물결 무늬 애니메이션 제거 - 최소 높이 지정 댓글이 없는 경우의 Default View - 높이 및 마진 조정 * refactor: UserInfoSharedPreferences의 파일, 키 이름 변경 - 패키지명 변경에 따라 해당 SF가 사용하는 파일, 키 이름 변경 * fix: xml 속성 수정 - layout_marginBottom 오타 수정 - app:itemAnimator 속성 제거 * feat: 댓글 입력 중 화면 터치 시 키보드 비활성화 구현 - MainActivity 에서 dispatchTouchEvent 를 오버라이드하여, focus 된 EditText의 focus를 해제하고, 키보드를 숨김처리하도록 구현 * ui: RecyclerView와 댓글이 없을 때 View의 높이 조정 * feat: 리사이클러뷰 애니메이션 효과 제거 및 adapter 설정 메서드명 변경 * feat: 댓글 수정하기 메뉴 제거 및 댓글 삭제 시 삭제 다이얼로그를 띄우도록 변경 * deploy: v1.0.1 (#356) * build: 프로젝트 생성 및 의존성 추가 * chore: 사용자 기능 및 권한 추가 * chore: gitignore 재설정 * chore: gitigonre .idea/ 추가 * build: develop-an 브랜치의 CI 설정 #3 (#10) * build: android-ci.yml 파일 생성 * chore: 오타 및 개행 수정 * chore: working-directory 수정 * build: ktLint 적용 및 format * ui: 디자인 시스템 구현 #11 (#44) * ui: color 정의 * ui: shape, selector 추가 * ui: icon 추가 * ui: font family 추가 - pretendard regular, medium, semibold, bold 추가 * ui: typography 정의 * ui: strings 정의 * ui: bottom sheet drag handle drawable 추가 * ui: styles 정의 * ui: detail toolbar 구현 - 상세 화면에서 사용 * ui: dialog, bottom sheet 구현 - 여행 및 방문 기록 삭제 dialog - 사진 등록 bottom sheet * ui: 사진 첨부 layout 구현 * feat: 삭제 다이얼로그, 사진 첨부 바텀 시트 fragment 추가 * ui: 세로모드로 고정 * build: data binding 의존성 추가 * style: strings resource 순서 정렬 * style: formatting * ui: plus icon 추가 * feat: jetpack navigation 및 바텀시트 프래그먼트 추가 #12 (#15) * build: androidx.navigation 및 dataBinding 의존성 추가 * feat: Binding 화면 클래스 및 bottomSheetNavigation 추가 * feat: TimelineFragment 임시 화면 추가 * feat: TravelFragment 임시 화면 추가 * feat: TravelCreationFragment 임시 화면 추가 * feat: VisitFragment 임시 화면 추가 * feat: VisitCreationFragment 임시 화면 추가 * feat: (여행, 방문 기록) 수정 화면 추가 * feat: (여행, 방문 기록) 생성 화면 이동 구현 * feat: BottomSheetController 설정 및 Navigation 이동 구현 * feat: 뒤로가기 버튼 클릭 시 BottomSheet, Toast 작동 구현 * feat: 여행, 방문 기록 생성을 위한 액티비티 추가 및 이동 구현 * feat: 여행, 방문 기록 수정을 위한 액티비티 추가 및 이동 구현 * build: 중복된 dataBinding 제거 * feat: 공통 이미지 로딩 BindingAdapter 설정 #33 (#41) * build: dataBinding 사용 설정 * feat: 이미지 로딩 바인딩 어댑터 설정 - Glide, Coil 바인딩 어댑터를 각각 작성 - placeholder 설정 * style: ktlint check - import 순서 조정 * fix: attribute 개수에 맞추어 BindingAdapter의 value 재설정 * style: 마지막 줄 개행 추가 * feat: placeHolder를 필수 속성으로 변경 및 coil 이미지 로딩 코드 수정 - placeHolder를 ImageView의 필수 속성으로 지정 - Coil BindingAdapter에서 url이 null인 경우에도 이미지를 로드하는 동작이 수행되도록 수정 * ui: 상단바 색상 변경 * build: develop-an의 CI 설정 수정 #38 (#39) - Git Action에 Secret으로 저장된 LOCAL_PROPERTIES_API_KEY를 변수로 가져온다. - 가져온 변수를 echo를 활용하여 local.properties에 설정한다. * build: develop-an 브랜치의 CI 파일 문법 오류 수정 #45 (#46) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: android-ci.yml 파일의 명령어 수정 #47 (#48) LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 * fix: develop-an 브랜치의 CI 파일 명령어 재수정 #47 (#49) * fix: android-ci.yml 파일의 명령어 수정 LOCAL_PROPERTIES_API_KEY에 접근하는 명령어 수정 * fix: 파이프라인 제거하여 명령어 수정 --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> * fix: 문자열 임을 명시하고 환경변수 설정 위치 조정 * fix: local.properties 생성 시점 수정 * feat: 데이터 패키지 설정 #13 (#35) * build: 서버 base url의 local.properties 사용 설정 및 BuildConfig 설정 * feat: Retrofit Client 작성 * fix: Merge Conflict 해결 - build.gradle.kts(project, app)의 ktlint 의존성 충돌 해결 - 버전 카탈로그 플러그인 충돌 해결 * feat: DTO 클래스 작성 * style: ktlint check - 불필요한 import 제거 - 개행 조정 - 콤마 추가 * feat: SerialName 어노테이션의 값을 camelCase로 수정 * refactor: DTO 클래스의 이름 수정 - API 요청으로 직접 보내거나 들어오는 JSON의 경우 DTO 클래스명 뒤에 Request/Response 를 붙이도록 설정 - JSON 안에 속성 값으로 들어가는 JSON은 DTO 클래스명 뒤에 Dto를 붙이도록 설정 * feat: 누락된 Dto 클래스 추가 TimelineResponse.kt - 타임라인 조회 시 여행 상세 목록을 불러올 때 사용되는 DTO 클래스 - TimelineTravelDto 리스트를 갖는다 * style: ktlint check * fix: const 키워드 제거 --------- Co-authored-by: hxeyexn * feat: 둥근 모서리의 이미지를 로드하는 BindingAdapters 추가 #58 (#59) * feat: 둥근 모서리로 이미지를 로딩하는 Glide 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - glideRoundedCornerImageUrl: 출력하고자 하는 이미지 url - glidePlaceHolder: placeHolder의 url - glideRoundingRadius: 모서리의 둥근 정도를 Int로 설정 * feat: 둥근 모서리로 이미지를 로딩하는 Coil 바인딩 어댑터 작성 - 세 속성이 모두 필요하다. - coilRoundedCornerImageUrl: 출력하고자 하는 이미지 url - coilPlaceHolder: placeHolder의 url - coilRoundingRadius: 모서리의 둥근 정도를 Float으로 설정 * fix: centerCrop 설정을 BindingAdapter 에 위임 - xml 속성으로 centerCrop을 주게 되면 Round Corner가 제대로 적용되지 않는 현상 발생 - Glide의 api로 제공되는 centerCrop() 메서드를 활용 * ui: 타임라인 프래그먼트(BottomSheet) 구현 #55 (#71) * ui: 타임라인 View xml 파일 작성 - 타임라인에 나타날 여행 상세 아이템 xml 작성 - 썸네일 사진 유무에 따라 뷰를 구분 - 타임라인이 나타날 fragment xml 작성 * feat: 타임라인 여행 상세 아이템 UI 모델 생성 * ui: 썸네일이 없는 여행상세 아이템의 margin 조정 * ui: Timeline RecyclerView의 layoutManager 설정 * ui: xml에서의 UiModel 데이터 바인딩 설정 * feat: ViewHolder 작성 - 썸네일 사진 유무에 따라 다른 ViewHolder로 구분 - 공통된 속성을 정의한 TimelineViewHolder 추상클래스 생성 * feat: TimelineRepository Interface 생성 * feat: 임시 TimelineRepository 구현체 생성 * feat: TimelineViewModel 및 Factory 생성 * feat: TimelineViewType 작성 * feat: TimelineAdapter 작성 * feat: TimelineFragment에 ViewModel과 Adapter 구현 * feat: 이미지 로딩 PlaceHolder drawable 추가 및 적용 * feat: 임시 데이터 연결 * ui: Timeline fragment 의 세부 설정 조정 * ui: Timeline의 Item xml 변경 - 뷰 타입을 3개로 분할: 첫 번째 아이템, 중간 아이템, 마지막 아이템 - 이에 따라 xml 파일 추가 및 view 수정 * feat: ViewType 변경에 따른 Adapter 및 ViewHolder 수정 * refactor: 불필요한 View 및 ViewHolder 제거 * feat: 여행 click 에 대한 event handler 생성 및 설정 * refactor: drawable 이름을 네이밍 컨벤션에 맞게 수정 * ui: RecyclerView의 마진 속성을 패딩 속성으로 변경 * feat: 바텀 시트 디자인 변경 및 툴바와의 상호작용 구현 * ui: 타임라인 글귀 추가 * style: ktlint check * ui: 둥근 모서리의 이미지로 변경 * ui: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 구현 #52 (#74) * ui: typography.body textSize 1sp 씩 증가 * feat: DeleteDialogFragment에 Handler 추가 * feat: 툴바의 수정, 삭제 버튼 제어를 위한 ToolbarHandler 추가 * feat: 방문 상세 화면을 위한 VisitDetailUiModel 추가 * ui: PlaceHolder를 위한 xml 파일 추가 * feat: 방문 기록 상세 화면을 위한 VisitAdapter 및 VisitViewHolder 구현 * feat: 임시 VisitViewModel와 VisitViewModelFactory 추가 * feat: VisitFragment 화면 구현 * feat: 방문 기록에 해당하는 여행 선택을 위한 TravelSelectionFragment 구현 * feat: 방문 기록에 해당하는 날짜 선택을 위한 VisitedAtSelectionFragment 구현 * feat: 방문 기록 생성을 위한 VisitCreationActivity 구현 * feat: 방문 기록 수정을 위한 VisitUpdateActivity 구현 * refactor: DialogHandler를 DeleteDialogFragment의 생성자에서 받도록 수정 * refactor: initVisitUpdateDoneButton 중복 로직 제거 * refactor: VisitViewHolderType 메서드 명 변경 of -> from * refactor: tv_place_name_title을 xml id convention에 맞게 수정 * ui: 여행 화면 구현 #51 (#75) * ui: 함께 간 사람들 item 구현 * ui: 방문 기록 item 구현 * ui: 여행 상세 화면 구현 * ui: 여행 생성 화면 구현 * ui: 여행 수정 화면 구현 * ui: placeholder에 사용할 drawable 추가 * ui: 여행 삭제 완료 string 추가 * feat: 둥근 모서리 이미지 BindingAdapter 구현 * feat: 함께 간 사람들 adapter 구현 * ui: 여행 상세 화면 NestedScrollView로 변경 - 이전: ScrollView - 이후: NestedScrollView * feat: 방문 기록 adapter 구현 * feat: 여행 상세 view 연결 * feat: 함께 간 사람들, 방문 기록 adapter 연결 * feat: 삭제 다이얼로그 handler 구현 * feat: 여행 상세 화면 toolbar handler 구현 - 뒤로가기 - 여행 수정 화면으로 이동 - 삭제 다이얼로그 show * feat: 여행 -> 방문 기록 화면 이동 구현 * ui: DatePickerStyle 추가 - DatePickerStyle, CustomMaterialCalendarStyle 추가 - staccato_blue 투명도 30 추가 * feat: 여행 저장 버튼, 여행 기간 BindingAdapter 추가 * feat: 여행 생성 view 연결 * feat: 여행 수정 view 연결 * style: formatting - Exceeded max line length 해결 - 임시 이미지 URL 변경 * refactor: 기간 선택 로직 메서드 분리 * feat: 타임라인의 API 적용 및 MainActivity의 Toolbar 제거 #81 (#93) * refactor: UI Model의 패키지 경로 변경 * refactor: API 명세 변경에 따른 TimelineTravelDto 수정 * refactor: repository 메서드 수정 - 서버 요청을 비동기적으로 처리하기 위해 suspend 키워드 삽입 - 기존의 임시 데이터 요청 코드를 위해 load 메서드 분리 * feat: Timeline의 API Service 작성 * feat: DataSource 인터페이스 작성 * feat: TimelineDataSource 구현체 생성 * refactor: 년도에 대한 default parameter 설정 * refactor: DataSource의 요청 메서드 네이밍 수정 * feat: http 통신이 가능하도록 Cleartext Traffic 허용 설정 * feat: Authorization Header를 삽입하기 위한 Interceptor 생성 * feat: Client에 HeaderInterceptor 추가 * refactor: errorBody의 message 속성 이름 변경 * feat: 도메인 모델 작성 * feat: Response(dto)에서 도메인 모델로 변환하는 확장함수 구현 * feat: 도메인 모델에서 UI 모델로 변환하는 확장함수 구현 * feat: Repository 수정 및 ViewModel 데이터 연결 * ui: MainActivity의 상단 툴바 제거 * refactor: ViewType에 viewType 속성 추가 및 when에서의 enum 활용 * refactor: Timeline의 공통 ViewHolder를 sealed class로 변경 * style: ktlint check 수행 * fix: Response 데이터의 nullable 속성에 맞추어 DTO 수정 및 누락된 DTO 추가 * fix: 데이터가 비어있는 경우(초기)에만 새로운 여행상세 목록을 받도록 수정 * refactor: lazy 로 지연 초기화 및 timelineService가 하나의 인스턴스로 관리되도록 수정 * fix: Travel의 description에 nullable 속성 추가 API 명세서 잘 좀 보자 제발 * refactor: create 메서드를 private으로 변경 Client 클래스에서 Service를 create 하여 제공 및 캐싱하기 때문에, 불필요한 인스턴스를 생성하지 않도록 create를 public으로 두지 않는 것이 좋다. * refactor: LocalDateConverters의 패키지 경로 수정 * refactor: 파일의 이름 수정 * style: ktlint check * refactor: 에러 메시지 상수화 * feat: 특정 여행 상세 조회 api 연결 #82 (#97) * feat: 특정 여행 상세 조회 api service 구현 * feat: 썸네일, 소개 타입 변경 및 기본 인자 설정 - 변경 data class : TravelResponse, TravelUiModel - 이전: String - 이후: String? * refactor: MatesUiModel 네이밍 변경 MatesUiModel이 공통적으로 사용될 예정이므로 MemberUiModel로 변경 - 이전: MatesUiModel - 이후: MemberUiModel * refactor: VisitUiModel 네이밍 변경 - 여행 상세 방문 기록에 사용되는 UiModel 이름을 명시적으로 변경 - 이전: VisitUiModel - 이후: TravelVisitUiModel * feat: 특정 여행 상세 조회에 사용할 domain model 추가 * feat: Api 응답 핸들링 로직 구현 * feat: 특정 여행 상세 조회 data source 구현 * feat: 특정 여행 상세 조회 repository 구현 * feat: 특정 여행 상세 조회 api 연결 * feat: 특정 여행 상세 조회 로직 매개변수 추가 - 타임라인에서 선택된 여행 id를 매개변수로 받도록 변경 * refactor: ApiResponseHandler 이름 오타 수정 * refactor: 에러 메세지 상수화 * feat: 특정 여행 상세 조회 시그니처 변경 - HeaderInterceptor 적용으로 authorization 매개변수 제거 * style: formatting * feat: 방문 기록, 방문 기록 생성, 방문 기록 수정 화면 API 연결 #79 (#99) * feat: VisitApiService 인터페이스 및 관련 data class 추가 * feat: VisitRepository, RemoteVisitDataSource 및 관련 class 추가 * feat: 각 Visit 화면들의 ViewModelFactory 구현 * feat: 각 Visit 화면들의 UiModel 클래스 및 Mapper 추가 * feat: 여행 선택 및 방문 날짜 선택을 위한 BottomSheetDialogFragment 수정 * feat: VisitFragment API 연결 * feat: VisitCreationActivity API 연결 * feat: VisitUpdateActivity API 연결 준비 * refactor: visitApiService를 StaccatoClient object로 이동 * refactor: TravelVisit 클래스의 visitImage 변수 nullable하게 수정 * refactor: VisitApiService의 중복된 @Header 제거 * refactor: 방문 생성 성공 시 created id를 가져오도록 리팩터링 * chore: 변수명 visitImage로 수정 및 ktLint 적용 * refactor: 여행 수정 완료 동작 구현 및 VisitUpdateActivity 함수 분리 * feat: 여행 생성 api 연결 #98 (#104) * feat: 여행 생성 api service 구현 * feat: 여행 생성 data source 구현 * feat: 방문 기록 썸네일 타입 변경 및 기본 인자 설정 - 변경 data class :  TravelVisitDto, TravelVisit, TravelVisitUiModel - 이전: String - 이후: String? * build: converter scalars 의존성 추가 * feat: 여행 생성 ApiService 반환값 및 DataSource 시그니처 변경 - 여행 생성 ApiService 반환값 변경 - DataSource 시그니처 변경 - TravelCreation DomainModel 구현 - TravelCreation Dto 변환 Mapper 구현 * feat: Client에 ScalarsConvert 추가 - Header 값을 읽어오기 위해 ScalarsConvert 추가 * feat: 여행 생성 repository 구현 * feat: 여행 생성 api 연결 * feat: TravelViewModel 생성자 변경 - 이전: travelId를 TravelViewModel 생성자로 넣어줌 - 이후: travelId를 loadTravel()의 매개변수로 넣어줌 * ui: map 화면 변경 * refactor: 컨벤션 통일 및 패키지 정리 #112 (#118) * refactor: bind 네임스페이스 적용 * refactor: BindingAdapters 메서드명 변경 * refactor: 컨벤션 맞게 xml 파일 이름 변경 * refactor: data 패키지 구조 정리 * refactor: RemoteVisitDataSource 컨벤션 따라 네이밍 변경 * refactor: 네트워킹 관련 메서드 이름 변경 - api service, data source, repository * refactor: presentation 패키지 구조 정리 * refactor: message utils 생성 및 적용 Co-authored-by: s6m1n Co-authored-by: Junyoung-WON * build: develop-an의 CI 테스트 자동화 추가 및 데모 APK 추출 #78 (#92) * build: test 자동화 Job 추가 * build: local.properties 생성 시점 변경 * build: 디버그 APK를 빌드하여 업로드하는 workflow 작성 * fix: test Job과 APK build Job에 local.properties 생성 동작 추가 * build: read 전용 권한 제거 * build: Firebase Analytics, Crashlytics 설정 #136 (#143) * build: Firebase Analytics, Crashlytics 의존성 추가 * chore: google-service.json ignore * feat: 특정 여행 상세 수정 api 연결 #109 (#146) * feat: 여행 수정 api service 구현 * feat: 여행 수정 data source 구현 * feat: 여행 수정 repository 구현 * feat: 여행 수정 화면 현재 데이터 로딩 기능 구현 * refactor: 컨벤션 따라 여행 api service의 수정 메서드명 변경 - 이전: updateTravel - 이후: putTravel * feat: 특정 여행 상세 수정 api 연결 * refactor: memberImage 타입 변경 및 기본 인자 설정 * refactor: MembersDto 삭제 * refactor: TravelCreationUiModel.kt 삭제 * refactor: TravelCreation 이름 변경 - 이전: TravelCreation - 이후: NewTravel * refactor: api 명세서 변경에 따른 도메인 모델 수정 및 여행 코드 리팩터링 #151 (#152) * refactor: nickName 변수명 변경 - 이전: nickName - 이후: nickname * ui: 여행 수정 화면 이미지 속성 수정 - glide -> coil 이용 - scaleType : fitXY -> centerCrop * style: import 정렬 * feat: 여행 상세 -> 방문 상세로 이동 시 여행 id 전달 * feat: 방문기록 조회 dto 수정 - 방문기록 조회 도메인 변경으로 인해 방문 기록이 조회되지 않음 - 따라서 api 명세서와 일치하도록 dto 수정하여 오류 해결 * refactor: 여행 생성을 위한 viewModel 메서드 분리 * refactor: 여행 조회를 위한 viewModel 메서드 분리 * feat: 여행 수정 handler 구현 * refactor: 여행 default id 변경 - 이전: -1L - 이후: 0L * refactor: TravelHandler 구현 위치 변경 - 이전: TravelViewModel - 이후: TravelFragment * style: 컨벤션에 맞게 TravelFragment의 메서드 순서 수정 * refactor: TravelFragment의 travelId 초기화 방식 변경 * feat: 여행 생성 및 수정 error toast 구현 * feat: 방문 생성 화면, 방문 수정 화면에서 갤러리 사진 불러오기 구현 #150 (#155) * feat: PhotoAttachFragment에 PhotoAttachHandler 연결 * feat: PhotoAttachFragment 앨범 접근 권한 관련 로직 구현 - API level 33 이상 : READ_MEDIA_IMAGES - API level 33 이하 : READ_EXTERNAL_STORAGE - ActivityResultLauncher를 이용한 권한 요청 - 권한 거부 시, 설정으로 이동하는 스낵바 띄우기 * feat: PhotoAttachFragment 앨범에서 불러온 이미지의 URI 추출하기 * feat: 불러온 이미지의 URI를 호스트 Activity로 전달 - OnUrisSelectedListener 인터페이스 추가 * feat: Uri를 File로 변환하는 메서드 파일 추가 * refactor: pr 리뷰 반영 * refactor: pr 리뷰 반영2 * build: develop-an의 android-ci 수정 #115 (#160) - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: android-ci 환경변수 생성 위치 조정 (#164) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * build: bash 쉘에 맞는 명령어 활용 #115 (#165) * build: local.properties 와 google-services.json 설정 - local.properties: 파일 생성 후 secrets로부터 base_url 설정 - google-services.json: firebase android 구성파일 설정을 위해 secrets로부터 생성 * fix: 환경 변수 설정 위치 변경 * fix: bash 쉘에 적합한 명령어 형식으로 변경 * feat: 특정 여행 상세 삭제 api 연결 #153 (#167) * feat: 특정 여행 삭제 api service 구현 * feat: 특정 여행 삭제 data source 구현 * feat: 특정 여행 삭제 repository 구현 * feat: 특정 여행 삭제 기능 api 연결 * feat: error handling 방식 수정 - 서버에서 들어오는 error body의 status와 message를 활용하는 방식으로 변경 * refactor: DialogHandler를 독립적으로 관리 * refactor: api path 상수 활용 * refactor: BuildConfig에 token 정의 * refactor: DEFAULT_VALUE 상수 제거 * feat: 여행 생성 기능 api 수정 #169 (#178) * feat: onUrisSelected 매개변수 가변인자로 변경 * feat: 여행 생성 화면 갤러리 이미지 로딩 기능 구현 * refactor: 이미지 선택 리스너 초기화 메서드명 오타 수정 * refactor: 스낵바 액션 설정 코드 간소화 * feat: TravelRequest 의 여행 썸네일 필드 제거 * refactor: 여행 썸네일 이미지 변수명 수정 * feat: 이미지 전송 기능 구현 * refactor: image url 변수명 변경 - 변수 끝에 url이 오도록 * feat: 여행 생성 progressBar 구현 * ui: 사진 첨부 아이콘 가시성 설정 * feat: 여행 상세 수정 기능 api 변경 및 여행 리팩터링 #180 (#181) * feat: 여행 수정 화면 갤러리 이미지 로딩 기능 구현 * feat: URL 및 URI 기반 이미지 로딩 BindingAdapter 구현 * feat: 이미지 전송 기능 구현 * feat: 여행 수정 progressBar 구현 * fix: 삭제 불가능한 여행 삭제 시도 관련 에러 토스트 문제 해결 삭제 불가능한 여행을 삭제하려고 시도 -> 방문 조회 -> 뒤로 가기 버튼 클릭 -> 삭제 불가능 에러 토스트가 다시 뜨는 문제가 발생해 이를 해결 * refactor: TravelCreationViewModel의 imageUrl 변수 제거 * ui: 여행 상세 내 방문 기록 이미지 scaleType 속성 설정 * ui: 여행 생성 썸네일 이미지 scaleType 속성 설정 * fix: 여행 소개 미입력 시 여행이 생성 되지 않는 오류 해결 * refactor: 타임라인 화면 리팩터링 #162 (#179) * ui: 타임라인 RecyclerView의 크기 조정 및 여백 수정 * feat: Activity와 Fragment 간 데이터를 공유하는 공유 ViewModel 생성 * feat: 공유 ViewModel을 이용하여 타임라인 업데이트 여부를 공유 * refactor: RecyclerView.Adapter에서 ListAdapter로 변환 * refactor: 처음 타임라인을 불러오는 동작을 ViewModel 초기화 시에 수행 * fix: ListAdapter 수정 - 불필요한 travels 프로퍼티와 getItemCounts 메서드 제거 - currentList를 사용하는 것으로 변경 * refactor: 에러 핸들링 방식 수정 및 ViewModel 수정 - TimelineDefaultRepository로 네이밍 변경 - ApiResponseHandler와 ResponseResult를 이용하여 에러 핸들링 처리 - TimelineViewModel 에러 메시지 LiveData 사용 - 그 외 repository, dataSource 프로퍼티 이름 수정하여 통일 * refactor: MutableLiveData의 값 업데이트를 setValue로 변경 및 메서드 분리 * style: ktlint 적용 * feat: 3차 스프린트에서 수정된 방문 기록 상세 API 연결 #163 (#183) * feat: 방문 상세 생성 API 연결 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 방문 기록 생성 및 수정 시 로딩과 토스트 추가 * feat: 닉네임을 활용한 로그인 기능 구현 #124 (#172) * ui: 로그인 화면 구성 - 로그인 화면에서 사용되는 텍스트를 strings에 추가 - 로그인 버튼 스타일에 대한 style 생성 - xml 임시로 작성 * ui: 앱 로고 삽입 및 margin 조정 - 임시 로고 이미지 저장 - 로고 크기 및 마진 조정 * feat: 로그인 API Service 작성 및 Retrofit 객체 생성 * feat: 로그인 DataSource 작성 * feat: 로그인 Repository 생성 * feat: 사용자 정보를 저장하는 SharedPreferences Manager 생성 - 토큰 값 불러오기 및 저장 - 추후 사용자 닉네임, 사용자 프로필 이미지 등의 정보 저장 가능 * feat: Application 생성 및 사용자 정보 Preferences Manager 캐싱 * ui: Splash Screen 화면 구성을 위한 테마 생성 * feat: Preferences 로부터 사용자 토큰 값을 가져와 헤더에 추가하도록 변경 * refactor: Repository 네이밍 통일 * refactor: DataSource 기본 인자 추가 * feat: LoginViewModel 및 Handler 작성 * feat: LoginViewModel 을 생성하는 ViewModel Factory 작성 * feat: LoginActivity 작성 및 양방향 데이터 바인딩 적용 * feat: StaccatoApplication과 LoginActivity 설정 및 LoginActivity를 시작 화면으로 변경 * style: 불필요한 namespace 제거 및 lint 확인 * refactor: LoginViewModel과 Factory를 viewmodel 패키지로 분리 * refactor: TimelineViewModel과 Factory를 viewmodel 패키지로 분리 * style: ktlint 적용 * fix: 불필요한 ConverterFactory 제거 - 더 이상 사용하지 않는 text/plain 변환용 ScalarsConverterFactory 제거 * feat: 닉네임 로그인 요청 및 응답에 대한 DTO 작성 * refactor: 로그인 요청, 응답 시 DTO 활용 * fix: 토큰 값을 불러오고 및 저장하는 동작의 비동기 처리 및 화면 전환 개선 * refactor: 토큰 값을 캐싱하여 저장하는 TokenManager 생성 및 적용 - 매번 runBlocking을 통해 Preference에 저장된 토큰 값을 불러오는 것은 네트워크 성능을 저하시킨다. - 따라서, token 값을 캐싱하여 저장하는 TokenManager를 활용한다. - 첫 네트워크 요청 시에만 토큰을 불러오는 작업을 동기적으로 처리하기 위해 Main Thread가 Blocking 된다. - TokenManager가 Preference로부터 가져온 토큰을 캐싱하여 저장한다. - 이후 요청부터는 캐시된 토큰을 가져오므로 Main Thread가 Blocking 되지 않는다. * style: ktlint 적용 * feat: Night 모드 비활성화 * refactor: 여행 기간 날짜 형식 변환을 BindingAdapter에서 수행 - TimelineTravelUiModel 프로퍼티 수정 - UiModel의 여행기간 날짜를 LocalDate로 갖도록 통일 - 추후 날짜 관련 UI가 변경되었을 때 확장성 고려 - BindingAdapters에 날짜 형식 변환해주는 메서드 작성 * chore: 주석 처리된 Log 코드 삭제 * style: xml View의 ID 네이밍 컨벤션 적용 * ui: 앱 심볼 로고 추가 및 스플래시 스크린에 적용 * feat: 방문 상세 생성 API 연결 * ui: 배경 색을 흰 색으로 지정 * feat: 키보드 활성화 상태에서 화면 터치 시 키보드를 내리는 기능 추가 * style: ktlint 적용 * feat: 방문 상세 수정, 삭제 API 연결 * feat: 방문 기록 생성/수정 시 양방향 데이터 바인딩 적용 * fix: merge 과정에서 발생한 id값 네이밍 충돌 해결 * build: 앱 version code와 version name 수정 * feat: 방문 기록 생성 화면 사진 다중 선택 구현 * feat: 방문 기록 생성 이미지 업로드 구현 * feat: 스플래시 스크린 시간 조정 및 데모 시연용 토큰 활성화 * fix: 동일한 사진이 여러 장 업로드되는 버그 수정 * feat: 기존 로그인 기능으로 롤백 --------- Co-authored-by: somin * fix: 테스트 배포를 위한 버그 수정 #198 (#219) * style: formatting * fix: 무한 로딩 오류 수정 * fix: 여행 생성 오류 수정 * add: 앱 아이콘 변경 * ui: timeline empty view 추가 * feat: timeline empty view 가시성 설정 * ui: 여행 내 방문 기록 empty view 추가 및 가시성 설정 * ui: 방문 기록 내 로그 미지원 기능 view 추가 * feat: 사진 첨부 카메라 미지원 기능 알림 추가 * ui: 필수값 표기 style 정의 * ui: 여행 생성 및 수정 필수값 표기 추가 * ui: 방문 기록 생성 및 수정 필수값 표기 추가 * feat: 생성, 수정, 로그인 시 다중 요청 전송을 막기 위한 화면 터치 제한 * feat: 장소 생성의 사진 첨부 리사이클러뷰 구현 - 사진 추가 & 삭제 구현 - GridLayout으로 변경 - 사진 중복 없이 최대 5장으로 제한 - 새로 추가된 사진이 기존 사진 뒤에 더해지도록 구현 * chore: 방문 생성 화면 rv_photo_attach로 xml id 수정 * ui: app icon 및 splash icon 변경 * refactor: xml ID 네이밍 컨벤션 적용 --------- Co-authored-by: somin Co-authored-by: Junyoung-WON * refactor: 도메인명 변경에 따라 travel을 memory로 수정 #217 (#231) * refactor: 패키지명 travel -> memory로 수정 * refactor: dto의 TravelMapper 를 MemoryMapper 로 네이밍 변경 * refactor: 여행(현 추억) 생성 response dto 네이밍 변경 - TravelCreationResponse -> MemoryCreationResponse * refactor: 여행(현 추억) request dto 네이밍 변경 - TravelRequest -> MemoryRequest * refactor: 여행(현 추억) 조회 response dto 네이밍 변경 - TravelResponse -> MemoryResponse * refactor: 여행(현 추억) 수정 request dto 네이밍 변경 - TravelUpdateRequest -> MemoryUpdateRequest * refactor: 여행(현 추억) 내 방문 dto 네이밍 변경 - TravelVisitDto -> MemoryVisitDto * refactor: 타임라인 여행(현 추억) item의 dto 네이밍 변경 - TimelineTravelDto -> TimelineMemoryDto * refactor: 여행(현 추억) ApiService 네이밍 변경 - TravelApiService -> MemoryApiService * refactor: 여행(현 추억) DataSource 네이밍 변경 - TravelDataSource -> MemoryDataSource - TravelRemoteDataSource -> MemoryRemoteDataSource * refactor: 여행(현 추억) Repository 네이밍 변경 - TravelRepository -> MemoryRepository - TravelDefaultRepository -> MemoryDefaultRepository * style: TimelineMapper import 재정렬 * refactor: NewTravel 도메인명을 NewMemory로 변경 * refactor: Travel 도메인명을 Memory로 변경 * refactor: TravelVisit 도메인명을 MemoryVisit으로 변경 * refactor: presentation의 TravelMapper 명 변경 - TravelMapper -> MemoryMapper * refactor: 여행(현 추억) ui 모델명 변경 - TravelUiModel -> MemoryUiModel - TravelVisitUiModel -> MemoryVisitUiModel * refactor: 여행(현 추억) view model 명 변경 - TravelViewModel -> MemoryViewModel - TravelViewModelFactory -> MemoryViewModelFactory * refactor: MemoryApiService의 Path 변경 - travel을 memory로 변경 - travels을 memories로 변경 * refactor: Memory 관련 dto 변수명 변경 - travel을 memory로 변경 * refactor: Timeline Dto의 Memory 관련 변수명 변경 - travel을 memory로 변경 - travels를 memories로 변경 * refactor: Memory 관련 도메인 모델의 변수명 변경 - travel을 memory로 변경 * refactor: Memory 관련 ui 모델의 변수명 변경 - travel을 memory로 변경 * refactor: data layer의 Memory 관련 함수 및 변수명 변경 - travel을 memory로 변경 * refactor: 방문 생성 request dto의 travelId 변수명 변경 - travelId -> memoryId * refactor: 여행(현 추억) 조회 view model 및 fragment의 네이밍 변경 - travel -> memory * refactor: fragment_travel 의 리소스 네이밍 변경 - travel -> memory - strings.xml의 리소스명 변경 * refactor: TravelCreationActivity 네이밍 변경 - TravelCreationActivity -> MemoryCreationActivity * refactor: 여행(현 추억) 생성의 ViewModel 관련 네이밍 변경 - TravelCreationViewModel -> MemoryCreationViewModel - TravelCreationViewModelFactory -> MemoryCreationViewModelFactory - 관련 함수 및 변수명 변경 - travel -> memory * refactor: 여행(현 추억) 생성, 수정에 관한 xml 리소스 명 변경 - travel -> memory - strings.xml 의 관련 리소스 수정 * refactor: 여행(현 추억) 수정 Activity, Handler 의 네이밍 변경 - travel -> memory * refactor: 여행(현 추억) 수정 ViewModel 의 네이밍 변경 - 관련 함수 및 변수 명 변경 - travel -> memory - Factory 클래스명 변경 * refactor: 여행(현 추억) 생성, 수정에서의 파일 변환 메서드명 변경 - travel -> memory - 자식 파일 명 상수화 * refactor: Timeline 의 UI 모델 및 Travel ID Key 의 리네이밍 - travel -> memory 로 일괄 변경 * refactor: presentation/timeline 내 travel 도메인명 변경 - travel -> memory - TimelineMapper 내 domain model -> ui model 변환 메서드명 변경 * refactor: dto/MemoryMapper 내 domain 변환 메서드명 변경 - dto/MemoryMapper 내 domain model을 dto로 변환하는 메서드명 변경 - travel -> memory * refactor: dummyTravel 을 dummyMemory 로 변경 * refactor: MainActivity 내 travel을 memory로 변경 * refactor: activity_main 내 travel을 memory로 변경 * refactor: TimeLineApiService 내 GET 메서드 path 수정 - travels -> memories * refactor: MemoryFragment 내 travel 을 memory 로 변경 - MemoryFragment, fragment_memory 내 travel 을 memory 로 변경 * refactor: MemoryViewModel 내 error message 변수명 변경 - TRAVEL_ERROR_MESSAGE -> MEMORY_ERROR_MESSAGE * refactor: navigation graph 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 extra 키 값 수정 - TRAVEL_ID_KEY -> MEMORY_ID_KEY - TRAVEL_TITLE_KEY -> MEMORY_TITLE_KEY * refactor: VisitFragment 내 travel을 memory로 변경 * refactor: VisitUpdateActivity 내 travel을 memory로 변경 * refactor: VisitUpdateViewModel 내 travel을 memory로 변경 * refactor: VisitTravelUiModel을 VisitMemoryUiModel로 변경 * refactor: 방문 수정 xml의 travel을 memory로 변경 * refactor: 여행(현 추억) 선택 xml 내 travel을 memory로 변경 * refactor: 여행 선택 바텀 시트 내 travel을 memory로 변경 - TravelSelectionFragment -> MemorySelectionFragment 로 수정 - TravelSelectionHandler -> MemorySelectionHandler 로 수정 - TravelSelectionFragment 내 메서드명 수정 - TravelSelectionHandler 내 매개변수명 수정 * refactor: VisitRepository와 구현체의 메서드 내 매개변수명 통일 * refactor: VisitsViewHolder 내 travel을 memory로 변경 * refactor: VisitCreationActivity 내 travel을 memory로 변경 * refactor: VisitCreationViewModel 내 travel을 memory로 변경 * refactor: 방문 생성 xml 내 travel을 memory로 변경 * refactor: BindingAdapters 내 travel을 memory로 변경 * refactor: strings 내 travel을 memory로 변경 - strings 내 '여행'을 '추억'으로 수정 Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * refactor: visit, visit log 도메인명 수정 #218 (#237) * refactor: VisitApiService 내 visit을 moment 로 변경 - 파일명 수정 - path 수정 - 메서드명 수정 - 매개변수명 수정 * refactor: data/visit 패키지명을 moment로 변경 * refactor: data/dto/visit 패키지명을 moment로 변경 * refactor: VisitCreationRequest 네이밍 변경 - 이전: VisitCreationRequest - 이후: MomentCreationRequest * style: StaccatoClient import 재정렬 * refactor: VisitCreationResponse 네이밍 변경 - 이전: VisitCreationResponse - 이후: MomentCreationResponse - 필드명 변경 : visitId -> momentId * refactor: VisitResponse 네이밍 변경 - 이전: VisitResponse - 이후: MomentResponse - VisitResponse 필드 내 visit을 moment로 변경 - VisitResponse 필드 내 visitLogs SerialName을 comments로 변경 * refactor: VisitUpdateRequest 네이밍 변경 - 이전: VisitUpdateRequest - 이후: MomentUpdateRequest - VisitUpdateRequest 필드 내 visit을 moment로 변경 * refactor: VisitLogDto 내 SerialName 변경 - visitLogId를 commentId로 변경 * refactor: MemoryResponse 내 visits SerialName 변경 - visits를 moments로 변경 * refactor: VisitCreationViewModel 내 FORM_DATA_NAME 변경 - 이전: visitImageFiles - 이후: momentImageFiles * refactor: MemoryVisitDto 내 visit를 moment로 변경 - MemoryVisitDto -> MemoryMomentDto로 변경 - visitId -> momentId로 변경 - visitImageUrl -> momentImageUrl로 변경 * refactor: VisitRemoteDataSource 내 visit을 moment로 변경 - VisitRemoteDataSource -> MomentRemoteDataSource로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: MomentRepository 및 구현체 내 visit을 moment로 변경 - VisitRepository -> MomentRepository로 변경 - VisitDefaultRepository -> MomentDefaultRepository로 변경 - 메서드명 변경 - 매개변수명 변경 * refactor: Visit 도메인 모델명 및 변수명 변경 - Visit -> Moment로 변경 - visitLogs -> comments로 변경 * refactor: Memory 도에인 모델의 visits을 moments로 변경 * refactor: MemoryVisit 도메인 모델 내 visit을 moment로 변경 * refactor: MemoryResponse의 visits 필드명을 moments로 변경 * refactor: dto/mapper/VisitMapper를 MomentMapper로 변경 * refactor: presentation/visit 패키지명을 moment로 변경 * refactor: VisitViewHolderType 네이밍 변경 - VisitViewHolderType -> MomentViewHolderType - enum 상수명 변경 - VISIT_DEFAULT -> MOMENT_DEFAULT - MY_VISIT_LOG -> MY_COMMENTS * refactor: VisitViewHolder 네이밍 변경 - VisitViewHolder -> MomentViewHolder - VisitDefaultViewHolder -> MomentDefaultViewHolder - MyVisitLogViewHolder -> MyCommentViewHolder * refactor: VisitAdapter 내 visit을 moment로 변경 - VisitAdapter -> MomentAdapter 로 변경 - visit -> moment 로 변경 * refactor: MomentAdapter 내 visit log를 comments로 변경 * refactor: VisitDetailUiModel 내 visit을 moment로 변경 - VisitDetailUiModel -> MomentDetailUiModel - VisitDefaultUiModel -> MomentDefaultUiModel - visitImageUrls -> momentImageUrls * refactor: VisitLogUiModel을 CommentsUiModel로 변경 * refactor: VISIT_ID_KEY extra key id 네이밍 변경 - VISIT_ID_KEY -> MOMENT_ID_KEY * refactor: VisitFragment 내 visit을 moment로 변경 * refactor: VisitViewModel 내 visit을 moment로 변경 - VisitViewModel -> MomentViewModel로 변경 - VisitViewModelFactory -> MomentViewModelFactory로 변경 * refactor: VisitMemoryUiModel 네이밍 변경 - VisitMemoryUiModel -> MomentMemoryUiModel로 변경 * refactor: presentation/visitcreation 패키지명 momentcreation으로 변경 * refactor: VisitCreationActivity 내 visit을 moment로 변경 - VisitCreationActivity -> MomentCreationActivity로 변경 * refactor: VisitCreationHandler 네이밍 변경 - VisitCreationHandler -> MomentCreationHandler로 변경 * refactor: VisitCreationViewModel 내 visit을 moment로 변경 - VisitCreationViewModel -> MomentCreationViewModel로 변경 - 메서드 및 변수명 변경 * refactor: 여행 -> 추억, 방문 기록 -> 스타카토로 도메인명 변경 * feat: s3 api 연결 #239 (#241) * feat: ImageResponse, ImageApiService 구현 * feat: ImageRepository 및 구현체 구현 Co-authored-by: s6m1n * fix: 추억 기능 버그 수정 #246 (#252) * fix: 일부 EditText 개행 불가 처리 및 키보드 숨김 처리 #247 (#249) * ui: 닉네임과 추억 생성, 수정 제목 입력 시 줄바꿈 제한 * fix: 키보드 활성화 상태에서 빈 화면 터치로 키보드 숨김 처리 - 메서드 명 변경: setHideKeyboardAction -> setHidingKeyboardAction * style: 클래스 내 override 메서드의 순서 변경 - 팀 코드 컨벤션에 맞게 순서 재정렬 - override 메서드를 상단에 둔다. * style: ktlint 적용 * fix: root뷰 터치 시 클릭 이벤트가 발생하지 않는 오류 수정 - 원인 분석: ConstraintLayout 내부 Toolbar 및 ScrollView, 그리고 그 자식 View들이 클릭 이벤트를 가로채기 때문에, 바인딩 된 최상단 root 뷰인 ConstraintLayout의 클릭 이벤트가 동작하지 않는다. - 해결 방법: 여러 클릭 이벤트를 가로채는 dispatchTouchEvent 메서드를 오버라이드하여, 터치된 부분이 현재 포커스가 되지 않은 View(키보드 바깥 화면) 범위라면, 키보드를 숨기는 동작을 추가하였다. * refactor: 키보드 숨김 동작을 handler 바인딩으로 적용 - LoginHandler 에 화면 터치에 대한 동작을 추가, 화면 터치 시 키보드를 숨김 처리하는 동작을 바인딩으로 설정 - InputMethodManager 인스턴스를 지연초기화하여 저장 * refactor: InputMethodManager 인스턴스를 lazy로 지연 초기화 * fix: 닉네임, 제목 입력 칸의 키보드 액션 버튼 변경 - 키보드의 액션 타입을 Search에서 Done으로 변경 * style: ktlint 적용 * refactor: 타임라인 리팩터링 #232 (#263) * refactor: TimelineViewModelFactory의 생성자 파라미터 추가 - 내부 프로퍼티에 속해있던 TimelineRepository를 생성자 프로퍼티로 변경 * fix: 추억 목록 아이템이 하나일 때의 View 수정 - 아이템 개수가 하나일 때는 타임라인의 선이 나타나지 않도록 변경 * chore: 코루틴 예외 처리 로그에context 출력 * refactor: 메서드 분리 및 순서 재정렬 - 코드 컨벤션: override 메서드는 상단에 위치한다 * refactor: TimelineViewModel 생성 팩토리 메서드 활용 * style: ktlint 적용 * ui: 화면 전환에 사용될 twin animation 효과 생성 * ui: animation 효과 활용하여 화면 전환 애니메이션 적용 * ui: Main 화면의 배경 색을 하얀색(#FFFFFF)으로 지정 * style: ktlint 적용 * feat: 기분 선택 기능 구현 및 스타카토 조회 화면 구조 변경 #191 (#289) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * style: ktlint 적용 * feat: 추억 API 변경사항 반영 및 리팩터링 #259 (#265) * ui: 추억 생성 화면 사진 로드 시 coil 라이브러리 사용 * ui: 삭제 버튼 아이콘 추가 * ui: 추억 생성 화면 사진 삭제 버튼 추가 * feat: 추억 생성 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 생성 화면 사진 삭제 구현 * feat: 추억 수정 화면 사진 첨부 icon 가시성 설정 * ui: 추억 수정 화면 사진 삭제 버튼 추가 * feat: 추억 수정 화면 사진 삭제 버튼 가시성 설정 * feat: 추억 수정 view model의 imageUri 설정 매개변수 타입 변경 * feat: 추억 수정 화면 사진 삭제 구현 * fix: 추억 생성 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * fix: 추억 수정 화면의 사진 첨부란 연속 클릭 시 앱 종료 되는 버그 수정 * feat: MemoryRequest dto에 썸네일 사진 url 필드 추가 * feat: 추억 생성 메서드의 시그니처 변경 - MemoryApiService 내 추억 생성 메서드의 시그니처 변경 - 위 변경에 따른 DataSource, Repository, ViewModel의 추억 생성 관련 메서드 시그니처 변경 * feat: 추억 생성 view model 주 생성자로 ImageRepository 주입 * feat: 추억 생성 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 생성 화면) - 추억 생성 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 생성 시 썸네일 사진 url 추가 * refactor: MemoryRequest의 추억 썸네일 사진 기본 인자 값 null로 설정 * feat: 추억 수정 메서드의 시그니처 변경 * feat: 추억 수정 view model 주 생성자로 ImageRepository 주입 * feat: 추억 수정 화면의 썸네일 사진 저장 기능 구현 * feat: 서버에서 저장된 사진을 불러오는 기능 추가 (추억 수정 화면) - 추억 수정 화면에서 서버에 저장된 사진을 로드하는 기능 구현 - UI에 불러온 사진을 표시하는 로직 수정 * feat: 추억 수정 시 썸네일 사진 url 추가 * refactor: 불필요한 MemoryUpdateRequest 제거 * ui: empty view 캐릭터 이미지 추가 * ui: 추억 설명글 유무에 따른 가시성 설정 * ui: 함께 한 사람들 가시성 gone 으로 설정 - 4차 스프린트 범위에서 제외됨 * feat: 이미지 선택 옵션 추가 (단일 선택 및 다중 선택 지원) * ui: TextInputLayout, TextInputEditText Style 정의 * ui: 추억 생성 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 수정 화면 입력란 TextInputLayout으로 변경 - counter 속성 사용을 위해 TextInputLayout으로 변경함 * ui: 추억 조회 화면 썸네일 사진 유무에 따른 가시성 설정 * ui: empty view 캐릭터 이미지 크기 변경 * ui: 앱 이름 Staccato_AN -> Staccato 로 수정 * refactor: 추억 생성 및 수정 화면 메서드 순서 정리 * ui: 제목용 TextInputEditTextStyle 정의 및 적용 * ui: 추억 생성 및 수정 화면 썸네일 coilPlaceHolder 변경 - 이전: shape_place_holder_rectangle - 이후: shape_all_gray1_8dp * refactor: 삭제 다이얼로그 show 메서드 호출 방식 변경 - apply를 사용하지 않는 방식으로 변경 * ui: 코멘트 미지원 안내 view 추가 * feat: 스타카토 생성, 수정 화면 사진 및 완료 버튼 개선 #242 (#291) * feat: (스타카토 생성 화면) 사진 드래그로 순서 변경 기능 구현 * refactor: data 패키지에 S3 이미지 API 분리 적용 * refactor: AttachedPhotoUiModel 및 프로그래스바 추가 * feat: recyclerView에서 지워진 사진의 job cancel 처리 * refactor: editText를 TextInputLayout로 수정 * feat: (스타카토 수정 화면) 사진 드래그로 순서 변경 / 로딩 구현 * refactor: 프로퍼티 네임 변경 및 visitedAt LocalDateTime으로 수정 * style: ktlint 적용 * build: 구글 맵 API 사용에 따른 CI 수정 #296 (#297) * build: 구글 맵 api key를 저장하는 파일을 설정하는 명령어 작성 * refactor: defaults 에 설정된 shell 설정에 따라 추가적인 shell 설정 삭제 * feat: Google Map 연결, 스타카토 목록 조회 API 연결 #54 (#295) * build: google map 의존성 추가 * build: 구글맵 관련 properties ignore 추가 * build: 구글맵 api key 설정 * feat: Google Map 연결 * feat: MainActivity Handler 구현 * ui: 추억 및 스타카토 생성 메뉴 추가 * ui: popup menu style 정의 * feat: 추억 생성 및 수정 menu 연결 - handler 연결 - 메서드 분리 * feat: 위치 권한 요청 구현 - ACCESS_FINE_LOCATION 권한 요청 - ACCESS_COARSE_LOCATION 권한 요청 * feat: 현 위치 표시 * style: MainActivity formatting * feat: locationPermissions 타입 변경 - 이전: List - 이후: Array * feat: MomentLocationDto, MomentLocationResponse 추가 * feat: 스타카토 목록 조회 api service 구현 * feat: 스타카토 목록 조회 data source 구현 * feat: MomentLocation 도메인 모델 구현 * feat: MomentLocationDto를 도메인 모델로 변환하는 mapper 구현 * feat: 스타카토 목록 조회 repository 구현 * feat: 스타카토 목록 조회 view model 구현 * feat: 스타카토 목록을 marker로 표시 * refactor: home 패키지명을 maps로 변경 * feat: 마커 클릭 시 스타카토 상세로 이동 기능 구현 * feat: 스타카토 조회 추억 id, 제목 필드 추가 * feat: 마지막 위치 위경도 찾기 * refactor: 안드로이드 1차 QA 반영 #299 (#301) * refactor: 안드로이드 1차 QA 반영 * refactor: 안드로이드 1차 QA 반영2 * refactor: 안드로이드 1차 QA 반영3 * refactor: 삭제 메시지 변경 * fix: 스타카토 조회 화면 스택 관리 및 ui 수정 #304 (#306) * feat: 지도 화면에서 스타카토 조회 화면으로 이동 시 스택 관리 * feat: 타임라인 화면에서 추억이 존재하지 않을 때 추억 생성 버튼 추가 * ui: 스타카토 조회 화면 툴바 위치 고정 * build: Android CD 적용 #300 (#308) * build: CD 워크플로우 yml 파일 작성 * build: keystore 접근을 위한 build.gradle.kts 파일 설정 * build: 기존 apk 추출 ci 파일 수정 - demo 버전의 apk를 추출 및 배포하는 목적에 맞게 파일 명 수정 - apk 빌드 후 테스트를 수행하는 job 추가 - firebase 앱 배포에 아티팩트 업로드하는 job 추가 * fix: ci 파일에도 keystore 생성 job 추가 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: 키스토어 환경변수를 base64로 디코딩하는 명령어 재수정 * fix: ci 파일에 키스토어 관련 설정 적용 * fix: 키스토어 관련 명령어 일부 수정 * fix: build.gradle.kts 불필요한 괄호 제거 * fix: keystore.properties 로 부터 프로퍼티를 가져오는 형식 변경 * fix: upload-artifact step에서 빌드 파일의 upload 경로 수정 (#316) upload-artifact 는 defaults 설정의 working-directory 경로가 적용되지 않음 * fix: android cd 재수정 (2차) #317 (#319) * fix: upload-artifact 빌드 파일의 upload 경로 3차 수정 * fix: 배포 시 빌드 파일의 경로 수정 * fix: 빌드 파일의 upload 경로 수정 및 파일이 없는 경우 에러 처리 * fix: 빌드 파일의 upload 경로 4차 수정 * fix: 빌드 파일의 upload 경로 5차 수정 * fix: 빌드 파일의 upload 경로 6차 수정 - 디렉터리 경로 생성 후 upload 실행 * fix: 빌드 파일의 upload 경로 7차 수정 github의 workspace 환경변수(절대경로) 활용 * fix: clean test 제거 및 디버그용 파일 경로 탐색 명령어 추가 * fix: 디버그용 파일 경로 검색 명령어 수정 * fix: 디버그용 파일 경로 검색 명령어 삭제 * fix: 디버그용 파일 검색 명령어 삭제 및 업로드 파일 경로명 수정 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 기능 구현 #314 (#324) * feat: MainActivity에서 주소를 가져오는 로직 삭제 * feat: 스타카토 생성 시 현 위치의 주소를 가져오는 로직 구현 * refactor: 메서드 순서 정렬 * refactor: 스타카토 조회 화면 ViewPager2 적용 및 UI 아이콘 개선 #318 (#320) * refactor: 아이콘 추가 및 UI 개선 * feat: 스타카토 상세 사진 Viewpager 적용 * feat: 스타카토 상세 사진 Viewpager에 dot indicator 추가 * style: ktLint Format * feat: 메인 지도 화면에서 스타카토 생성하는 플로우 구현 #321 (#327) * feat: 날짜로 추억 목록 불러오는 getMemories API 추가 * feat: 메인에서 스타카토 생성 시 추억 목록 선택 가능 * feat: 스타카토 생성 시 역지오코딩과 추억 선택 연동 * build: debug와 release로 buildTypes 분리 (#329) - appName, appId, baseUrl 분리 - release에 난독화 적용 * build: debug 와 release 배포 분기에 따른 CD 수정 - CD에 대한 트리거 재설정 : main 브랜치에 대한 push 및 pr * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 #326 (#330) * refactor: 지도 화면 onResume에서 스타카토 목록 load * refactor: 스타카토 목록 로드 메서드명 변경 - 이전: loadMoments - 이후: loadStaccatos * feat: 공유 view model에 스타카토 목록 업데이트 상태 추가 * fix: 스타카토 생성, 삭제 후 지도 화면의 마커가 갱신되지 않는 오류 해결 * feat: 지도 로드 시 현위치로 이동하도록 구현 * build: ci 및 cd 파일 수정 ci - 불필요한 gradle 빌드 및 테스트 제거 cd - 타겟 브랜치 develop 제거 * feat: 댓글 조회, 생성, 삭제 기능 구현 #290 (#331) * feat: 기분 수정 요청을 보내는 Request Dto 작성 * feat: MomentApiService 에 기분 수정 요청에 대한 API 작성 * feat: 기분 수정 요청에 대한 DataSource 메서드 작성 * feat: 기분 도메인 모델 생성 * feat: 기분 도메인을 기분 수정 Request로 변환하는 메서드 작성 * ui: 기분 아이콘 이미지 리소스 추가 * ui: 기분 아이콘의 테두리를 selector로 생성 - 선택/미선택에 따라 다른 ui를 나타낸다 * ui: 기분 아이콘에 사용할 style 지정 * fix: API 변경에 따라 DTO 및 Mapper 변경 - 순간(현 스타카토)의 visitedAt의 타입을 LocalDate에서 LocalDateTime으로 변경 * fix: 순간 DTO에 기분 필드 추가 - 순간 Dto에 기분(Feeling) 필드를 추가함에 따라 Mapper 및 도메인 수정 * feat: 기분 선택 api에 필요한 repository 메서드 작성 * feat: 기분 uiModel 생성 * feat: 댓글에 대한 UI 모델 생성 * feat: 순간(현 스타카토) 상세 정보에 대한 UI 모델 생성 * feat: 기분 ImageView 의 선택 상태 바인딩 어댑터 작성 * feat: 댓글 화면 구성 및 Adapter, Fragment 작성 * feat: 순간(현 스타카토)의 Ui Model Mapper 변경 MomentDetailUiModel.CommentsUiModel -> CommentUiModel MomentDetailUiModel.MomentDefaultUiModel -> MomentDetailUiModel Feeling을 Ui Model로 변환하는 Mapper 추가 * feat: 기분 선택 View 구성 및 Fragment, ViewModel, Adapter, Handler 작성 * feat: 순간 상세에 대한 View 구성 및 Fragment, ViewModel 작성 * fix: 기분 선택 클릭 리스너와 바인딩 어댑터 설정 및 View 수정 * fix: 누락된 ViewModel 데이터 바인딩 설정 * feat: 순간 조회 화면 재구성 * refactor: 네비게이션 action 및 id 네이밍 수정 visit -> moment로 수정 * refactor: 방문 -> 순간 으로 키워드 변경 * refactor: 불필요한 클래스 및 xml 파일 제거 * ui: xml 컨벤션에 맞추어진 타 사용자의 댓글 ui 구성 * feat: 댓글 API의 DTO 작성 * feat: 댓글 API Service 작성 * feat: 댓글 CRUD DataSource 작성 * refactor: CommentApiService 각 메서드의 반환 값을 Response로 변경 * feat: CommentApiService 를 create * feat: CommentDataSource 구현체 생성 * refactor: 댓글 Dto 클래스 네이밍 변경 - VisitLogDto -> CommentDto * refactor: CommentDto 의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * refactor: VisitLog 도메인 모델 클래스의 네이밍 변경 - VisitLog -> Comment * refactor: Comment 도메인 모델의 ID 프로퍼티 네이밍 변경 - visitLogId -> commentId * feat: 새로운 댓글 도메인 모델 생성 * feat: CommentRepository 작성 * feat: Domain 모델과 DTO 모델을 변환해주는 Mapper 작성 - CommentDto를 Comment로 변환하는 메서드를 CommentMapper.kt로 이동 * feat: CommentRepository의 기본 구현체 작성 * feat: 댓글 ViewModel, Factory 작성 및 Comment 불러오기 구현 * ui: ViewModel 데이터바인딩 및 빈 댓글 문구에 대한 strings 설정 * feat: CommentsViewModel 활용 및 옵저빙 * feat: 댓글 조회, 생성, 삭제 기능 구현 * chore: ktlint 적용 * feat: 추억 생성 및 수정 이미지 로딩 중 표시 및 저장 버튼 비활성화 #332 (#334) * feat: 추억 생성 이미지 로딩 중 표시 * feat: 추억 수정 이미지 로딩 중 표시 * feat: 추억 생성 및 수정 이미지 로딩 중 저장 버튼 비활성화 * style: formatting * refactor: 댓글 화면 개선 및 리팩터링 #333 (#335) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 * build: defaultConfig의 버전 코드와 이름 수정 versionCode : 2 -> 3 versionName : 1.1 -> 1.0.0 (배포 버전과 동일) * refactor: 패키지명 변경 #342 (#343) - 5차 스프린트 요구사항 만족을 위해 패키지명 변경 - 이전: com.woowacourse.staccato - 이후: com.on.staccato * ui: 타임라인 화면 디자인 수정 #347 (#348) * layout: 타임라인 디자인 수정 및 STATE_HALF_EXPANDED 구현 * chore: 불필요한 파일 삭제 * chore: 수정된 패키지명 반영 * layout: empty 추억 view 높이 조절 * layout: 기분 선택 여부 컬러/흑백 처리 * ui: 추억 화면 디자인 수정 및 추억 생성 플로우 변경 #346 (#355) * ui: 추억 썸네일 이미지용 gradient drawable 구현 * ui: 스타카토 썸네일 이미지용 gradient drawable 구현 * ui: 추억 조회 화면 ui 수정 - 추억 상세 내용 ui 수정 - 스타카토 목록 ui 수정 * ui: 스타카토 추가 버튼 수정 * feat: 홈 화면의 추억 생성 플로우 제거 - 홈 화면에서는 스타카토 생성만 가능하게 변경 * ui: 추억 생성 및 수정 화면 toolbar 제목 추가 * ui: 스타카토 생성 및 수정 화면 toolbar 제목 추가 * ui: 타임라인 화면 추억 추가 및 정렬 버튼 추가 * style: formatting * refactor: 댓글 화면 개선 #333 (#354) * fix: merge conflicts 해결 * fix: 글자 수 제한 500자로 수정 * style: ktlint 체크 * build: CD 수정 - 구글 플레이스토어 업로드 스텝 추가 * ui: 댓글 구성요소의 UI 개선 RecyclerView - 아이템 변화 시 애니메이션 효과 제거 - 스크롤 시 물결 무늬 애니메이션 제거 - 최소 높이 지정 댓글이 없는 경우의 Default View - 높이 및 마진 조정 * refactor: UserInfoSharedPreferences의 파일, 키 이름 변경 - 패키지명 변경에 따라 해당 SF가 사용하는 파일, 키 이름 변경 * fix: xml 속성 수정 - layout_marginBottom 오타 수정 - app:itemAnimator 속성 제거 * feat: 댓글 입력 중 화면 터치 시 키보드 비활성화 구현 - MainActivity 에서 dispatchTouchEvent 를 오버라이드하여, focus 된 EditText의 focus를 해제하고, 키보드를 숨김처리하도록 구현 * ui: RecyclerView와 댓글이 없을 때 View의 높이 조정 * feat: 리사이클러뷰 애니메이션 효과 제거 및 adapter 설정 메서드명 변경 * feat: 댓글 수정하기 메뉴 제거 및 댓글 삭제 시 삭제 다이얼로그를 띄우도록 변경 --------- Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Junyoung-WON Co-authored-by: s6m1n * style: code convention 적용 * fix: 중복 닉네임 입력 시 유저 정보 불러오도록 수정 #344 (#345) * build: develop 브랜치 배포 트리거 추가 * fix: 중복 닉네임 사용 가능하도록 수정 * style: code convention 적용 * feat: 추억 생성/수정 시 기간을 nullable하게 변경 #350 (#352) * test: 추억 기간이 null일 때 추억 생성이 가능한지 테스트 추가 * test: 기간이 존재하는 추억에 대해 기간이 존재하지 않도록 변경 테스트 추가 * refactor: Term 생성 시 시작 날짜와 끝 날짜 중 하나만 존재하는 경우 예외 메시지 수정 * test: 예외 메시지 수정 사항을 테스트 코드에 반영 * fix: 중복 닉네임 입력 시 유저 정보 불러오도록 수정 #344 (#345) * build: develop 브랜치 배포 트리거 추가 * fix: 중복 닉네임 사용 가능하도록 수정 * style: code convention 적용 * fix: 사용자의 추억 내에서 중복 제목 검증하도록 수정 #365 (#366) * chore: android/backed path & trigger 수정 #367 (#368) * chore: BE/AN path 지정 및 trigger 수정 * chore: BE/AN trigger 수정 * chore: BE trigger 수정 * chore: path 오류 수정 * fix: embedded 인스턴스화 관련 NPE 버그 해결 #371 (#372) * build: create_empty_composites.enable로 embedded 인스턴스화 시 NPE 방지 * docs: 기간 미필수 변경사항 문서에 반영 * chore: dev 서버 배포 trigger 수정 * refactor: 테스트 리팩터링 #349 (#370) * refactor: AuthControllerTest의 테스트 데이터 String 형식으로 변경 * refactor: LoginRequest, ExceptionResponse fixture 분리 * refactor: Comment 테스트 픽스처 분리 및 Controller 테스트 데이터 타입 변경 * refactor: Auth 테스트 픽스처 제거 및 Controller 테스트 책임 명확하게 수정 * refactor: Comment 테스트 픽스처 제거 및 Controller 테스트 책임 명확하게 수정 * fix: 양방향 참조용 리스트에 중복 저장 로직 제거 * refactor: Memory 테스트 픽스처 및 Controller 테스트 책임 명확하게 수정 * refactor: 컨트롤러 테스트의 책임에 맞게 테스트 수정 * refactor: Comment 요청 픽스처 분리 * refactor: Login 요청 픽스처 분리 * refactor: Comment 수정 요청 픽스처 분리 * refactor: Comment 패키지 이동 * refactor: Moment 수정 요청 픽스처 분리 * style: code convention 적용 * fix: 테스트 오류 수정 * refactor: 테스트명 수정 * refactor: 미사용 fixture 제거 * test: 이미지 개수 경계값 테스트 추가 * test: displayName 수정 및 미필수 값 null일 때 역직렬화 테스트 추가 * feat: 스타카토 수정 시 날짜, 장소 변경 가능하도록 수정 #353 (#362) * feat: 스타카토 수정 시 장소, 날짜, 추억도 변경할 수 있도록 서비스 메서드 구현 * feat: 스타카토 수정 시 장소, 날짜, 추억도 변경할 수 있도록 컨트롤러 메서드 구현 * test: 존재하지 않는 스타카토 수정 시 예외 발생 테스트 추가 * refactor: 가독성을 위한 메서드명, 변수명 변경 * refactor: 사용하는 DTO 클래스명과 매칭되도록 변수명 수정 * test: 컨트롤러 예외 테스트에서는 ObjectMapper를 사용하도록 테스트 변경 * test: 가독성을 위해 줄바꿈 제거 * test: 실패 케이스에서는 DTO 형식을 검증하지 않도록 변경 * test: 서비스 단에서 검증 책임이 없는 사항은 검증하지 않도록 변경 * feat: Logging 레벨 수정 및 DB 예외 로깅, AOP 적용 #351 (#358) * refactor: 로깅 레벨 수정 * feat: DB Exception 관련 로깅 적용 * feat: 로깅 AOP 적용 * refactor: 예외 헨들러 추가 * feat: 모든 Controller, Service 메서드 로깅 * hotfix: 서버 마이그레이션 오류 해결 #383 (#384) * deploy: v1.0.2 (#369) * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * docs: 서비스 소개글 작성 (#127) * docs: PR 템플릿 오타 수정 (#154) - 오타 수정 및 개행 조정 - Issue Number 태그 형식 추가 * deploy: 스타카토 v1.0.0 #312 (#313) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 --------- Co-authored-by: devhoya97 Co-authored-by: somin Co-authored-by: BurningFalls Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * build: CI 적용 브랜치 추가 * hotfix: QA #322 (#323) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3Ob… * hotfix: 서버 마이그레이션 오류 해결 #383 (#384) * chore: stage서버에서 사용하는 DB를 별도의 EC2 인스턴스로 분리 및 flyway 적용 #381 (#382) * chore: stage cd시 docker-compose를 사용하지 않도록 변경 * feature: flyway 적용 * chore: pull_request stage cd 임시 해제 * chore: pull_request stage cd 롤백 * feat: DB 마이그레이션 #386 (#389) * test: 컨트롤러 테스트의 책임이 아닌 테스트 제거 - 사진 5장 초과 테스트의 책임은 MomentImages이므로 제거 * chore: 운영 서버 datasource 설정 변경 * feat: dataSourceConfiguration 구현 * fix: profile 설정 * chore: 다중 운영 환경에 서버 마이그레이션 적용 * fix: OSIV 비활성화 * chore: 트리거 변경 * feat: 스타카토 생성/조회/수정 시 title과 placeName을 각각 저장 #373 (#385) * refactor: placeName을 DTO에서는 staccatoTitle로, 엔티티에서는 title로 변경 * feat: 스타카토 관련 모든 DTO와 Spot 객체에 placeName 필드 추가 * chore: flyway를 사용해서 DB 변경사항 적용 * fix: 사용자의 추억 내에서 중복 제목 검증하도록 수정 #365 (#366) * fix: 스타카토 조회 시 위도 경도까지 반환하도록 변경 (#391) * feat: 기존 스타카토 조회 API 복구 (#396) * feat: 이전 기록 불러오기 API 구현 #374 (#379) * feat: 중복 닉네임 입력 불가능 검증 복구 * feat: 이전 기록 불러오기 컨트롤러 구현 * feat: 사용자 등록 시 고유 코드 발급하도록 구현 * feat: 고유 코드로 사용자 조회해서 토큰 발급하는 서비스 구현 * test: 존재하지 않는 고유 코드로 사용자 조회 실패 테스트 추가 * docs: 이전 기록 불러오기 API 문서화 * build: flyway 의존성 및 설정 추가 * chore: sql init script 추가 * chore: 로컬 환경에서는 flyway 비활성화 * chore: dev cicd trigger 수정 * chore: visitedAt 타입 변경 스크립트 추가 * chore: startAt, endAt nullable 스크립트 추가 * chore: dev 서버 ddl 옵션 변경 * chore: stage 서버 ddl 옵션 변경 * chore: dev서버 콘솔 로깅 추가 * chore: defer-datasource-initialization 설정 변경 * chore: stage 서버 설정 파일에 flyway 활성화 * chore: member code 필드 스크립트 추가 * chore: 운영 서버에 flyway 임시 비활성화 * fix: 스크립트 오류 수정 * fix: 스크립트 오류 수정 * fix: 스크립트 오류 수정 * fix: 스크립트 오류 수정 * fix: 스크립트 오류 수정 * style: eol추가 * refactor: api http method 변경 --------- Co-authored-by: BurningFalls * feat: 사용자 프로필 사진 수정 API 구현 #376 (#380) * feat: 사용자 프로필 사진 변경 컨트롤러 구현 * feat: 사용자 프로필 사진 변경 서비스 구현 * docs: 프로필 사진 변경 API 문서화 * refactor: 명세서 형식 일관성있게 통일 * style: code convention 적용 * style: 변경된 code convention 적용 * refactor: 테스트명 적절하게 변경 * refactor: HTTP 응답 코드 변경 * refactor: pathVariable 제거 * refactor: URI 변경 * feat: 추억의 기간을 필수가 아닌 선택으로 변경 #363 (#387) * feat: 추억의 기간을 필수가 아닌 선택으로 변경 - 변경된 요구사항 : 추억의 기간은 필수가 아닌 선택이다. - 위 요구사항에 맞춰 Memory에 관한 비즈니스 로직 변경 : startAt과 endAt을 nullable로 변경 및 기본값 null 설정 - startAt과 endAt이 모두 null인 경우, 기간이 설정되지 않은 추억 - LocalDate 또한 nullable로 변경, 문자열로부터 변환할 때의 에러 발생 방지 처리 * fix: 추억 기간을 설정하지 않고도 생성이 가능하도록 수정 BindingAdapter.kt - 추억 생성 버튼의 enable 속성 수정 - 기간(시작 날짜, 종료 날짜)이 둘다 Null 또는 Not Null인 경우 enable MemoryMapper.kt - 추억 생성 모델 NewMemory에서 Request Body로 변경될 때, 기간 속성에 null이 적용되지 않는 오류 수정 * ui: 추억 기간 설정 switch의 구성 요소 xml 작성 * ui: 추억 기간 설정 Switch 구성요소(track, thumb) 변경 * ui: 추억 기간 설정 Switch와 설명문 삽입 - SwitchMaterial 로 설정 - 기간 설정에 대한 설명문 추가 - 바인딩 어댑터 수정 : 기간이 없거나 있는 경우(둘다 Null이거나 Not Null) 생성 버튼이 활성화되도록 수정 - 사용하지 않는 drawable 제거 * fix: 추억 저장 버튼의 활성화 조건 오류 수정 - 날짜 범위가 있거나 없을 때를 판단하는 연산자 수정 * feat: 추억 생성 화면에 기간 설정 기능 구현 - BindingAdapter: 스위치의 Checked State에 따라 TextView 가시성을 처리하는 로직 구현 - MemoryCreationViewModel: 기간 설정 스위치 상태를 나타내는 MutableLiveData 생성, 스위치가 off 상태일 때 startDate와 endDate의 값을 null로 처리 - activity_memory_creation.xml: Switch 설정 및 데이터바인딩 설정 * feat: 추억 수정 시 기간 설정 로직 구현 - MemoryUpdateViewModel: 기간 설정 스위치 상태를 나타내는 (isPeriodSet: MutableLiveData) 생성, 마지막으로 설정된 기간을 저장하는 lastStartDate, lastEndDate * feat: 추억 수정 화면에 기간 선택 기능 연결 및 바인딩 어댑터 수정 activity_memory_update.xml - SwitchMaterial 추가 및 constraints, id 명 수정 - 스위치 on/off에 따라 기간 선택 버튼의 가시성을 바인딩 어댑터로 설정 BindingAdapters.kt, activity_memory_creation.xml - 기간 선택 버튼 가시성 속성 이름 변경 * refactor: 추억 조회 화면의 기간 날짜 형식 바인딩 어댑터 수정 BindingAdapters.kt - 기간의 날짜 형식을 지정하는 바인딩 메서드 수정 - 불필요한 주석 제거 및 코드 리팩터링 fragment_memory.xml - 기간 날짜 형식을 바인딩 어댑터로 적용 layout_timeline.xml - tools의 예시 날짜 형식 수정 * style: ktlint 체크 * feat: 스타카토 생성/수정 화면에서 위치 선택 기능 구현 (#397) * feat: 스타카토 생성/수정 플레이스 검색 버튼 추가 * style: ktLint에 맞게 파일 명 수정 * build: 구글 Place 의존성 및 Client 추가 * feat: 스타카토 생성 화면에서 장소 선택 기능 추가 * feat: 스타카토 관련 API 수정 사항 반영 - staccatoTitle과 placeName 분리 - MomentResponse에 위경도 좌표 추가 - MemoryCandidate에 시작, 종료 날짜 추가 * feat: 스타카토 생성 화면 장소 선택 기능 구현 * feat: 스타카토 수정 화면 장소 선택 기능 구현 * style: KtLint 적용 * style: Manifest 불필요한 AutocompleteActivity 제거 * layout: Constraint 버그 해결 및 margin 미세 수정 * fix: GPS 및 위치 권한, 현위치 버그 수정 및 바텀시트 상태에 따른 지도 카메라 이동 #341 (#399) * feat: MainActivity에 GoogleMap 추가 * feat: location 권한 요청 및 내 위치 레이어 구현 - MapsFragment에 있던 location 권한 요청 및 내 위치 레이어 로직 MainActivity로 이동 * refactor: activityResultLauncher 관련 코드 정리 - MapsFragment에 있던 location 권한 요청 및 내 위치 레이어 로직 MainActivity로 이동 * feat: location 권한 요청 및 내 위치 레이어 활성화 로직 수정 * feat: 현위치로 카메라 이동하는 기능 구현 * feat: 스타카토 목록 조회 및 marker 생성 * refactor: 메서드 순서 정리 * feat: BottomSheet State에 따라 지도의 Camera가 이동하는 기능 구현 - BottomSheet의 State가 HALF_EXPANDED라면 현 위치 포인터를 화면 상단에 위치하도록 한다 - BottomSheet의 State가 HALF_EXPANDED 상태가 아니라면 현 위치 포인터를 화면 정중앙에 위치하도록 한다 * feat: 위치 권한 교육용 CustomDialog 구현 * feat: 지도 화면의 스타카토 마커 클릭 시 스타카토 상세 화면으로 이동하는 기능 구현 * feat: 위치 설정 요청 기능 구현 * refactor: MapsFragment 제거 및 지도 지도 관련 파일 이동 * refactor: 키보드 숨김 로직 개선 및 리팩터링 #361 (#400) * feat: 키보드 숨김 처리 로직 세분화 및 BindingActivity 로 마이그레이션 * chore: gitignore 에 keystore.properties 추가 * fix: 코멘트 입력 시 개행이 가능하도록 변경 TextInputEditText - IME Option을 actionNone으로 지정하여 개행이 가능하도록 수정 - inputType을 textMultiLine으로 설정 * refactor: 메서드 접근 제한자 및 정의 순서 변경 * fix: EditText에서 EditText로 focus가 변경될 때 키보드가 사라지지 않는다 - SingleTapEvent를 처리하기 전에 dispatchTouchEvent를 먼저 전파해야함 - 메서드 분리 및 변수명 변경 * ui: 프로필 이미지의 place holder를 oval로 변경 * style: ktlint check * style: ktlint 적용 * feat: 사용자 정보 조회 API #398 (#408) * refactor: 컨트롤러명 변경 * feat: 사용자 정보 조회 API 컨트롤러 구현 * docs: 사용자 정보 조회 API 문서화 * refactor: 미사용 메서드 제거 * docs: 응답 상황 명세 수정 * refactor: 추억 조회 시 created_at 기준 정렬을 DB단이 아닌 애플리케이션 단에서 수행 #404 (#409) * refactor: 회원의 모든 추억 조회시 정렬을 앱단에서 수행 * refactor: 특정 날짜를 포함한 특정 회원의 모든 추억 조회시 정렬을 앱단에서 수행 * refactor: fk에 대한 인덱스는 자동적용되므로 코드상에서 제거 * refactor: 특정 스타카토의 모든 댓글 조회시 생성 순 정렬을 앱단에서 수행 * feat: 스타카토 생성/수정 화면에서 추억, 날짜, 시간 선택 기능 구현 #401 (#412) * refactor: startAt과 endAt nullable하게 수정 * refactor: 스타카토의 유효한 일시를 계산하는 메서드 추가 * refactor: 추억 화면에서 스타카토 생성 가능 기간 확인 로직 제거 * feat: MemoryVisitedAtSelectionFragment 구현 * feat: 스타카토 생성 화면에서 추억, 날짜, 시간 선택 기능 구현 * feat: 스타카토 수정 화면에서 추억, 날짜, 시간 선택 기능 구현 * style: 불필요한 주석 제거 * style: KtLint CI 에러 수정 * feat: 이전 기록 불러오기 화면 구현 #395 (#407) * refactor: 댓글 생성 API 메서드명 변경 * feat: 이전 기록 복구 요청에 대한 응답 DTO 작성 * feat: MemberApiService 생성 및 이전 기록 불러오기 API 작성 * feat: MemberApiService 인스턴스 프로퍼티 생성 * feat: MemberDataSource와 구현체 작성 * feat: MemberRepository와 구현체 작성 * refactor: DataSource 레이어 제거 - 하나에 요청 메서드를 가진 것에 반해 과도한 계층 분리가 이루어진 것 같아 DataSource를 제거함 * ui: 이전 기록을 불러오는 화면 작성 * feat: 이전 데이터 복구 기능 구현 - 복구(사용자 고유) 코드로 불러오기 요청을 보내고, 성공 시 새로운 토큰 값을 SharedPreference에 저장한다. - 저장 완료 후, 복구 성공 상태를 변경하여 MainActivity로 이동한다. - 에러 발생 시 토스트 메시지를 띄운다. * feat: 이전 기록 불러오기 화면과 비즈니스 로직 연결 - RecoveryViewModel 데이터바인딩 설정 - 복구 코드 입력 최대길이 설정 : 36자 - 바인딩어댑터를 적용하여, 복구코드 입력값에 따라 버튼 활성화/비활성화 제어 * refactor: 바인딩 어댑터 속성 이름 수정 및 코드 수정 * ui: 로그인 화면의 로고 이미지 변경 * ui: 로그인 화면에 이전 기록 복구 화면으로 넘어가는 텍스트 버튼 생성 * feat: 이전 기록 복구 화면 연결 * ui: 이전 기록 불러오기 화면으로 넘어가는 버튼 터치영역 확대 - 수직 padding을 설정하여 선택 영역을 넓힘 * ui: 화면 전환 커스텀 애니메이션 제거 - 화면 전환 애니메이션이 매끄럽지 않은 관계로, 기존 애니메이션을 사용 * ui: 현위치 불러오기 버튼의 아이콘 배치와 간격 조정 - iconGravity 속성을 이용하여 아이콘 배치를 변경할 수 있다. - iconPadding 속성으로 버튼 text 사이 간격을 설정할 수 있다. * ui: 추억 조회 화면에서 기간이 없는 경우 날짜 텍스트를 Gone 처리 - 마진 조정 및 추억 조회 화면의 날짜에 대한 바인딩 어댑터 메서드 추가 * feat: Hilt 적용 #405 (#413) * build: hilt 의존성 추가 * feat: Application 클래스에 Hilt를 설정 * build: kapt 및 hilt 의존성 수정 * feat: Hilt 적용 * refactor: 스타카토 추억, 날짜, 시간 선택 버그 수정 및 리팩토링 (#415) * refactor: startAt과 endAt nullable하게 수정 * refactor: 스타카토의 유효한 일시를 계산하는 메서드 추가 * refactor: 추억 화면에서 스타카토 생성 가능 기간 확인 로직 제거 * feat: MemoryVisitedAtSelectionFragment 구현 * feat: 스타카토 생성 화면에서 추억, 날짜, 시간 선택 기능 구현 * feat: 스타카토 수정 화면에서 추억, 날짜, 시간 선택 기능 구현 * style: 불필요한 주석 제거 * style: KtLint CI 에러 수정 * layout: 스타카토 조회 시 오전/오후 텍스트 표시 * refactor: MemoryVisitedAtSelectionFragment 리팩토링 * refactor: 수정 화면에서 타겟 스타카토의 Memory와 VisitedAt 데이터로 selected 데이터 초기화 * refactor: 생성 화면 메인/추억 플로우 별 selected 데이터 초기화 * fix: 누락된 의존성 다시 import * style: ktlint 적용 --------- Co-authored-by: Junyoung-WON * refactor: 스타카토 조회 API 응답 수정 #422 (#423) * refactor: 스타카토 조회 응답에서 comment 제거 * refactor: Moment 도메인 내 Comment 양방향 매핑 제거 및 추억/스타카토에서 댓글 직접 삭제 * refactor: 사용하지 않는 API 제거 * refactor: 미사용 스타카토 수정 API 제거 및 URI 버저닝 제거 * feat: DB 마이그레이션 #386 (#389) * test: 컨트롤러 테스트의 책임이 아닌 테스트 제거 - 사진 5장 초과 테스트의 책임은 MomentImages이므로 제거 * chore: 운영 서버 datasource 설정 변경 * feat: dataSourceConfiguration 구현 * fix: profile 설정 * chore: 다중 운영 환경에 서버 마이그레이션 적용 * fix: OSIV 비활성화 * chore: 트리거 변경 * feat: 운영 서버 flyway 적용 #421 (#426) * build: prod 서버 flyway 활성화 및 baseline 설정 * chore: 예전 dev 서버 관련 설정 제거 * chore: 기존 stage를 dev로 이름을 바꾸고, 관련 설정 변경 * refactor: 스타카토 조회 API 응답에 추억 기간 추가 #427 (#428) * refactor: 추억 기간 응답 추가 * refactor: null 일 경우 필드 포함하지 않고 응답하도록 수정 * fix: yml 이름 수정 #429 (#430) * feat: 스타카토 생성 및 수정 화면 위치 권한 플로우 변경 #416 (#420) * feat: LocationPermissionManager 구현 - MainActivity 내 위치(GPS) 설정 및 위치 권한 설정 관련 로직 LocationPermissionManager로 이동 * feat: 스타카토 생성 화면 위치(GPS) 설정 및 위치 권한 요청 플로우 변경 * refactor: MomentCreationActivity 메서드 순서 변경 * refactor: fusedLocationProviderClient 초기화 로직 메서드 분리 * refactor: MomentCreationActivity 내 전역 변수 순서 정리 * feat: 스타카토 생성 화면 onCreate 내 위치 권한 설정 메서드 호출 제거 - onCreate와 onResume에서 중복 호출하고 있어 onCreate 내 위치 권한 설정 메서드 호출을 제거함 * feat: 스타카토 수정 화면 위치(GPS) 설정 및 위치 권한 요청 플로우 변경 * feat: 바텀시트 SkipCollapsed 활성화 여부 설정 * refactor: 위치 설정 성공, 실패 리스너 등록을 하나의 메서드로 관리 * refactor: 위치 권한 설정 허용 여부 변수명 변경 - 이전: checkSelfLocationPermission - 이후: isLocationPermissionGranted * refactor: 위치 권한 목록 변수를 동반 객체로 이동 * feat: LocationPermissionManager 주생성자 중 activity의 타입 변경 * feat: 개발용 닉네임 관련 로직 제거 #424 (#425) * ui: 현위치 로드 시 로딩 애니메이션 보여주기 #418 (#419) * gradle: 로딩 애니메이션을 위한 로티 의존성 추가 * ui: 스타카토 생성 화면 로딩 애니메이션 추가 * ui: 스타카토 수정 화면 로딩 애니메이션 추가 * fix: CI 에러 수정 * fix: 불필요한 close 태그 삭제 * ui: 0.5초 동안 기본 로딩 애니메이션 적용 * refactor: 현위치 버튼 공통 속성 styles.xml로 분리 * refactor: BindingAdapters에서 중복된 설정 제거 * feat: 마이페이지 구현 및 일부 기능 개선 #417 (#431) * ui: 마이페이지 UI 작성 * ui: 기본 사용자 프로필 아이콘 추가 * refactor: api path 경로를 동반객체로 분리 및 변수명 수정 * feat: 마이페이지 API 서비스 작성 및 RetrofitModule 에 의존성 추가 * feat: 마이페이지 Repository 와 구현체 작성 및 RepositoryModule 에 의존성 추가 - 프로필 정보 응답 MyProfileResponse 과 도메인 모델 MyProfile 생성 - 프로필 이미지 응답 ProfileImageResponse 생성 - DTO -> Domain Model 로 변경하는 Mapper 추가 작성 * feat: 프로필 정보를 나타내는 UI 모델 및 Mapper 작성 * feat: 마이페이지의 기능을 담고있는 MyPageViewModel - MyPageHandler 작성 및 구현 * feat: MyPageActivity, MenuHandler 구현 및 데이터바인딩 연결 * ui: 닫기 버튼이 있는 Toolbar 작성 및 스타일, 핸들러 설정 - 기존 toolbar_mypage.xml 제거 * feat: 웹 브라우저를 보여주는 WebViewActivity 구현 * feat: Manifest 에 새로 생성한 Activity 등록 * feat: 마이페이지 화면 이동 로직 구현 * style: ktlint 체크 * ui: 스타카토 조회의 기분, 코멘트 제목 크기 및 스타일 변경 * fix: 스타카토 조회 시 댓글은 응답으로 들어오지 않음 * fix: 스타카토 수정 화면에서 place 좌표 null인 버그 수정 * style: ktLintFormat * ui: 입력한 닉네임 글자 수 힌트 추가 * refactor: Toolbar의 데이터 바인딩에 대한 name space를 bind로 설정 * refactor: LinearLayout 대신 ConstraintLayout의 속성 활용 - '복구코드 복사하기' 텍스트와 Button 사이에 constraint 지정하여 chain 설정 - 해당 chain 의 속성을 packed 로 변경하여 두 View를 가깝게 붙임 * refactor: 중복된 Url Path 제거 * refactor: 웹뷰의 기본 텍스트 크기 값 상수화 * refactor: Intent 의 apply 연산 제거 * refactor: layout_width 속성 값을 match_parent 에서 0dp 로 변경 - ConstraintLayout 에 포함된 View의 너비, 높이 속성을 지정할 때, match_parent는 권장되지 않는다. * refactor: MyProfile 에서 AccountInformation 으로 클래스명 변경 - UI 모델, api 요청 메서드명 등 관련 클래스, 변수 및 함수명 일괄 변경 * refactor: WebView 를 띄우도록 변경 * style: ktlint 적용 --------- Co-authored-by: somin * refactor: 스타카토 생성/수정 화면에서 추억과 일시를 선택하는 바텀 시트 분리 #434 (#435) * ui: 마이페이지 UI 작성 * ui: 기본 사용자 프로필 아이콘 추가 * refactor: api path 경로를 동반객체로 분리 및 변수명 수정 * feat: 마이페이지 API 서비스 작성 및 RetrofitModule 에 의존성 추가 * feat: 마이페이지 Repository 와 구현체 작성 및 RepositoryModule 에 의존성 추가 - 프로필 정보 응답 MyProfileResponse 과 도메인 모델 MyProfile 생성 - 프로필 이미지 응답 ProfileImageResponse 생성 - DTO -> Domain Model 로 변경하는 Mapper 추가 작성 * feat: 프로필 정보를 나타내는 UI 모델 및 Mapper 작성 * feat: 마이페이지의 기능을 담고있는 MyPageViewModel - MyPageHandler 작성 및 구현 * feat: MyPageActivity, MenuHandler 구현 및 데이터바인딩 연결 * ui: 닫기 버튼이 있는 Toolbar 작성 및 스타일, 핸들러 설정 - 기존 toolbar_mypage.xml 제거 * feat: 웹 브라우저를 보여주는 WebViewActivity 구현 * feat: Manifest 에 새로 생성한 Activity 등록 * feat: 마이페이지 화면 이동 로직 구현 * style: ktlint 체크 * ui: 스타카토 조회의 기분, 코멘트 제목 크기 및 스타일 변경 * fix: 스타카토 조회 시 댓글은 응답으로 들어오지 않음 * fix: 스타카토 수정 화면에서 place 좌표 null인 버그 수정 * style: ktLintFormat * ui: 입력한 닉네임 글자 수 힌트 추가 * refactor: 추억 선택 프래그먼트 UI 및 로직 분리 * refactor: startAt과 endAt 추가된 스타카토 조회 Api 반영 * feat: 스타카토 생성/수정 화면 추억 & 일시 선택 구현 * chore: 불필요한 파일 삭제 * style: MomentCreationViewModel.kt 파일 ktLintFormat * style: ktLintFormat * refactor: 클립보드 복사 토스트 제거 --------- Co-authored-by: Junyoung-WON * chore: 운영 서버 docker 포트 포워딩 변경 #437 (#439) * refactor: 추억 기간 설정 기능 개선 #432 (#436) * refactor: 추억 기간 설정 시 오늘 날짜 범위가 기본으로 설정 * refactor: 변수명 변경 및 추억 생성 시 이전 기간을 저장 - isPeriodSet -> isPeriodSettingOn - isPeriodSettingOn 이 true인 경우에만 기간이 설정 * refactor: 변수명 변경 및 지난 추억을 저장하는 변수 제거 - isPeriodSet -> isPeriodSettingOn - isPeriodSettingOn 이 true인 경우에만 기간이 설정 - lastStartDate와 lastEndDate 제거 * refactor: 추억 저장 버튼 활성화 로직 변경 - 기간 설정이 On 일 때는 기간이 존재해야만(선택 되어야만) 버튼 활성화 * refactor: 기간 설정이 On일 경우 화면의 맨 아래로 스크롤 * refactor: 기간 설정 상태에 따라 추억 기간을 설정하는 메서드 분리 * style: ktlint 적용 * refactor: isPeriodSettingOn 에서 isPeriodActive 로 변수명 변경 * refactor: 사용하지 않는 바인딩 어댑터 메서드 제거 * refactor: 기간 설정 상태의 유효성을 판단하는 변수명을 명시적으로 변경 * deploy: 1.1.0 배포 #438 (#440) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * test: 실수로 빠뜨린 when & then 적용 * feat: 댓글 삭제 API 구현 #255 (#257) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내용을 입력하지 않거나 빈 문자열로 입력 후 댓글 수정 시 예외처리 * refactor: 댓글 생성 시 최소 글자수 조건이 NotBlank에 의해 필요 없으므로 삭제 * refactor: 순서가 불필요하므로 GroupSequence 설정 제거 * feat: updateDTO에 Swagger 적용 * feat: 댓글 삭제 API 해피케이스 구현 * feat: 본인이 쓴 댓글이 아닌데 삭제를 시도하면 예외 처리 기능 구현 * feat: 댓글 삭제 컨트롤러 메서드 구현 * test: 댓글 식별자가 양수가 아닐 경우 댓글 삭제 실패 테스트 * feat: 댓글 삭제 API에 Swagger 적용 * feat: 추억 수정 API 수정 #261 (#262) * feat: 이미지 컨트롤러 분리로 변경된 사항 반영 * refactor: 미사용 메서드 제거 * test: 인증 관련 테스트 추가 * docs: 명세서 누락 및 오류 수정 * test: aaa 주석 수정 * chore: dev 서버 push 트리거 제거 * feat: 순간 수정 API 구현 #244 (#248) * refactor: Moment 수정 서비스 로직 수정 * refactor: Moment 수정 컨트롤러 로직 수정 * refactor: 레거시 코드 변경 및 예외 메세지 변경 * docs: 누락 DTO 명세 추가 * docs: 명세 수정 * feat: 순간 삭제 API 구현 #243 (#250) * style: 네이밍 컨벤션 적용 * docs: 명세 수정 * feat: 순간 조회/목록 조회 API 구현 #251 (#253) * feat: 순간 조회/목록 조회 서비스 로직 구현 * feat: 순간 조회/목록 조회 컨트롤러 로직 구현 * test: 메서드 쿼리 검증 테스트 추가 * refactor: 클래스 명 수정 * test: 불필요한 테스트 데이터 삭제 * feat: image upload 예외 처리 추가 #268 (#269) * feat: MissingServletRequestPartException 에러 핸들링 * chore: dev 서버 PR CD 임시 해제 * chore: dev 서버 push cd 삭제 * refactor: 같은 메시지 주는 예외 동일한 exceptionHandler로 묶기 * refactor: 예외 핸들러를 다시 분리 * refactor: 에러 메시지 적절하게 변경 * feat: 서버 별로 이미지 저장 경로 설정 (#272) * refactor: S3 로직 리팩터링 #274 (#275) * refactor: 미사용 메서드 삭제 * refactor: 미사용 import 삭제 * refactor: 명세 변경에 따른 swagger 메시지 변경 * refactor: 요청 크기 제한 100->20으로 변경 * refactor: 메서드 순서 변경 * refactor: 개행 삭제 * chore: 운영 서버 구축 #264 (#270) * chore: prod 서버 환경설정 * feat: prod 환경 로깅 설정 * chore: prod 환경 테스트를 위한 CD 트리거 변경 * fix: env 파일 경로 수정 * chore: 로그 파일 저장 위치 지정 * chore: 로그 폴더 생성 명령 삭제 * chore: 로그 생성 위치 변경 * chore: 도커 이미지 재실행 코드 추가 * chore: 도커 이미지 재실행 코드 수정 * chore: 로그 콘솔 출력 * chore: 로그 저장 위치 수정 * feat: 운영 환경에서 어드민 로직 비활성화 * refactor: main에 push시에만 prod cd trigger 실행하도록 workflow 변경 --------- Co-authored-by: yoonjuho * fix: 닉네임 앞뒤 공백 제거 #277 (#278) * fix: 닉네임 앞뒤 공백 제거 * fix: 닉네임 요청 형식에서 앞뒤 공백 제거 NPE 해결 * fix: 순간 조회 응답 형식 수정 (#276) * fix: 순간 조회 응답 형식 수정 * fix: 순간 목록 응답 인자 명 수정 * feat: 추억 이름 중복 불가 예외 처리 #280 (#282) * feat: 추억 제목 중복 검사 구현 * docs: 예외 발생 케이스 문서화 * test: 픽스처 활용 * feat: 추억 수정 시 이미 존재하는 타 추억 이름으로 변경 불가능 예외 처리 * test: 주석 오타 수정 * fix: 순간 날짜 반환 형식 변경 #283 (#286) * fix: 순간 날짜 응답 형식 수정 * refactor: 메서드 분리 로직 삭제 * fix: 날짜 ms 제거 * feat: 현재 날짜를 포함하고 있는 추억 목록 조회 구현 #281 (#285) * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * feat: 특정 날짜를 포함하는 모든 추억 조회 기능 구현 * test: 메시지 변경으로 인한 테스트코드 수정 * feat: 날짜로 추억 목록 조회 컨트롤러 분리 * style: 미사용 import 제거 * feat: 날짜를 포함하는 모든 추억을 조회시 기간이 없는 추억도 함께 조회 * refactor: 순간 수정 이미지 순서 적용 #287 (#288) * refactor: 순간 수정 이미지 순서 적용 * test: 순간 수정 이미지 순서 검증 테스트 추가 * refactor: 순간 수정 이미지 순서 중복 로직 삭제 * refactor: 사용되지 않는 메서드 삭제 * fix: 순간 조회 응답 필드 추가 #292 (#293) * fix: 순간 응답 필드에 추억 관련 필드 추가 * test: 픽스쳐 사용 * refactor: 예외 메시지 수정 #294 (#298) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * docs: 문서 수정 Co-authored-by: devhoya97 --------- Co-authored-by: devhoya97 * chore: 운영 서버에서 명세서 비활성화 #302 (#303) * feat : 스타카토 제목, 추억 제목에 trim 적용 #305 (#307) * refactor: 예외 메시지의 순간을 스타카토로 변경 Co-authored-by: devhoya97 * refactor: 예외 메시지 수정 Co-authored-by: devhoya97 * refactor: 순간 -> 스타카토 Co-authored-by: devhoya97 * refactor: 추억 생성 시 title에 trim 적용 * refactor: 스타카토 생성 시 placeName에 trim 적용 * fix: dto에서 size 검증 시 min 조건 제거 --------- Co-authored-by: linirini <2001yerin@naver.com> * chore: ci에 jacoco 추가 (#309) * chore: ci에 jacoco 추가 * chore: ci에 jacoco 위한 권한 변경 * chore: ci에 jacoco 위한 권한 변경 * chore: test report 경로 오류 수정 * build: jacoco 빌드 설정 * build: jacoco 대상에서 builder 제외 * build: jacoco 제한 제거 * build: jacocoCoverageVerification 제거 * chore: 단위 테스트 결과 가져오기 적용 * build: CI/CD 트리거 수정 * build: CI 적용 브랜치 추가 * hotfix: QA #322 (#323) * init: 프로젝트 세팅 * refactor: PR 템플릿 파일명 및 경로 수정 * refactor: pr 템플릿 경로 수정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: develop-be 브랜치의 CI 설정 #6 (#7) * build: 초기 ci 템플릿 생성 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * build: ci 초기 트리거 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 수정 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: working directory 설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * fix: 권한 재설정 Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo --------- Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: devhoya97 Co-authored-by: YoonJuHo * feat: Entity 구성 #2 (#17) * chore: 데이터 베이스 설정 * feat: Base Entity 구성 * feat: Pin Entity 구성 * feat: Travel Entity 구성 * feat: Member Entity 구성 * feat: Mate Entity 구성 * feat: Visit Entity 구성 * feat: Visit Image Entity 구성 * feat: Visit Log Entity 구성 * refactor: Table 애노테이션 삭제 * refactor: Soft Delete 적용 * feat: ControllerAdvice 생성 #29 (#34) * feat: Visit domain skeleton 구현 #31 (#37) Co-authored-by: linirini <2001yerin@naver.com> * feat: Travel Domain Skeleton Code 작성 #32 (#36) * feat: travel skeleton code 작성 * feat: travel 생성, 수정 dto 작성 및 예외 핸들링 * feat: Mate 도메인 빌더 추가 * style: 코드 컨벤션 준수를 위한 공백 제거 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 특정 방문 기록 삭제 API 구현 #26 (#42) * feat: 특정 방문 기록 삭제 API 구현 * feat: 양수가 아닌 id로 특정 방문 기록 삭제를 시도할 때 예외 처리 기능 구현 * feat: 방문 기록 삭제 시 방문 로그도 함께 삭제되는 기능 구현 * refactor: 커스텀 예외를 제거하는 방향으로 변경 * fix: 예외를 못 잡던 문제 해결 * refactor: 메서드명 적절하게 변경 * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * fix: rebase 과정에서 파일이 꼬인 문제 해결 * test: HttpHeaders.AUTHORIZATION 사용 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: Pin, Visit, VisitLog 생성자에 builder 추가 * feat: Pin repository 추가 * refactor: visit이 삭제되기 전에 visit에 의존하는 visitLog들이 먼저 삭제되도록 순서 변경 * test: 방문 기록 삭제에 대한 서비스 슬라이스 테스트 추가 * test: 방문 기록이 갖는 모든 방문 로그 삭제 메서드 테스트 * fix: Modifying을 사용할 때 영속성컨텍스트와 관련하여 발생하던 문제 해결 * refactor: visitLog의 content를 필수값으로 변경 * test: 컨벤션에 맞게 Controller 테스트 클래스 변경 * fix: ConstraintViolationException의 예외 메시지를 정해둔 형식에 맞게 변경 --------- Co-authored-by: YoonJuHo Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> * refactor: 여행 상세 생성 서비스 반환 타입 변경 (#63) * feat: 여행 상세 목록 조회 API 구현 #19 (#60) * test: 여행 상세 목록 조회 통합 테스트 작성 * feat: 여행 상세 목록 조회 DTO 구현 * feat: 모든 여행 상세 목록 조회 서비스 구현 * refactor: 미사용 반환값 제거 * feat: 년도 조건에 따른 여행 상세 조회 서비스 구현 * test: import 수정 * test: 년도와 사용자 식별자로 여행 목록 조회하는 JPQL 테스트 추가 * style: 코드 컨벤션 적용 * test: 여행 상세 목록 조회 컨트롤러 구현 * test: disabled 제거 및 테스트 오류 수정 * refactor: 불필요한 변수 분리 제거 * refactor: Optional로 분기 처리 * test: DisplayName 수정 * refactor: DTO 이름 변경 * feat: 방문 기록 생성 API 구현 #21 (#64) * feat: 방문 기록 생성 기능 구현 * feat: getter 및 builder 추가 * feat: VisitService에 Transactional 적용 * test: 방문 기록 생성 테스트 * fix: 오타 수정 * style: 코드 컨벤션 적용 * fix: deleteById에 Transactional annotation 추가 * refactor: builder 파라미터 NonNull 설정 추가 * refactor: 데이터 개수 감소 * refactor: 예외 메시지 구체화 및 상태 코드 변경 * feat: 특정 여행 상세 수정 API 구현 #22 (#62) * build: Docker Compose Setting #27 (#40) * chore: gitignore 파일 추가 * chore: mysql 디펜던시 추가 * chore: Profile 분리 * feat: Docker 파일 설정 * feat: 여행 상세 생성 API 구현 #18 (#43) * build: RestAssured 의존성 추가 * test: 여행 상세 생성 인수 테스트 작성 * feat: 임시 MemberIdArgumentResolver 구현 * feat: Lombok 추가 * feat: Database 초기화 구현 * feat: 여행 상세 성공 서비스 구현 * fix: resolveArgument 반환 타입 오류 수정 * feat: 여행 상세 생성 성공 컨트롤러 구현 * feat: 여행 상세 생성 시 필수값 누락 검증 구현 * test: 글자 수 제한 검증 인수 테스트 추가 * refactor: 생성자에 builder 지정 * feat: 시작 날짜와 끝 날짜 도메인 검증 구현 * feat: 시작 날짜와 끝 날짜 예외 처리 테스트 및 구현 * style: 코드 컨벤션 적용 * refactor: parameter명 변경 * feat: transactional 적용 * style: paremeter 형식 통일 * style: parameter 형식 통일 * refactor: display name 오류 수정 * refactor: 불필요한 상수 제거 * refactor: paramterized test로 리팩터링 * style: 개행 제거 * refactor: 인자 변경 * refactor: 공통 예외 클래스명 변경 * feat: 범위 예외 핸들러 추가 * refactor: 서비스, 통합 테스트 보일러 플레이트 코드 제거 * refactor: builder 사용 시 필수 값 누락 제약 추가 * refactor: 도메인으로 변환하는 메서드를 dto에 추가 * build: CD yml 파일 구성 #28 (#53) * feat: CI/CD 설정 * feat: CI/CD 검증용 트리거 설정 * fix: CI/CD workflow 수정 * fix: CI/CD workflow 재수정 * fix: CI/CD workflow 절대 경로 수정 * chore: DDL 생성 전략 변경 * chore: dev 환경 DDL 생성 전략 변경 * refactor: 검증용 트리거 제거 * fix: 도커 이미지 기반 컨테이너 생성으로 변경 * refactor: 중간 테이블 엔티티 수정 #56 (#57) * refactor: 중간 테이블명 TravelMember로 변경 * refactor: 중간 테이블 OneToMany 필드 추가 * refactor: Member OneToMany 제거 * refactor: OneToMany List 초기화 * refactor: 연관관계 편의 메서드 사용 * chore: ddl 전략 임시 변경 * chore: ddl 전략 변경 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * feat: 비어있는 요청 에러 핸들링 추가 * feat: 특정 여행 상세 수정 서비스 구현 * feat: 특정 여행 상세 수정 컨트롤러 구현 * refactor: DirtiesContext 삭제 * refactor: Transactional 읽기 전용 옵션 구성 * feat: 방문 기록 날짜 검증 로직 추가 * refactor: 메서드 체이닝 적용 * refactor: 수정 작업 테스트 환경 동일하게 유지 --------- Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 논리적 삭제 데이터는 조회에서 제외 #66 (#68) * test: 쿼리 메서드 사용 * fix: sqlDelete문에 테이블명 변경사항 반영 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 삭제된 데이터 제외하고 조회하도록 조건 추가 * fix: 특정 방문 기록 삭제 API 호출 시 관련된 VisitImage를 모두 삭제하도록 수정 #65 (#67) * feat: visitId에 맞는 visitImage들을 모두 삭제하는 기능 구현 * fix: visit을 삭제해도 visit에 포함된 모든 visitImage들이 삭제되지 않던 문제 해결 * test: 엔티티 생성시 가독성을 위한 개행 삭제 * refactor: JPQL에서 VisitLog를 vl로 축약 * fix: 충돌해결 * test: 경계값에 포함되지 않는 변수 제거 * feat: 특정 여행 상세 조회 API 구현 #20 (#73) * test: 특정 여행 상세 조회 통합 테스트 작성 * feat: 특정 여행 상세 조회 DTO 구현 * fix: 삭제되지 않은 데이터만 찾도록 쿼리 메서드 수정 * feat: 특정 여행 상세 조회 서비스 구현 * feat: 특정 여행 상세 조회 컨트롤러 구현 * test: 존재하지 않는 특정 여행 상세 조회 테스트 * feat: null 필드 응답에 미포함 구현 * style: 코드 컨벤션 적용 * fix: 응답 형식 오류 수정 * feat: 특정 여행 상세 삭제 API 구현 #24 (#72) * style: 코드 컨벤션 적용 * feat: 특정 여행 상세 삭제 서비스 구현 * feat: 특정 여행 상세 삭제 컨트롤러 구현 * refactor: 검증 메서드 분리 * refactor: Visit 논리적 삭제 전파 순서 수정 * feat: 특정 방문 기록 조회 API 구현 #25 (#76) * feat: 특정 방문 기록 조회 API 기능 구현 * fix: Repository 조회시 논리적 삭제가 되지 않은 엔티티들만 가져오도록 변경 * test: System.out 메서드 제거 * refactor: 메서드명 통일 및 CRUD 순서로 배치 * refactor: 사용하지 않는 DTO 제거 * test: 서비스 메서드명 변경에 따른 테스트 메서드명 변경 * fix: 특정 방문 기록이 몇 번째 방문인지 계산할 때, 더 늦게 방문한 기록까지 세던 문제 해결 * test: 몇 번째 방문인지 계산할 때, 이전의 방문만 셀 수 있는지 테스트 * feat: Pin 연관관계 추가 #80 (#83) * feat: Pin에 Member 연관관계 추가 * refactor: private 보조 메서드 순서 변경 * feat: logging 추가 #86 (#89) * feat: 간단한 Error Logging 추가 * refactor: Logging Level 변경 * feat: VisitLog, VisitImage 양방향 관계 설정 및 논리적 삭제 제거 #87 (#88) * feat: visitLog, visitImage 논리적 삭제 제거 * feat: visitLog, visitImage 양방향 설정 및 양방향 관계 설정에 따른 여행, 방문기록 삭제 로직 변경 * fix: 여행 상세 수정 날짜 필터링 오류와 썸네일 저장 오류 수정 #90 (#91) * fix: 여행 상세 수정 날짜 필터링 오류 수정 * fix: 여행 상세 생성 시 썸네일을 저장하지 않는 오류 수정 * refactor: dto 필드 수정 (#95) * feat: 여행 상세 목록 조회 시 최신순 정렬 #96 (#100) * feat: 여행 상세 목록 최신순으로 조회 * refactor: JPQL 메서드명 변경 * feat: 특정 여행 상세 조회 API에서 방문 기록 오래된 순 정렬 #101 (#102) * refactor: 반환값 제거 및 미사용 Param 제거 * feat: 특정 여행 상세 조회 시 방문 기록 오래된 순 조회 구현 * fix: Travel 삭제시 발생하는 오류 수정 #103 (#105) * fix: 여행에 포함된 방문 기록의 존재 여부를 검사할 때 논리적으로 삭제되지 않은 방문 기록만 고려하도록 수정 * fix: 여행을 삭제하면 연관된 TravelMember에 논리적 삭제가 전파되도록 수정 * refactor: JPQL에서 쿼리메서드로 변경 * refactor: @SQLRestriction으로 soft-delete하도록 변경 #106 (#107) * refactor: @SQLRestriction으로 soft-delete하도록 변경 * fix: 정렬 조건 누락 추가 * test: displayName 변경 * docs: swagger 컨벤션 설정 및 적용 (#116) * build: 중복 의존성 정의 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: OpenApi 의존성 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: 전역적인 media type 설정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * chore: open api skeleton code 작성 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * fix: constraint redefine 불가로 인한 오류 수정 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 의미없는 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * docs: 누락된 설명 추가 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * feat: Entity 수정 (#119) * feat: 엔티티 구조 변경 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * style: 불필요한 개행 제거 Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls --------- Co-authored-by: YoonJuHo Co-authored-by: devhoya97 Co-authored-by: BurningFalls * build: 사용하지 않는 도커 이미지 삭제 workflow 구성 #84 (#120) * build: CD 작업 시 기존 도커 이미지 삭제 * build: CD 작업 시 기존 도커 이미지 삭제 순서 변경 * build: CD 트리거 수정 * refactor: 엔티티 수정 #125 (#126) * refactor: base entity 필드명 수정 * refactor: visitLog에 base Entity 추가 및 논리적 삭제 구현 * feat: 로그인 API 구현 #123 (#128) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * fix: CD 실패로 인한 workflow 수정 (#135) * build: jwt 의존성 추가 * chore: jwt 관련 환경 설정 추가 * test: 회원 생성 및 토큰 발급 성공 테스트 & 닉네임 중복 테스트 추가 * feat: 토큰 발급 구현 * feat: 로그인 서비스 구현 * feat: 로그인 컨트롤러 구현 * feat: 닉네임 VO 분리 및 예외 처리 구현 * refactor: getter 재정의 제거 * test: 닉네임 형식 예외 처리에 따른 테스트 수정 * feat: 필수값 누락 예외 처리 구현 * style: 코드 컨벤션 적용 * refactor: 누락된 dto 패키지 추가 * refactor: 애너테이션명 변경 * feat: 토큰 파싱해서 member 찾도록 resolver 구현 * fix: @MemberId -> @LoginMember로 변경되며 long에서 member로 타입 변경에 따른 테스트 실패 수정 * style: 코드 컨벤션 적용 * feat: 401 예외 핸들러 구현 * docs: swagger 명세 추가 * feat: 인가 관련 예외 & 핸들러 추가 * test: authorization 헤더 로직 구현에 따른 테스트 수정 * chore: CI run 임시 수정 * refactor: 필드 접근 제어자 수정 * refactor: 변수 분리 * test: 테스트명 수정 * refactor: handler 메서드명 변경 * docs: 예외 설명 추가 * refactor: 상수 재활용 * docs: schema description 수정 * refactor: 불필요한 개행 제거 * docs: 예외 발생 상황 설명 수정 * test: 토큰 생성 검증 추가 * chore: CI run 이전 상태로 수정 * docs: 응답 명세 작성 * feat: transactional 적용 * chore: CI run을 self hosted로 임시 변경 * chore: CI run을 self hosted로 권한 부여 * chore: CI/CD workflow 트리거 임시 설정 * chore: CI/CD runs on 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 권한 재설정 * chore: CI/CD workflow 임시용 트리거 제거 * fix: TravelResponses 필드 wrapping 오류 수정 (#145) * refactor: 방문기록 조회/수정 도메인 변경으로 인한 수정 #121 (#131) * feat: 특정 방문 기록 조회 API 문서화 * test: Test Fixture 생성 * refactor: 특정 방문 기록 조회 서비스 수정 * test: 특정 방문 기록 조회 컨트롤러 단위 테스트 추가 * refactor: API 명세에 맞게 변수명 변경 * feat: 일급컬렉션 구성 및 연관관계 편의 메서드 위치 변경 * feat: 특정 방문 기록 수정 서비스 구현 * feat: 특정 방문 기록 수정 컨트롤러 구현 * fix: ci 환경 변경 * feat: Multipart 문서화 및 검증 로직 추가 * refactor: 검증하고자 하는 부분을 명시적으로 표현 * refactor: 상수 접근제어자 변경 * refactor: NoArgsConstructor 접근 제어자 변경 * refactor: 생성자 Builder로 표현 * refactor: 부정으로만 사용되는 메서드 명 변경 * refactor: 메서드 명 변경 * refactor: 테스트 검증 방법 변경 * fix: 수정 요청 값 필수 * feat: 메시지 검증 로직 추가 * refactor: 불필요한 Content 애노테이션 제거 * refactor: API 명세 요청 변수 명 변경으로 인한 필드 명 수정 * refactor: 메서드 분리 * fix: AuthService Mocking * refactor: 명세에 맞게 닉네임 필드 명 변경 * refactor: 방문 기록 생성/삭제 도메인 변경으로 인한 수정 #122 (#129) * refactor: api명세에 맞게 필드명 변경 * test: TDD를 위한 컨트롤러 테스트코드 작성 * refactor: 방문 상세 생성 컨트롤러 api명세에 맞게 리팩토링 * refactor: 코드 컨벤션에 맞게 필드와 어노테이션을 다른 줄로 구분 * fix: 여행 식별자가 양수인지 검증하는 코드 추가 * test: 방문 기록을 생성할 수 없는 케이스 테스트 * feat: 사진이 5장을 초과하면 예외처리 기능 구현 * refactor: API 명세의 이름과 변수명 통일 * test: 방문 기록 생성 테스트 추가 * test: 메서드 명을 명확하게 변경 * fix: visitImagesUrl이 null일 때 NPE가 발생하는 문제 수정 * test: 양수가 아닌 식별자로 방문 기록 삭제시 예외 발생 테스트 * refactor: 코드 컨벤션에 맞게 컨트롤러 코드 수정 * test: Visit을 삭제하면 VisitImage도 삭제되는지 테스트 * refactor: 방문 기록 생성시 경계값을 테스트하면서 필요없어지는 메서드 제거 * refactor: 방문 기록 삭제 시 visitId는 null일 수 없으므로 long 타입으로 변경 * test: 방문 기록과 관련된 통합테스트 제거 * test: invalidVisitRequestProvider의 위치를 맨 위로 이동 * fix: 여행 기간에 포함되지 않는 방문 기록은 생성하지 못하도록 수정 * refactor: 가독성을 위한 예외 메시지 수정 * refactor: 불필요한 개행 제거 * refactor: 컨벤션에 맞게 메서드 위치 변경 * test: 가독성을 위한 개행 추가 * refactor: 검증 메서드명을 더 명확하게 수정 * feat: 방문 기록 생성에 Swagger 적용 * fix: visitImageFile이 필수 값으로 설정되어 있던 버그 수정 * refactor: 패키지 위치 적절하게 변경 * feat: 방문 기록 생성 DTO에 Swagger 적용 * feat: 방문 기록 삭제 Swagger 적용 * test: 방문 기록 생성시 경계값 성공 테스트 추가 * refactor: dto에 Schema 설명 추가 * refactor: 방문 사진이 없는 경우 null이 아닌 빈 리스트로 오므로 null 체크 제거 * test: mockMvc 검증에서 content 활용 * test: 가독성을 위한 변경 * refactor: 추후 ExceptionHandler에서 처리할 상황 제거 * refactor: RequestPart value와 dto 변수명을 명세에 맞게 변경 * refactor: null 값을 다룰 가능성이 없는 필드에 Long이 아닌 long을 사용 * test: DisplayName을 더 명확하게 수정 * refactor: 코드 컨벤션에 맞게 개행 제거 * test: 상수 활용 * refacotr: VisitControllerDocs에 @Parameter 추가 * refacotr: 컨트롤러 메서드 순서를 CRUD순으로 정렬 * refactor: 방문기록 생성 시 이미지가 없어도 빈 리스트가 오므로 required=false 제거 * test: 자동정렬로 인한 의도치 않은 개행 제거 * feat: 여행 상세 생성 API 수정 #141 (#147) * refactor: where 검증절 이동 * feat: 여행 상세 생성 서비스에서 multipart 처리 위한 기반 코드 구현 * feat: 여행 상세 생성 컨트롤러에서 multipartFile 받도록 구현 * docs: 여행 상세 생성 명세서 작성 * docs: 여행 상세 생성 명세서 상 key 오류 수정 * docs: 여행 상세 생성 명세서 상 설명 오타 수정 * refactor: cascadeType 변경 및 부모 엔티티가 관리하도록 수정 * test: 모호한 displayName 수정 * refactor: persist 전파 위해 순서 변경 * feat: 여행 상세 목록 조회, 특정 여행 상세 조회, 특정 여행 상세 삭제 API 수정 #148 (#149) * docs: 여행 상세 목록 조회 API 문서화 * docs: 특정 여행 상세 조회 API 문서화 * docs: 공통 예외 문서화 * docs: 특정 여행 상세 삭제 API 문서화 * refactor: 응답 변수 분리 * feat: 특정 여행 상세 조회 시 권한 예외 처리 구현 * feat: 특정 여행 상세 삭제 시 권한 예외 처리 구현 * refactor: 메서드 순서 조정 (CRUD 순서) * fix: dto 필드 오류 수정 * test: 여행 상세 목록 조회 테스트 작성 * test: 특정 여행 상세 조회 테스트 작성 * test: 특정 여행 상세 삭제 컨트롤러 테스트 작성 * test: 여행 상세 목록 조회 JPQL 테스트 수정 * docs: example 제거 * fix: 동일성 비교 * test: 가독성있게 pathVariable 분리 * refactor: 방문기록 썸네일 메서드 분리 * fix: 삭제하려는 여행 상세 없을 시 예외 발생하지 않도록 수정 * refactor: member entity 외 논리적 삭제 제거 #132 (#156) * refactor: member 외 soft delete 제거 * chore: ddl 교체 위한 환경 임시 변경 * fix: 닉네임 형식 수정 #157 (#158) * fix: 닉네임 형식 수정 * chore: ddl 변경 위한 환경 임시변경 * feat: AWS S3 SDK 구현 (#137) * build: aws sdk 의존성 추가 * chore: application-secrets 반영하도록 변경 * chore: multipart 최대파일크기와 최대요청크기를 10MB로 확장 * feat: S3Client 설정 커스텀 * feat: S3Exception 에러 핸들러 추가 * feat: s3Client를 사용하는 CloudStorageClient 생성 * feat: 이미지를 S3에 올리고 URL을 받아오는 비즈니스 로직 작성 * feat: file upload API 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * chore: secret 변수들을 env로 관리하도록 변경 * chore: dev 서버도 멀티파트 용량 확장 * chore: application.yml 파일에 cloud 관련 재설정 * chore: cd 과정에서 환경 변수 설정하기 * fix: env 파일 인식하도록 수정 * fix: CI/CD에서 env를 읽을 수 있도록 수정 * chore: pull_request 시 CD 돌아가지 않도록 수정 * chore: pull_request 시 CD 돌아가도록 임시 수정 * fix: dev에 빠진 security 설정 추가 * chore: dev에도 cloud 관련 설정 추가 * chore: yml 파일 롤백 * chore: ci/cd workflow 롤백 * chore: cloud 관련 설정 추가 * chore: 이미지 용량 제한 늘리는 설정 추가 * chore: yml에 실제 값 대입 * chore: pull_request에도 CD가 적용되도록 임시 수정 * fix: s3Client build를 CLoudStorageClient에서 수행 * chore: cloud 관련 설정 값 대입 * refactor: s3Client build를 S3ClientConfig에서 수행 * refactor: s3Client build를 CloudStorageClient에서 수행 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로 오류 수정 * fix: 파일 경로가 버킷을 포함하지 않도록 수정 * feat: file 이름이 겹치는 경우, UUID를 뒤에 붙이는 기능 구현 * chore: push에만 cd가 적용되도록 다시 변경 * refactor: 에러 메시지 변경 * refactor: MultipartFile 여러 개 받을 수 있도록 수정 * feat: S3 객체 삭제하는 API 구현 * chore: pull_request에도 cd가 적용되도록 다시 변경 * chore: push에만 cd가 적용되도록 다시 변경 * style: ci/cd workflow endline 롤백 * feat: 방문 기록 관련 인가 구현 #140 (#161) * feature: 특정 방문기록 조회시 인가 처리 * feature: 특정 방문기록 수정, 삭제시 인가 처리 * style: 미사용 import 제거 * feat: 방문 기록 생성 시 여행 상세의 주인인지 인가 추가 * refactor: 불필요한 개행 제거 * test: 테스트 실패 지점을 하나로 수정 * chore: 서버 DDL 생성 전략 변경 * feat: 여행 상세 수정 API 수정 #142 (#159) * refactor: 썸네일이 없는 경우 기존 썸네일 유지 * feat: 여행 수정 서비스 multipart와 인가 기능 추가 * feat: 여행 수정 컨트롤러 multipart와 인가 기능 추가 * fix: 여행 썸네일 추출 임시 로직 구성 * refactor: 400 에러 메세지 응답 API 문서에 추가 * docs: id 예시 값 추가 * chore: 개발 서버 DDL 생성 전략 변경 * refactor: 이미지 수정 요청 분기 처리 위치 변경 및 테스트 작성 * feat: 이미지가 필요한 API에 S3 적용 #166 (#168) * test: S3 테스트를 위해 fake 객체 생성 * feat: 여행 상세 생성 시 S3에 썸네일 저장 * feat: 여행 상세 수정 시 S3에 썸네일 대치 * feat: 방문 기록 생성 시 S3에 이미지 저장 * feat: 방문 기록 수정 시 S3에 이미지 대치 * chore: pull request에도 CD가 돌아가도록 임시 설정 * chore: pull request에도 CD가 돌아가도록 임시 설정한 것 원상복구 * refactor: Objects.isNull 활용 및 메서드 위치 변경 * feat: 로깅 프레임워크 적용 #134 (#171) * feat: 로거 환경 설정 * feat: 로거 형식 정의 * feat: 요청/응답 로깅 구현 * feat: 예외에 대한 로거 형식 적용 * feat: token 유무 식별 로그 추가 * refactor: thread 식별명 추가 * refactor: 예외 발생 구체 클래스/메서드 로깅 * chore: CD 트리거 수정 * chore: CD 트리거 복원 * chore: 임시 예외 케이스 생성 및 로그 테스트 * chore: 임시 예외 케이스 수정 및 로그 테스트 * chore: 임시 예외 케이스 재수정 및 로그 테스트 * chore: 임시 예외 케이스 삭제 * chore: CD 트리거 복원 * fix: Logging 데이터 변경 * chore: CD 트리거 복원 * fix: Logging 데이터 오류 수정 * chore: CD 트리거 복원 * feat: 로깅 White List 추가 * feat: 방문 기록 목록 조회시 시간 순으로도 정렬되는 기능 구현 (#175) * feat: 방문 기록의 방문 날짜 저장 시, 시간까지 저장하도록 변경 * fix: request dto에서 LocalDateTime에 대한 패턴이 시간까지 포함하도록 변경 * refactor: 여행에 포함된 날짜인지 비교시 LocalDateTime을 넘겨주도록 변경 * refactor: 사진 url 관련 dto 필드명 끝에 url 추가 * refactor: 기대한대로 작동하지 않는 ExceptionHandler 메서드 주석 처리 * refactor: 파일 이름 및 형식 오류 수정 #176 (#177) * refactor: 파일 이름을 UUID로만 구성하도록 수정 * refactor: content-type을 multipart/formed-data로 고정 * feat: swagger https 적용하기 #184 (#185) * feat: swagger가 https 접근 가능하도록 하는 기능 구현 * chore: pull_request에도 CD가 적용되도록 임시 변경 * style: push에만 CD가 적용되도록 롤백 * feat: 빈/공백 문자열 예외 처리 #186 (#187) * fix: 여행 제목은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 방문 기록의 이름은 공백 문자열 불가, 1자 이상 30자 이하로 설정할 수 있도록 예외 처리 * fix: 닉네임의 이름은 공백 문자열 불가, 1자 이상 20자 이하로 설정할 수 있도록 예외 처리 * test: displayName 변경 * fix: Swagger 인증 헤더 형식 변경 #188 (#189) * fix: Swagger 인증 헤더 수정 * refactor: 로깅 정보 수정 * chore: stage/dev 서버 분리 #192 (#197) * fix: 포트 수정 * refactor: 설정 파일 profile 별로 분리 * fix: timezone 설정 * refactor: ci-cd 파일명 변경 * refactor: ci-cd 분리 * test: 경계값 테스트로 수정 * test: 경계값 테스트로 수정 및 발생하는 오류 수정 * chore: back-end 개발용 CD 트리거 변경 * fix: 불필요한 파일 삭제 * refactor: stage용 환경 파일 분리 * refactor: DockerFile 분리 * refactor: 태그 설정 * refactor: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 * fix: 태그 설정 수정 * refactor: CI runs-on 변경 * refactor: dev용 CICD trigger 변경 * refactor: dev용 CICD runs on 변경 * refactor: dev용 CICD trigger 변경 * refactor: runner 재설치로 인해 임시로 변경했던 dev용 CICD runs-on & trigger 복구 * refactor: hub push 시 로그인 재수행 * fix: 명령어 오류 수정 * feat: 단체 계정으로 dockerhub 변경 * refactor: 정상 작동 확인 후 트리거 복구 * fix: image push 시 권한 오류 수정 (#200) * feat:admin용 계정 로직 추가 (#201) * fix: add stage logging (#204) * feat: 이미지 확장자와 content-type 설정 #196 (#202) * feat: content-type을 확장자로 분석하는 기능 구현 * chore: PR CD 임시 적용 * chore: PR CD 해제 * refactor: dev, stage, local 환경의 swagger url 설정 (#208) * refactor: 이미지 용량 제한 확장 (한 이미지: 20MB, 한 요청: 100MB) (#206) * fix: 이미지 전송 안되는 에러 수정 #209 (#210) * chore: PR CD 임시 적용 * fix: 파일 형식에 .추가 및 디폴트 형식 변경 * temp: 확인용 에러 * temp: 롤백 * refactor: 디폴트 mime type 변경 * temp: 일단 image의 내부 메서드 사용 * fix: file-extension 지정 롤백 * fix: content-type 지정 * temp: 에러 체크를 위해 메시지 임시 변경 * temp: 에러 메시지 롤백 * feat: content-type 확장자로부터 추출 * chore: PR CD 해제 * refactor: API명세 변경에 따른 URI, DTO 변수명 변경 #211 (#212) * refactor: URI, DTO 변수명 변경 * refactor: DTO 클래스명을 API명세에 맞게 변경 * refactor: imageFile 변수명 변경 * test: pathVariable명을 클래스명을 고려하여 변경 * refactor: 엔티티, 메서드명 API 명세에 맞게 변경 * refactor: 여행을 추억으로, 방문을 순간으로 네이밍 변경 * feat: 추억 목록 조회 API 수정 #215 (#216) * feat: startAt, endAt 필드 nullable하게 변경 * feat: memory의 createdAt 기준 최신순 정렬로 변경 * style: code convention 적용 * style: 응답 형식 변경 (mates 제거 및 기간 미필수 응답 필드로 변경) * feat: 올바르지 않은 년도 형식 예외 처리 * refactor: 추억 상세 -> 추억 * test: 메세지 오류 수정 * test: 저장 순서 오류 수정 * refactor: fixture 패키지 이동 * refactor: fixture 분리 * test: 경계값 검증으로 수정 * feat: 사용자 로깅, Nginx 로깅, DB 로깅 #190 (#224) * feat: MDC 적용 * refactor: 중복 예외 제거 * feat: 사용자 식별 로깅 추가 * refactor: 예외 메세지 형식 json으로 변경 * feat: 추억 삭제 API 수정 #221 (#222) * feat: 변경사항 docs 반영 * feat: 순간이 존재하는 경우 추억을 삭제할 수 없었던 예외 제거 * style: code convention 적용 * feat: 추억 삭제 시 속한 순간도 함께 삭제되도록 서비스 구현 * refactor: 불필요한 개행 제거 * feat: 추억 조회 API 수정 #227 (#228) * feat: 기간 필수 여부 변경에 따른 어노테이션 추가 * docs: 도메인명 변경에 따른 명세서 수정 * build: stage 서버 CICD 임시 비활성화 #234 (#235) * chore: stage 비활성화 적용 전 dev에서 시범 적용 * chore: dev 서버 cicd 비활성화 해제 * chore: dev 서버 cicd 트리거 복구 * chore: stage 서버 cicd 임시 비활성화 * feat: 댓글 생성, 조회 API 구현 #214 (#225) * refactor: 댓글과 관련된 클래스를 별도의 패키지로 분리 * test: tdd를 위한 댓글 생성 서비스 테스트 추가 * feat: 댓글 생성 서비스 메서드 구현 * test: 댓글 생성 관련 컨트롤러 테스트 코드 작성 * feat: 댓글 생성 기능 구현 * feat: 댓글 조회 서비스 메서드를 위한 tdd 틀 작성 * feat: 댓글 조회 서비스 메서드 구현 * test: 댓글 컨트롤러 테스트 클래스 패키지 위치 변경 * refactor: 댓글 읽기 메서드명을 더 명확하게 변경 * test: 댓글 읽기 테스트 코드 추가 * feat: 댓글 읽기 컨트롤러 메서드 구현 * feat: 댓글 생성, 조회 API에 swagger 적용 및 순간 기록을 순간으로 변경 * fix: Swagger 적용으로 인한 문제 해결 * test: 순간 기록이라는 말을 순간으로 변경 * refactor: 댓글의 글자수로 인한 예외 메시지에 '1자 이상'이라는 말을 제거 * fix: 댓글 생성 메서드에 Transactional 적용 * chore: stage 서버 CI/CD 활성화 * feat: 감정 선택 API 구현 #230 (#236) * feat: 기분 유형 생성 * feat: Moment 비즈니스 로직에 기분 표현 적용 * feat: 기분 표현 컨트롤러 구현 * feat: default 기분 생성 * style: 코드 컨벤션 적용 * refactor: 예외 메세지 변경 * feat: 순간 생성 API 구현 #226 (#229) * refactor: 기한이 없는 memory 구현 * test: 기한없는 Memory에 Moment 생성 테스트 * feat: Moment 생성 서비스 구현 * feat: Moment 생성 컨트롤러 구현 * refactor: builder 선택 필드 제외 * style: 잘못된 네이밍 수정 * refactor: MomentImages 생성 책임 Moment로 위임 * feat: 하나의 사진 업로드 API 생성 #256 (#258) * feat: api 이름 captures로 변경 * feat: RequestBody imageFiles로 이름 변경 * refactor: 변수명 iamge -> file로 통합 * refactor: requestparam -> requestpart로 변경 * feat: 다섯 장을 넘기지 않도록 예외 추가 * feat: 빈 배열을 받는 경우 로직을 수행하지 않도록 변경 * style: CamelCase 적용 * refactor: 에러 메시지 수정 * feat: 특정 content-type을 처리하도록 명시 * feat: validated 어노테이션 추가해서 유효성 검사 수행 * test: 사진 개수에 따른 성공/실패 테스트 수행 * test: 빈 멀티파일 리스트가 들어올 시, 빈 url 리스트가 들어오는 테스트 수행 * refactor: byte 처리에서 나는 오류를 StaccatoException으로 처리 * chore: dev 서버 PR CD 임시 적용 * refactor: API명 captures -> images로 변경 * chore: dev 서버 PR CD 해제 * fix: test에도 변경된 api명 적용 * feat: 파일을 한 장만 업로드하도록 변경 * feat: dto를 반환하는 새로운 메서드 생성 * test: 테스트 Disabled * refactor: CloudStorage -> Image로 이름 단순화 * feat: S3 객체 삭제 로직 삭제 * refactor: 미사용 import 삭제 * refactor: 전체 경로를 yml에서 지정 * refactor: getFileExtension 메서드 리팩터링 * feat: ImageUrlResponse 생성 * refactor: file을 전부 image로 변경 * refactor: S3Client를 S3ObjectClient로 변경 * refactor: S3Exception 로깅에 EXCEPTION_LOGGING_FORM 적용 * feat: 로그인한 사용자만 images API를 사용가능하게 함 * refactor: ImageExtension을 사용하는 Service 폴더로 이동 * feat: yml에서 설정한 파일 용량 제한 예외를 잡는 MultipartExceptionHandler 구현 * refactor: 충돌방지 이름변경 * refactor: @Size 사라지면서 Validated 삭제 * test: 컨트롤러 단위 테스트 수행 * refactor: 미사용 import문 삭제 * style: /images API swagger 적용 * refactor: file -> image * refactor: uploadImages -> uploadImage * refactor: 미사용 import문 삭제 * chore: PR CD를 수동으로 실행 가능하게 설정 * refactor: 기존 테스트 삭제 * fix: 반영되지 않은 수정사항 관련 테스트 disabled * chore: dev 서버 PR CD 임시 해제 * fix: 이미지 저장 폴더 재지정 * refactor: 테스트 메서드 네이밍 수정 * refactor: 폴더명 수정 * refactor: 닫는 괄호 추가 * refactor: S3ObjectClient를 infrastructure 패키지로 이동 * refactor: 컨벤션에 맞추어 줄바꿈 * refactor: infra 패키지를 image 패키지 내부로 이동 * feat: 추억 생성 API 수정 #238 (#260) * feat: multipartFile 제거 및 contentType을 application/json으로 변경 * refactor: term(startAt, endAt) 객체 분리 * feat: startAt, endAt 중 누락 예외 처리 * fix: 기간이 없을 경우 순간 날짜 포함 여부 예외 처리 오류 수정 * test: 기간 포함 날짜 검증 테스트 추가 * refactor: 가독성 있게 로직 수정 * docs: 요청 형식 설명 수정 * feat: 댓글 수정 API 구현 #245 (#254) * test: Fixture를 활용하도록 기존 테스트 변경 * feat: 댓글을 생성하는 기능 해피케이스 구현 * feat: 댓글을 찾을 수 없는 경우 예외 발생 테스트 * feat: 본인이 달지 않은 댓글에 대해 수정을 시도하면 예외 발생 기능 구현 * test: 조회 권한이 없는 순간에 달린 댓글들 조회를 시도했을 때 예외 발생 테스트 추가 * feat: 댓글 수정 컨트롤러 메서드 구현 * test: 양수가 아닌 댓글 식별자로 댓글 수정 시 예외 발생 테스트 * feat: 댓글 내… * fix & feat: 스타카토 생성 시 현주소 로딩 버그 수정 & 사진 길게 눌러 순서 변경 기능 #441 (#443) * feat: 사진 길게 눌러 드래그 기능 구현 * fix: 구글 장소 검색 프래그먼트로 인한 onResume 호출 버그 수정 * refactor: 나의 추억들(전 타임라인) 로딩 lottie 구현 #433 (#446) * feat: 타임라인 empty view 가시성 설정 BindingAdapter 구현 * feat: 타임라인 로딩 lottie 구현 * ui: lottie layout_constraintHeight_percent 속성 설정 * ui: 나의 추억 empty view 이미지 사이즈 변경 - 화면 크기별로 유동적으로 조절되도록 변경 * refactor: xml 컨벤션 따라 lottie id 수정 * refactor: 나의 추억들 empty view 바인딩 어댑터 속성 네이밍 수정 * fix: 추억 수정 시 사진 등록 중이라면 저장 버튼을 비활성화 #447 (#451) * refactor: isPhotoPosting에 잘못 할당된 변수 변경 - 이전: _isPosting - 이후: _isPhotoPosting * refactor: 추억 수정 화면에서 사진 업로드 후 _isPhotoPosting 상태를 false로 설정하도록 변경 * fix: 현주소 로딩 버그 수정, 사진 드래그 시 투명하게 조절 #444 (#449) * fix: onPause시 autocompleteFragment 클릭 여부 검사 * ui: 스타카토 사진 첨부 rv 드래그 시 투명도 조절 * ui: 스타카토 생성 및 수정 화면에서 overScrollMode never 설정 * fix: 오타 수정 * refactor: 불필요한 if문 제거 리뷰 반영 * refactor: 클립보드 복사 시 토스트 메시지가 뜨지 않는 문제 해결 #448 (#450) * refactor: 안드로이드 버전 13 미만인 경우 복사 시 토스트 메세지를 띄움 * refactor: 추억 수정 서버 통신 중 progressBar가 보이도록 설정 * feat: collation 변경 sql 반영 #452 (#454) * feat: Actuator 적용 및 모니터링 연동 #364 (#375) * feat: Actuator 적용 및 모니터링 연동 * feat: Actuator 적용 및 모니터링 연동 * refactor: health check api 삭제 * chore: 환경별 actuator 설정 * chore: Dev 서버 모니터링 테스트를 위한 임시 CD 트리거 변경 * chore: Dev 서버 모니터링 테스트를 위한 임시 CD 트리거 수정 * chore: Dev 서버 모니터링 테스트를 위한 base-path 변경 * chore: Dev 서버 모니터링 테스트를 위한 base-path 복구 * chore: 서버 모니터링을 위한 트리거 수정 * build: 앱 버전 업데이트 #442 (#456) - versionCode: 3 -> 4 - versionName: "1.0.0" -> "1.1.0" * fix: conflict 해결 (#461) * chore: 운영 서버 docker 포트 포워딩 변경 (#462) Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> * fix: 누락된 파일 추가 * build: 누락된 android ci/cd 파일 복구 (#467) * refactor: 마이페이지의 앱 버전 수정 #463 (#464) Co-authored-by: hxeyexn Co-authored-by: s6m1n * build: 누락된 android ci/cd 파일 복구 #465 (#466) Co-authored-by: hxeyexn Co-authored-by: s6m1n --------- Co-authored-by: hxeyexn Co-authored-by: s6m1n * refactor: BindingAdapter 분리 및 리팩토링 #469 (#472) * refactor: BindingAdapter 파일 분리 * refactor: ButtonBindingAdapter 리팩토링 * refactor: ImageBindingAdapter 리팩토링 * refactor: TextBindingAdapter 리팩토링 * refactor: ExtBindingAdapter 리팩토링 * refactor: 오전, 오후 텍스트 strings.xml로 분리 * refactor: 매직 넘버 상수로 분리 * style: EtxBindingAdapters -> BindingAdapters.kt * chore: 불필요한 메서드 제거 * refactor: 상수화 및 String formatting * fix: 추억 수정 화면 dateRangePicker 중복 버그 해결 * refactor: 추억 기간 선택 시 visibility 바인딩 어댑터 적용 * refactor: okhttp3 import 제거 및 scrollToBottom rename * refactor: 추억 및 스타카토 생성, 수정 화면 loading lottie 적용 #453 (#476) * ui: LottieStyle 정의 * ui: loading ui 구현 * refactor: 추억 및 스타카토 생성, 수정 loading view 변경 - 이전: ProgressBar 사용 - 이후: Lottie 사용 * refactor: 세로 모드 고정 적용이 누락된 activity에 세로 모드 고정 적용 * ui: 스타카토 조회 화면 주소 view 제약 조건 추가 * refactor: 추억 생성, 수정 사진 업로드 loading view 변경 * refactor: 스타카토 사진 업로드 loading view 변경 * refactor: LottieStyle layout_height wrap_content로 변경 * refactor: 추억 사진 업로드 로딩 가시성을 설정하는 BindingAdapter 함수명 변경 * refactor: 사진 게시 중 알림 toast 제거 * style: activity_memory_update.xml formatting * refactor: lottie 가시성 binding adapter 활용 * refactor: 리소스 리팩터링 및 xml 컨벤션 적용 #473 (#478) * refactor: View 별 스타일 분리 및 세분화 - 너무 많은 스타일을 가지고 있는 View 의 경우 따로 파일을 생성하여 분리 - 연관성 있는 View style 끼리 정렬 - 주석으로 View 별 스타일 구분 - 스타일 추가 및 세분화 * refactor: 사용하지 않는 layout 제거 - Google Map Fragment 레이아웃과 방문기록(현 스타카토) 레이아웃 제거 * refactor: 상세 페이지 Toolbar의 레이아웃을 include - 기존에 사용하던 toolbar_detail 의 레이아웃을 include 태그로 적용 * refactor: NavigationToolbar 의 paddingEnd 속성을 style에 지정 * refactor: ConstraintLayout 리팩터링 - ConstraintLayout 내부 View 들의 match_parent 속성을 0dp 로 변경하고 constraint 설정 - 중첩된 ConstraintLayout 제거 * refactor: 기분 선택 리사이클러뷰의 padding 속성 수정 * refactor: 이미지 contentDescription 설정 및 lint 설정 * refactor: xml layout 의 ID 네이밍 컨벤션 적용 - 누락된 이미지 contentDescription 설정 * fix: 스타카토 조회 화면에서 사용하는 Toolbar로 롤백 - 수정, 삭제 시 Memory의 ID가 필요하기 때문에 기존에 사용하는 Toolbar 와 동작이 다름 * ui: 추억 소개 InputText 의 크기 축소 및 여백 너비 조정 * refactor: TextInput style의 이름 변경 - TextInputEditTextStyle.OneLine -> TextInputEditTextStyle.SingleLine * refactor: View 에서 MaterialDivider 로 변경 * refactor: MaterialDivider View의 id명 변경 및 divider 색상 속성 변경 - view_timeline_line -> divider_timeline - foreground -> dividerColor * refactor: 마이페이지 및 로그인 화면 리팩터링 #477 (#479) * refactor: 마이페이지 중첩된 Layout 제거 - ConstraintLayout을 사용하고 있음에도 중첩된 ConstraintLayout, FrameLayout 으로 구성되어 있음 - 중첩된 Layout을 제거 * refactor: 로그인 화면 xml 리팩터링 - 중첩된 ConstraintLayout 제거 - ScrollView를 추가하여 스크롤 가능하게 변경 * refactor: 프로필 정보 클래스 명 및 변수명 수정 - AccountInformation -> MemberProfile 로 변경 - 관련 변수명 및 메서드 명 일괄 수정 - 사용하지 않는 MyProfile 관련 클래스 제거 * refactor: 컨벤션에 맞추어 override 메서드 순서 변경 * refactor: MyProfile 클래스 제거 * refactor: 프로필이 Null일 때 사용자 상호작용에 대한 예외 처리 - checkMemberProfileNotNull() 메서드를 작성하여 사용자 프로필이 null임을 확인하고, null이 아닐 때 로직을 수행하도록 처리 * style: ktlint 적용 * refactor: visit, moment -> staccato로 도메인명 수정 #359 (#480) * refactor: data/dto/moment 패키지명 변경 - 이전: data/dto/moment - 이후: data/dto/staccato * refactor: 스타카토 생성 dto명 변경 - MomentCreationRequest -> StaccatoCreationRequest - MomentCreationResponse -> StaccatoCreationResponse * refactor: 스타카토 수정 dto명 변경 - 이전: MomentUpdateRequest - 이후: StaccatoUpdateRequest * refactor: 스타카토 조회 dto 변경 - 이전: MomentResponse - 이후: StaccatoResponse * refactor: 스타카토 마커 조회 dto 변경 - MomentLocationDto -> StaccatoLocationDto - MomentLocationResponse -> StaccatoLocationResponse * refactor: data/moment 패키지명 변경 - 이전: data/moment - 이후: data/staccato * refactor: 스타카토 ApiService명 변경 - 이전: MomentApiService - 이후: StaccatoApiService * refactor: 스타카토 DataSource명 변경 - 이전: MomentDataSource, MomentRemoteDataSource - 이후: StaccatoDataSource, StaccatoRemoteDataSource * refactor: 스타카토 Repository명 변경 - 이전: MomentRepository, MomentDefaultRepository - 이후: StaccatoRepository, StaccatoDefaultRepository * refactor: Moment 도메인 모델명을 Staccato로 변경 * refactor: MomentLocation 도메인 모델명 변경 - 이전: MomentLocation - 이후: StaccatoLocation * refactor: MemoryMoment 도메인 모델명 변경 - 이전: MemoryMoment - 이후: MemoryStaccato * refactor: Memory 도메인 모델의 moments 주생성자 이름 변경 - 이전: moments - 이후: staccatos * refactor: CommentDataSource 내 moment를 staccato로 변경 * refactor: CommentRepository 내 moment를 staccato로 변경 * refactor: DataSourceModule 내 moment를 staccato로 변경 * refactor: RepositoryModule 내 moment를 staccato로 변경 * refactor: NewComment 도메인 모델의 momentId 주생성자명 변경 - 이전: momentId - 이후: staccatoId * refactor: MemoryMomentDto를 MemoryStaccatoDto로 변경 * refactor: MomentMapper를 StaccatoMapper로 변경 * refactor: presentation/moment 패키지명 변경 - 이전: presentation/moment - 이후: presentation/staccato * refactor: presentation/momentcreation 패키지명 변경 - 이전: presentation/momentcreation - 이후: presentation/staccatocreation * refactor: presentation/visitcreation 패키지 제거 - presentation/visitcreation의 adapter 폴더를 presentation/staccatocreation 패키지로 이동 후 presentation/visitcreation 패키지 제거 * refactor: presentation/momentupdate 패키지명 변경 - 이전: presentation/momentupdate - 이후: presentation/staccatoupdate * refactor: 사용되지 않는 MomentDetailUiModel 제거 * refactor: MomentDetailUiModel 이름 변경 - 이전: MomentDetailUiModel - 이후: StaccatoDetailUiModel * refactor: MemoryVisitUiModel 이름 변경 및 주생성자 이름 변경 MemoryVisitUiModel 이름 변경 - 이전: MemoryVisitUiModel - 이후: MemoryStaccatoUiModel 주생성자 visitImageUrl 이름 변경 - 이전: visitImageUrl - 이후: staccatoImageUrl * refactor: VisitUiModelMapper 이름 변경 - 이전: VisitUiModelMapper - 이후: StaccatoUiModelMapper * refactor: MomentViewModel 이름 변경 - 이전: MomentViewModel - 이후: StaccatoViewModel * refactor: StaccatoViewModel 내 moment를 staccato로 변경 * refactor: MomentCreationViewModel 이름 변경 - 이전: MomentCreationViewModel - 이후: StaccatoCreationViewModel * refactor: 스타카토 생성 ViewModel의 스타카토 생성 메서드명 변경 - 이전: createMoment - 이후: createStaccato * refactor: VisitUpdateViewModel 이름 변경 - 이전: VisitUpdateViewModel - 이후: StaccatoUpdateViewModel * refactor: 스타카토 수정 ViewModel 내 visit, moment 이름 변경 - 이전: visit, moment - 이후: staccato * refactor: MomentFeelingSelectionViewModel 이름 변경 - 이전: MomentFeelingSelectionViewModel - 이후: StaccatoFeelingSelectionViewModel * refactor: 스타카토 기분 선택 ViewModel 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: MomentCommentsViewModel 이름 변경 - 이전: MomentCommentsViewModel - 이후: StaccatoCommentsViewModel * refactor: StaccatoCommentsViewModel 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: SharedViewModel 내 사용하지 않는 읽기 전용 변수 삭제 - isStaccatoUpdated 변수 삭제 * refactor: MapsViewModel 내 moment를 staccato로 변경 * refactor: MomentToolbarHandler 이름 변경 - 이전: MomentToolbarHandler - 이후: StaccatoToolbarHandler * refactor: MomentCreationHandler 이름 변경 - 이전: MomentCreationHandler - 이후: StaccatoCreationHandler * refactor: VisitUpdateHandler 이름 변경 - 이전: VisitUpdateHandler - 이후: StaccatoUpdateHandler * refactor: MemoryHandler 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: StaccatoFragment 내 visit, moment 이름 변경 - 이전: visit, moment - 이후: staccato * refactor: MomentFeelingSelectionFragment 이름 변경 - 이전: MomentFeelingSelectionFragment - 이후: StaccatoFeelingSelectionFragment * refactor: 스타카토 기분 선택 Fragment 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: MomentCommentsFragment 이름 변경 - 이전: MomentCommentsFragment - 이후: StaccatoCommentsFragment * refactor: StaccatoCommentsFragment 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: StaccatoCreationActivity 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: MemoryFragment 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: MainActivity 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: MemberUiModel 내 사용하지 않는 dummyMates 제거 * refactor: VisitsViewHolder 이름 변경 - 이전: VisitsViewHolder - 이후: StaccatoViewHolder * refactor: StaccatoViewHolder 의 bind 메서드 매개변수명 변경 - 이전: memoryVisit - 이후: memoryStaccato * refactor: VisitsAdapter 이름 변경 - 이전: VisitsAdapter - 이후: StaccatosAdapter * refactor: StaccatosAdapter 내 visits 이름 변경 - 이전: visits - 이후: staccatos * refactor: fragment_moment.xml 이름 변경 - 이전: fragment_moment - 이후: fragment_staccato * refactor: fragment_staccato.xml 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: 스타카토 기분 선택 xml 이름 변경 - 이전: fragment_moment_feeling_selection.xml - 이후: fragment_staccato_feeling_selection.xml * refactor: 스타카토 기분 선택 xml 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: fragment_moment_comments.xml 이름 변경 - 이전: fragment_moment_comments.xml - 이후: fragment_staccato_comments.xml * refactor: 스타카토 댓글 xml 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: 사용되지 않는 fragment_visit.xml 제거 * refactor: activity_visit_creation.xml 이름 변경 - 이전: activity_visit_creation.xml - 이후: activity_staccato_creation.xml * refactor: 스타카토 생성 xml 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: activity_visit_update.xml 이름 변경 - 이전: activity_visit_update.xml - 이후: activity_staccato_update.xml * refactor: activity_staccato_update.xml 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: 사용하지 않는 fragment_maps.xml 제거 * refactor: fragment_memory.xml 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: fragment_timeline.xml 내 visit 이름 변경 - 이전: visit - 이후: staccato * refactor: item_moment_feeling_selection.xml 이름 변경 - 이전: item_moment_feeling_selection.xml - 이후: item_staccato_feeling_selection.xml * refactor: item_visits.xml 이름 변경 - 이전: item_visits.xml - 이후: item_staccatos.xml * refactor: 사용하지 않는 item_visits_date.xml 제거 * refactor: strings.xml 내 visit, moment 이름 변경 - 이전: visit, moment - 이후: staccato * refactor: 사용하지 않는 string 제거 * refactor: shape_my_visit_log_12dp.xml 이름 변경 - 이전: shape_my_visit_log_12dp.xml - 이후: shape_my_staccato_log_12dp.xml * refactor: shape_others_visit_log_12dp.xml 이름 변경 - 이전: shape_others_visit_log_12dp.xml - 이후: shape_others_staccato_log_12dp.xml * refactor: item_moment_my_comment.xml 이름 변경 - 이전: item_moment_my_comment.xml - 이후: item_staccato_my_comment.xml * refactor: 스타카토 my comment 아이템 xml 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: item_moment_others_comment.xml 이름 변경 - 이전: item_moment_others_comment.xml - 이후: item_staccato_others_comment.xml * refactor: item_staccatos의 visit 변수명 변경 - 이전: visit - 이후: staccato * refactor: 스타카토 others comment 아이템 xml 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: bottom_navigation_graph 내 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: MemoryStaccatoDto의 momentId 변수명 변경 - 이전: momentId - 이후: staccatoId * refactor: MemoryResponse의 moments 변수명 변경 - 이전: moments - 이후: staccatos * refactor: StaccatoCreationRequest의 moment 이름 변경 - 이전: momentImageUrls - 이후: staccatoImageUrls * refactor: StaccatoCreationResponse의 moment 이름 변경 - 이전: momentId - 이후: staccatoId * refactor: StaccatoLocationDto의 momentId 변수명 변경 - 이전: momentId - 이후: staccatoId * refactor: StaccatoResponse의 moment 이름 변경 - 이전: moment - 이후: staccato * refactor: item_staccatos.xml 내 visits 이름 변경 - 이전: visits - 이후: staccatos * refactor: fragment_staccato.xml 컨벤션따라 id 수정 * refactor: fragment_timeline.xml 내 staccatos id 수정 - 이전: staccatos - 이후: memories * chore: 무중단 배포 #482 (#483) * chore: 노출할 포트 추가 * chore: 배포 브랜치 분리에 따른 트리거 브랜치 변경 * chore: prod-a 서버에 deploy.sh 실행 시도 * chore: deploy 사용에 따른 배포 flow 제거 * chore: runs-on 수정 * fix: datasource initialization 비활성화 * fix: bash 명령어로 수정 * fix: runs-on 라벨 추가 * chore: 임시 트리거 제거 * fix: 중복된 toMemoryCandidate() 함수 제거 * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * deploy: 1.1.1 배포 #484 (#491) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) --------- Co-authored-by: hxeyexn * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * deploy: 1.1.2 배포 (#504) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> --------- Co-authored-by: hxeyexn Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: YoonJuHo Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 * deploy: 1.1.3 배포 (#506) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 --------- Co-authored-by: hxeyexn Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: BurningFalls Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * feat: 기본 추억 제공 구현 #508 (#509) * feat: 기본 추억 생성 구현 * refactor: 기본 추억 설명 수정 * fix: persist 전파되도록 로직 순서 변경 * deploy: 1.2.0 배포 (#510) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 * feat: 기본 추억 제공 구현 #508 (#509) * feat: 기본 추억 생성 구현 * refactor: 기본 추억 설명 수정 * fix: persist 전파되도록 로직 순서 변경 --------- Co-authored-by: hxeyexn Co-authored-by: BurningFalls Co-authored-by: YoonJuHo Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * fix: file changed 인식 불가로 인한 순서 변경 (#511) * feat: 모든 화면에서 네트워크 에러 핸들링 #501 (#516) * fix: ApiResponseHandler try-catch문 범위 수정 * refactor: StaccatoApiService의 반환값 Response로 wrapping * refactor: StaccatoDataSource의 반환값 ResponseResult로 wrapping * refactor: StaccatoRepository의 반환값 ResponseResult로 wrapping * refactor: StaccatoRepository를 사용하는 ViewModel에 에러 처리 변경사항 적용 * feat: MessageUtils.kt에 showSnackBarWithAction 추가 * feat: TimelineFragment 네트워크 에러 발생 시 스낵바 처리 * feat: MemoryFragment 네트워크 에러 발생 시 스낵바 처리 * feat: StaccatoFragment 네트워크 에러 발생 시 스낵바 처리 * refactor: 불필요한 Log.e 메서드 제거 * style: 네트워크 에러 메시지 상수명 통일 * refactor: MessageUtils에 getSnackBarWithAction 메서드 추가 * feat: Memory 생성/수정 화면 에러 핸들링 * feat: Staccato 생성/수정 화면 에러 핸들링 * feat: 마이페이지 화면 네트워크 에러 핸들링 * fix: 스타카토 조회 화면 코멘트 에러 핸들링 * refactor: 추억 에러 관련 data class 리네이밍 Photo -> Thumbnail * refactor: 추억 생성 에러 data class 리네이밍 MemoryCreate -> MemoryCreation * refactor: 메서드명 카멜 케이스로 통일 (reCreate) * refactor: 추억 업데이트 에러 data class 리네이밍 MemoryInitialize -> MemoryInitialization * refactor: getSnackBarWithAction의 length를 named arguments로 수정 * refactor: EXCEPTION_NETWORK_ERROR_MESSAGE 텍스트 내용 수정 * refactor: 이미지 업로드 실패 메시지 상수화 * refactor: StaccatoUpdateViewModel의 메시지 상수화 및 PhotoException 분리 * refactor: 스낵바 Util 불필요한 apply 제거 * build: 안드로이드 CI/CD 재설정 #445 (#513) * build: android ci 타겟 브랜치 변경 - develop-an -> develop 브랜치로 변경 * build: 개발 단계용 android ci, cd 설정 - Debug용 APK 파일이 아닌 Release용 APK 파일을 추출하도록 변경 - gradle assembleRelease : 앱을 release 모드로 빌드, Debug 정보를 포함하지 않기에 용량이 더 적고, 난독화가 적용되어 있다. * build: 개발 단계용 android ci, cd 설정 - 타겟 브랜치 변경 : develop -> release-an 으로 변경 - Debug용 APK 파일이 아닌 Release용 APK 파일을 추출하도록 변경 - gradle assembleRelease : 앱을 release 모드로 빌드, Debug 정보를 포함하지 않기에 용량이 더 적고, 난독화가 적용되어 있다. * build: android ci 워크플로우 이름 변경 * build: android cd 재설정 - 구글 플레이 콘솔 자동 배포 설정 * build: Play Console 배포 설정 변경 - 서비스 계정 Key 파일 secret 변수 변경 - whatsNewDirectory 설정 * build: android ci 적용 브랜치 수정 - release-an 브랜치, main 브랜치 추가 * fix: 안드로이드 CI 오류 수정 #519 (#521) * fix: android-ci.yml 파일 수정 * fix: android-ci.yml 파일 수정 * feat: 나의 추억들 정렬 기능 구현 #503 (#507) * ui: 정렬 메뉴 ui 구현 * feat: 나의 추억들 정렬 기능 구현 * feat: 기간 유무에 따른 추억 필터 기능 구현 * refactor: 정렬 타입에 따른 정렬 선택 로직을 view model이 가지도록 변경 - 정렬 타입과 정렬 menu id를 가지고 있는 SortType Enum Class 생성 * refactor: timeline ui model 셋팅 로직 수정 * refactor: 사용자가 선택한 menuId와 일치하는 SortType을 찾는 로직을 팩토리 함수로 분리 * refactor: 원본 timeline clear 로직 추가 * refactor: 기간 있는 추억 내림차순 정렬 조건 추가 * fix: 추억 삭제 후 나의 추억들(타임라인)이 갱신되지 않는 오류 수정 * fix: 나의 추억들(타임라인) 정렬 시 포커스가 유지되는 문제 해결 * refactor: originalTimeline 타입 변경 * ui: 기분 캐릭터 변경 #522 (#523) * ui: 음표 기분 캐릭터 추가 * refactor: 음표 기분 캐릭터 적용 * feat: 카메라 촬영 기능 연결 #514 (#524) * build: androidx camera 의존성 추가 - 버전 카탈로그 활용 * build: AndroidManifest 카메라 접근 기능 수정 - android.hardware.camera.any 로 설정하여 전, 후면 모두 사용 가능하도록 변경 * ui: 사진 업로드 다이얼로그에서 ㄷ사용할 문자열 리소스 설정 - 권한 관련 안내 메시지 추가 * feat: 카메라 기능 추가 - 접근 권한 확인 후 카메라 실행 - 카메라에서 촬영한 사진을 가져와 Activity에게 이미지 URI 전달 * style: ktlint 적용 * fix: 권한 요청 스낵바와 에러 메시지 스낵바 분리 * ui: 권한 요청 스낵바의 문구 수정 * fix: 외부 저장소 쓰기 권한 추가 * deploy: v.1.2.0 배포 준비 #515 (#525) * refactor: versionCode 및 versionName 업데이트 - versionCode: 4 -> 5 - versionName: "1.1.0" -> "1.2.0" * ui: 마이페이지에 노출될 앱 버전 명 업데이트 - 앱 버전: "1.1.0" -> "1.2.0" * docs: 1.2.0 버전 출시 노트 추가 * deploy: v.1.2.0 배포 (#526) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * deploy: 1.1.1 배포 #484 (#491) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) --------- Co-authored-by: hxeyexn * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * deploy: 1.1.2 배포 (#504) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> --------- Co-authored-by: hxeyexn Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: YoonJuHo Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 * deploy: 1.1.3 배포 (#506) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 --------- Co-authored-by: hxeyexn Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: BurningFalls Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * feat: 기본 추억 제공 구현 #508 (#509) * feat: 기본 추억 생성 구현 * refactor: 기본 추억 설명 수정 * fix: persist 전파되도록 로직 순서 변경 * deploy: 1.2.0 배포 (#510) * fix: 누락된 not 연산자 추가 * refactor: whitelist 추가 #489 (#490) * feat: 인덱스 설정 스크립트 작성 #474 (#475) Co-authored-by: BurningFalls * feat: Bulk Delete 예전 pr 코드 이동 (#487) * refactor: N+1 문제 해결 (#488) * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 * refactor: 반응형 ui 적용 및 접근성 향상 #481 (#502) * ui: login 화면 반응형 ui 대응 * ui: 고유 코드 복구 화면 반응형 ui 대응 * ui: 마이페이지 화면 반응형 ui 대응 * ui: 나의 추억들 화면 반응형 ui 대응 * ui: 추억 화면 반응형 ui 대응 - span count 조정 * refactor: 스타카토 생성 화면 반응형 ui 대응 * refactor: 스타카토 수정 화면 반응형 ui 대응 * refactor: 추억 생성 화면 반응형 ui 대응 * refactor: 추억 수정 화면 반응형 ui 대응 * ui: 다크모드 대응 - colors 대응 - themes 대응 - 지도 대응 * fix: 지도 화면의 구성 변경으로 일어나는 크래시 해결 * ui: 스플래시 다크모드 대응 * feat: 스타카토 마커 커스텀 * ui: 스타카토 마커 다크모드 대응 * feat: 사용자 피드백 수집을 위한 구글 폼 연동 * feat: 인스타그램 페이지 연동 * refactor: 마이페이지 버튼 터치 영역 확대 * refactor: TextInputEditText 터치 영역 확대 * refactor: 추억 기간 선택 box 터치 영역 확대 * refactor: 툴바 수정 및 삭제 메뉴 버튼 터치 영역 확대 * refactor: 마이페이지 인스타그램 버튼 터치 영역 확대 * refactor: 스타카토 장소 선택 box 버튼 터치 영역 확대 * refactor: 스타카토 추억, 날짜 및 시간 선택 box 터치 영역 확대 * ui: typography.Body에 Not.Resizable 추가 * ui: styles에 Not.Resizable 적용 * ui: 스타카토 생성 수정 화면 styles 적용 * ui: 추억 생성 수정 화면 styles 적용 * ui: styles_button.xml에 BoundedIconButtonStyle 추가 * ui: 추억, 타임라인 화면에 BoundedIconButtonStyle 적용 * ui: 타임라인 화면 글씨 크기 조절 대응 * ui: layout_photo_attach.xml 글씨 크기 조절 대응 * ui: 추억 조회 화면 글씨 크기 조절 대응 * ui: 행간 겹침 방지를 위해 lineHeight 단위 sp로 수정 * ui: empty 관련 텍스트 Not.Resizable 설정 * ui: 로그인 및 복구 화면 글씨 크기 조절 대응 * refactor: 홈 화면 content description 추가 * refactor: 나의 추억들 화면 content description 추가 * refactor: 추억 화면 content description 추가 * refactor: 추억 생성 및 수정 화면 content description 추가 * refactor: 스타카토 사진 첨부 item content description 추가 * refactor: 나의 추억들 아이템 중첩된 레이아웃 제거 * refactor: 스타카토 화면 content description 추가 * refactor: 마이페이지 화면 content description 추가 * refactor: 로그인 화면 content description 추가 * refactor: 나의 추억들 item content description 추가 * refactor: 댓글 item content description 추가 * refactor: 함께 한 사람들 item content description 추가 * fix: 스타카토 댓글 UI 오류 해결 및 개선 #493 (#494) * ui: 스타카토 조회 오류 메시지를 strings 리소스에 작성 * ui: 키보드 입력 시 MainActivity의 화면 크기 조정되도록 변경 - MainActivity에 windowSoftInputMode를 adjustPan으로 설정 * refactor: 댓글과 조회 Fragment 병합 및 댓글 화면 개선 StaccatoFragment - 메서드 순서 조정 및 이름 변경 - staccatoId를 lazy 로 지연초기화하여 받아오도록 수정 - 댓글 ViewModel과 Adapter 추가 및 연결 - 댓글 업로드 시 스크롤 뷰의 스크롤을 하단으로 옮기도록 구현 StaccatoCommentsViewModel - 댓글 전송 성공한 상태를 저장하는 LiveData 추가 - Staccato ID 기본값 상수화 fragment_staccato.xml - 댓글 화면 마이그레이션 - 댓글 입력 창을 화면 최하단에 고정 - 전송 버튼 UI 오류 수정: 고정된 크기 * refactor: 기분 선택 fragment 리팩터링 진행 * refactor: 사용하지 않는 댓글 Fragment 제거 * ui: 댓글 전송 버튼 디자인 변경 - 이미지에서 Vector drawable 로 변경 - 색상 수정 * style: ktlint 적용 * refactor: StaccatoFragment 코드 정리 - onViewCreated의 함수 호출 순서대로 메서드 정렬 - pagePhotoAdapter 초기화를 lateinit에서 by lazy로 변경 - 메서드명 수정 - setUpBindings -> setUpBindings - initToolbarHandler -> setNavigationClickListener - initViewPagerAdapter -> setUpViewPager - loadStaccatoData -> loadStaccato * refactor: 메서드 순서를 컨벤션에 맞게 정렬 * refactor: 댓글 ViewModel의 스타카토 ID 설정 로직 수정 - Fragment가 댓글을 불러오는 동작을 알 필요가 없고, ViewModel에게 일일히 지시할 필요가 없다. - Fragment는 스타카토의 ID를 넘겨주기만 하고, ViewModel이 스타카토 ID를 알아서 설정하도록 변경 * refactor: ViewModel을 옵저빙하는 메서드 세분화 - StaccatoViewModel과 StaccatoCommentsViewModel을 옵저빙하는 메서드를 세분화 * refactor: StaccatoFeelingFragment 설정하는 메서드 리팩터링 - 메서드명 변경 : setStaccatoIdToFeelingFragment -> setStaccatoFeelingFragment - Fragment 생성 로직과 fragmentManager에 add하는 동작 분리 * ui: 댓글 입력 창과 전송 버튼 수정 - 댓글 전송 버튼의 크기를 줄이되, padding 설정으로 터치 영역 크기는 그대로 유지 - 댓글 전송 버튼의 제약 조건 수정하여 댓글 입력 창 내부에 위치하도록 변경 - 댓글 입력 창의 textAppearance 설정으로 텍스트 크기 고정 - 댓글 입력 창의 제약 조건 수정하여 전송 버튼을 감싸도록 수정 * ui: 가시성을 변경하는 바인딩어댑터 적용 * ui: viewTreeObserver 의 GlobalLayoutListener 제거 시점 변경 * ui: 댓글 전송 버튼을 텍스트 필드 범위의 바깥으로 이동 * style: ktlint 적용 --------- Co-authored-by: somin Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> * hotfix: 이미지 삭제 전파 (#505) * fix: 이미지 삭제 전파 * fix: 이미지 삭제 전파 수정 * feat: 기본 추억 제공 구현 #508 (#509) * feat: 기본 추억 생성 구현 * refactor: 기본 추억 설명 수정 * fix: persist 전파되도록 로직 순서 변경 --------- Co-authored-by: hxeyexn Co-authored-by: BurningFalls Co-authored-by: YoonJuHo Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin * fix: file changed 인식 불가로 인한 순서 변경 (#511) * feat: 모든 화면에서 네트워크 에러 핸들링 #501 (#516) * fix: ApiResponseHandler try-catch문 범위 수정 * refactor: StaccatoApiService의 반환값 Response로 wrapping * refactor: StaccatoDataSource의 반환값 ResponseResult로 wrapping * refactor: StaccatoRepository의 반환값 ResponseResult로 wrapping * refactor: StaccatoRepository를 사용하는 ViewModel에 에러 처리 변경사항 적용 * feat: MessageUtils.kt에 showSnackBarWithAction 추가 * feat: TimelineFragment 네트워크 에러 발생 시 스낵바 처리 * feat: MemoryFragment 네트워크 에러 발생 시 스낵바 처리 * feat: StaccatoFragment 네트워크 에러 발생 시 스낵바 처리 * refactor: 불필요한 Log.e 메서드 제거 * style: 네트워크 에러 메시지 상수명 통일 * refactor: MessageUtils에 getSnackBarWithAction 메서드 추가 * feat: Memory 생성/수정 화면 에러 핸들링 * feat: Staccato 생성/수정 화면 에러 핸들링 * feat: 마이페이지 화면 네트워크 에러 핸들링 * fix: 스타카토 조회 화면 코멘트 에러 핸들링 * refactor: 추억 에러 관련 data class 리네이밍 Photo -> Thumbnail * refactor: 추억 생성 에러 data class 리네이밍 MemoryCreate -> MemoryCreation * refactor: 메서드명 카멜 케이스로 통일 (reCreate) * refactor: 추억 업데이트 에러 data class 리네이밍 MemoryInitialize -> MemoryInitialization * refactor: getSnackBarWithAction의 length를 named arguments로 수정 * refactor: EXCEPTION_NETWORK_ERROR_MESSAGE 텍스트 내용 수정 * refactor: 이미지 업로드 실패 메시지 상수화 * refactor: StaccatoUpdateViewModel의 메시지 상수화 및 PhotoException 분리 * refactor: 스낵바 Util 불필요한 apply 제거 * build: 안드로이드 CI/CD 재설정 #445 (#513) * build: android ci 타겟 브랜치 변경 - develop-an -> develop 브랜치로 변경 * build: 개발 단계용 android ci, cd 설정 - Debug용 APK 파일이 아닌 Release용 APK 파일을 추출하도록 변경 - gradle assembleRelease : 앱을 release 모드로 빌드, Debug 정보를 포함하지 않기에 용량이 더 적고, 난독화가 적용되어 있다. * build: 개발 단계용 android ci, cd 설정 - 타겟 브랜치 변경 : develop -> release-an 으로 변경 - Debug용 APK 파일이 아닌 Release용 APK 파일을 추출하도록 변경 - gradle assembleRelease : 앱을 release 모드로 빌드, Debug 정보를 포함하지 않기에 용량이 더 적고, 난독화가 적용되어 있다. * build: android ci 워크플로우 이름 변경 * build: android cd 재설정 - 구글 플레이 콘솔 자동 배포 설정 * build: Play Console 배포 설정 변경 - 서비스 계정 Key 파일 secret 변수 변경 - whatsNewDirectory 설정 * build: android ci 적용 브랜치 수정 - release-an 브랜치, main 브랜치 추가 * fix: 안드로이드 CI 오류 수정 #519 (#521) * fix: android-ci.yml 파일 수정 * fix: android-ci.yml 파일 수정 * feat: 나의 추억들 정렬 기능 구현 #503 (#507) * ui: 정렬 메뉴 ui 구현 * feat: 나의 추억들 정렬 기능 구현 * feat: 기간 유무에 따른 추억 필터 기능 구현 * refactor: 정렬 타입에 따른 정렬 선택 로직을 view model이 가지도록 변경 - 정렬 타입과 정렬 menu id를 가지고 있는 SortType Enum Class 생성 * refactor: timeline ui model 셋팅 로직 수정 * refactor: 사용자가 선택한 menuId와 일치하는 SortType을 찾는 로직을 팩토리 함수로 분리 * refactor: 원본 timeline clear 로직 추가 * refactor: 기간 있는 추억 내림차순 정렬 조건 추가 * fix: 추억 삭제 후 나의 추억들(타임라인)이 갱신되지 않는 오류 수정 * fix: 나의 추억들(타임라인) 정렬 시 포커스가 유지되는 문제 해결 * refactor: originalTimeline 타입 변경 * ui: 기분 캐릭터 변경 #522 (#523) * ui: 음표 기분 캐릭터 추가 * refactor: 음표 기분 캐릭터 적용 * feat: 카메라 촬영 기능 연결 #514 (#524) * build: androidx camera 의존성 추가 - 버전 카탈로그 활용 * build: AndroidManifest 카메라 접근 기능 수정 - android.hardware.camera.any 로 설정하여 전, 후면 모두 사용 가능하도록 변경 * ui: 사진 업로드 다이얼로그에서 ㄷ사용할 문자열 리소스 설정 - 권한 관련 안내 메시지 추가 * feat: 카메라 기능 추가 - 접근 권한 확인 후 카메라 실행 - 카메라에서 촬영한 사진을 가져와 Activity에게 이미지 URI 전달 * style: ktlint 적용 * fix: 권한 요청 스낵바와 에러 메시지 스낵바 분리 * ui: 권한 요청 스낵바의 문구 수정 * fix: 외부 저장소 쓰기 권한 추가 * deploy: v.1.2.0 배포 준비 #515 (#525) * refactor: versionCode 및 versionName 업데이트 - versionCode: 4 -> 5 - versionName: "1.1.0" -> "1.2.0" * ui: 마이페이지에 노출될 앱 버전 명 업데이트 - 앱 버전: "1.1.0" -> "1.2.0" * docs: 1.2.0 버전 출시 노트 추가 --------- Co-authored-by: hxeyexn Co-authored-by: linirini <101927543+linirini@users.noreply.github.com> Co-authored-by: BurningFalls Co-authored-by: YoonJuHo Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: somin Co-authored-by: linirini <2001yerin@naver.com> Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> * fix: Android CD 수정 #527 (#528) * fix: push branch 에 release-an 추가 * fix: 출시 노트 옵션 파일경로 수정 * chore: Thread, Hikari CP 변경 (#518) * feat: Hikari CP, Thread 설정 변경 * fix: writer, reader에 각각 hikari 설정 * feat: 기본 추억 제목 변경 #530 (#531) * feat: 기본 추억 이름을 ~의 추억으로 설정 * refactor: 변수 사용 * fix: 스타카토 삭제 시 마커가 갱신되지 않는 오류 해결 #533 (#534) * fix: 스타카토 삭제 시 마커가 갱신되지 않는 오류 해결 * build: versionCode 업그레이드 - versionCode: 5 -> 6 --------- Co-authored-by: Junyoung-WON * feat & fix: 사진 코루틴 취소 버그 수정 / ACTION_PICK_IMAGES 적용 #536 (#537) * chore: 카메라와 사진 권한 메시지 분리 * feat: ACTION_PICK_IMAGES 적용 및 장 수 선택 제한 * fix: 사진 업로드 코루틴에서 예외 시 isActive 체크 * style: StaccatoUpdateViewModel ktlintFormat * refactor: 코드 리뷰 반영 * refactor: 코드 리뷰 반영 - 상수화 * docs: bug-issue-template 생성 * docs: 기능 이슈 템플릿 작성 * docs: 기능 이슈 템플릿 수정 * docs: 기능 이슈 템플릿 수정 * docs: 리팩터링 이슈 템플릿 작성 * docs: 기존 이슈 템플릿 제거 * chore: cd workflow 작동 브랜치 수정 --------- Co-authored-by: YoonJuHo Co-authored-by: Hyeyeon Gong <103019852+hxeyexn@users.noreply.github.com> Co-authored-by: hodu <92203597+Junyoung-WON@users.noreply.github.com> Co-authored-by: devhoya97 <146502065+devhoya97@users.noreply.github.com> Co-authored-by: Somin Lee <46596035+s6m1n@users.noreply.github.com> Co-authored-by: Seongju Lee Co-authored-by: somin Co-authored-by: Junyoung-WON Co-authored-by: devhoya97 Co-authored-by: hxeyexn --- .github/ISSUE_TEMPLATE/bug-issue-template.md | 19 + .github/ISSUE_TEMPLATE/feat-issue-template.md | 26 + .../ISSUE_TEMPLATE/refactor-issue-template.md | 23 + .../ISSUE_TEMPLATE/staccato-issue-template.md | 14 - .github/workflows/android-cd.yml | 21 +- ...apk.yml.disabled => android-ci-cd-dev.yml} | 16 +- .github/workflows/android-ci.yml | 6 +- .github/workflows/backend-ci-cd-prod.yml | 21 +- android/Staccato_AN/.gitignore | 2 +- android/Staccato_AN/app/build.gradle.kts | 11 +- .../app/src/main/AndroidManifest.xml | 47 +- .../com/on/staccato/StaccatoApplication.kt | 3 +- .../on/staccato/data/ApiResponseHandler.kt | 10 +- .../data/comment/CommentDataSource.kt | 2 +- .../data/comment/CommentDefaultRepository.kt | 16 +- .../data/comment/CommentRemoteDataSource.kt | 4 +- .../staccato/data/dto/mapper/CommentMapper.kt | 2 +- .../staccato/data/dto/mapper/FeelingMapper.kt | 2 +- .../staccato/data/dto/mapper/MemoryMapper.kt | 16 +- .../staccato/data/dto/mapper/MyPageMapper.kt | 8 +- .../{MomentMapper.kt => StaccatoMapper.kt} | 22 +- .../data/dto/mapper/TimelineMapper.kt | 2 +- .../data/dto/memory/MemoryResponse.kt | 2 +- ...emoryMomentDto.kt => MemoryStaccatoDto.kt} | 4 +- .../data/dto/moment/MomentCreationResponse.kt | 9 - .../data/dto/moment/MomentLocationResponse.kt | 9 - .../data/dto/mypage/MemberProfileResponse.kt | 11 + .../{moment => staccato}/FeelingRequest.kt | 2 +- .../StaccatoCreationRequest.kt} | 10 +- .../dto/staccato/StaccatoCreationResponse.kt | 9 + .../StaccatoLocationDto.kt} | 6 +- .../dto/staccato/StaccatoLocationResponse.kt | 9 + .../StaccatoResponse.kt} | 6 +- .../StaccatoUpdateRequest.kt} | 8 +- .../data/image/ImageDefaultRepository.kt | 4 +- .../data/login/LoginDefaultRepository.kt | 4 +- .../data/member/MemberDefaultRepository.kt | 4 +- .../data/memory/MemoryDefaultRepository.kt | 12 +- .../staccato/data/module/DataSourceModule.kt | 6 +- .../staccato/data/module/RepositoryModule.kt | 6 +- .../on/staccato/data/module/RetrofitModule.kt | 4 +- .../staccato/data/moment/MomentApiService.kt | 54 -- .../staccato/data/moment/MomentDataSource.kt | 29 - .../data/moment/MomentDefaultRepository.kt | 111 ---- .../data/moment/MomentRemoteDataSource.kt | 51 -- .../staccato/data/mypage/MyPageApiService.kt | 4 +- .../data/mypage/MyPageDefaultRepository.kt | 13 +- .../data/staccato/StaccatoApiService.kt | 54 ++ .../data/staccato/StaccatoDataSource.kt | 29 + .../staccato/StaccatoDefaultRepository.kt | 190 ++++++ .../data/staccato/StaccatoRemoteDataSource.kt | 53 ++ .../timeline/TimelineDefaultRepository.kt | 6 +- .../on/staccato/domain/model/MemberProfile.kt | 7 + .../com/on/staccato/domain/model/Memory.kt | 2 +- .../on/staccato/domain/model/MemoryMoment.kt | 10 - .../staccato/domain/model/MemoryStaccato.kt | 10 + .../on/staccato/domain/model/NewComment.kt | 2 +- .../domain/model/{Moment.kt => Staccato.kt} | 6 +- ...{MomentLocation.kt => StaccatoLocation.kt} | 4 +- .../domain/repository/CommentRepository.kt | 2 +- .../domain/repository/MomentRepository.kt | 43 -- .../domain/repository/MyPageRepository.kt | 4 +- .../domain/repository/StaccatoRepository.kt | 43 ++ .../staccato/presentation/BindingAdapters.kt | 610 ------------------ .../bindingadapter/BindingAdapters.kt | 76 +++ .../bindingadapter/ButtonBindingAdapter.kt | 112 ++++ .../bindingadapter/ImageBindingAdapter.kt | 91 +++ .../bindingadapter/TextBindingAdapter.kt | 158 +++++ .../common/AttachedPhotoHandler.kt | 2 +- .../presentation/common/LocalDateFormatter.kt | 35 + .../presentation/common/MemberUiModel.kt | 47 -- .../common/PhotoAttachFragment.kt | 300 ++++++--- .../login/viewmodel/LoginViewModel.kt | 18 - .../presentation/main/MainActivity.kt | 56 +- .../main/viewmodel/MapsViewModel.kt | 18 +- .../main/viewmodel/SharedViewModel.kt | 3 +- .../presentation/mapper/MemoryMapper.kt | 16 +- ...odelMapper.kt => StaccatoUiModelMapper.kt} | 26 +- .../presentation/memory/MemoryFragment.kt | 54 +- .../presentation/memory/MemoryHandler.kt | 4 +- .../memory/adapter/StaccatoViewHolder.kt | 16 + .../memory/adapter/StaccatosAdapter.kt | 46 ++ .../memory/adapter/VisitsAdapter.kt | 46 -- .../memory/adapter/VisitsViewHolder.kt | 16 - ...sitUiModel.kt => MemoryStaccatoUiModel.kt} | 4 +- .../memory/model/MemoryUiModel.kt | 2 +- .../memory/viewmodel/MemoryViewModel.kt | 11 +- .../memorycreation/MemoryCreationActivity.kt | 48 +- .../memorycreation/MemoryCreationError.kt | 9 + .../viewmodel/MemoryCreationViewModel.kt | 46 +- .../memoryupdate/MemoryUpdateActivity.kt | 58 +- .../memoryupdate/MemoryUpdateError.kt | 11 + .../viewmodel/MemoryUpdateViewModel.kt | 60 +- .../presentation/moment/MomentFragment.kt | 130 ---- .../moment/comments/MomentCommentsFragment.kt | 68 -- .../moment/feeling/FeelingUiModel.kt | 8 - .../feeling/MomentFeelingSelectionFragment.kt | 49 -- .../moment/model/MomentDetailUiModel.kt | 21 - .../moment/viewmodel/MomentViewModel.kt | 60 -- .../mypage/MemberProfileHandler.kt | 5 + .../presentation/mypage/MyPageActivity.kt | 55 +- .../presentation/mypage/MyPageMenuHandler.kt | 4 + .../mypage/viewmodel/MyPageViewModel.kt | 59 +- .../recovery/viewmodel/RecoveryViewModel.kt | 18 - .../presentation/staccato/StaccatoFragment.kt | 236 +++++++ .../StaccatoToolbarHandler.kt} | 4 +- .../comments/CommentHandler.kt | 2 +- .../comments/CommentUiModel.kt | 2 +- .../comments/CommentViewHolder.kt | 6 +- .../comments/CommentsAdapter.kt | 6 +- .../comments/StaccatoCommentsViewModel.kt} | 73 +-- .../detail/StaccatoDetailUiModel.kt} | 6 +- .../detail/ViewpagePhotoAdapter.kt | 2 +- .../detail/ViewpagePhotoViewHolder.kt | 2 +- .../feeling/FeelingHandler.kt | 2 +- .../feeling/FeelingSelectionAdapter.kt | 8 +- .../staccato/feeling/FeelingUiModel.kt | 10 + .../StaccatoFeelingSelectionFragment.kt | 52 ++ .../StaccatoFeelingSelectionViewModel.kt} | 16 +- .../staccato/viewmodel/StaccatoViewModel.kt | 83 +++ .../CurrentLocationHandler.kt | 2 +- .../OnUrisSelectedListener.kt | 2 +- .../StaccatoCreationActivity.kt} | 111 +++- .../staccatocreation/StaccatoCreationError.kt | 7 + .../StaccatoCreationHandler.kt} | 4 +- .../AttachedPhotoItemTouchHelperCallback.kt | 3 +- .../adapter/ItemDragListener.kt | 4 +- .../adapter/ItemMoveListener.kt | 2 +- .../adapter/PhotoAttachAdapter.kt | 6 +- .../adapter/PhotoAttachViewHolder.kt | 4 +- .../dialog/MemorySelectionFragment.kt | 2 +- .../dialog/MemorySelectionHandler.kt | 2 +- .../dialog/VisitedAtSelectionFragment.kt | 4 +- .../dialog/VisitedAtSelectionHandler.kt | 2 +- .../model/AttachedPhotoUiModel.kt | 6 +- .../model/AttachedPhotosUiModel.kt | 2 +- .../viewmodel/StaccatoCreationViewModel.kt} | 84 ++- .../StaccatoUpdateActivity.kt} | 118 +++- .../staccatoupdate/StaccatoUpdateError.kt | 9 + .../StaccatoUpdateHandler.kt} | 4 +- .../viewmodel/StaccatoUpdateViewModel.kt} | 133 ++-- .../presentation/timeline/TimelineFragment.kt | 48 +- .../timeline/adapter/TimelineAdapter.kt | 7 +- .../presentation/timeline/model/SortType.kt | 19 + .../timeline/viewmodel/TimelineViewModel.kt | 61 +- .../presentation/util/MessageUtils.kt | 25 + .../icon_location_pin_3x.png | Bin 0 -> 16654 bytes .../drawable-xxxhdpi/icon_location_pin_3x.png | Bin 0 -> 16515 bytes .../main/res/drawable/feeling_angry_note.png | Bin 0 -> 121603 bytes .../res/drawable/feeling_angry_note_gray.png | Bin 0 -> 59377 bytes .../res/drawable/feeling_excited_note.png | Bin 0 -> 108716 bytes .../drawable/feeling_excited_note_gray.png | Bin 0 -> 61916 bytes .../main/res/drawable/feeling_happy_note.png | Bin 0 -> 115741 bytes .../res/drawable/feeling_happy_note_gray.png | Bin 0 -> 60743 bytes .../main/res/drawable/feeling_sad_note.png | Bin 0 -> 117936 bytes .../res/drawable/feeling_sad_note_gray.png | Bin 0 -> 59665 bytes .../main/res/drawable/feeling_scared_note.png | Bin 0 -> 143563 bytes .../res/drawable/feeling_scared_note_gray.png | Bin 0 -> 70147 bytes .../src/main/res/drawable/icon_instagram.xml | 65 ++ .../main/res/drawable/icon_send_disabled.png | Bin 13567 -> 0 bytes .../main/res/drawable/icon_send_disabled.xml | 12 + .../main/res/drawable/icon_send_enabled.png | Bin 6101 -> 0 bytes .../main/res/drawable/icon_send_enabled.xml | 12 + .../drawable/icon_staccato_symbol_dark.png | Bin 0 -> 85909 bytes .../drawable/selector_comment_sendable.xml | 4 +- ...2dp.xml => shape_my_staccato_log_12dp.xml} | 0 ...xml => shape_others_staccato_log_12dp.xml} | 0 .../src/main/res/layout/activity_login.xml | 79 +-- .../app/src/main/res/layout/activity_main.xml | 12 +- .../res/layout/activity_memory_creation.xml | 81 +-- .../res/layout/activity_memory_update.xml | 84 ++- .../src/main/res/layout/activity_mypage.xml | 186 +++--- .../src/main/res/layout/activity_recovery.xml | 105 +-- ...ion.xml => activity_staccato_creation.xml} | 174 ++--- ...pdate.xml => activity_staccato_update.xml} | 169 ++--- .../fragment_delete_impossibility_dialog.xml | 4 +- .../app/src/main/res/layout/fragment_maps.xml | 8 - .../src/main/res/layout/fragment_memory.xml | 61 +- .../res/layout/fragment_memory_selection.xml | 2 +- .../fragment_memory_visited_at_selection.xml | 8 +- .../src/main/res/layout/fragment_moment.xml | 178 ----- .../res/layout/fragment_moment_comments.xml | 122 ---- .../src/main/res/layout/fragment_staccato.xml | 272 ++++++++ .../res/layout/fragment_staccato_comments.xml | 112 ++++ ...> fragment_staccato_feeling_selection.xml} | 16 +- .../src/main/res/layout/fragment_timeline.xml | 58 +- .../src/main/res/layout/fragment_visit.xml | 43 -- .../layout/fragment_visited_at_selection.xml | 10 +- .../main/res/layout/item_attached_photo.xml | 33 +- .../app/src/main/res/layout/item_mates.xml | 2 +- .../src/main/res/layout/item_my_visit_log.xml | 65 -- .../main/res/layout/item_others_visit_log.xml | 65 -- ...ml => item_staccato_feeling_selection.xml} | 8 +- ...mment.xml => item_staccato_my_comment.xml} | 32 +- ...t.xml => item_staccato_others_comment.xml} | 20 +- .../src/main/res/layout/item_staccatos.xml | 97 +++ .../app/src/main/res/layout/item_timeline.xml | 76 ++- .../main/res/layout/item_viewpage_photo.xml | 5 +- .../app/src/main/res/layout/item_visits.xml | 94 --- .../src/main/res/layout/item_visits_date.xml | 16 - .../src/main/res/layout/layout_loading.xml | 38 ++ .../main/res/layout/layout_photo_attach.xml | 9 +- .../src/main/res/layout/layout_timeline.xml | 90 --- .../src/main/res/layout/toolbar_detail.xml | 3 +- .../app/src/main/res/menu/menu_sort.xml | 18 + .../navigation/bottom_navigation_graph.xml | 12 +- .../main/res/raw-night/google_map_style.json | 250 +++++++ .../src/main/res/raw/google_map_style.json | 19 + .../app/src/main/res/values-night/colors.xml | 20 + .../app/src/main/res/values-night/themes.xml | 31 +- .../src/main/res/values-w600dp/integers.xml | 4 + .../app/src/main/res/values/colors.xml | 4 + .../app/src/main/res/values/integers.xml | 4 + .../app/src/main/res/values/strings.xml | 153 +++-- .../app/src/main/res/values/styles.xml | 244 ++----- .../app/src/main/res/values/styles_button.xml | 110 ++++ .../src/main/res/values/styles_comment.xml | 41 ++ .../src/main/res/values/styles_text_input.xml | 46 ++ .../src/main/res/values/styles_toolbar.xml | 38 ++ .../app/src/main/res/values/typography.xml | 50 +- .../deploy/whatsnew/whatsnew-ko-KR | 19 + android/Staccato_AN/gradle/libs.versions.toml | 6 + backend/Dockerfile.prod | 2 +- .../staccato/auth/service/AuthService.java | 10 + .../comment/repository/CommentRepository.java | 7 +- .../staccato/config/log/LoggingFilter.java | 11 +- .../com/staccato/memory/domain/Memory.java | 16 +- .../repository/MemoryMemberRepository.java | 13 +- .../memory/service/MemoryService.java | 19 +- .../staccato/moment/domain/MomentImages.java | 5 +- .../repository/MomentImageRepository.java | 10 +- .../moment/repository/MomentRepository.java | 9 +- .../moment/service/MomentService.java | 6 +- .../src/main/resources/application-prod.yml | 17 + .../db/migration/V8__create_indexes.sql | 5 + .../auth/service/AuthServiceTest.java | 20 + .../repository/CommentRepositoryTest.java | 57 ++ .../fixture/comment/CommentFixture.java | 8 + .../staccato/memory/domain/MemoryTest.java | 16 + .../MemoryMemberRepositoryTest.java | 44 ++ .../memory/service/MemoryServiceTest.java | 5 +- .../repository/MomentImageRepositoryTest.java | 57 ++ .../repository/MomentRepositoryTest.java | 53 ++ 243 files changed, 5127 insertions(+), 3664 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-issue-template.md create mode 100644 .github/ISSUE_TEMPLATE/feat-issue-template.md create mode 100644 .github/ISSUE_TEMPLATE/refactor-issue-template.md delete mode 100644 .github/ISSUE_TEMPLATE/staccato-issue-template.md rename .github/workflows/{android-ci-cd-demo-apk.yml.disabled => android-ci-cd-dev.yml} (85%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/{MomentMapper.kt => StaccatoMapper.kt} (59%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/{MemoryMomentDto.kt => MemoryStaccatoDto.kt} (80%) delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationResponse.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationResponse.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mypage/MemberProfileResponse.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/{moment => staccato}/FeelingRequest.kt (80%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/{moment/MomentUpdateRequest.kt => staccato/StaccatoCreationRequest.kt} (75%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationResponse.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/{moment/MomentLocationDto.kt => staccato/StaccatoLocationDto.kt} (61%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationResponse.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/{moment/MomentResponse.kt => staccato/StaccatoResponse.kt} (86%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/{moment/MomentCreationRequest.kt => staccato/StaccatoUpdateRequest.kt} (87%) delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentApiService.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDataSource.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDefaultRepository.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentRemoteDataSource.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoApiService.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDataSource.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDefaultRepository.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoRemoteDataSource.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemberProfile.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryMoment.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryStaccato.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/{Moment.kt => Staccato.kt} (82%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/{MomentLocation.kt => StaccatoLocation.kt} (62%) delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MomentRepository.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/StaccatoRepository.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/BindingAdapters.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/BindingAdapters.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ButtonBindingAdapter.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ImageBindingAdapter.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/TextBindingAdapter.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/LocalDateFormatter.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/{VisitUiModelMapper.kt => StaccatoUiModelMapper.kt} (51%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatoViewHolder.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatosAdapter.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsAdapter.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsViewHolder.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/{MemoryVisitUiModel.kt => MemoryStaccatoUiModel.kt} (68%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationError.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateError.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentFragment.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsFragment.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingUiModel.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionFragment.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/model/MomentDetailUiModel.kt delete mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/viewmodel/MomentViewModel.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MemberProfileHandler.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoFragment.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment/MomentToolbarHandler.kt => staccato/StaccatoToolbarHandler.kt} (58%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/comments/CommentHandler.kt (73%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/comments/CommentUiModel.kt (75%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/comments/CommentViewHolder.kt (91%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/comments/CommentsAdapter.kt (89%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment/comments/MomentCommentsViewModel.kt => staccato/comments/StaccatoCommentsViewModel.kt} (66%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment/detail/MomentDetailUiModel.kt => staccato/detail/StaccatoDetailUiModel.kt} (68%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/detail/ViewpagePhotoAdapter.kt (95%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/detail/ViewpagePhotoViewHolder.kt (85%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/feeling/FeelingHandler.kt (61%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment => staccato}/feeling/FeelingSelectionAdapter.kt (88%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingUiModel.kt create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionFragment.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{moment/feeling/MomentFeelingSelectionViewModel.kt => staccato/feeling/StaccatoFeelingSelectionViewModel.kt} (83%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/viewmodel/StaccatoViewModel.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/CurrentLocationHandler.kt (57%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/OnUrisSelectedListener.kt (65%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation/MomentCreationActivity.kt => staccatocreation/StaccatoCreationActivity.kt} (79%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationError.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation/MomentCreationHandler.kt => staccatocreation/StaccatoCreationHandler.kt} (54%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitcreation => staccatocreation}/adapter/AttachedPhotoItemTouchHelperCallback.kt (93%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitcreation => staccatocreation}/adapter/ItemDragListener.kt (57%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitcreation => staccatocreation}/adapter/ItemMoveListener.kt (65%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/adapter/PhotoAttachAdapter.kt (92%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/adapter/PhotoAttachViewHolder.kt (89%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/dialog/MemorySelectionFragment.kt (97%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/dialog/MemorySelectionHandler.kt (71%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/dialog/VisitedAtSelectionFragment.kt (98%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/dialog/VisitedAtSelectionHandler.kt (67%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/model/AttachedPhotoUiModel.kt (63%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation => staccatocreation}/model/AttachedPhotosUiModel.kt (96%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{momentcreation/viewmodel/MomentCreationViewModel.kt => staccatocreation/viewmodel/StaccatoCreationViewModel.kt} (78%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitupdate/VisitUpdateActivity.kt => staccatoupdate/StaccatoUpdateActivity.kt} (77%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateError.kt rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitupdate/VisitUpdateHandler.kt => staccatoupdate/StaccatoUpdateHandler.kt} (55%) rename android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/{visitupdate/viewmodel/VisitUpdateViewModel.kt => staccatoupdate/viewmodel/StaccatoUpdateViewModel.kt} (69%) create mode 100644 android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/model/SortType.kt create mode 100644 android/Staccato_AN/app/src/main/res/drawable-night-xxxhdpi/icon_location_pin_3x.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable-xxxhdpi/icon_location_pin_3x.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_angry_note.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_angry_note_gray.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_excited_note.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_excited_note_gray.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_happy_note.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_happy_note_gray.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note_gray.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_scared_note.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/feeling_scared_note_gray.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_instagram.xml delete mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_send_disabled.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_send_disabled.xml delete mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.png create mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.xml create mode 100644 android/Staccato_AN/app/src/main/res/drawable/icon_staccato_symbol_dark.png rename android/Staccato_AN/app/src/main/res/drawable/{shape_my_visit_log_12dp.xml => shape_my_staccato_log_12dp.xml} (100%) rename android/Staccato_AN/app/src/main/res/drawable/{shape_others_visit_log_12dp.xml => shape_others_staccato_log_12dp.xml} (100%) rename android/Staccato_AN/app/src/main/res/layout/{activity_visit_creation.xml => activity_staccato_creation.xml} (64%) rename android/Staccato_AN/app/src/main/res/layout/{activity_visit_update.xml => activity_staccato_update.xml} (65%) delete mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_maps.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_moment.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_moment_comments.xml create mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_staccato.xml create mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_staccato_comments.xml rename android/Staccato_AN/app/src/main/res/layout/{fragment_moment_feeling_selection.xml => fragment_staccato_feeling_selection.xml} (75%) delete mode 100644 android/Staccato_AN/app/src/main/res/layout/fragment_visit.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/item_my_visit_log.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/item_others_visit_log.xml rename android/Staccato_AN/app/src/main/res/layout/{item_moment_feeling_selection.xml => item_staccato_feeling_selection.xml} (68%) rename android/Staccato_AN/app/src/main/res/layout/{item_moment_my_comment.xml => item_staccato_my_comment.xml} (60%) rename android/Staccato_AN/app/src/main/res/layout/{item_moment_others_comment.xml => item_staccato_others_comment.xml} (74%) create mode 100644 android/Staccato_AN/app/src/main/res/layout/item_staccatos.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/item_visits.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/item_visits_date.xml create mode 100644 android/Staccato_AN/app/src/main/res/layout/layout_loading.xml delete mode 100644 android/Staccato_AN/app/src/main/res/layout/layout_timeline.xml create mode 100644 android/Staccato_AN/app/src/main/res/menu/menu_sort.xml create mode 100644 android/Staccato_AN/app/src/main/res/raw-night/google_map_style.json create mode 100644 android/Staccato_AN/app/src/main/res/raw/google_map_style.json create mode 100644 android/Staccato_AN/app/src/main/res/values-night/colors.xml create mode 100644 android/Staccato_AN/app/src/main/res/values-w600dp/integers.xml create mode 100644 android/Staccato_AN/app/src/main/res/values/integers.xml create mode 100644 android/Staccato_AN/app/src/main/res/values/styles_button.xml create mode 100644 android/Staccato_AN/app/src/main/res/values/styles_comment.xml create mode 100644 android/Staccato_AN/app/src/main/res/values/styles_text_input.xml create mode 100644 android/Staccato_AN/app/src/main/res/values/styles_toolbar.xml create mode 100644 android/Staccato_AN/deploy/whatsnew/whatsnew-ko-KR create mode 100644 backend/src/main/resources/db/migration/V8__create_indexes.sql create mode 100644 backend/src/test/java/com/staccato/comment/repository/CommentRepositoryTest.java create mode 100644 backend/src/test/java/com/staccato/moment/repository/MomentImageRepositoryTest.java diff --git a/.github/ISSUE_TEMPLATE/bug-issue-template.md b/.github/ISSUE_TEMPLATE/bug-issue-template.md new file mode 100644 index 000000000..e9ebc3e49 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-issue-template.md @@ -0,0 +1,19 @@ +--- +name: bug issue template +about: 이슈를 생성해주세요. +title: 'fix: 작업 제목' +labels: 'fix' +assignees: '' + +--- + +## 🤮 As Is (오마이갓 비상사태) +> 어떤 상황에서 발생한 버그인지 설명해주세요. (육하원칙이면 더 좋아요!) + +## 🤬 To Be +> 버그가 없었다면 어떻게 동작해야 하는지 설명해주세요. + +## 😇 이때까지 끝낼게요! +> 버그 해결 예상 날짜를 작성해주세요. 신중하게 생각해요! + +## 😵 참고 자료(선택) diff --git a/.github/ISSUE_TEMPLATE/feat-issue-template.md b/.github/ISSUE_TEMPLATE/feat-issue-template.md new file mode 100644 index 000000000..ff69b085f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feat-issue-template.md @@ -0,0 +1,26 @@ +--- +name: feat issue template +about: 이슈를 생성해주세요. +title: 'feat: 작업 제목' +labels: 'feat' +assignees: '' + +--- + +## 🥸 어떤 기능인가요? +> 추가하려는 기능을 설명해주세요. + +## ✅ 작업 내용 +- [ ] TODO +- [ ] TODO +- [ ] TODO + +## 😇 이때까지 끝낼게요! +> 기능 개발 완료 예상 날짜를 작성해주세요. 신중하게 생각해요! + +## 😵 참고할만한 자료(선택) + +## 🙇‍♀️ 이슈 확인했어요:) +> 팀원에게 이슈 확인을 부탁해요! 이슈를 확인한 팀원은 체크 표시를 해주세요! +- [ ] 팀원명 + diff --git a/.github/ISSUE_TEMPLATE/refactor-issue-template.md b/.github/ISSUE_TEMPLATE/refactor-issue-template.md new file mode 100644 index 000000000..dc000f9ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/refactor-issue-template.md @@ -0,0 +1,23 @@ +--- +name: refactor issue template +about: 이슈를 생성해주세요. +title: 'refactor: 작업 제목' +labels: 'refactor' +assignees: '' + +--- + +## 🤮 As Is +> 리팩터링하고자 하는 파트와 이유를 구체적으로 설명해주세요. + +## 🤩 To Be +> 리팩터링 방향을 구체적으로 공유해주세요. + +## 😇 이때까지 끝낼게요! +> 리팩터링 완료 예상 날짜를 작성해주세요. 신중하게 생각해요! + +## 😵 참고 자료(선택) + +## 🙇‍♀️이슈 확인했어요:) +> 팀원에게 이슈 확인을 부탁해요! +- [ ] 팀원명 diff --git a/.github/ISSUE_TEMPLATE/staccato-issue-template.md b/.github/ISSUE_TEMPLATE/staccato-issue-template.md deleted file mode 100644 index 13b0491b8..000000000 --- a/.github/ISSUE_TEMPLATE/staccato-issue-template.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: staccato issue template -about: 이슈를 생성해주세요. -title: 'prefix: 작업 제목' -labels: '' -assignees: '' - ---- - -### ✅ CheckList -- [ ] -- [ ] -- [ ] -- [ ] diff --git a/.github/workflows/android-cd.yml b/.github/workflows/android-cd.yml index 413857c5e..e90fc373f 100644 --- a/.github/workflows/android-cd.yml +++ b/.github/workflows/android-cd.yml @@ -3,7 +3,7 @@ name: Android CI/CD for release on: push: paths: 'android/**' - branches: [ "main" ] + branches: [ "release-an" ] env: BASE_URL: ${{ secrets.BASE_URL }} @@ -70,22 +70,23 @@ jobs: - name: Build Release AAB run: ./gradlew bundleRelease - - name: Upload Release APK + - name: Upload Release APK in artifact uses: actions/upload-artifact@v3 with: name: app-release.apk path: android/Staccato_AN/app/build/outputs/apk/release/app-release.apk - - name: Upload Release AAB + - name: Upload Release AAB in artifact uses: actions/upload-artifact@v3 with: name: app-release.aab path: android/Staccato_AN/app/build/outputs/bundle/release/app-release.aab -# - name: Upload On Google Play -# uses: r0adkll/upload-google-play@v1 -# with: -# serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }} -# packageName: com.on.staccato -# releaseFiles: android/Staccato_AN/app/build/outputs/bundle/release/app-release.aab -# track: internal + - name: Deploy AAB On Google Play Console + uses: r0adkll/upload-google-play@v1 + with: + serviceAccountJsonPlainText: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY_JSON }} + packageName: com.on.staccato + releaseFiles: android/Staccato_AN/app/build/outputs/bundle/release/app-release.aab + track: product + whatsNewDirectory: android/Staccato_AN/deploy/whatsnew diff --git a/.github/workflows/android-ci-cd-demo-apk.yml.disabled b/.github/workflows/android-ci-cd-dev.yml similarity index 85% rename from .github/workflows/android-ci-cd-demo-apk.yml.disabled rename to .github/workflows/android-ci-cd-dev.yml index 79dfd12f1..d1fbdee45 100644 --- a/.github/workflows/android-ci-cd-demo-apk.yml.disabled +++ b/.github/workflows/android-ci-cd-dev.yml @@ -1,9 +1,9 @@ -name: Android CI/CD for generating demo APK +name: Android CI/CD for release(generating demo APK) on: push: paths: 'android/**' - branches: [ "develop" ] + branches: [ "release-an" ] env: BASE_URL: ${{ secrets.BASE_URL }} @@ -69,14 +69,14 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Build Debug APK - run: ./gradlew assembleDebug + - name: Build Release APK + run: ./gradlew assembleRelease - - name: Upload Debug APK + - name: Upload Release APK uses: actions/upload-artifact@v3 with: - name: app-debug.apk - path: android/Staccato_AN/app/build/outputs/apk/debug/app-debug.apk + name: app-release.apk + path: android/Staccato_AN/app/build/outputs/apk/release/app-release.apk - name: Upload Artifact to Firebase App Distribution uses: wzieba/Firebase-Distribution-Github-Action@v1 @@ -84,4 +84,4 @@ jobs: appId: ${{secrets.FIREBASE_APP_ID}} serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }} groups: staccato_tester - file: android/Staccato_AN/app/build/outputs/apk/debug/app-debug.apk + file: android/Staccato_AN/app/build/outputs/apk/release/app-release.apk diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index baeac0ce0..486c82327 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -1,9 +1,9 @@ -name: Android CI for develop-an +name: Android CI for develop on: pull_request: paths: 'android/**' - branches: [ "develop-an" ] + branches: [ "develop", "release-an", "main" ] env: BASE_URL: ${{ secrets.BASE_URL }} @@ -62,7 +62,7 @@ jobs: run: | mkdir ./app/signing echo "$UPLOAD_KEY_STORE_JKS" | base64 --decode > ./app/signing/upload_key_store.jks - echo $KEY_STORE_PROPERTIES > ./app/signing/keystore.properties + echo "$KEY_STORE_PROPERTIES" > ./app/signing/keystore.properties - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.github/workflows/backend-ci-cd-prod.yml b/.github/workflows/backend-ci-cd-prod.yml index 8d8e92d30..b283cfbff 100644 --- a/.github/workflows/backend-ci-cd-prod.yml +++ b/.github/workflows/backend-ci-cd-prod.yml @@ -3,7 +3,7 @@ name: Backend CI/CD prod on: push: paths: [ 'backend/**', '.github/**' ] - branches: [ "main" ] + branches: [ "release-be" ] jobs: ci: @@ -58,20 +58,5 @@ jobs: runner: [ prod-a, prod-b ] steps: - - name: Pull Docker image - run: | - sudo docker login --username ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }} --password ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }} - sudo docker pull staccato/staccato:prod - - - name: Stop and remove existing container - run: | - sudo docker stop staccato-backend-app || true - sudo docker rm staccato-backend-app || true - - - name: Docker run - run: | - sudo docker run --env-file /home/ubuntu/staccato/.env \ - -v /home/ubuntu/staccato/logs:/logs \ - -p 8080:8080 \ - -d --name staccato-backend-app staccato/staccato:prod - sudo docker image prune -af + - name: execute deploy.sh + run: bash /home/ubuntu/staccato/deploy.sh diff --git a/android/Staccato_AN/.gitignore b/android/Staccato_AN/.gitignore index ecf6379e5..4cf2bf300 100644 --- a/android/Staccato_AN/.gitignore +++ b/android/Staccato_AN/.gitignore @@ -178,7 +178,7 @@ captures/ # Keystore files *.jks *.keystore -keystore.properties +app/signing/keystore.properties # Google Services (e.g. APIs or Firebase) google-services.json diff --git a/android/Staccato_AN/app/build.gradle.kts b/android/Staccato_AN/app/build.gradle.kts index b3ead0262..a6f9d2e1e 100644 --- a/android/Staccato_AN/app/build.gradle.kts +++ b/android/Staccato_AN/app/build.gradle.kts @@ -30,8 +30,8 @@ android { applicationId = "com.on.staccato" minSdk = 26 targetSdk = 34 - versionCode = 4 - versionName = "1.1.0" + versionCode = 6 + versionName = "1.2.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -165,6 +165,13 @@ dependencies { // Lottie implementation(libs.lottie) + + // CameraX + implementation(libs.androidx.camera.core) + implementation(libs.androidx.camera.camera2) + implementation(libs.androidx.camera.lifecycle) + implementation(libs.androidx.camera.view) + implementation(libs.androidx.camera.extension) } secrets { diff --git a/android/Staccato_AN/app/src/main/AndroidManifest.xml b/android/Staccato_AN/app/src/main/AndroidManifest.xml index 91d05ed51..d5c54f8c8 100644 --- a/android/Staccato_AN/app/src/main/AndroidManifest.xml +++ b/android/Staccato_AN/app/src/main/AndroidManifest.xml @@ -3,9 +3,17 @@ - + + + + + + + + + @@ -16,8 +24,9 @@ - + + + + + + android:name=".presentation.staccatoupdate.StaccatoUpdateActivity" + android:exported="false" + android:screenOrientation="portrait" /> + + android:exported="false" + android:screenOrientation="portrait" /> + + android:name=".presentation.staccatocreation.StaccatoCreationActivity" + android:exported="false" + android:screenOrientation="portrait" /> + + android:exported="false" + android:screenOrientation="portrait" /> + + android:exported="false" + android:screenOrientation="portrait" /> + + android:exported="false" + android:screenOrientation="portrait" /> + diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/StaccatoApplication.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/StaccatoApplication.kt index 56be63b6c..49da11781 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/StaccatoApplication.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/StaccatoApplication.kt @@ -1,7 +1,6 @@ package com.on.staccato import android.app.Application -import androidx.appcompat.app.AppCompatDelegate import com.google.android.libraries.places.api.net.PlacesClient import com.on.staccato.data.PlacesClientProvider import com.on.staccato.data.UserInfoPreferencesManager @@ -11,7 +10,7 @@ import dagger.hilt.android.HiltAndroidApp class StaccatoApplication : Application() { override fun onCreate() { super.onCreate() - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + // AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) userInfoPrefsManager = UserInfoPreferencesManager(applicationContext) placesClient = PlacesClientProvider.getClient(this) } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/ApiResponseHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/ApiResponseHandler.kt index 3c268f59c..0ef7ac1d1 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/ApiResponseHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/ApiResponseHandler.kt @@ -9,16 +9,18 @@ import retrofit2.Response object ApiResponseHandler { suspend fun handleApiResponse(execute: suspend () -> Response): ResponseResult { - val response: Response = execute() - val body: T? = response.body() - return try { + val response: Response = execute() + val body: T? = response.body() + when { response.isSuccessful && response.code() == 201 -> ResponseResult.Success(body as T) response.isSuccessful && body != null -> ResponseResult.Success(body) response.isSuccessful && response.code() == 204 -> ResponseResult.Success(Unit as T) else -> { - val errorBody: ResponseBody = response.errorBody() ?: throw IllegalArgumentException("errorBody를 찾을 수 없습니다.") + val errorBody: ResponseBody = + response.errorBody() + ?: throw IllegalArgumentException("errorBody를 찾을 수 없습니다.") val errorResponse: ErrorResponse = getErrorResponse(errorBody) ResponseResult.ServerError( status = Status.Message(errorResponse.status), diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDataSource.kt index 2dc715d1c..833a07c2c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDataSource.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDataSource.kt @@ -6,7 +6,7 @@ import com.on.staccato.data.dto.comment.CommentUpdateRequest import com.on.staccato.data.dto.comment.CommentsResponse interface CommentDataSource { - suspend fun getComments(momentId: Long): ResponseResult + suspend fun getComments(staccatoId: Long): ResponseResult suspend fun createComment(commentRequest: CommentRequest): ResponseResult diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDefaultRepository.kt index a9a39abce..e351d2f69 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentDefaultRepository.kt @@ -14,14 +14,14 @@ class CommentDefaultRepository constructor( private val commentDataSource: CommentDataSource, ) : CommentRepository { - override suspend fun fetchComments(momentId: Long): ResponseResult> = - when (val responseResult = commentDataSource.getComments(momentId)) { + override suspend fun fetchComments(staccatoId: Long): ResponseResult> = + when (val responseResult = commentDataSource.getComments(staccatoId)) { is ResponseResult.ServerError -> { ResponseResult.ServerError(responseResult.status, responseResult.message) } is ResponseResult.Exception -> { - ResponseResult.Exception(responseResult.e, responseResult.message) + ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) } is ResponseResult.Success -> { @@ -36,7 +36,7 @@ class CommentDefaultRepository } is ResponseResult.Exception -> { - ResponseResult.Exception(responseResult.e, responseResult.message) + ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) } is ResponseResult.Success -> { @@ -59,7 +59,7 @@ class CommentDefaultRepository } is ResponseResult.Exception -> { - ResponseResult.Exception(responseResult.e, responseResult.message) + ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) } is ResponseResult.Success -> { @@ -75,11 +75,15 @@ class CommentDefaultRepository } is ResponseResult.Exception -> { - ResponseResult.Exception(responseResult.e, responseResult.message) + ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) } is ResponseResult.Success -> { ResponseResult.Success(responseResult.data) } } + + companion object { + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." + } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentRemoteDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentRemoteDataSource.kt index f19926cc9..02f55049d 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentRemoteDataSource.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/comment/CommentRemoteDataSource.kt @@ -12,8 +12,8 @@ class CommentRemoteDataSource constructor( private val commentApiService: CommentApiService, ) : CommentDataSource { - override suspend fun getComments(momentId: Long): ResponseResult = - handleApiResponse { commentApiService.getComments(momentId) } + override suspend fun getComments(staccatoId: Long): ResponseResult = + handleApiResponse { commentApiService.getComments(staccatoId) } override suspend fun createComment(commentRequest: CommentRequest): ResponseResult = handleApiResponse { commentApiService.postComment(commentRequest) } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/CommentMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/CommentMapper.kt index a27b33fee..73365fd52 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/CommentMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/CommentMapper.kt @@ -19,6 +19,6 @@ fun CommentDto.toDomain(): Comment = fun NewComment.toDto(): CommentRequest = CommentRequest( - momentId = momentId, + momentId = staccatoId, content = content, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/FeelingMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/FeelingMapper.kt index b7f2c87b2..3bb3701b9 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/FeelingMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/FeelingMapper.kt @@ -1,6 +1,6 @@ package com.on.staccato.data.dto.mapper -import com.on.staccato.data.dto.moment.FeelingRequest +import com.on.staccato.data.dto.staccato.FeelingRequest import com.on.staccato.domain.model.Feeling fun Feeling.toFeelingRequest(): FeelingRequest = diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MemoryMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MemoryMapper.kt index e90b3e84f..e74bc764c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MemoryMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MemoryMapper.kt @@ -1,13 +1,13 @@ package com.on.staccato.data.dto.mapper import com.on.staccato.data.dto.memory.MemoriesResponse -import com.on.staccato.data.dto.memory.MemoryMomentDto import com.on.staccato.data.dto.memory.MemoryRequest import com.on.staccato.data.dto.memory.MemoryResponse +import com.on.staccato.data.dto.memory.MemoryStaccatoDto import com.on.staccato.domain.model.Memory import com.on.staccato.domain.model.MemoryCandidate import com.on.staccato.domain.model.MemoryCandidates -import com.on.staccato.domain.model.MemoryMoment +import com.on.staccato.domain.model.MemoryStaccato import com.on.staccato.domain.model.NewMemory import java.time.LocalDate import java.time.LocalDateTime @@ -21,7 +21,7 @@ fun MemoryResponse.toDomain() = endAt = endAt?.let { LocalDate.parse(endAt) }, description = description, mates = mates.map { it.toDomain() }, - moments = moments.map { it.toDomain() }, + staccatos = staccatos.map { it.toDomain() }, ) fun MemoriesResponse.toDomain(): MemoryCandidates = @@ -36,11 +36,11 @@ fun MemoriesResponse.toDomain(): MemoryCandidates = }, ) -fun MemoryMomentDto.toDomain() = - MemoryMoment( - momentId = momentId, - momentTitle = staccatoTitle, - momentImageUrl = staccatoImageUrl, +fun MemoryStaccatoDto.toDomain() = + MemoryStaccato( + staccatoId = staccatoId, + staccatoTitle = staccatoTitle, + staccatoImageUrl = staccatoImageUrl, visitedAt = LocalDateTime.parse(visitedAt), ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MyPageMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MyPageMapper.kt index 942cae172..7ebd8e43b 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MyPageMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MyPageMapper.kt @@ -1,10 +1,10 @@ package com.on.staccato.data.dto.mapper -import com.on.staccato.data.dto.mypage.AccountInformationResponse -import com.on.staccato.domain.model.AccountInformation +import com.on.staccato.data.dto.mypage.MemberProfileResponse +import com.on.staccato.domain.model.MemberProfile -fun AccountInformationResponse.toDomain() = - AccountInformation( +fun MemberProfileResponse.toDomain() = + MemberProfile( profileImageUrl = profileImageUrl, nickname = nickname, uuidCode = code, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MomentMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/StaccatoMapper.kt similarity index 59% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MomentMapper.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/StaccatoMapper.kt index d231a2c0b..df3abf4bf 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/MomentMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/StaccatoMapper.kt @@ -1,23 +1,23 @@ package com.on.staccato.data.dto.mapper -import com.on.staccato.data.dto.moment.MomentLocationDto -import com.on.staccato.data.dto.moment.MomentResponse +import com.on.staccato.data.dto.staccato.StaccatoLocationDto +import com.on.staccato.data.dto.staccato.StaccatoResponse import com.on.staccato.domain.model.Feeling -import com.on.staccato.domain.model.Moment -import com.on.staccato.domain.model.MomentLocation +import com.on.staccato.domain.model.Staccato +import com.on.staccato.domain.model.StaccatoLocation import java.time.LocalDate import java.time.LocalDateTime -fun MomentResponse.toDomain() = - Moment( - momentId = momentId, +fun StaccatoResponse.toDomain() = + Staccato( + staccatoId = staccatoId, memoryId = memoryId, memoryTitle = memoryTitle, staccatoTitle = staccatoTitle, placeName = placeName, latitude = latitude, longitude = longitude, - momentImageUrls = momentImageUrls, + staccatoImageUrls = momentImageUrls, address = address, visitedAt = LocalDateTime.parse(visitedAt), startAt = startAt?.let { LocalDate.parse(startAt) }, @@ -25,9 +25,9 @@ fun MomentResponse.toDomain() = feeling = Feeling.fromValue(feeling), ) -fun MomentLocationDto.toDomain() = - MomentLocation( - momentId = momentId, +fun StaccatoLocationDto.toDomain() = + StaccatoLocation( + staccatoId = staccatoId, latitude = latitude, longitude = longitude, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/TimelineMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/TimelineMapper.kt index e72b7080b..5ae8e2df7 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/TimelineMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mapper/TimelineMapper.kt @@ -33,7 +33,7 @@ fun TimelineMemoryDto.toDomain(): Memory { endAt = endAt?.let { LocalDate.parse(it) }, description = description, mates = emptyList(), - moments = emptyList(), + staccatos = emptyList(), ) } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryResponse.kt index 09ed542ce..38a3748bc 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryResponse.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryResponse.kt @@ -13,5 +13,5 @@ data class MemoryResponse( @SerialName("endAt") val endAt: String? = null, @SerialName("description") val description: String? = null, @SerialName("mates") val mates: List, - @SerialName("moments") val moments: List, + @SerialName("moments") val staccatos: List, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryMomentDto.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryStaccatoDto.kt similarity index 80% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryMomentDto.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryStaccatoDto.kt index 63899bca6..ef929e201 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryMomentDto.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/memory/MemoryStaccatoDto.kt @@ -4,8 +4,8 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class MemoryMomentDto( - @SerialName("momentId") val momentId: Long, +data class MemoryStaccatoDto( + @SerialName("momentId") val staccatoId: Long, @SerialName("staccatoTitle") val staccatoTitle: String, @SerialName("momentImageUrl") val staccatoImageUrl: String? = null, @SerialName("visitedAt") val visitedAt: String, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationResponse.kt deleted file mode 100644 index f912fef3e..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationResponse.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.on.staccato.data.dto.moment - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class MomentCreationResponse( - @SerialName("momentId") val momentId: Long, -) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationResponse.kt deleted file mode 100644 index ea96475d0..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationResponse.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.on.staccato.data.dto.moment - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class MomentLocationResponse( - @SerialName("momentLocationResponses") val momentLocationResponses: List, -) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mypage/MemberProfileResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mypage/MemberProfileResponse.kt new file mode 100644 index 000000000..09891b089 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/mypage/MemberProfileResponse.kt @@ -0,0 +1,11 @@ +package com.on.staccato.data.dto.mypage + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MemberProfileResponse( + @SerialName("nickname") val nickname: String, + @SerialName("profileImageUrl") val profileImageUrl: String? = null, + @SerialName("code") val code: String, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/FeelingRequest.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/FeelingRequest.kt similarity index 80% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/FeelingRequest.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/FeelingRequest.kt index dc1f9d605..cfdbc0a06 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/FeelingRequest.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/FeelingRequest.kt @@ -1,4 +1,4 @@ -package com.on.staccato.data.dto.moment +package com.on.staccato.data.dto.staccato import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentUpdateRequest.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationRequest.kt similarity index 75% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentUpdateRequest.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationRequest.kt index 31fffd63f..8c297f46a 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentUpdateRequest.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationRequest.kt @@ -1,16 +1,16 @@ -package com.on.staccato.data.dto.moment +package com.on.staccato.data.dto.staccato import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class MomentUpdateRequest( +data class StaccatoCreationRequest( @SerialName("staccatoTitle") val staccatoTitle: String, + @SerialName("memoryId") val memoryId: Long, @SerialName("placeName") val placeName: String, - @SerialName("address") val address: String, @SerialName("latitude") val latitude: Double, @SerialName("longitude") val longitude: Double, + @SerialName("address") val address: String, @SerialName("visitedAt") val visitedAt: String, - @SerialName("memoryId") val memoryId: Long, - @SerialName("momentImageUrls") val momentImageUrls: List, + @SerialName("momentImageUrls") val staccatoImageUrls: List, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationResponse.kt new file mode 100644 index 000000000..67effc2fc --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoCreationResponse.kt @@ -0,0 +1,9 @@ +package com.on.staccato.data.dto.staccato + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class StaccatoCreationResponse( + @SerialName("momentId") val staccatoId: Long, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationDto.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationDto.kt similarity index 61% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationDto.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationDto.kt index d88afbcdc..921678cc6 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentLocationDto.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationDto.kt @@ -1,11 +1,11 @@ -package com.on.staccato.data.dto.moment +package com.on.staccato.data.dto.staccato import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class MomentLocationDto( - @SerialName("momentId") val momentId: Long, +data class StaccatoLocationDto( + @SerialName("momentId") val staccatoId: Long, @SerialName("latitude") val latitude: Double, @SerialName("longitude") val longitude: Double, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationResponse.kt new file mode 100644 index 000000000..0125a3e55 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoLocationResponse.kt @@ -0,0 +1,9 @@ +package com.on.staccato.data.dto.staccato + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class StaccatoLocationResponse( + @SerialName("momentLocationResponses") val staccatoLocationResponses: List, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentResponse.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoResponse.kt similarity index 86% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentResponse.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoResponse.kt index 11479e9c4..039b6f1ec 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentResponse.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoResponse.kt @@ -1,11 +1,11 @@ -package com.on.staccato.data.dto.moment +package com.on.staccato.data.dto.staccato import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class MomentResponse( - @SerialName("momentId") val momentId: Long, +data class StaccatoResponse( + @SerialName("momentId") val staccatoId: Long, @SerialName("memoryId") val memoryId: Long, @SerialName("memoryTitle") val memoryTitle: String, @SerialName("startAt") val startAt: String? = null, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationRequest.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoUpdateRequest.kt similarity index 87% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationRequest.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoUpdateRequest.kt index fb04e6c31..1e0ffc0f2 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/moment/MomentCreationRequest.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/dto/staccato/StaccatoUpdateRequest.kt @@ -1,16 +1,16 @@ -package com.on.staccato.data.dto.moment +package com.on.staccato.data.dto.staccato import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class MomentCreationRequest( +data class StaccatoUpdateRequest( @SerialName("staccatoTitle") val staccatoTitle: String, - @SerialName("memoryId") val memoryId: Long, @SerialName("placeName") val placeName: String, + @SerialName("address") val address: String, @SerialName("latitude") val latitude: Double, @SerialName("longitude") val longitude: Double, - @SerialName("address") val address: String, @SerialName("visitedAt") val visitedAt: String, + @SerialName("memoryId") val memoryId: Long, @SerialName("momentImageUrls") val momentImageUrls: List, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/image/ImageDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/image/ImageDefaultRepository.kt index 89ff82ba5..0684fcc0c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/image/ImageDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/image/ImageDefaultRepository.kt @@ -15,7 +15,7 @@ class ImageDefaultRepository override suspend fun convertImageFileToUrl(imageFile: MultipartBody.Part): ResponseResult { val responseResult = handleApiResponse { imageApiService.postImage(imageFile) } return when (responseResult) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -27,6 +27,6 @@ class ImageDefaultRepository } companion object { - const val ERROR_MESSAGE = "이미지 업로드에 실패했습니다." + const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/login/LoginDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/login/LoginDefaultRepository.kt index 9945fbf0d..c784a3424 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/login/LoginDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/login/LoginDefaultRepository.kt @@ -11,13 +11,13 @@ class LoginDefaultRepository ) : LoginRepository { override suspend fun loginWithNickname(nickname: String): ResponseResult { return when (val result = loginDataSource.requestLoginWithNickname(nickname)) { - is ResponseResult.Exception -> ResponseResult.Exception(result.e, EXCEPTION_ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(result.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError(result.status, result.message) is ResponseResult.Success -> ResponseResult.Success(result.data.token) } } companion object { - private const val EXCEPTION_ERROR_MESSAGE = "예기치 못한 에러가 발생했습니다. 다시 시도해주세요." + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/member/MemberDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/member/MemberDefaultRepository.kt index 32c856e31..1abc20294 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/member/MemberDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/member/MemberDefaultRepository.kt @@ -16,13 +16,13 @@ class MemberDefaultRepository override suspend fun fetchTokenWithRecoveryCode(recoveryCode: String): ResponseResult { val responseResult = handleApiResponse { memberApiService.postRecoveryCode(recoveryCode) } return when (responseResult) { - is Exception -> Exception(responseResult.e, EXCEPTION_ERROR_MESSAGE) + is Exception -> Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ServerError -> ServerError(responseResult.status, responseResult.message) is Success -> Success(responseResult.data.token) } } companion object { - private const val EXCEPTION_ERROR_MESSAGE = "예기치 못한 에러가 발생했습니다. 다시 시도해주세요." + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/memory/MemoryDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/memory/MemoryDefaultRepository.kt index 7cec5697c..d6eaeee4c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/memory/MemoryDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/memory/MemoryDefaultRepository.kt @@ -16,7 +16,7 @@ class MemoryDefaultRepository ) : MemoryRepository { override suspend fun getMemory(memoryId: Long): ResponseResult { return when (val responseResult = memoryDataSource.getMemory(memoryId)) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -30,7 +30,7 @@ class MemoryDefaultRepository override suspend fun getMemories(currentDate: String?): ResponseResult { return when (val responseResult = memoryDataSource.getMemories(currentDate)) { is ResponseResult.Success -> ResponseResult.Success(responseResult.data.toDomain()) - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -41,7 +41,7 @@ class MemoryDefaultRepository override suspend fun createMemory(newMemory: NewMemory): ResponseResult { return when (val responseResult = memoryDataSource.createMemory(newMemory)) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -57,7 +57,7 @@ class MemoryDefaultRepository newMemory: NewMemory, ): ResponseResult { return when (val responseResult = memoryDataSource.updateMemory(memoryId, newMemory)) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -70,7 +70,7 @@ class MemoryDefaultRepository override suspend fun deleteMemory(memoryId: Long): ResponseResult { return when (val responseResult = memoryDataSource.deleteMemory(memoryId)) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) + is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, EXCEPTION_NETWORK_ERROR_MESSAGE) is ResponseResult.ServerError -> ResponseResult.ServerError( responseResult.status, @@ -82,6 +82,6 @@ class MemoryDefaultRepository } companion object { - const val ERROR_MESSAGE = "예기치 않은 오류가 발생했습니다" + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/DataSourceModule.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/DataSourceModule.kt index e141e0432..5b0d38923 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/DataSourceModule.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/DataSourceModule.kt @@ -6,8 +6,8 @@ import com.on.staccato.data.login.LoginDataSource import com.on.staccato.data.login.LoginRemoteDataSource import com.on.staccato.data.memory.MemoryDataSource import com.on.staccato.data.memory.MemoryRemoteDataSource -import com.on.staccato.data.moment.MomentDataSource -import com.on.staccato.data.moment.MomentRemoteDataSource +import com.on.staccato.data.staccato.StaccatoDataSource +import com.on.staccato.data.staccato.StaccatoRemoteDataSource import com.on.staccato.data.timeline.TimelineDataSource import com.on.staccato.data.timeline.TimelineRemoteDataSource import dagger.Binds @@ -28,7 +28,7 @@ abstract class DataSourceModule { abstract fun bindMemoryDataSource(memoryRemoteDataSource: MemoryRemoteDataSource): MemoryDataSource @Binds - abstract fun bindMomentDataSource(momentRemoteDataSource: MomentRemoteDataSource): MomentDataSource + abstract fun bindStaccatoDataSource(staccatoRemoteDataSource: StaccatoRemoteDataSource): StaccatoDataSource @Binds abstract fun bindTimelineDataSource(timelineRemoteDataSource: TimelineRemoteDataSource): TimelineDataSource diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RepositoryModule.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RepositoryModule.kt index 3d40530f3..1cbcc3482 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RepositoryModule.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RepositoryModule.kt @@ -5,16 +5,16 @@ import com.on.staccato.data.image.ImageDefaultRepository import com.on.staccato.data.login.LoginDefaultRepository import com.on.staccato.data.member.MemberDefaultRepository import com.on.staccato.data.memory.MemoryDefaultRepository -import com.on.staccato.data.moment.MomentDefaultRepository import com.on.staccato.data.mypage.MyPageDefaultRepository +import com.on.staccato.data.staccato.StaccatoDefaultRepository import com.on.staccato.data.timeline.TimelineDefaultRepository import com.on.staccato.domain.repository.CommentRepository import com.on.staccato.domain.repository.ImageRepository import com.on.staccato.domain.repository.LoginRepository import com.on.staccato.domain.repository.MemberRepository import com.on.staccato.domain.repository.MemoryRepository -import com.on.staccato.domain.repository.MomentRepository import com.on.staccato.domain.repository.MyPageRepository +import com.on.staccato.domain.repository.StaccatoRepository import com.on.staccato.domain.repository.TimelineRepository import dagger.Binds import dagger.Module @@ -37,7 +37,7 @@ abstract class RepositoryModule { abstract fun bindMemoryRepository(memoryDefaultRepository: MemoryDefaultRepository): MemoryRepository @Binds - abstract fun bindMomentRepository(momentDefaultRepository: MomentDefaultRepository): MomentRepository + abstract fun bindStaccatoRepository(staccatoDefaultRepository: StaccatoDefaultRepository): StaccatoRepository @Binds abstract fun bindTimelineRepository(timelineDefaultRepository: TimelineDefaultRepository): TimelineRepository diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RetrofitModule.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RetrofitModule.kt index d74114022..14219b65e 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RetrofitModule.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/module/RetrofitModule.kt @@ -6,8 +6,8 @@ import com.on.staccato.data.image.ImageApiService import com.on.staccato.data.login.LoginApiService import com.on.staccato.data.member.MemberApiService import com.on.staccato.data.memory.MemoryApiService -import com.on.staccato.data.moment.MomentApiService import com.on.staccato.data.mypage.MyPageApiService +import com.on.staccato.data.staccato.StaccatoApiService import com.on.staccato.data.timeline.TimeLineApiService import dagger.Module import dagger.Provides @@ -32,7 +32,7 @@ object RetrofitModule { @Singleton @Provides - fun provideStaccatoApiService(): MomentApiService = StaccatoClient.create(MomentApiService::class.java) + fun provideStaccatoApiService(): StaccatoApiService = StaccatoClient.create(StaccatoApiService::class.java) @Singleton @Provides diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentApiService.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentApiService.kt deleted file mode 100644 index ab4b1c55a..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentApiService.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.on.staccato.data.moment - -import com.on.staccato.data.dto.moment.FeelingRequest -import com.on.staccato.data.dto.moment.MomentCreationRequest -import com.on.staccato.data.dto.moment.MomentCreationResponse -import com.on.staccato.data.dto.moment.MomentLocationResponse -import com.on.staccato.data.dto.moment.MomentResponse -import com.on.staccato.data.dto.moment.MomentUpdateRequest -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path - -interface MomentApiService { - @GET(MOMENTS_PATH) - suspend fun getMoments(): Response - - @GET(MOMENT_PATH_WITH_ID) - suspend fun getMoment( - @Path(value = "momentId") momentId: Long, - ): MomentResponse - - @POST(MOMENTS_PATH) - suspend fun postMoment( - @Body momentCreationRequest: MomentCreationRequest, - ): MomentCreationResponse - - @PUT(MOMENT_PATH_WITH_ID) - suspend fun putMoment( - @Path(value = "momentId") momentId: Long, - @Body momentUpdateRequest: MomentUpdateRequest, - ) - - @DELETE(MOMENT_PATH_WITH_ID) - suspend fun deleteMoment( - @Path(value = "momentId") momentId: Long, - ) - - @POST(FEELING_PATH) - suspend fun postFeeling( - @Path(value = "momentId") momentId: Long, - @Body feelingRequest: FeelingRequest, - ) - - companion object { - private const val MOMENTS_PATH = "/moments" - private const val MOMENT_ID = "/{momentId}" - private const val MOMENT_PATH_WITH_ID = "$MOMENTS_PATH$MOMENT_ID" - private const val FEELING_PATH = "$MOMENT_PATH_WITH_ID/feeling" - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDataSource.kt deleted file mode 100644 index fbc5b115c..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDataSource.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.on.staccato.data.moment - -import com.on.staccato.data.ResponseResult -import com.on.staccato.data.dto.moment.FeelingRequest -import com.on.staccato.data.dto.moment.MomentCreationRequest -import com.on.staccato.data.dto.moment.MomentCreationResponse -import com.on.staccato.data.dto.moment.MomentLocationResponse -import com.on.staccato.data.dto.moment.MomentResponse -import com.on.staccato.data.dto.moment.MomentUpdateRequest - -interface MomentDataSource { - suspend fun fetchMoments(): ResponseResult - - suspend fun fetchMoment(momentId: Long): MomentResponse - - suspend fun createMoment(momentCreationRequest: MomentCreationRequest): MomentCreationResponse - - suspend fun updateMoment( - momentId: Long, - momentUpdateRequest: MomentUpdateRequest, - ) - - suspend fun deleteMoment(momentId: Long) - - suspend fun updateFeeling( - momentId: Long, - feelingRequest: FeelingRequest, - ) -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDefaultRepository.kt deleted file mode 100644 index e2e707916..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentDefaultRepository.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.on.staccato.data.moment - -import com.on.staccato.data.ResponseResult -import com.on.staccato.data.dto.mapper.toDomain -import com.on.staccato.data.dto.moment.FeelingRequest -import com.on.staccato.data.dto.moment.MomentCreationRequest -import com.on.staccato.data.dto.moment.MomentCreationResponse -import com.on.staccato.data.dto.moment.MomentUpdateRequest -import com.on.staccato.domain.model.Moment -import com.on.staccato.domain.model.MomentLocation -import com.on.staccato.domain.repository.MomentRepository -import java.time.LocalDateTime -import javax.inject.Inject - -class MomentDefaultRepository - @Inject - constructor( - private val remoteDataSource: MomentRemoteDataSource, - ) : - MomentRepository { - override suspend fun getMoments(): ResponseResult> { - return when (val responseResult = remoteDataSource.fetchMoments()) { - is ResponseResult.Exception -> ResponseResult.Exception(responseResult.e, ERROR_MESSAGE) - is ResponseResult.ServerError -> ResponseResult.ServerError(responseResult.status, responseResult.message) - is ResponseResult.Success -> ResponseResult.Success(responseResult.data.momentLocationResponses.map { it.toDomain() }) - } - } - - override suspend fun getMoment(momentId: Long): Result { - return runCatching { - remoteDataSource.fetchMoment(momentId).toDomain() - } - } - - override suspend fun createMoment( - memoryId: Long, - staccatoTitle: String, - placeName: String, - latitude: Double, - longitude: Double, - address: String, - visitedAt: LocalDateTime, - momentImageUrls: List, - ): Result { - return runCatching { - remoteDataSource.createMoment( - MomentCreationRequest( - memoryId = memoryId, - staccatoTitle = staccatoTitle, - placeName = placeName, - latitude = latitude, - longitude = longitude, - address = address, - visitedAt = visitedAt.toString(), - momentImageUrls = momentImageUrls, - ), - ) - } - } - - override suspend fun updateMoment( - momentId: Long, - staccatoTitle: String, - placeName: String, - address: String, - latitude: Double, - longitude: Double, - visitedAt: LocalDateTime, - memoryId: Long, - momentImageUrls: List, - ): Result { - return runCatching { - remoteDataSource.updateMoment( - momentId = momentId, - momentUpdateRequest = - MomentUpdateRequest( - staccatoTitle = staccatoTitle, - placeName = placeName, - address = address, - latitude = latitude, - longitude = longitude, - visitedAt = visitedAt.toString(), - memoryId = memoryId, - momentImageUrls = momentImageUrls, - ), - ) - } - } - - override suspend fun deleteMoment(momentId: Long): Result { - return runCatching { - remoteDataSource.deleteMoment(momentId) - } - } - - override suspend fun updateFeeling( - momentId: Long, - feeling: String, - ): Result { - return runCatching { - remoteDataSource.updateFeeling( - momentId = momentId, - feelingRequest = FeelingRequest(feeling), - ) - } - } - - companion object { - const val ERROR_MESSAGE = "스타카토 목록을 조회할 수 없어요." - } - } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentRemoteDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentRemoteDataSource.kt deleted file mode 100644 index ce24df46b..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/moment/MomentRemoteDataSource.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.on.staccato.data.moment - -import com.on.staccato.data.ApiResponseHandler.handleApiResponse -import com.on.staccato.data.ResponseResult -import com.on.staccato.data.dto.moment.FeelingRequest -import com.on.staccato.data.dto.moment.MomentCreationRequest -import com.on.staccato.data.dto.moment.MomentCreationResponse -import com.on.staccato.data.dto.moment.MomentLocationResponse -import com.on.staccato.data.dto.moment.MomentResponse -import com.on.staccato.data.dto.moment.MomentUpdateRequest -import javax.inject.Inject - -class MomentRemoteDataSource - @Inject - constructor( - private val momentApiService: MomentApiService, - ) : MomentDataSource { - override suspend fun fetchMoments(): ResponseResult = handleApiResponse { momentApiService.getMoments() } - - override suspend fun fetchMoment(momentId: Long): MomentResponse { - return momentApiService.getMoment(momentId = momentId) - } - - override suspend fun createMoment(momentCreationRequest: MomentCreationRequest): MomentCreationResponse { - return momentApiService.postMoment(momentCreationRequest) - } - - override suspend fun updateMoment( - momentId: Long, - momentUpdateRequest: MomentUpdateRequest, - ) { - return momentApiService.putMoment( - momentId = momentId, - momentUpdateRequest, - ) - } - - override suspend fun deleteMoment(momentId: Long) { - momentApiService.deleteMoment(momentId) - } - - override suspend fun updateFeeling( - momentId: Long, - feelingRequest: FeelingRequest, - ) { - momentApiService.postFeeling( - momentId = momentId, - feelingRequest = feelingRequest, - ) - } - } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageApiService.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageApiService.kt index 1817e2cd5..3275190fc 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageApiService.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageApiService.kt @@ -1,6 +1,6 @@ package com.on.staccato.data.mypage -import com.on.staccato.data.dto.mypage.AccountInformationResponse +import com.on.staccato.data.dto.mypage.MemberProfileResponse import com.on.staccato.data.dto.mypage.ProfileImageResponse import okhttp3.MultipartBody import retrofit2.Response @@ -11,7 +11,7 @@ import retrofit2.http.Part interface MyPageApiService { @GET(MYPAGE_PATH) - suspend fun getAccountInformation(): Response + suspend fun getMemberProfile(): Response @Multipart @POST(PROFILE_IMAGE_CHANGE_PATH) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageDefaultRepository.kt index 399bebd01..5dfa60749 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/mypage/MyPageDefaultRepository.kt @@ -4,7 +4,7 @@ import com.on.staccato.data.ApiResponseHandler.handleApiResponse import com.on.staccato.data.ResponseResult import com.on.staccato.data.dto.mapper.toDomain import com.on.staccato.data.dto.mypage.ProfileImageResponse -import com.on.staccato.domain.model.AccountInformation +import com.on.staccato.domain.model.MemberProfile import com.on.staccato.domain.repository.MyPageRepository import okhttp3.MultipartBody import javax.inject.Inject @@ -14,13 +14,13 @@ class MyPageDefaultRepository constructor( private val myPageApiService: MyPageApiService, ) : MyPageRepository { - override suspend fun getAccountInformation(): ResponseResult { - val responseResult = handleApiResponse { myPageApiService.getAccountInformation() } + override suspend fun getMemberProfile(): ResponseResult { + val responseResult = handleApiResponse { myPageApiService.getMemberProfile() } return when (responseResult) { is ResponseResult.Exception -> ResponseResult.Exception( responseResult.e, - ERROR_MESSAGE_GET_PROFILE_FAIL, + EXCEPTION_NETWORK_ERROR_MESSAGE, ) is ResponseResult.ServerError -> @@ -43,7 +43,7 @@ class MyPageDefaultRepository is ResponseResult.Exception -> ResponseResult.Exception( responseResult.e, - ERROR_MESSAGE_CHANGE_PROFILE_IMAGE_FAIL, + EXCEPTION_NETWORK_ERROR_MESSAGE, ) is ResponseResult.ServerError -> @@ -57,7 +57,6 @@ class MyPageDefaultRepository } companion object { - const val ERROR_MESSAGE_GET_PROFILE_FAIL = "프로필 정보를 가져올 수 없습니다." - const val ERROR_MESSAGE_CHANGE_PROFILE_IMAGE_FAIL = "프로필 이미지 변경에 실패했습니다." + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoApiService.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoApiService.kt new file mode 100644 index 000000000..c92916623 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoApiService.kt @@ -0,0 +1,54 @@ +package com.on.staccato.data.staccato + +import com.on.staccato.data.dto.staccato.FeelingRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationResponse +import com.on.staccato.data.dto.staccato.StaccatoLocationResponse +import com.on.staccato.data.dto.staccato.StaccatoResponse +import com.on.staccato.data.dto.staccato.StaccatoUpdateRequest +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.PUT +import retrofit2.http.Path + +interface StaccatoApiService { + @GET(STACCATOS_PATH) + suspend fun getStaccatos(): Response + + @GET(STACCATO_PATH_WITH_ID) + suspend fun getStaccato( + @Path(value = "momentId") momentId: Long, + ): Response + + @POST(STACCATOS_PATH) + suspend fun postStaccato( + @Body staccatoCreationRequest: StaccatoCreationRequest, + ): Response + + @PUT(STACCATO_PATH_WITH_ID) + suspend fun putStaccato( + @Path(value = "momentId") momentId: Long, + @Body staccatoUpdateRequest: StaccatoUpdateRequest, + ): Response + + @DELETE(STACCATO_PATH_WITH_ID) + suspend fun deleteStaccato( + @Path(value = "momentId") momentId: Long, + ): Response + + @POST(FEELING_PATH) + suspend fun postFeeling( + @Path(value = "momentId") momentId: Long, + @Body feelingRequest: FeelingRequest, + ): Response + + companion object { + private const val STACCATOS_PATH = "/moments" + private const val STACCATO_ID = "/{momentId}" + private const val STACCATO_PATH_WITH_ID = "$STACCATOS_PATH$STACCATO_ID" + private const val FEELING_PATH = "$STACCATO_PATH_WITH_ID/feeling" + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDataSource.kt new file mode 100644 index 000000000..b23fc0327 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDataSource.kt @@ -0,0 +1,29 @@ +package com.on.staccato.data.staccato + +import com.on.staccato.data.ResponseResult +import com.on.staccato.data.dto.staccato.FeelingRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationResponse +import com.on.staccato.data.dto.staccato.StaccatoLocationResponse +import com.on.staccato.data.dto.staccato.StaccatoResponse +import com.on.staccato.data.dto.staccato.StaccatoUpdateRequest + +interface StaccatoDataSource { + suspend fun fetchStaccatos(): ResponseResult + + suspend fun fetchStaccato(staccatoId: Long): ResponseResult + + suspend fun createStaccato(staccatoCreationRequest: StaccatoCreationRequest): ResponseResult + + suspend fun updateStaccato( + staccatoId: Long, + staccatoUpdateRequest: StaccatoUpdateRequest, + ): ResponseResult + + suspend fun deleteStaccato(staccatoId: Long): ResponseResult + + suspend fun updateFeeling( + staccatoId: Long, + feelingRequest: FeelingRequest, + ): ResponseResult +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDefaultRepository.kt new file mode 100644 index 000000000..76d92b07f --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoDefaultRepository.kt @@ -0,0 +1,190 @@ +package com.on.staccato.data.staccato + +import com.on.staccato.data.ResponseResult +import com.on.staccato.data.dto.mapper.toDomain +import com.on.staccato.data.dto.staccato.FeelingRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationResponse +import com.on.staccato.data.dto.staccato.StaccatoUpdateRequest +import com.on.staccato.domain.model.Staccato +import com.on.staccato.domain.model.StaccatoLocation +import com.on.staccato.domain.repository.StaccatoRepository +import java.time.LocalDateTime +import javax.inject.Inject + +class StaccatoDefaultRepository + @Inject + constructor( + private val remoteDataSource: StaccatoRemoteDataSource, + ) : + StaccatoRepository { + override suspend fun getStaccatos(): ResponseResult> { + return when (val responseResult = remoteDataSource.fetchStaccatos()) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data.staccatoLocationResponses.map { it.toDomain() }) + } + } + + override suspend fun getStaccato(staccatoId: Long): ResponseResult { + return when (val responseResult = remoteDataSource.fetchStaccato(staccatoId)) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data.toDomain()) + } + } + + override suspend fun createStaccato( + memoryId: Long, + staccatoTitle: String, + placeName: String, + latitude: Double, + longitude: Double, + address: String, + visitedAt: LocalDateTime, + staccatoImageUrls: List, + ): ResponseResult { + return when ( + val responseResult = + remoteDataSource.createStaccato( + StaccatoCreationRequest( + memoryId = memoryId, + staccatoTitle = staccatoTitle, + placeName = placeName, + latitude = latitude, + longitude = longitude, + address = address, + visitedAt = visitedAt.toString(), + staccatoImageUrls = staccatoImageUrls, + ), + ) + ) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data) + } + } + + override suspend fun updateStaccato( + staccatoId: Long, + staccatoTitle: String, + placeName: String, + address: String, + latitude: Double, + longitude: Double, + visitedAt: LocalDateTime, + memoryId: Long, + staccatoImageUrls: List, + ): ResponseResult { + return when ( + val responseResult = + remoteDataSource.updateStaccato( + staccatoId = staccatoId, + staccatoUpdateRequest = + StaccatoUpdateRequest( + staccatoTitle = staccatoTitle, + placeName = placeName, + address = address, + latitude = latitude, + longitude = longitude, + visitedAt = visitedAt.toString(), + memoryId = memoryId, + momentImageUrls = staccatoImageUrls, + ), + ) + ) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data) + } + } + + override suspend fun deleteStaccato(staccatoId: Long): ResponseResult { + return when (val responseResult = remoteDataSource.deleteStaccato(staccatoId)) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data) + } + } + + override suspend fun updateFeeling( + staccatoId: Long, + feeling: String, + ): ResponseResult { + return when ( + val responseResult = + remoteDataSource.updateFeeling( + staccatoId = staccatoId, + feelingRequest = FeelingRequest(feeling), + ) + ) { + is ResponseResult.Exception -> + ResponseResult.Exception( + responseResult.e, + EXCEPTION_NETWORK_ERROR_MESSAGE, + ) + + is ResponseResult.ServerError -> + ResponseResult.ServerError( + responseResult.status, + responseResult.message, + ) + + is ResponseResult.Success -> ResponseResult.Success(responseResult.data) + } + } + + companion object { + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." + } + } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoRemoteDataSource.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoRemoteDataSource.kt new file mode 100644 index 000000000..f098efc11 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/staccato/StaccatoRemoteDataSource.kt @@ -0,0 +1,53 @@ +package com.on.staccato.data.staccato + +import com.on.staccato.data.ApiResponseHandler.handleApiResponse +import com.on.staccato.data.ResponseResult +import com.on.staccato.data.dto.staccato.FeelingRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationRequest +import com.on.staccato.data.dto.staccato.StaccatoCreationResponse +import com.on.staccato.data.dto.staccato.StaccatoLocationResponse +import com.on.staccato.data.dto.staccato.StaccatoResponse +import com.on.staccato.data.dto.staccato.StaccatoUpdateRequest +import javax.inject.Inject + +class StaccatoRemoteDataSource + @Inject + constructor( + private val staccatoApiService: StaccatoApiService, + ) : StaccatoDataSource { + override suspend fun fetchStaccatos(): ResponseResult = + handleApiResponse { staccatoApiService.getStaccatos() } + + override suspend fun fetchStaccato(staccatoId: Long): ResponseResult = + handleApiResponse { staccatoApiService.getStaccato(momentId = staccatoId) } + + override suspend fun createStaccato(staccatoCreationRequest: StaccatoCreationRequest): ResponseResult = + handleApiResponse { staccatoApiService.postStaccato(staccatoCreationRequest) } + + override suspend fun updateStaccato( + staccatoId: Long, + staccatoUpdateRequest: StaccatoUpdateRequest, + ): ResponseResult = + handleApiResponse { + staccatoApiService.putStaccato( + momentId = staccatoId, + staccatoUpdateRequest, + ) + } + + override suspend fun deleteStaccato(staccatoId: Long): ResponseResult = + handleApiResponse { + staccatoApiService.deleteStaccato(staccatoId) + } + + override suspend fun updateFeeling( + staccatoId: Long, + feelingRequest: FeelingRequest, + ): ResponseResult = + handleApiResponse { + staccatoApiService.postFeeling( + momentId = staccatoId, + feelingRequest = feelingRequest, + ) + } + } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/timeline/TimelineDefaultRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/timeline/TimelineDefaultRepository.kt index dfc0922f5..44c0ef6a7 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/data/timeline/TimelineDefaultRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/data/timeline/TimelineDefaultRepository.kt @@ -25,7 +25,7 @@ class TimelineDefaultRepository is ResponseResult.Exception -> ResponseResult.Exception( responseResult.e, - EXCEPTION_ERROR_MESSAGE, + EXCEPTION_NETWORK_ERROR_MESSAGE, ) } } @@ -42,12 +42,12 @@ class TimelineDefaultRepository is ResponseResult.Exception -> ResponseResult.Exception( responseResult.e, - EXCEPTION_ERROR_MESSAGE, + EXCEPTION_NETWORK_ERROR_MESSAGE, ) } } companion object { - private const val EXCEPTION_ERROR_MESSAGE = "예기치 못한 오류입니다.\n잠시 후에 다시 시도해주세요." + private const val EXCEPTION_NETWORK_ERROR_MESSAGE = "네트워크 연결이 불안정합니다.\n연결을 재설정한 후 다시 시도해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemberProfile.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemberProfile.kt new file mode 100644 index 000000000..c86f13140 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemberProfile.kt @@ -0,0 +1,7 @@ +package com.on.staccato.domain.model + +data class MemberProfile( + val profileImageUrl: String? = null, + val nickname: String, + val uuidCode: String, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Memory.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Memory.kt index 53f9ffb4d..ba3965563 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Memory.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Memory.kt @@ -10,5 +10,5 @@ data class Memory( val endAt: LocalDate? = null, val description: String? = null, val mates: List, - val moments: List, + val staccatos: List, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryMoment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryMoment.kt deleted file mode 100644 index a6f482681..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryMoment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.on.staccato.domain.model - -import java.time.LocalDateTime - -data class MemoryMoment( - val momentId: Long, - val momentTitle: String, - val momentImageUrl: String? = null, - val visitedAt: LocalDateTime, -) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryStaccato.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryStaccato.kt new file mode 100644 index 000000000..e28d4305a --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MemoryStaccato.kt @@ -0,0 +1,10 @@ +package com.on.staccato.domain.model + +import java.time.LocalDateTime + +data class MemoryStaccato( + val staccatoId: Long, + val staccatoTitle: String, + val staccatoImageUrl: String? = null, + val visitedAt: LocalDateTime, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/NewComment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/NewComment.kt index b3874b7f9..c4388cd99 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/NewComment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/NewComment.kt @@ -1,6 +1,6 @@ package com.on.staccato.domain.model data class NewComment( - val momentId: Long, + val staccatoId: Long, val content: String, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Moment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Staccato.kt similarity index 82% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Moment.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Staccato.kt index b42e28088..fbf25f63b 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Moment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/Staccato.kt @@ -3,14 +3,14 @@ package com.on.staccato.domain.model import java.time.LocalDate import java.time.LocalDateTime -data class Moment( - val momentId: Long, +data class Staccato( + val staccatoId: Long, val staccatoTitle: String, val placeName: String, val address: String, val latitude: Double, val longitude: Double, - val momentImageUrls: List, + val staccatoImageUrls: List, val memoryId: Long, val memoryTitle: String, val visitedAt: LocalDateTime, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MomentLocation.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/StaccatoLocation.kt similarity index 62% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MomentLocation.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/StaccatoLocation.kt index 8d9712c37..09d6577b7 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/MomentLocation.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/model/StaccatoLocation.kt @@ -1,7 +1,7 @@ package com.on.staccato.domain.model -data class MomentLocation( - val momentId: Long, +data class StaccatoLocation( + val staccatoId: Long, val latitude: Double, val longitude: Double, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/CommentRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/CommentRepository.kt index aaf11b79f..c7efed4dd 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/CommentRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/CommentRepository.kt @@ -5,7 +5,7 @@ import com.on.staccato.domain.model.Comment import com.on.staccato.domain.model.NewComment interface CommentRepository { - suspend fun fetchComments(momentId: Long): ResponseResult> + suspend fun fetchComments(staccatoId: Long): ResponseResult> suspend fun createComment(newComment: NewComment): ResponseResult diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MomentRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MomentRepository.kt deleted file mode 100644 index fb8ce5175..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MomentRepository.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.on.staccato.domain.repository - -import com.on.staccato.data.ResponseResult -import com.on.staccato.data.dto.moment.MomentCreationResponse -import com.on.staccato.domain.model.Moment -import com.on.staccato.domain.model.MomentLocation -import java.time.LocalDateTime - -interface MomentRepository { - suspend fun getMoments(): ResponseResult> - - suspend fun getMoment(momentId: Long): Result - - suspend fun createMoment( - memoryId: Long, - staccatoTitle: String, - placeName: String, - latitude: Double, - longitude: Double, - address: String, - visitedAt: LocalDateTime, - momentImageUrls: List, - ): Result - - suspend fun updateMoment( - momentId: Long, - staccatoTitle: String, - placeName: String, - address: String, - latitude: Double, - longitude: Double, - visitedAt: LocalDateTime, - memoryId: Long, - momentImageUrls: List, - ): Result - - suspend fun deleteMoment(momentId: Long): Result - - suspend fun updateFeeling( - momentId: Long, - feeling: String, - ): Result -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MyPageRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MyPageRepository.kt index 481a75755..50ceecf68 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MyPageRepository.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/MyPageRepository.kt @@ -2,11 +2,11 @@ package com.on.staccato.domain.repository import com.on.staccato.data.ResponseResult import com.on.staccato.data.dto.mypage.ProfileImageResponse -import com.on.staccato.domain.model.AccountInformation +import com.on.staccato.domain.model.MemberProfile import okhttp3.MultipartBody interface MyPageRepository { - suspend fun getAccountInformation(): ResponseResult + suspend fun getMemberProfile(): ResponseResult suspend fun changeProfileImage(profileImageFile: MultipartBody.Part): ResponseResult } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/StaccatoRepository.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/StaccatoRepository.kt new file mode 100644 index 000000000..4293c33f4 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/domain/repository/StaccatoRepository.kt @@ -0,0 +1,43 @@ +package com.on.staccato.domain.repository + +import com.on.staccato.data.ResponseResult +import com.on.staccato.data.dto.staccato.StaccatoCreationResponse +import com.on.staccato.domain.model.Staccato +import com.on.staccato.domain.model.StaccatoLocation +import java.time.LocalDateTime + +interface StaccatoRepository { + suspend fun getStaccatos(): ResponseResult> + + suspend fun getStaccato(staccatoId: Long): ResponseResult + + suspend fun createStaccato( + memoryId: Long, + staccatoTitle: String, + placeName: String, + latitude: Double, + longitude: Double, + address: String, + visitedAt: LocalDateTime, + staccatoImageUrls: List, + ): ResponseResult + + suspend fun updateStaccato( + staccatoId: Long, + staccatoTitle: String, + placeName: String, + address: String, + latitude: Double, + longitude: Double, + visitedAt: LocalDateTime, + memoryId: Long, + staccatoImageUrls: List, + ): ResponseResult + + suspend fun deleteStaccato(staccatoId: Long): ResponseResult + + suspend fun updateFeeling( + staccatoId: Long, + feeling: String, + ): ResponseResult +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/BindingAdapters.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/BindingAdapters.kt deleted file mode 100644 index 835f4eae1..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/BindingAdapters.kt +++ /dev/null @@ -1,610 +0,0 @@ -package com.on.staccato.presentation - -import android.graphics.drawable.Drawable -import android.net.Uri -import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.NumberPicker -import android.widget.ProgressBar -import android.widget.ScrollView -import android.widget.TextView -import androidx.core.view.isGone -import androidx.core.view.isInvisible -import androidx.databinding.BindingAdapter -import coil.load -import coil.transform.RoundedCornersTransformation -import com.airbnb.lottie.LottieAnimationView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.resource.bitmap.RoundedCorners -import com.bumptech.glide.request.RequestOptions -import com.google.android.material.button.MaterialButton -import com.on.staccato.R -import com.on.staccato.domain.model.MemoryCandidate -import com.on.staccato.domain.model.MemoryCandidates -import com.on.staccato.presentation.momentcreation.model.AttachedPhotosUiModel -import com.on.staccato.presentation.timeline.model.TimelineUiModel -import okhttp3.internal.format -import java.time.LocalDate -import java.time.LocalDateTime - -@BindingAdapter( - value = ["coilImageUrl", "coilPlaceHolder"], -) -fun ImageView.loadImageWithCoil( - url: String?, - placeHolder: Drawable? = null, -) { - load(url) { - placeholder(placeHolder) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["coilImageUri", "coilPlaceHolder"], -) -fun ImageView.loadImageByUriWithCoil( - uri: Uri?, - placeHolder: Drawable? = null, -) { - load(uri) { - placeholder(placeHolder) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["coilCircleImageUrl", "coilPlaceHolder"], -) -fun ImageView.setCircleImageWithCoil( - url: String?, - placeHolder: Drawable? = null, -) { - load(url) { - placeholder(placeHolder) - transformations(RoundedCornersTransformation(1000f)) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["coilRoundedCornerImageUrl", "coilPlaceHolder", "coilRoundingRadius"], -) -fun ImageView.setRoundedCornerImageWithCoil( - url: String?, - placeHolder: Drawable? = null, - roundingRadius: Float, -) { - load(url) { - placeholder(placeHolder) - transformations(RoundedCornersTransformation(roundingRadius)) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["coilUriRoundedCorner", "coilUriPlaceHolder", "coilUriRoundingRadius"], -) -fun ImageView.setRoundedCornerUriWithCoil( - uri: Uri?, - placeHolder: Drawable? = null, - roundingRadius: Float, -) { - load(uri) { - placeholder(placeHolder) - transformations(RoundedCornersTransformation(roundingRadius)) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["coilImageUrl", "coilImageUri", "coilPlaceHolder", "coilRoundingRadius"], -) -fun ImageView.setRoundedCornerUpdateImageWithCoil( - url: String?, - uri: Uri?, - placeHolder: Drawable? = null, - roundingRadius: Float, -) { - val image = uri ?: url - load(image) { - placeholder(placeHolder) - transformations(RoundedCornersTransformation(roundingRadius)) - error(placeHolder) - } -} - -@BindingAdapter( - value = ["glideImageUrl", "glidePlaceHolder"], -) -fun ImageView.loadImageWithGlide( - url: String?, - placeHolder: Drawable? = null, -) { - Glide.with(context) - .load(url) - .placeholder(placeHolder) - .centerCrop() - .error(placeHolder) - .into(this) -} - -@BindingAdapter( - value = ["glideCircleImageUrl", "glidePlaceHolder"], -) -fun ImageView.setCircleImageWithGlide( - url: String?, - placeHolder: Drawable? = null, -) { - Glide.with(context) - .load(url) - .placeholder(placeHolder) - .circleCrop() - .error(placeHolder) - .into(this) -} - -@BindingAdapter( - value = ["glideRoundedCornerImageUrl", "glidePlaceHolder", "glideRoundingRadius"], -) -fun ImageView.setRoundedCornerImageWithGlide( - url: String?, - placeHolder: Drawable? = null, - roundingRadius: Int, -) { - Glide.with(context) - .load(url) - .placeholder(placeHolder) - .centerCrop() - .apply(RequestOptions.bitmapTransform(RoundedCorners(roundingRadius))) - .error(placeHolder) - .into(this) -} - -@BindingAdapter(value = ["glideUriRoundedCornerImageUri", "glideUriPlaceHolder", "glideUriRoundingRadius"]) -fun ImageView.setRoundedCornerImageByUriWithGlide( - uri: Uri?, - placeHolder: Drawable? = null, - roundingRadius: Int, -) { - Glide.with(context) - .load(uri) - .centerCrop() - .apply(RequestOptions.bitmapTransform(RoundedCorners(roundingRadius))) - .error(placeHolder) - .into(this) -} - -@BindingAdapter( - value = ["memoryTitle", "startDate", "endDate", "isPeriodActive", "isPhotoPosting"], -) -fun Button.setMemorySaveButtonActive( - title: String?, - startDate: LocalDate?, - endDate: LocalDate?, - isPeriodActive: Boolean, - isPhotoPosting: Boolean?, -) { - val isPeriodNotExistent = (startDate == null) || (endDate == null) - val isPeriodRequirementsInvalid = isPeriodActive && isPeriodNotExistent - isEnabled = - if (title.isNullOrBlank() || isPhotoPosting == true || isPeriodRequirementsInvalid) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter( - value = ["staccatoTitle", "address", "visitedAt", "photos", "selectedMemory"], -) -fun Button.setStaccatoCreationButtonActive( - title: String?, - address: String?, - visitedAt: LocalDateTime?, - photos: AttachedPhotosUiModel?, - selectedMemory: MemoryCandidate?, -) { - isEnabled = - if (title.isNullOrBlank() || address == null || selectedMemory == null || visitedAt == null || photos?.isLoading() == true) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter(value = ["setSelectedMemory", "setMemoryCandidates"]) -fun TextView.setSelectedMemory( - selectedMemory: MemoryCandidate?, - memoryCandidates: MemoryCandidates?, -) { - if (memoryCandidates?.memoryCandidate?.isEmpty() == true) { - text = resources.getString(R.string.visit_creation_no_memory_hint) - setTextColor(resources.getColor(R.color.gray3, null)) - isClickable = false - isFocusable = false - } else if (selectedMemory == null) { - text = resources.getString(R.string.visit_creation_memory_selection_hint) - setTextColor(resources.getColor(R.color.gray3, null)) - isClickable = true - isFocusable = true - } else { - text = selectedMemory.memoryTitle - setTextColor(resources.getColor(R.color.staccato_black, null)) - } -} - -@BindingAdapter(value = ["setDateTimeWithAmPm", "setMemoryCandidates"]) -fun TextView.setDateTimeWithAmPm( - setNowDateTime: LocalDateTime?, - memoryCandidates: MemoryCandidates?, -) { - if (memoryCandidates?.memoryCandidate?.isEmpty() == true) { - text = resources.getString(R.string.visit_creation_memory_selection_hint) - setTextColor(resources.getColor(R.color.gray3, null)) - isClickable = false - isFocusable = false - } else { - text = setNowDateTime?.let(::getFormattedLocalDateTime) ?: "" - setTextColor(resources.getColor(R.color.staccato_black, null)) - isClickable = true - isFocusable = true - } -} - -@BindingAdapter("setDateTimeWithAmPm") -fun TextView.setDateTimeWithAmPm(setNowDateTime: LocalDateTime?) { - text = setNowDateTime?.let(::getFormattedLocalDateTime) ?: "" -} - -@BindingAdapter( - value = ["startDate", "endDate"], -) -fun TextView.setMemoryPeriod( - startDate: LocalDate?, - endDate: LocalDate?, -) { - if (startDate == null || endDate == null) { - text = resources.getString(R.string.memory_creation_period_hint) - setTextColor(resources.getColor(R.color.gray3, null)) - } else { - text = - resources.getString(R.string.memory_creation_selected_period) - .format(startDate, endDate) - setTextColor(resources.getColor(R.color.staccato_black, null)) - } -} - -@BindingAdapter("visitedAtConfirmButtonActive") -fun Button.setVisitedAtConfirmButtonActive(items: List?) { - isEnabled = - if (items.isNullOrEmpty()) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter("memoryVisitedAtConfirmButtonActive") -fun Button.setMemoryVisitedAtConfirmButtonActive(items: List?) { - isEnabled = - if (items.isNullOrEmpty()) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter("visitedAtNumberPickerItems") -fun NumberPicker.setVisitedAtNumberPickerItems(items: List?) { - items?.map { it.toLocalDate() } - if (items.isNullOrEmpty()) { - isGone = true - } else { - displayedValues = items.map(::getFormattedLocalDateTime).toTypedArray() - } -} - -@BindingAdapter("localDateNumberPickerItems") -fun NumberPicker.setLocalDateNumberPickerItems(items: List?) { - if (items.isNullOrEmpty()) { - isGone = true - } else { - displayedValues = items.map(::getFormattedLocalDate).toTypedArray() - } -} - -private fun View.getFormattedLocalDate(setNowDate: LocalDate) = - setNowDate.let { - val year = setNowDate.year - val month = setNowDate.monthValue - val day = setNowDate.dayOfMonth - resources.getString(R.string.all_date_kr_format) - .format(year, month, day) - } - -private fun View.getFormattedLocalDateTime(setNowDateTime: LocalDateTime) = - setNowDateTime.let { - val year = setNowDateTime.year - val month = setNowDateTime.monthValue - val day = setNowDateTime.dayOfMonth - val hour = if (setNowDateTime.hour % 12 == 0) 12 else setNowDateTime.hour % 12 - val noonText = if (setNowDateTime.hour < 12) "오전" else "오후" - resources.getString(R.string.all_date_time_am_pm_kr_format) - .format(year, month, day, noonText, hour) - } - -@BindingAdapter("memoryIsEmptyVisibility") -fun TextView.setMemoryIsEmptyVisibility(memoryCandidates: MemoryCandidates?) { - isGone = !memoryCandidates?.memoryCandidate.isNullOrEmpty() -} - -@BindingAdapter("visitedAtIsEmptyVisibility") -fun TextView.setVisitedAtIsEmptyVisibility(items: List?) { - isGone = !items.isNullOrEmpty() -} - -@BindingAdapter("visitedAt") -fun TextView.combineVisitedAt(visitedAt: LocalDateTime?) { - text = - if (visitedAt != null) { - val hour = if (visitedAt.hour % 12 == 0) 12 else visitedAt.hour % 12 - val noonText = if (visitedAt.hour < 12) "오전" else "오후" - format( - resources.getString(R.string.visit_history), - visitedAt.year, - visitedAt.monthValue, - visitedAt.dayOfMonth, - noonText, - hour, - ) - } else { - "" - } -} - -@BindingAdapter( - value = ["startAt", "endAt"], -) -fun TextView.convertLocalDateToDatePeriodString( - startAt: LocalDate?, - endAt: LocalDate?, -) { - val periodFormatString = resources.getString(R.string.memory_period_dot) - text = - if (startAt != null && endAt != null) { - visibility = View.VISIBLE - format( - periodFormatString, - startAt.year, - startAt.monthValue, - startAt.dayOfMonth, - endAt.year, - endAt.monthValue, - endAt.dayOfMonth, - ) - } else { - visibility = View.INVISIBLE - null - } -} - -@BindingAdapter( - value = ["memoryStartAt", "memoryEndAt"], -) -fun TextView.convertLocalDateToDatePeriodStringInMemory( - startAt: LocalDate?, - endAt: LocalDate?, -) { - val periodFormatString = resources.getString(R.string.memory_period_dot) - text = - if (startAt != null && endAt != null) { - visibility = View.VISIBLE - format( - periodFormatString, - startAt.year, - startAt.monthValue, - startAt.dayOfMonth, - endAt.year, - endAt.monthValue, - endAt.dayOfMonth, - ) - } else { - visibility = View.GONE - null - } -} - -@BindingAdapter("setAttachedPhotoVisibility") -fun ImageView.setAttachedPhotoVisibility(items: Array?) { - if (items.isNullOrEmpty()) { - visibility = View.GONE - } else { - visibility = View.VISIBLE - Glide.with(context) - .load(items[0]) - .centerCrop() - .into(this) - } -} - -@BindingAdapter("setAttachedPhotoVisibility") -fun FrameLayout.setAttachedPhotoVisibility(items: Array?) { - isInvisible = !items.isNullOrEmpty() -} - -@BindingAdapter("setEnabled") -fun Button.setEnabled(isUpdateCompleted: Boolean?) { - isEnabled = !(isUpdateCompleted ?: true) -} - -@BindingAdapter("loginEnabled") -fun Button.setLoginEnabled(nickName: String?) { - isEnabled = - if (nickName.isNullOrBlank()) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter(value = ["currentPhotoNumbers", "maxPhotoNumbers"]) -fun TextView.setPhotoNumbers( - currentPhotoNumbers: Int, - maxPhotoNumbers: Int, -) { - text = - resources.getString(R.string.all_photo_number).format(currentPhotoNumbers, maxPhotoNumbers) -} - -@BindingAdapter("photoDragHintVisibility") -fun TextView.setPhotoDragHintVisibility(currentPhotoNumbers: Int) { - isGone = currentPhotoNumbers < 2 -} - -@BindingAdapter("setSelected") -fun ImageView.setSelectedState(selected: Boolean) { - isSelected = selected -} - -@BindingAdapter( - value = [ - "colorImageResource", - "grayImageResource", - ], -) -fun ImageView.setImageResourceWithId( - colorResId: Int, - grayResId: Int, -) { - setImageResource( - if (isSelected) { - colorResId - } else { - grayResId - }, - ) -} - -@BindingAdapter("setAddress") -fun TextView.setAddress(address: String?) { - text = address ?: context.getString(R.string.visit_creation_empty_address) -} - -@BindingAdapter("sendEnabled") -fun ImageView.setSendEnabled(comment: String?) { - isEnabled = !comment.isNullOrBlank() -} - -@BindingAdapter("setLoadingLottieVisibility") -fun LottieAnimationView.setLoadingLottieVisibility(isLoading: Boolean?) { - if (isLoading == true) { - visibility = View.VISIBLE - } else { - visibility = View.GONE - } -} - -@BindingAdapter("setCurrentLocationButtonLoading") -fun MaterialButton.setCurrentLocationButtonLoading(isLoading: Boolean?) { - isClickable = isLoading == false - if (isLoading == true) { - setText(R.string.all_empty) - setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) - } else { - setText(R.string.visit_creation_load_current_location) - } -} - -@BindingAdapter(value = ["thumbnailUri", "thumbnailUrl"]) -fun ProgressBar.setThumbnailLoadingProgressBar( - thumbnailUri: Uri?, - thumbnailUrl: String?, -) { - visibility = - if (thumbnailUri != null && thumbnailUrl == null) { - View.VISIBLE - } else { - View.GONE - } -} - -@BindingAdapter(value = ["thumbnailUri", "thumbnailUrl"]) -fun View.setThumbnail( - thumbnailUri: Uri?, - thumbnailUrl: String?, -) { - visibility = - if (thumbnailUri == null && thumbnailUrl == null) { - View.VISIBLE - } else { - View.GONE - } -} - -@BindingAdapter("periodSelectionVisibility") -fun TextView.setPeriodSelectionVisibility(isChecked: Boolean) { - isGone = !isChecked -} - -@BindingAdapter("recoveryEnabled") -fun Button.setRecoveryEnabled(recoveryCode: String?) { - isEnabled = - if (recoveryCode.isNullOrBlank() || recoveryCode.length < 36) { - setTextColor(resources.getColor(R.color.gray4, null)) - false - } else { - setTextColor(resources.getColor(R.color.white, null)) - true - } -} - -@BindingAdapter("scrollToBottom") -fun ScrollView.scrollToBottom(isPeriodActive: Boolean) { - if (isPeriodActive) { - post { fullScroll(ScrollView.FOCUS_DOWN) } - } -} - -@BindingAdapter( - value = ["visibilityByTimeline", "visibilityByLoading"], -) -fun View.setTimelineEmptyViewVisible( - timeLine: List? = null, - isTimelineLoading: Boolean, -) { - visibility = - if (timeLine.isNullOrEmpty() && isTimelineLoading.not()) { - View.VISIBLE - } else { - View.GONE - } -} - -@BindingAdapter( - value = ["visibilityByTimeline", "visibilityByLoading"], -) -fun ViewGroup.setMemoryAddButtonVisible( - timeLine: List? = null, - isTimelineLoading: Boolean, -) { - visibility = - if (timeLine.isNullOrEmpty() && isTimelineLoading.not()) { - View.GONE - } else { - View.VISIBLE - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/BindingAdapters.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/BindingAdapters.kt new file mode 100644 index 000000000..971e95b47 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/BindingAdapters.kt @@ -0,0 +1,76 @@ +package com.on.staccato.presentation.bindingadapter + +import android.net.Uri +import android.view.View +import android.view.ViewGroup +import android.widget.ScrollView +import androidx.databinding.BindingAdapter +import com.on.staccato.presentation.timeline.model.TimelineUiModel + +@BindingAdapter("visibleOrGone") +fun View.setVisibility(isVisible: Boolean?) { + visibility = + if (isVisible == true) { + View.VISIBLE + } else { + View.GONE + } +} + +@BindingAdapter("scrollToBottom") +fun ScrollView.setScrollToBottom(isScrollable: Boolean) { + if (isScrollable) { + post { fullScroll(ScrollView.FOCUS_DOWN) } + } +} + +@BindingAdapter(value = ["visibilityByEmptyThumbnailUri", "visibilityByEmptyThumbnailUrl"]) +fun View.setThumbnailVisibility( + thumbnailUri: Uri?, + thumbnailUrl: String?, +) { + visibility = + if (thumbnailUri == null && thumbnailUrl == null) { + View.VISIBLE + } else { + View.GONE + } +} + +@BindingAdapter(value = ["loadingVisibilityByThumbnailUri", "visibilityByEmptyThumbnailUrl"]) +fun View.setThumbnailLoadingVisibility( + thumbnailUri: Uri?, + thumbnailUrl: String?, +) { + visibility = + if (thumbnailUri != null && thumbnailUrl == null) { + View.VISIBLE + } else { + View.GONE + } +} + +@BindingAdapter( + value = ["visibilityByTimeline", "visibilityByLoading"], +) +fun View.setTimelineEmptyViewVisible( + timeLine: List? = null, + isTimelineLoading: Boolean, +) { + visibility = if (isTimeLineEmpty(timeLine, isTimelineLoading)) View.VISIBLE else View.GONE +} + +@BindingAdapter( + value = ["visibilityByTimeline", "visibilityByLoading"], +) +fun ViewGroup.setMemoryAddButtonVisible( + timeLine: List? = null, + isTimelineLoading: Boolean, +) { + visibility = if (isTimeLineEmpty(timeLine, isTimelineLoading)) View.GONE else View.VISIBLE +} + +private fun isTimeLineEmpty( + timeLine: List?, + isTimelineLoading: Boolean, +) = timeLine.isNullOrEmpty() && isTimelineLoading.not() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ButtonBindingAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ButtonBindingAdapter.kt new file mode 100644 index 000000000..74a2ce9a9 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ButtonBindingAdapter.kt @@ -0,0 +1,112 @@ +package com.on.staccato.presentation.bindingadapter + +import android.widget.Button +import android.widget.ImageButton +import androidx.databinding.BindingAdapter +import com.google.android.material.button.MaterialButton +import com.on.staccato.R +import com.on.staccato.domain.model.MemoryCandidate +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotosUiModel +import java.time.LocalDate +import java.time.LocalDateTime + +@BindingAdapter("loginButtonEnabled") +fun Button.setLoginButtonEnabled(nickName: String?) { + isEnabled = + if (nickName.isNullOrBlank()) { + setTextColor(resources.getColor(R.color.gray4, null)) + false + } else { + setTextColor(resources.getColor(R.color.white, null)) + true + } +} + +@BindingAdapter( + value = ["staccatoTitle", "staccatoAddress", "staccatoVisitedAt", "staccatoPhotos", "staccatoMemory"], +) +fun Button.setStaccatoSaveButtonEnabled( + staccatoTitle: String?, + staccatoAddress: String?, + staccatoVisitedAt: LocalDateTime?, + staccatoPhotos: AttachedPhotosUiModel?, + staccatoMemory: MemoryCandidate?, +) { + isEnabled = + if (staccatoTitle.isNullOrBlank() || + staccatoAddress == null || + staccatoMemory == null || + staccatoVisitedAt == null || + staccatoPhotos?.isLoading() == true + ) { + setTextColor(resources.getColor(R.color.gray4, null)) + false + } else { + setTextColor(resources.getColor(R.color.white, null)) + true + } +} + +@BindingAdapter( + value = ["memoryTitle", "memoryStartDate", "memoryEndDate", "isPeriodActive", "isPhotoUploading"], +) +fun Button.setMemorySaveButtonEnabled( + memoryTitle: String?, + memoryStartDate: LocalDate?, + memoryEndDate: LocalDate?, + isPeriodActive: Boolean, + isPhotoUploading: Boolean?, +) { + val isPeriodNotExistent = (memoryStartDate == null) || (memoryEndDate == null) + val isPeriodRequirementsInvalid = isPeriodActive && isPeriodNotExistent + isEnabled = + if (memoryTitle.isNullOrBlank() || isPhotoUploading == true || isPeriodRequirementsInvalid) { + setTextColor(resources.getColor(R.color.gray4, null)) + false + } else { + setTextColor(resources.getColor(R.color.white, null)) + true + } +} + +@BindingAdapter("visitedAtSelectButtonEnabled") +fun Button.setVisitedAtSelectButtonEnabled(years: List?) { + isEnabled = + if (years.isNullOrEmpty()) { + setTextColor(resources.getColor(R.color.gray4, null)) + false + } else { + setTextColor(resources.getColor(R.color.white, null)) + true + } +} + +@BindingAdapter("recoveryButtonEnabled") +fun Button.setRecoveryButtonEnabled(recoveryCode: String?) { + isEnabled = + if (recoveryCode.isNullOrBlank() || recoveryCode.length < MAX_RECOVERY_CODE) { + setTextColor(resources.getColor(R.color.gray4, null)) + false + } else { + setTextColor(resources.getColor(R.color.white, null)) + true + } +} + +@BindingAdapter("currentLocationButtonLoading") +fun MaterialButton.setCurrentLocationButtonLoading(isLoading: Boolean?) { + isClickable = isLoading == false + if (isLoading == true) { + setText(R.string.all_empty) + setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) + } else { + setText(R.string.staccato_creation_load_current_location) + } +} + +@BindingAdapter("sendButtonEnabled") +fun ImageButton.setSendButtonEnabled(value: String?) { + isEnabled = !value.isNullOrBlank() +} + +private const val MAX_RECOVERY_CODE = 36 diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ImageBindingAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ImageBindingAdapter.kt new file mode 100644 index 000000000..8898a77d6 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/ImageBindingAdapter.kt @@ -0,0 +1,91 @@ +package com.on.staccato.presentation.bindingadapter + +import android.graphics.drawable.Drawable +import android.net.Uri +import android.widget.ImageView +import androidx.databinding.BindingAdapter +import coil.load +import coil.transform.RoundedCornersTransformation + +@BindingAdapter("selected") +fun ImageView.setSelected(selected: Boolean) { + isSelected = selected +} + +@BindingAdapter( + value = ["coilImageUrl", "coilPlaceHolder"], +) +fun ImageView.loadCoilImage( + url: String?, + placeHolder: Drawable? = null, +) { + load(url) { + placeholder(placeHolder) + error(placeHolder) + } +} + +@BindingAdapter( + value = ["coilCircleImageUrl", "coilPlaceHolder"], +) +fun ImageView.loadCoilCircleImage( + url: String?, + placeHolder: Drawable? = null, +) { + load(url) { + placeholder(placeHolder) + transformations(RoundedCornersTransformation(1000f)) + error(placeHolder) + } +} + +@BindingAdapter( + value = ["coilRoundedCornerImageUrl", "coilRoundedCornerPlaceHolder", "coilRoundingRadius"], +) +fun ImageView.setCoilRoundedCornerImage( + url: String?, + placeHolder: Drawable? = null, + roundingRadius: Float, +) { + load(url) { + placeholder(placeHolder) + transformations(RoundedCornersTransformation(roundingRadius)) + error(placeHolder) + } +} + +@BindingAdapter( + value = ["coilRoundedCornerImageUrl", "coilRoundedCornerImageUri", "coilRoundedCornerPlaceHolder", "coilRoundingRadius"], +) +fun ImageView.setCoilRoundedCornerImageWithUri( + url: String?, + uri: Uri?, + placeHolder: Drawable? = null, + roundingRadius: Float, +) { + val image = uri ?: url + load(image) { + placeholder(placeHolder) + transformations(RoundedCornersTransformation(roundingRadius)) + error(placeHolder) + } +} + +@BindingAdapter( + value = [ + "colorImageResource", + "grayImageResource", + ], +) +fun ImageView.setImageResourceWithId( + colorResId: Int, + grayResId: Int, +) { + setImageResource( + if (isSelected) { + colorResId + } else { + grayResId + }, + ) +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/TextBindingAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/TextBindingAdapter.kt new file mode 100644 index 000000000..be83faf81 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/bindingadapter/TextBindingAdapter.kt @@ -0,0 +1,158 @@ +package com.on.staccato.presentation.bindingadapter + +import android.view.View +import android.widget.TextView +import androidx.core.view.isGone +import androidx.databinding.BindingAdapter +import com.on.staccato.R +import com.on.staccato.domain.model.MemoryCandidate +import com.on.staccato.domain.model.MemoryCandidates +import com.on.staccato.presentation.common.getFormattedLocalDateTime +import java.time.LocalDate +import java.time.LocalDateTime + +@BindingAdapter(value = ["selectedMemory", "memoryCandidates"]) +fun TextView.setSelectedMemory( + selectedMemory: MemoryCandidate?, + memoryCandidates: MemoryCandidates?, +) { + if (memoryCandidates?.memoryCandidate?.isEmpty() == true) { + text = resources.getString(R.string.staccato_creation_no_memory_hint) + setTextColor(resources.getColor(R.color.gray3, null)) + isClickable = false + isFocusable = false + } else if (selectedMemory == null) { + text = resources.getString(R.string.staccato_creation_memory_selection_hint) + setTextColor(resources.getColor(R.color.gray3, null)) + isClickable = true + isFocusable = true + } else { + text = selectedMemory.memoryTitle + setTextColor(resources.getColor(R.color.staccato_black, null)) + } +} + +@BindingAdapter(value = ["dateTimeWithAmPm", "memoryCandidates"]) +fun TextView.setDateTimeWithAmPm( + dateTime: LocalDateTime?, + memoryCandidates: MemoryCandidates?, +) { + if (memoryCandidates?.memoryCandidate?.isEmpty() == true) { + text = resources.getString(R.string.staccato_creation_memory_selection_hint) + setTextColor(resources.getColor(R.color.gray3, null)) + isClickable = false + isFocusable = false + } else { + text = dateTime?.let(::getFormattedLocalDateTime) ?: EMPTY_TEXT + setTextColor(resources.getColor(R.color.staccato_black, null)) + isClickable = true + isFocusable = true + } +} + +@BindingAdapter( + value = ["startDate", "endDate"], +) +fun TextView.setMemoryPeriod( + startDate: LocalDate?, + endDate: LocalDate?, +) { + if (startDate == null || endDate == null) { + text = resources.getString(R.string.memory_creation_period_hint) + setTextColor(resources.getColor(R.color.gray3, null)) + } else { + text = + resources.getString(R.string.memory_creation_selected_period) + .format(startDate, endDate) + setTextColor(resources.getColor(R.color.staccato_black, null)) + } +} + +@BindingAdapter("isMemoryCandidatesEmpty") +fun TextView.setIsMemoryCandidatesEmptyVisibility(memoryCandidates: MemoryCandidates?) { + isGone = !memoryCandidates?.memoryCandidate.isNullOrEmpty() +} + +@BindingAdapter("isMemoryEmpty") +fun TextView.setIsMemoryEmptyVisibility(items: List?) { + isGone = !items.isNullOrEmpty() +} + +@BindingAdapter("visitedAtHistory") +fun TextView.formatVisitedAtHistory(visitedAt: LocalDateTime?) { + text = visitedAt?.let { + resources.getString(R.string.staccato_at_history).format(getFormattedLocalDateTime(it)) + } ?: EMPTY_TEXT +} + +@BindingAdapter( + value = ["startAt", "endAt"], +) +fun TextView.formatLocalDateToDatePeriod( + startAt: LocalDate?, + endAt: LocalDate?, +) { + val periodFormatString = resources.getString(R.string.memory_period_dot) + text = + if (startAt != null && endAt != null) { + visibility = View.VISIBLE + periodFormatString.format( + startAt.year, + startAt.monthValue, + startAt.dayOfMonth, + endAt.year, + endAt.monthValue, + endAt.dayOfMonth, + ) + } else { + visibility = View.INVISIBLE + null + } +} + +@BindingAdapter( + value = ["memoryStartAt", "memoryEndAt"], +) +fun TextView.formatLocalDateToDatePeriodInMemory( + startAt: LocalDate?, + endAt: LocalDate?, +) { + val periodFormatString = resources.getString(R.string.memory_period_dot) + text = + if (startAt != null && endAt != null) { + visibility = View.VISIBLE + periodFormatString.format( + startAt.year, + startAt.monthValue, + startAt.dayOfMonth, + endAt.year, + endAt.monthValue, + endAt.dayOfMonth, + ) + } else { + visibility = View.GONE + null + } +} + +@BindingAdapter(value = ["attachedPhotoNumbers", "maxPhotoNumbers"]) +fun TextView.setPhotoNumbers( + attachedPhotoNumbers: Int, + maxPhotoNumbers: Int, +) { + text = + resources.getString(R.string.all_photo_number).format(attachedPhotoNumbers, maxPhotoNumbers) +} + +@BindingAdapter("photoDragHintVisibility") +fun TextView.setPhotoDragHintVisibility(currentPhotoNumbers: Int) { + isGone = currentPhotoNumbers < DRAGGABLE_PHOTO_NUMBER +} + +@BindingAdapter("selectedAddress") +fun TextView.setSelectedAddress(address: String?) { + text = address ?: context.getString(R.string.staccato_creation_empty_address) +} + +private const val DRAGGABLE_PHOTO_NUMBER = 2 +private const val EMPTY_TEXT = "" diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/AttachedPhotoHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/AttachedPhotoHandler.kt index 3e1e1e880..21a50da77 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/AttachedPhotoHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/AttachedPhotoHandler.kt @@ -1,6 +1,6 @@ package com.on.staccato.presentation.common -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel interface AttachedPhotoHandler { fun onDeleteClicked(deletedPhoto: AttachedPhotoUiModel) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/LocalDateFormatter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/LocalDateFormatter.kt new file mode 100644 index 000000000..e5dd550d6 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/LocalDateFormatter.kt @@ -0,0 +1,35 @@ +package com.on.staccato.presentation.common + +import android.view.View +import com.on.staccato.R +import java.time.LocalDate +import java.time.LocalDateTime + +fun View.getFormattedLocalDate(setNowDate: LocalDate): String = + setNowDate.let { + val year = setNowDate.year + val month = setNowDate.monthValue + val day = setNowDate.dayOfMonth + resources.getString(R.string.all_date_kr_format) + .format(year, month, day) + } + +fun View.getFormattedLocalDateTime(setNowDateTime: LocalDateTime): String = + setNowDateTime.let { + val year = setNowDateTime.year + val month = setNowDateTime.monthValue + val day = setNowDateTime.dayOfMonth + val hour = if (setNowDateTime.hour % HALF_DAY_HOUR == 0) HALF_DAY_HOUR else setNowDateTime.hour % HALF_DAY_HOUR + val noonText = + if (setNowDateTime.hour < HALF_DAY_HOUR) { + resources.getString(R.string.all_am) + } else { + resources.getString( + R.string.all_pm, + ) + } + resources.getString(R.string.all_date_time_am_pm_kr_format) + .format(year, month, day, noonText, hour) + } + +private const val HALF_DAY_HOUR = 12 diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/MemberUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/MemberUiModel.kt index 7ee1f2e83..01fa8458c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/MemberUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/MemberUiModel.kt @@ -5,50 +5,3 @@ data class MemberUiModel( val nickname: String, val memberImage: String? = null, ) - -val dummyMates: List = - listOf( - MemberUiModel( - id = 1L, - nickname = "hxeyexn", - memberImage = - "https://mblogthumb-phinf.pstatic.net/MjAxODA2MjZfMjkw/MDAxNTI5OTQ3MjI2MDkw." + - "rQGJoaHxSRynjcOYQeLNJG8oOLK_o1s0K_jJchjmTCcg.8tusXVn2oRB6RdIASkgU2oXo0iDF9ocMEocb" + - "Sox0ZGog.JPEG.sinnam88/%EB%94%94%EC%A6%88%EB%8B%88_%EB%9D%BC%ED%91%BC%EC%A0%A4_%E" + - "B%B0%B0%EA%B2%BD%ED%99%94%EB%A9%B4_%EA%B3%A0%ED%99%94%EC%A7%88_%EB%AA%A8%EC%9D%8C_%283%29.jpg?type=w800", - ), - MemberUiModel( - id = 2L, - nickname = "s6m1n", - memberImage = - "https://search.pstatic.net/common/?src=http%3A%2F%2Fimage.nmv.nav" + - "er.net%2Fcafe_2023_09_19_1290%2Fd9bcfa00-56af-11ee-9ba4-a0369ffb3258_01.jpg&type=sc960_832", - ), - MemberUiModel( - id = 3L, - nickname = "hodu", - memberImage = - "https://mblogthumb-phinf.pstatic.net/20160314_83/siriusdhk_145788795704" + - "0ztVBc_PNG/nick_vector_by_simmeh-d9j99me.png?type=w420", - ), - MemberUiModel( - id = 4L, - nickname = "linirini", - memberImage = "", - ), - MemberUiModel( - id = 5L, - nickname = "Ho-Tea", - memberImage = "", - ), - MemberUiModel( - id = 6L, - nickname = "카고", - memberImage = "", - ), - MemberUiModel( - id = 7L, - nickname = "폭포", - memberImage = "", - ), - ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/PhotoAttachFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/PhotoAttachFragment.kt index 2a5502ec9..09ce1c5b9 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/PhotoAttachFragment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/common/PhotoAttachFragment.kt @@ -1,14 +1,19 @@ package com.on.staccato.presentation.common +import android.Manifest import android.Manifest.permission.READ_EXTERNAL_STORAGE import android.Manifest.permission.READ_MEDIA_IMAGES import android.app.Activity.RESULT_OK +import android.content.ActivityNotFoundException +import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build +import android.os.Build.VERSION import android.os.Bundle +import android.os.ext.SdkExtensions import android.provider.MediaStore import android.provider.Settings import android.view.LayoutInflater @@ -16,14 +21,18 @@ import android.view.View import android.view.ViewGroup import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresExtension +import androidx.annotation.StringRes import androidx.core.content.ContextCompat import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.snackbar.Snackbar import com.on.staccato.R import com.on.staccato.databinding.FragmentPhotoAttachBinding -import com.on.staccato.presentation.momentcreation.OnUrisSelectedListener -import com.on.staccato.presentation.util.showToast +import com.on.staccato.presentation.staccatocreation.OnUrisSelectedListener import dagger.hilt.android.AndroidEntryPoint +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale @AndroidEntryPoint class PhotoAttachFragment : BottomSheetDialogFragment(), PhotoAttachHandler { @@ -31,21 +40,68 @@ class PhotoAttachFragment : BottomSheetDialogFragment(), PhotoAttachHandler { private val binding get() = _binding!! private lateinit var uriSelectedListener: OnUrisSelectedListener - private lateinit var requestPermissionLauncher: ActivityResultLauncher + private lateinit var requestGalleryPermissionLauncher: ActivityResultLauncher> + private lateinit var requestCameraPermissionLauncher: ActivityResultLauncher> private lateinit var galleryLauncher: ActivityResultLauncher + private lateinit var cameraLauncher: ActivityResultLauncher private var multipleAbleOption: Boolean = false + private var currentImageUri: Uri? = null + private var attachableImageCount: Int = INVALID_ATTACHABLE_IMAGE_COUNT override fun onAttach(context: Context) { super.onAttach(context) initUrisSelectedListener(context) initRequestPermissionLauncher() + initCameraLauncher() initGalleryLauncher() } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = FragmentPhotoAttachBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle?, + ) { + binding.handler = this + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + currentImageUri = null + } + + override fun onCameraClicked() { + checkPermissionsAndLaunch( + permissions = CAMERA_REQUIRED_PERMISSIONS, + requestPermissionLauncherOnNotGranted = requestCameraPermissionLauncher, + onGranted = { startCamera() }, + ) + } + + override fun onGalleryClicked() { + checkPermissionsAndLaunch( + permissions = arrayOf(GALLERY_REQUIRED_PERMISSION), + requestPermissionLauncherOnNotGranted = requestGalleryPermissionLauncher, + onGranted = { launchGallery() }, + ) + } + fun setMultipleAbleOption(option: Boolean) { multipleAbleOption = option } + fun setCurrentImageCount(count: Int) { + attachableImageCount = count + } + private fun initUrisSelectedListener(context: Context) { if (context is OnUrisSelectedListener) { uriSelectedListener = context @@ -55,39 +111,163 @@ class PhotoAttachFragment : BottomSheetDialogFragment(), PhotoAttachHandler { } private fun initRequestPermissionLauncher() { - requestPermissionLauncher = - registerForActivityResult(ActivityResultContracts.RequestPermission()) { isPermissionGranted -> - if (isPermissionGranted) { - launchGallery() - } else { - showPermissionSnackBar() + requestCameraPermissionLauncher = + buildRequestPermissionLauncher(::startCamera, ::handleCameraPermissionNotGranted) + requestGalleryPermissionLauncher = + buildRequestPermissionLauncher(::launchGallery, ::handleGalleryPermissionNotGranted) + } + + private fun initCameraLauncher() { + cameraLauncher = + registerForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess -> + val imageUri = currentImageUri + if (isSuccess && imageUri != null) { + uriSelectedListener.onUrisSelected(imageUri) + dismiss() + } + } + } + + private fun initGalleryLauncher() { + galleryLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val imageUris = extractImageUris(result.data) + if (imageUris.isNotEmpty()) { + uriSelectedListener.onUrisSelected(*imageUris.toTypedArray()) + dismiss() + } else { + showGalleryErrorSnackBar() + } } } } + private fun buildRequestPermissionLauncher( + actionOnPermissionGranted: () -> Unit, + actionOnPermissionNotGranted: () -> Unit, + ): ActivityResultLauncher> = + registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> + if (permissions.all { (_, isGranted) -> isGranted }) { + actionOnPermissionGranted() + } else { + actionOnPermissionNotGranted() + } + } + + private fun startCamera() { + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + if (takePictureIntent.resolveActivity(requireActivity().packageManager) != null) { + launchCamera() + } else { + showNoCameraSnackBar() + } + } + + private fun launchCamera() { + try { + currentImageUri = createImageUri() + currentImageUri?.let { imageUri -> + cameraLauncher.launch(imageUri) + } + } catch (e: ActivityNotFoundException) { + showCameraErrorSnackBar() + } + } + private fun launchGallery() { val intent = Intent(Intent.ACTION_PICK) - .setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*") + .setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_TYPE) .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multipleAbleOption) galleryLauncher.launch(intent) } - private fun showPermissionSnackBar() { - val snackBar = makeSnackBar() - setSnackBarAction(snackBar) + private fun checkPermissionsAndLaunch( + permissions: Array, + requestPermissionLauncherOnNotGranted: ActivityResultLauncher>, + onGranted: () -> Unit, + ) { + val isPermissionGranted = + permissions.all { permission -> + ContextCompat.checkSelfPermission( + requireContext(), permission, + ) == PackageManager.PERMISSION_GRANTED + } + if (isPermissionGranted) { + onGranted() + } else { + requestPermissionLauncherOnNotGranted.launch(permissions) + } + } + + private fun handleCameraPermissionNotGranted() { + showSettingSnackBar(R.string.photo_require_camera_permission) + } + + private fun handleGalleryPermissionNotGranted() { + if (isPhotoPickerAvailable()) { + val intent = + Intent(MediaStore.ACTION_PICK_IMAGES) + .setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_TYPE) + .setImageCountLimit() + galleryLauncher.launch(intent) + } else { + showSettingSnackBar(R.string.photo_require_photo_album_permission) + } + } + + private fun isPhotoPickerAvailable() = + (Build.VERSION_CODES.TIRAMISU <= VERSION.SDK_INT) || ( + (Build.VERSION_CODES.R <= VERSION.SDK_INT) && + (MIN_EXTENSION_VERSION <= SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R)) + ) + + @RequiresExtension(extension = Build.VERSION_CODES.R, version = 2) + private fun Intent.setImageCountLimit(): Intent { + if (!multipleAbleOption || attachableImageCount < MIN_COUNT_FOR_PICK_IMAGES_MAX) return this + putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, attachableImageCount) + return this + } + + private fun showCameraErrorSnackBar() { + showSnackBar(R.string.snack_bar_camera_error) + } + + private fun showGalleryErrorSnackBar() { + showSnackBar(R.string.snack_bar_gallery_error) + } + + private fun showNoCameraSnackBar() { + showSnackBar(R.string.snack_bar_no_camera) + } + + private fun showSnackBar( + @StringRes resId: Int, + ) { + val snackBar = makeSnackBar(resId) + snackBar.show() + } + + private fun showSettingSnackBar( + @StringRes resId: Int, + ) { + val snackBar = makeSnackBar(resId) + setSnackBarActionMoveToSetting(snackBar) snackBar.show() } - private fun makeSnackBar(): Snackbar { + private fun makeSnackBar( + @StringRes resId: Int, + ): Snackbar { return Snackbar.make( binding.root, - R.string.snack_bar_require_photo_album_permission, + resId, Snackbar.LENGTH_LONG, ) } - private fun setSnackBarAction(snackBar: Snackbar) { + private fun setSnackBarActionMoveToSetting(snackBar: Snackbar) { snackBar.setAction(R.string.snack_bar_move_to_setting) { val uri = Uri.fromParts(PACKAGE_SCHEME, requireContext().packageName, null) val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri) @@ -95,21 +275,6 @@ class PhotoAttachFragment : BottomSheetDialogFragment(), PhotoAttachHandler { } } - private fun initGalleryLauncher() { - galleryLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == RESULT_OK) { - val imageUris = extractImageUris(result.data) - if (imageUris.isNotEmpty()) { - uriSelectedListener.onUrisSelected(*imageUris.toTypedArray()) - dismiss() - } else { - showToast("사진을 불러올 수 없습니다.") - } - } - } - } - private fun extractImageUris(intent: Intent?): List { val imageUris = mutableListOf() intent?.let { @@ -124,54 +289,43 @@ class PhotoAttachFragment : BottomSheetDialogFragment(), PhotoAttachHandler { return imageUris } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentPhotoAttachBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - binding.handler = this - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - override fun onCameraClicked() { - showToast(getString(R.string.all_default_not_supported)) - } - - override fun onGalleryClicked() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - checkPermissionsAndLaunch(READ_MEDIA_IMAGES) - } else { - checkPermissionsAndLaunch(READ_EXTERNAL_STORAGE) - } + private fun createImageUri(): Uri? { + val timeStamp = SimpleDateFormat(FILENAME_DATE_FORMAT, Locale.KOREA).format(Date()) + val content = createImageContent(timeStamp) + return requireActivity().contentResolver.insert( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + content, + ) } - private fun checkPermissionsAndLaunch(permission: String) { - val isPermissionGranted = - ContextCompat.checkSelfPermission( - requireContext(), - permission, - ) == PackageManager.PERMISSION_GRANTED - if (isPermissionGranted) { - launchGallery() - } else { - requestPermissionLauncher.launch(permission) + private fun createImageContent(fileName: String): ContentValues = + ContentValues().apply { + put(MediaStore.Images.Media.DISPLAY_NAME, "img_$fileName.jpg") + put(MediaStore.Images.Media.MIME_TYPE, IMAGE_JPG_TYPE) } - } companion object { const val TAG = "PhotoAttachModalBottomSheet" const val PACKAGE_SCHEME = "package" + private const val IMAGE_JPG_TYPE = "image/jpg" + private const val IMAGE_TYPE = "image/*" + private const val FILENAME_DATE_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" + private const val MIN_COUNT_FOR_PICK_IMAGES_MAX = 2 + private const val MIN_EXTENSION_VERSION = 2 + private const val INVALID_ATTACHABLE_IMAGE_COUNT = -1 + private val CAMERA_REQUIRED_PERMISSIONS = + mutableListOf( + Manifest.permission.CAMERA, + ).apply { + if (VERSION.SDK_INT <= Build.VERSION_CODES.P) { + add(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + }.toTypedArray() + private val GALLERY_REQUIRED_PERMISSION = + if (VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + READ_MEDIA_IMAGES + } else { + READ_EXTERNAL_STORAGE + } } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/login/viewmodel/LoginViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/login/viewmodel/LoginViewModel.kt index cdc119808..f2fd3961f 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/login/viewmodel/LoginViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/login/viewmodel/LoginViewModel.kt @@ -1,6 +1,5 @@ package com.on.staccato.presentation.login.viewmodel -import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -54,19 +53,6 @@ class LoginViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - when (status) { - is Status.Message -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.message}, message: $errorMessage", - ) - - is Status.Code -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.code}, message: $errorMessage", - ) - } } private fun handleException( @@ -74,9 +60,5 @@ class LoginViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - Log.e( - this::class.java.simpleName, - "Exception Caught | throwable: $e, message: $errorMessage", - ) } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/MainActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/MainActivity.kt index ee1f9ca49..401245f75 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/MainActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/MainActivity.kt @@ -21,7 +21,9 @@ import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment +import com.google.android.gms.maps.model.BitmapDescriptorFactory import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.maps.model.MapStyleOptions import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.MarkerOptions import com.google.android.gms.tasks.Task @@ -31,7 +33,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDE import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED import com.on.staccato.R import com.on.staccato.databinding.ActivityMainBinding -import com.on.staccato.domain.model.MomentLocation +import com.on.staccato.domain.model.StaccatoLocation import com.on.staccato.presentation.base.BindingActivity import com.on.staccato.presentation.common.LocationPermissionManager import com.on.staccato.presentation.common.LocationPermissionManager.Companion.locationPermissions @@ -39,9 +41,9 @@ import com.on.staccato.presentation.main.model.MarkerUiModel import com.on.staccato.presentation.main.viewmodel.MapsViewModel import com.on.staccato.presentation.main.viewmodel.SharedViewModel import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.momentcreation.MomentCreationActivity import com.on.staccato.presentation.mypage.MyPageActivity +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.STACCATO_ID_KEY +import com.on.staccato.presentation.staccatocreation.StaccatoCreationActivity import com.on.staccato.presentation.util.showToast import dagger.hilt.android.AndroidEntryPoint @@ -76,8 +78,9 @@ class MainActivity : setupGoogleMap() setupFusedLocationProviderClient() observeCurrentLocation() - observeMomentLocations() + observeStaccatoLocations() observeStaccatoId() + observeDeletedStaccato() setupBottomSheetController() setupBackPressedHandler() setUpBottomSheetBehaviorAction() @@ -92,6 +95,7 @@ class MainActivity : override fun onMapReady(map: GoogleMap) { googleMap = map + setMapStyle(map) moveDefaultLocation() checkLocationSetting() onMarkerClicked(map) @@ -103,7 +107,7 @@ class MainActivity : } override fun onStaccatoCreationClicked() { - MomentCreationActivity.startWithResultLauncher( + StaccatoCreationActivity.startWithResultLauncher( 0L, "임시 추억", this, @@ -134,6 +138,12 @@ class MainActivity : locationPermissionManager.checkLocationSetting(actionWhenHavePermission = ::enableMyLocation) } + private fun setMapStyle(map: GoogleMap) { + map.setMapStyle( + MapStyleOptions.loadRawResourceStyle(this, R.raw.google_map_style), + ) + } + private fun moveDefaultLocation() { val defaultLocation = LatLng(SEOUL_STATION_LATITUDE, SEOUL_STATION_LONGITUDE) @@ -225,21 +235,25 @@ class MainActivity : googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, DEFAULT_ZOOM)) } - private fun observeMomentLocations() { - mapsViewModel.momentLocations.observe(this) { momentLocations -> - if (this::googleMap.isInitialized) googleMap.clear() - addMarkers(momentLocations) + private fun observeStaccatoLocations() { + mapsViewModel.staccatoLocations.observe(this) { staccatoLocations -> + if (this::googleMap.isInitialized) { + googleMap.clear() + addMarkers(staccatoLocations) + } } } - private fun addMarkers(momentLocations: List) { + private fun addMarkers(staccatoLocations: List) { val markers: MutableList = mutableListOf() - momentLocations.forEach { momentLocation -> - val latLng = LatLng(momentLocation.latitude, momentLocation.longitude) + staccatoLocations.forEach { staccatoLocation -> + val latLng = LatLng(staccatoLocation.latitude, staccatoLocation.longitude) val markerOptions: MarkerOptions = MarkerOptions().position(latLng) - val marker: Marker = googleMap.addMarker(markerOptions) ?: return + val marker: Marker = + googleMap.addMarker(markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_location_pin_3x))) + ?: return val markerId: String = marker.id - markers.add(MarkerUiModel(momentLocation.momentId, markerId)) + markers.add(MarkerUiModel(staccatoLocation.staccatoId, markerId)) } mapsViewModel.setMarkers(markers) } @@ -261,15 +275,23 @@ class MainActivity : } } + private fun observeDeletedStaccato() { + sharedViewModel.isStaccatosUpdated.observe(this) { isDeleted -> + if (isDeleted) { + mapsViewModel.loadStaccatos() + } + } + } + private fun navigateToStaccato(staccatoId: Long?) { val navOptions = NavOptions.Builder() - .setPopUpTo(R.id.momentFragment, true) + .setPopUpTo(R.id.staccatoFragment, true) .build() val bundle = bundleOf(STACCATO_ID_KEY to staccatoId) - navController.navigate(R.id.momentFragment, bundle, navOptions) + navController.navigate(R.id.staccatoFragment, bundle, navOptions) } private fun setupBackPressedHandler() { @@ -322,7 +344,7 @@ class MainActivity : if (result.resultCode == RESULT_OK) { result.data?.let { val bundle: Bundle = makeBundle(it, STACCATO_ID_KEY) - navigateTo(R.id.momentFragment, R.id.momentFragment, bundle, true) + navigateTo(R.id.staccatoFragment, R.id.staccatoFragment, bundle, true) } } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/MapsViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/MapsViewModel.kt index 98f838847..f040f347d 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/MapsViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/MapsViewModel.kt @@ -10,8 +10,8 @@ import com.on.staccato.data.ApiResponseHandler.onException import com.on.staccato.data.ApiResponseHandler.onServerError import com.on.staccato.data.ApiResponseHandler.onSuccess import com.on.staccato.data.dto.Status -import com.on.staccato.domain.model.MomentLocation -import com.on.staccato.domain.repository.MomentRepository +import com.on.staccato.domain.model.StaccatoLocation +import com.on.staccato.domain.repository.StaccatoRepository import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData import com.on.staccato.presentation.main.model.MarkerUiModel @@ -23,10 +23,10 @@ import javax.inject.Inject class MapsViewModel @Inject constructor( - private val momentRepository: MomentRepository, + private val staccatoRepository: StaccatoRepository, ) : ViewModel() { - private val _momentLocations = MutableLiveData>() - val momentLocations: LiveData> get() = _momentLocations + private val _staccatoLocations = MutableLiveData>() + val staccatoLocations: LiveData> get() = _staccatoLocations private val _markers = MutableLiveData>() val markers: LiveData> get() = _markers @@ -62,15 +62,15 @@ class MapsViewModel fun loadStaccatos() { viewModelScope.launch { - val result = momentRepository.getMoments() - result.onSuccess(::setMomentLocations) + val result = staccatoRepository.getStaccatos() + result.onSuccess(::setStaccatoLocations) .onServerError(::handleServerError) .onException(::handelException) } } - private fun setMomentLocations(momentLocations: List) { - _momentLocations.value = momentLocations + private fun setStaccatoLocations(staccatoLocations: List) { + _staccatoLocations.value = staccatoLocations } private fun handleServerError( diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/SharedViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/SharedViewModel.kt index d1176429d..0391e14f4 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/SharedViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/main/viewmodel/SharedViewModel.kt @@ -12,7 +12,8 @@ class SharedViewModel : ViewModel() { get() = _isTimelineUpdated private val _isStaccatosUpdated = MutableSingleLiveData(false) - val isStaccatosUpdated: SingleLiveData get() = _isStaccatosUpdated + val isStaccatosUpdated: SingleLiveData + get() = _isStaccatosUpdated private val _isPermissionCancelClicked = MutableLiveData(false) val isPermissionCancelClicked: LiveData get() = _isPermissionCancelClicked diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/MemoryMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/MemoryMapper.kt index 255c7e0ea..58e95f0ff 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/MemoryMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/MemoryMapper.kt @@ -2,10 +2,10 @@ package com.on.staccato.presentation.mapper import com.on.staccato.domain.model.Member import com.on.staccato.domain.model.Memory -import com.on.staccato.domain.model.MemoryMoment +import com.on.staccato.domain.model.MemoryStaccato import com.on.staccato.presentation.common.MemberUiModel +import com.on.staccato.presentation.memory.model.MemoryStaccatoUiModel import com.on.staccato.presentation.memory.model.MemoryUiModel -import com.on.staccato.presentation.memory.model.MemoryVisitUiModel fun Memory.toUiModel() = MemoryUiModel( @@ -16,7 +16,7 @@ fun Memory.toUiModel() = endAt = endAt, description = description, mates = mates.map { it.toUiModel() }, - visits = moments.map { it.toUiModel() }, + staccatos = staccatos.map { it.toUiModel() }, ) fun Member.toUiModel() = @@ -26,10 +26,10 @@ fun Member.toUiModel() = memberImage = memberImage, ) -fun MemoryMoment.toUiModel() = - MemoryVisitUiModel( - id = momentId, - staccatoTitle = momentTitle, - visitImageUrl = momentImageUrl, +fun MemoryStaccato.toUiModel() = + MemoryStaccatoUiModel( + id = staccatoId, + staccatoTitle = staccatoTitle, + staccatoImageUrl = staccatoImageUrl, visitedAt = visitedAt, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/VisitUiModelMapper.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/StaccatoUiModelMapper.kt similarity index 51% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/VisitUiModelMapper.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/StaccatoUiModelMapper.kt index 6e515129b..b62cbf622 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/VisitUiModelMapper.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mapper/StaccatoUiModelMapper.kt @@ -3,21 +3,21 @@ package com.on.staccato.presentation.mapper import com.on.staccato.R import com.on.staccato.domain.model.Comment import com.on.staccato.domain.model.Feeling -import com.on.staccato.domain.model.Moment -import com.on.staccato.presentation.moment.comments.CommentUiModel -import com.on.staccato.presentation.moment.detail.MomentDetailUiModel -import com.on.staccato.presentation.moment.feeling.FeelingUiModel +import com.on.staccato.domain.model.Staccato +import com.on.staccato.presentation.staccato.comments.CommentUiModel +import com.on.staccato.presentation.staccato.detail.StaccatoDetailUiModel +import com.on.staccato.presentation.staccato.feeling.FeelingUiModel -fun Moment.toMomentDetailUiModel(): MomentDetailUiModel { - return MomentDetailUiModel( - id = momentId, +fun Staccato.toStaccatoDetailUiModel(): StaccatoDetailUiModel { + return StaccatoDetailUiModel( + id = staccatoId, memoryId = memoryId, memoryTitle = memoryTitle, staccatoTitle = staccatoTitle, placeName = placeName, latitude = latitude, longitude = longitude, - momentImageUrls = momentImageUrls, + staccatoImageUrls = staccatoImageUrls, address = address, visitedAt = visitedAt, ) @@ -35,11 +35,11 @@ fun Comment.toCommentUiModel() = fun Feeling.toFeelingUiModel(selectedFeeling: String = Feeling.NOTHING.value): FeelingUiModel { val colorAndGraySrc = when (this) { - Feeling.HAPPY -> R.drawable.feeling_happy to R.drawable.feeling_happy_gray - Feeling.ANGRY -> R.drawable.feeling_angry to R.drawable.feeling_angry_gray - Feeling.SAD -> R.drawable.feeling_sad to R.drawable.feeling_sad_gray - Feeling.SCARED -> R.drawable.feeling_scared to R.drawable.feeling_scared_gray - Feeling.EXCITED -> R.drawable.feeling_excited to R.drawable.feeling_excited_gray + Feeling.HAPPY -> R.drawable.feeling_happy_note to R.drawable.feeling_happy_note_gray + Feeling.ANGRY -> R.drawable.feeling_angry_note to R.drawable.feeling_angry_note_gray + Feeling.SAD -> R.drawable.feeling_sad_note to R.drawable.feeling_sad_note_gray + Feeling.SCARED -> R.drawable.feeling_scared_note to R.drawable.feeling_scared_note_gray + Feeling.EXCITED -> R.drawable.feeling_excited_note to R.drawable.feeling_excited_note_gray Feeling.NOTHING -> null } return FeelingUiModel( diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryFragment.kt index dd091a2e6..825cff414 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryFragment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryFragment.kt @@ -6,6 +6,7 @@ import androidx.core.os.bundleOf import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R import com.on.staccato.databinding.FragmentMemoryBinding import com.on.staccato.presentation.base.BindingFragment @@ -15,11 +16,12 @@ import com.on.staccato.presentation.common.ToolbarHandler import com.on.staccato.presentation.main.MainActivity import com.on.staccato.presentation.main.viewmodel.SharedViewModel import com.on.staccato.presentation.memory.adapter.MatesAdapter -import com.on.staccato.presentation.memory.adapter.VisitsAdapter +import com.on.staccato.presentation.memory.adapter.StaccatosAdapter import com.on.staccato.presentation.memory.viewmodel.MemoryViewModel import com.on.staccato.presentation.memoryupdate.MemoryUpdateActivity -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.momentcreation.MomentCreationActivity +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.STACCATO_ID_KEY +import com.on.staccato.presentation.staccatocreation.StaccatoCreationActivity +import com.on.staccato.presentation.util.showSnackBarWithAction import com.on.staccato.presentation.util.showToast import dagger.hilt.android.AndroidEntryPoint @@ -37,7 +39,7 @@ class MemoryFragment : private val deleteDialog = DeleteDialogFragment { onConfirmClicked() } private lateinit var matesAdapter: MatesAdapter - private lateinit var visitsAdapter: VisitsAdapter + private lateinit var staccatosAdapter: StaccatosAdapter override fun onViewCreated( view: View, @@ -46,10 +48,11 @@ class MemoryFragment : initBinding() initToolbar() initMatesAdapter() - initVisitsAdapter() + initStaccatosAdapter() observeMemory() observeIsDeleteSuccess() showErrorToast() + showExceptionSnackBar() viewModel.loadMemory(memoryId) } @@ -66,13 +69,13 @@ class MemoryFragment : deleteDialog.show(parentFragmentManager, DeleteDialogFragment.TAG) } - override fun onVisitClicked(visitId: Long) { + override fun onStaccatoClicked(staccatoId: Long) { viewModel.memory.value?.let { val bundle = bundleOf( - STACCATO_ID_KEY to visitId, + STACCATO_ID_KEY to staccatoId, ) - findNavController().navigate(R.id.action_memoryFragment_to_momentFragment, bundle) + findNavController().navigate(R.id.action_memoryFragment_to_staccatoFragment, bundle) } } @@ -80,14 +83,14 @@ class MemoryFragment : viewModel.deleteMemory(memoryId) } - override fun onVisitCreationClicked() { + override fun onStaccatoCreationClicked() { viewModel.memory.value?.let { - val visitCreationLauncher = (activity as MainActivity).staccatoCreationLauncher - MomentCreationActivity.startWithResultLauncher( + val staccatoCreationLauncher = (activity as MainActivity).staccatoCreationLauncher + StaccatoCreationActivity.startWithResultLauncher( memoryId, it.title, requireContext(), - visitCreationLauncher, + staccatoCreationLauncher, ) } } @@ -108,7 +111,7 @@ class MemoryFragment : private fun observeMemory() { viewModel.memory.observe(viewLifecycleOwner) { memory -> matesAdapter.updateMates(memory.mates) - visitsAdapter.updateVisits(memory.visits) + staccatosAdapter.updateStaccatos(memory.staccatos) } } @@ -127,17 +130,32 @@ class MemoryFragment : binding.rvMemoryMates.adapter = matesAdapter } - private fun initVisitsAdapter() { - visitsAdapter = VisitsAdapter(handler = this) - binding.rvMemoryVisits.adapter = visitsAdapter + private fun initStaccatosAdapter() { + staccatosAdapter = StaccatosAdapter(handler = this) + binding.rvMemoryStaccatos.adapter = staccatosAdapter } private fun showErrorToast() { - viewModel.errorMessage.observe(viewLifecycleOwner) { - showToast(it) + viewModel.errorMessage.observe(viewLifecycleOwner) { message -> + showToast(message) } } + private fun showExceptionSnackBar() { + viewModel.exceptionMessage.observe(viewLifecycleOwner) { message -> + view?.showSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = ::onRetryAction, + Snackbar.LENGTH_INDEFINITE, + ) + } + } + + private fun onRetryAction() { + viewModel.loadMemory(memoryId) + } + companion object { const val MEMORY_ID_KEY = "memoryId" const val MEMORY_TITLE_KEY = "memoryTitle" diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryHandler.kt index 30a4dfbf6..f315a6e63 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/MemoryHandler.kt @@ -1,7 +1,7 @@ package com.on.staccato.presentation.memory interface MemoryHandler { - fun onVisitClicked(visitId: Long) + fun onStaccatoClicked(staccatoId: Long) - fun onVisitCreationClicked() + fun onStaccatoCreationClicked() } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatoViewHolder.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatoViewHolder.kt new file mode 100644 index 000000000..e912bb904 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatoViewHolder.kt @@ -0,0 +1,16 @@ +package com.on.staccato.presentation.memory.adapter + +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.on.staccato.databinding.ItemStaccatosBinding +import com.on.staccato.presentation.memory.MemoryHandler +import com.on.staccato.presentation.memory.model.MemoryStaccatoUiModel + +class StaccatoViewHolder( + private val binding: ItemStaccatosBinding, + private val handler: MemoryHandler, +) : ViewHolder(binding.root) { + fun bind(memoryStaccato: MemoryStaccatoUiModel) { + binding.staccato = memoryStaccato + binding.handler = handler + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatosAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatosAdapter.kt new file mode 100644 index 000000000..1e04a77b6 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/StaccatosAdapter.kt @@ -0,0 +1,46 @@ +package com.on.staccato.presentation.memory.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import com.on.staccato.databinding.ItemStaccatosBinding +import com.on.staccato.presentation.memory.MemoryHandler +import com.on.staccato.presentation.memory.model.MemoryStaccatoUiModel + +class StaccatosAdapter(private val handler: MemoryHandler) : ListAdapter(diffUtil) { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int, + ): StaccatoViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = ItemStaccatosBinding.inflate(inflater, parent, false) + return StaccatoViewHolder(binding, handler) + } + + override fun onBindViewHolder( + holder: StaccatoViewHolder, + position: Int, + ) { + holder.bind(getItem(position)) + } + + fun updateStaccatos(staccatos: List) { + submitList(staccatos) + } + + companion object { + val diffUtil = + object : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: MemoryStaccatoUiModel, + newItem: MemoryStaccatoUiModel, + ): Boolean = oldItem.id == newItem.id + + override fun areContentsTheSame( + oldItem: MemoryStaccatoUiModel, + newItem: MemoryStaccatoUiModel, + ): Boolean = oldItem == newItem + } + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsAdapter.kt deleted file mode 100644 index af8f00329..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.on.staccato.presentation.memory.adapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import com.on.staccato.databinding.ItemVisitsBinding -import com.on.staccato.presentation.memory.MemoryHandler -import com.on.staccato.presentation.memory.model.MemoryVisitUiModel - -class VisitsAdapter(private val handler: MemoryHandler) : ListAdapter(diffUtil) { - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int, - ): VisitsViewHolder { - val inflater = LayoutInflater.from(parent.context) - val binding = ItemVisitsBinding.inflate(inflater, parent, false) - return VisitsViewHolder(binding, handler) - } - - override fun onBindViewHolder( - holder: VisitsViewHolder, - position: Int, - ) { - holder.bind(getItem(position)) - } - - fun updateVisits(visits: List) { - submitList(visits) - } - - companion object { - val diffUtil = - object : DiffUtil.ItemCallback() { - override fun areItemsTheSame( - oldItem: MemoryVisitUiModel, - newItem: MemoryVisitUiModel, - ): Boolean = oldItem.id == newItem.id - - override fun areContentsTheSame( - oldItem: MemoryVisitUiModel, - newItem: MemoryVisitUiModel, - ): Boolean = oldItem == newItem - } - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsViewHolder.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsViewHolder.kt deleted file mode 100644 index 787428f63..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/adapter/VisitsViewHolder.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.on.staccato.presentation.memory.adapter - -import androidx.recyclerview.widget.RecyclerView.ViewHolder -import com.on.staccato.databinding.ItemVisitsBinding -import com.on.staccato.presentation.memory.MemoryHandler -import com.on.staccato.presentation.memory.model.MemoryVisitUiModel - -class VisitsViewHolder( - private val binding: ItemVisitsBinding, - private val handler: MemoryHandler, -) : ViewHolder(binding.root) { - fun bind(memoryVisit: MemoryVisitUiModel) { - binding.visit = memoryVisit - binding.handler = handler - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryVisitUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryStaccatoUiModel.kt similarity index 68% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryVisitUiModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryStaccatoUiModel.kt index e5f00bbc1..6c08c3bcb 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryVisitUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryStaccatoUiModel.kt @@ -2,9 +2,9 @@ package com.on.staccato.presentation.memory.model import java.time.LocalDateTime -data class MemoryVisitUiModel( +data class MemoryStaccatoUiModel( val id: Long, val staccatoTitle: String, - val visitImageUrl: String? = null, + val staccatoImageUrl: String? = null, val visitedAt: LocalDateTime, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryUiModel.kt index 661a90006..c75488a09 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/model/MemoryUiModel.kt @@ -11,7 +11,7 @@ data class MemoryUiModel( val endAt: LocalDate? = null, val description: String? = null, val mates: List, - val visits: List, + val staccatos: List, ) { companion object { fun buildDatesInRange( diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/viewmodel/MemoryViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/viewmodel/MemoryViewModel.kt index 4064100e2..8d3a10a41 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/viewmodel/MemoryViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memory/viewmodel/MemoryViewModel.kt @@ -31,6 +31,9 @@ class MemoryViewModel private val _errorMessage = MutableSingleLiveData() val errorMessage: SingleLiveData get() = _errorMessage + private val _exceptionMessage = MutableSingleLiveData() + val exceptionMessage: SingleLiveData get() = _exceptionMessage + private val _isDeleteSuccess = MutableSingleLiveData(false) val isDeleteSuccess: SingleLiveData get() = _isDeleteSuccess @@ -65,17 +68,13 @@ class MemoryViewModel status: Status, message: String, ) { - _errorMessage.setValue(message) + _errorMessage.postValue(message) } private fun handelException( e: Throwable, message: String, ) { - _errorMessage.setValue(MEMORY_ERROR_MESSAGE) - } - - companion object { - private const val MEMORY_ERROR_MESSAGE = "추억을 조회할 수 없습니다" + _exceptionMessage.postValue(message) } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationActivity.kt index 95c7f869f..b8370d7e0 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationActivity.kt @@ -10,13 +10,15 @@ import androidx.activity.viewModels import androidx.core.util.Pair import androidx.fragment.app.FragmentManager import com.google.android.material.datepicker.MaterialDatePicker +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R import com.on.staccato.databinding.ActivityMemoryCreationBinding import com.on.staccato.presentation.base.BindingActivity import com.on.staccato.presentation.common.PhotoAttachFragment import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY import com.on.staccato.presentation.memorycreation.viewmodel.MemoryCreationViewModel -import com.on.staccato.presentation.momentcreation.OnUrisSelectedListener +import com.on.staccato.presentation.staccatocreation.OnUrisSelectedListener +import com.on.staccato.presentation.util.getSnackBarWithAction import com.on.staccato.presentation.util.showToast import dagger.hilt.android.AndroidEntryPoint @@ -31,6 +33,7 @@ class MemoryCreationActivity : private val photoAttachFragment = PhotoAttachFragment() private val fragmentManager: FragmentManager = supportFragmentManager private val dateRangePicker = buildDateRangePicker() + private var currentSnackBar: Snackbar? = null override fun initStartView(savedInstanceState: Bundle?) { initBinding() @@ -38,6 +41,7 @@ class MemoryCreationActivity : updateMemoryPeriod() observeCreatedMemoryId() showErrorToast() + handleError() } override fun onPeriodSelectionClicked() { @@ -58,14 +62,15 @@ class MemoryCreationActivity : } override fun onImageDeletionClicked() { + currentSnackBar?.dismiss() viewModel.setThumbnailUri(null) viewModel.setThumbnailUrl(null) } override fun onUrisSelected(vararg uris: Uri) { + currentSnackBar?.dismiss() viewModel.createThumbnailUrl(this, uris.first()) viewModel.setThumbnailUri(uris.first()) - showToast(getString(R.string.all_posting_photo)) } private fun buildDateRangePicker() = @@ -115,6 +120,45 @@ class MemoryCreationActivity : } } + private fun handleError() { + viewModel.error.observe(this) { error -> + when (error) { + is MemoryCreationError.Thumbnail -> handleCreatePhotoUrlFail(error) + is MemoryCreationError.MemoryCreation -> handleCreateException(error) + } + } + } + + private fun handleCreatePhotoUrlFail(error: MemoryCreationError.Thumbnail) { + showExceptionSnackBar(error.message) { reCreateThumbnailUrl(error.uri) } + } + + private fun handleCreateException(error: MemoryCreationError.MemoryCreation) { + window.clearFlags(FLAG_NOT_TOUCHABLE) + showExceptionSnackBar(error.message) { reCreateMemory() } + } + + private fun reCreateThumbnailUrl(uri: Uri) { + viewModel.createThumbnailUrl(this, uri) + } + + private fun reCreateMemory() { + viewModel.createMemory() + } + + private fun showExceptionSnackBar( + message: String, + onRetryAction: () -> Unit, + ) { + currentSnackBar = + binding.root.getSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = onRetryAction, + length = Snackbar.LENGTH_INDEFINITE, + ).apply { show() } + } + companion object { fun startWithResultLauncher( context: Context, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationError.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationError.kt new file mode 100644 index 000000000..7316f1b72 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/MemoryCreationError.kt @@ -0,0 +1,9 @@ +package com.on.staccato.presentation.memorycreation + +import android.net.Uri + +sealed interface MemoryCreationError { + data class Thumbnail(val message: String, val uri: Uri) : MemoryCreationError + + data class MemoryCreation(val message: String) : MemoryCreationError +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/viewmodel/MemoryCreationViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/viewmodel/MemoryCreationViewModel.kt index 15a62f2d8..b6d1c7f46 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/viewmodel/MemoryCreationViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memorycreation/viewmodel/MemoryCreationViewModel.kt @@ -17,7 +17,10 @@ import com.on.staccato.data.dto.memory.MemoryCreationResponse import com.on.staccato.domain.model.NewMemory import com.on.staccato.domain.repository.ImageRepository import com.on.staccato.domain.repository.MemoryRepository +import com.on.staccato.presentation.common.MutableSingleLiveData +import com.on.staccato.presentation.common.SingleLiveData import com.on.staccato.presentation.memorycreation.DateConverter.convertLongToLocalDate +import com.on.staccato.presentation.memorycreation.MemoryCreationError import com.on.staccato.presentation.util.convertMemoryUriToFile import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -43,9 +46,6 @@ class MemoryCreationViewModel private val _createdMemoryId = MutableLiveData() val createdMemoryId: LiveData get() = _createdMemoryId - private val _errorMessage = MutableLiveData() - val errorMessage: LiveData get() = _errorMessage - private val _thumbnailUri = MutableLiveData(null) val thumbnailUri: LiveData get() = _thumbnailUri @@ -60,6 +60,12 @@ class MemoryCreationViewModel val isPeriodActive = MutableLiveData(false) + private val _errorMessage = MutableLiveData() + val errorMessage: LiveData get() = _errorMessage + + private val _error = MutableSingleLiveData() + val error: SingleLiveData get() = _error + fun createThumbnailUrl( context: Context, thumbnailUri: Uri, @@ -71,8 +77,10 @@ class MemoryCreationViewModel val result: ResponseResult = imageRepository.convertImageFileToUrl(thumbnailFile) result.onSuccess(::setThumbnailUrl) - .onServerError(::handleServerError) - .onException(::handelException) + .onServerError(::handlePhotoError) + .onException { e, message -> + handlePhotoException(e, message, thumbnailUri) + } } } @@ -101,8 +109,8 @@ class MemoryCreationViewModel memoryRepository.createMemory(memory) result .onSuccess(::setCreatedMemoryId) - .onServerError(::handleServerError) - .onException(::handelException) + .onServerError(::handleCreateServerError) + .onException(::handleCreateException) } } @@ -127,24 +135,38 @@ class MemoryCreationViewModel } } - private fun handleServerError( + private fun handlePhotoError( + status: Status, + message: String, + ) { + _errorMessage.postValue(message) + } + + private fun handlePhotoException( + e: Throwable, + message: String, + thumbnailUri: Uri, + ) { + _error.setValue(MemoryCreationError.Thumbnail(message, thumbnailUri)) + } + + private fun handleCreateServerError( status: Status, message: String, ) { _isPosting.value = false - _errorMessage.value = message + _errorMessage.postValue(message) } - private fun handelException( + private fun handleCreateException( e: Throwable, message: String, ) { _isPosting.value = false - _errorMessage.value = MEMORY_CREATION_ERROR_MESSAGE + _error.setValue(MemoryCreationError.MemoryCreation(message)) } companion object { private const val MEMORY_FILE_NAME = "imageFile" - private const val MEMORY_CREATION_ERROR_MESSAGE = "추억 생성에 실패했습니다" } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateActivity.kt index acfded7d6..62e8db679 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateActivity.kt @@ -10,13 +10,15 @@ import androidx.activity.viewModels import androidx.core.util.Pair import androidx.fragment.app.FragmentManager import com.google.android.material.datepicker.MaterialDatePicker +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R import com.on.staccato.databinding.ActivityMemoryUpdateBinding import com.on.staccato.presentation.base.BindingActivity import com.on.staccato.presentation.common.PhotoAttachFragment import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY import com.on.staccato.presentation.memoryupdate.viewmodel.MemoryUpdateViewModel -import com.on.staccato.presentation.momentcreation.OnUrisSelectedListener +import com.on.staccato.presentation.staccatocreation.OnUrisSelectedListener +import com.on.staccato.presentation.util.getSnackBarWithAction import com.on.staccato.presentation.util.showToast import dagger.hilt.android.AndroidEntryPoint @@ -32,6 +34,7 @@ class MemoryUpdateActivity : private val photoAttachFragment = PhotoAttachFragment() private val fragmentManager: FragmentManager = supportFragmentManager private val dateRangePicker = buildDateRangePicker() + private var currentSnackBar: Snackbar? = null override fun initStartView(savedInstanceState: Bundle?) { initBinding() @@ -40,10 +43,13 @@ class MemoryUpdateActivity : updateMemoryPeriod() observeIsUpdateSuccess() showErrorToast() + handleError() } override fun onPeriodSelectionClicked() { - dateRangePicker.show(supportFragmentManager, dateRangePicker.toString()) + if (!dateRangePicker.isAdded) { + dateRangePicker.show(supportFragmentManager, dateRangePicker.toString()) + } } override fun onSaveClicked() { @@ -58,14 +64,15 @@ class MemoryUpdateActivity : } override fun onPhotoDeletionClicked() { + currentSnackBar?.dismiss() viewModel.setThumbnailUri(null) viewModel.setThumbnailUrl(null) } override fun onUrisSelected(vararg uris: Uri) { + currentSnackBar?.dismiss() viewModel.setThumbnailUri(uris.first()) viewModel.createThumbnailUrl(this, uris.first()) - showToast(getString(R.string.all_posting_photo)) } private fun buildDateRangePicker() = @@ -122,6 +129,51 @@ class MemoryUpdateActivity : } } + private fun handleError() { + viewModel.error.observe(this) { error -> + when (error) { + is MemoryUpdateError.MemoryInitialization -> handleInitializeFail(error) + is MemoryUpdateError.Thumbnail -> handleCreatePhotoUrlFail(error) + is MemoryUpdateError.MemoryUpdate -> handleMemoryUpdateFail(error) + } + } + } + + private fun handleInitializeFail(error: MemoryUpdateError.MemoryInitialization) { + finish() + showToast(error.message) + } + + private fun handleCreatePhotoUrlFail(error: MemoryUpdateError.Thumbnail) { + showExceptionSnackBar(error.message) { reCreateThumbnailUrl(error.uri) } + } + + private fun handleMemoryUpdateFail(error: MemoryUpdateError.MemoryUpdate) { + window.clearFlags(FLAG_NOT_TOUCHABLE) + showExceptionSnackBar(error.message) { reUpdateMemory() } + } + + private fun reCreateThumbnailUrl(uri: Uri) { + viewModel.createThumbnailUrl(this, uri) + } + + private fun reUpdateMemory() { + viewModel.updateMemory() + } + + private fun showExceptionSnackBar( + message: String, + onRetryAction: () -> Unit, + ) { + currentSnackBar = + binding.root.getSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = onRetryAction, + length = Snackbar.LENGTH_INDEFINITE, + ).apply { show() } + } + companion object { private const val DEFAULT_MEMORY_ID = 0L diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateError.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateError.kt new file mode 100644 index 000000000..ddc6a5d98 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/MemoryUpdateError.kt @@ -0,0 +1,11 @@ +package com.on.staccato.presentation.memoryupdate + +import android.net.Uri + +sealed interface MemoryUpdateError { + data class MemoryInitialization(val message: String) : MemoryUpdateError + + data class Thumbnail(val message: String, val uri: Uri) : MemoryUpdateError + + data class MemoryUpdate(val message: String) : MemoryUpdateError +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/viewmodel/MemoryUpdateViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/viewmodel/MemoryUpdateViewModel.kt index 539ce6df0..28e70ad59 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/viewmodel/MemoryUpdateViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/memoryupdate/viewmodel/MemoryUpdateViewModel.kt @@ -20,6 +20,7 @@ import com.on.staccato.domain.repository.MemoryRepository import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData import com.on.staccato.presentation.memorycreation.DateConverter.convertLongToLocalDate +import com.on.staccato.presentation.memoryupdate.MemoryUpdateError import com.on.staccato.presentation.util.convertMemoryUriToFile import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -54,9 +55,6 @@ class MemoryUpdateViewModel private val _isUpdateSuccess = MutableSingleLiveData(false) val isUpdateSuccess: SingleLiveData get() = _isUpdateSuccess - private val _errorMessage = MutableLiveData() - val errorMessage: LiveData get() = _errorMessage - private val _isPosting = MutableLiveData() val isPosting: LiveData get() = _isPosting @@ -67,14 +65,20 @@ class MemoryUpdateViewModel private var memoryId: Long = 0L + private val _errorMessage = MutableLiveData() + val errorMessage: LiveData get() = _errorMessage + + private val _error = MutableSingleLiveData() + val error: SingleLiveData get() = _error + fun fetchMemory(memoryId: Long) { fetchMemoryId(memoryId) viewModelScope.launch { val result = memoryRepository.getMemory(memoryId) result .onSuccess(::initializeMemory) - .onServerError(::handleServerError) - .onException(::handelException) + .onServerError(::handleInitializeMemoryError) + .onException(::handleInitializeMemoryException) } } @@ -94,8 +98,10 @@ class MemoryUpdateViewModel val result: ResponseResult = imageRepository.convertImageFileToUrl(thumbnailFile) result.onSuccess(::setThumbnailUrl) - .onServerError(::handleServerError) - .onException(::handelException) + .onServerError(::handlePhotoError) + .onException { e, message -> + handlePhotoException(e, message, thumbnailUri) + } } } @@ -115,8 +121,8 @@ class MemoryUpdateViewModel val result: ResponseResult = memoryRepository.updateMemory(memoryId, newMemory) result .onSuccess { updateSuccessStatus() } - .onServerError(::handleServerError) - .onException(::handelException) + .onServerError(::handleUpdateError) + .onException(::handleUpdateException) } } @@ -163,7 +169,36 @@ class MemoryUpdateViewModel _isUpdateSuccess.setValue(true) } - private fun handleServerError( + private fun handlePhotoError( + status: Status, + message: String, + ) { + _errorMessage.value = message + } + + private fun handlePhotoException( + e: Throwable, + message: String, + uri: Uri, + ) { + _error.setValue(MemoryUpdateError.Thumbnail(message, uri)) + } + + private fun handleInitializeMemoryError( + status: Status, + message: String, + ) { + _errorMessage.value = message + } + + private fun handleInitializeMemoryException( + e: Throwable, + message: String, + ) { + _error.setValue(MemoryUpdateError.MemoryInitialization(message)) + } + + private fun handleUpdateError( status: Status, message: String, ) { @@ -171,16 +206,15 @@ class MemoryUpdateViewModel _errorMessage.value = message } - private fun handelException( + private fun handleUpdateException( e: Throwable, message: String, ) { _isPosting.value = false - _errorMessage.value = MEMORY_UPDATE_ERROR_MESSAGE + _error.setValue(MemoryUpdateError.MemoryUpdate(message)) } companion object { private const val MEMORY_FILE_NAME = "imageFile" - private const val MEMORY_UPDATE_ERROR_MESSAGE = "추억 수정에 실패했습니다" } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentFragment.kt deleted file mode 100644 index d4fc3a33a..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentFragment.kt +++ /dev/null @@ -1,130 +0,0 @@ -package com.on.staccato.presentation.moment - -import android.os.Bundle -import android.view.View -import androidx.core.os.bundleOf -import androidx.fragment.app.activityViewModels -import androidx.fragment.app.viewModels -import androidx.navigation.fragment.findNavController -import com.google.android.material.tabs.TabLayoutMediator -import com.on.staccato.R -import com.on.staccato.databinding.FragmentMomentBinding -import com.on.staccato.presentation.base.BindingFragment -import com.on.staccato.presentation.common.DeleteDialogFragment -import com.on.staccato.presentation.main.MainActivity -import com.on.staccato.presentation.main.viewmodel.SharedViewModel -import com.on.staccato.presentation.moment.comments.MomentCommentsFragment -import com.on.staccato.presentation.moment.detail.ViewpagePhotoAdapter -import com.on.staccato.presentation.moment.feeling.MomentFeelingSelectionFragment -import com.on.staccato.presentation.moment.viewmodel.MomentViewModel -import com.on.staccato.presentation.util.showToast -import com.on.staccato.presentation.visitupdate.VisitUpdateActivity -import dagger.hilt.android.AndroidEntryPoint -import kotlin.properties.Delegates - -@AndroidEntryPoint -class MomentFragment : - BindingFragment(R.layout.fragment_moment), MomentToolbarHandler { - private val momentViewModel: MomentViewModel by viewModels() - private var momentId by Delegates.notNull() - private lateinit var pagePhotoAdapter: ViewpagePhotoAdapter - private val sharedViewModel: SharedViewModel by activityViewModels() - private val deleteDialog = - DeleteDialogFragment { - momentViewModel.deleteMoment(momentId) - } - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - momentId = arguments?.getLong(STACCATO_ID_KEY) ?: return - binding.viewModel = momentViewModel - initToolbarHandler() - initViewPagerAdapter() - loadMomentData() - observeData() - createChildFragments(savedInstanceState) - observeViewModel() - } - - private fun initViewPagerAdapter() { - pagePhotoAdapter = ViewpagePhotoAdapter() - binding.vpPhotoHorizontal.adapter = pagePhotoAdapter - TabLayoutMediator( - binding.tabPhotoHorizontal, - binding.vpPhotoHorizontal, - ) { _, _ -> }.attach() - } - - private fun observeViewModel() { - momentViewModel.momentDetail.observe(viewLifecycleOwner) { momentDetail -> - pagePhotoAdapter.submitList(momentDetail.momentImageUrls) - } - } - - private fun loadMomentData() { - momentViewModel.loadMoment(momentId) - } - - private fun createChildFragments(savedInstanceState: Bundle?) { - if (savedInstanceState == null) { - val bundle = - bundleOf(STACCATO_ID_KEY to momentId) - val momentFeelingSelectionFragment = - MomentFeelingSelectionFragment().apply { - arguments = bundle - } - val momentCommentsFragment = MomentCommentsFragment().apply { arguments = bundle } - childFragmentManager.beginTransaction() - .replace(R.id.container_moment_feeling_selection, momentFeelingSelectionFragment) - .replace(R.id.container_moment_comments, momentCommentsFragment) - .commit() - } - } - - private fun initToolbarHandler() { - binding.toolbarHandler = this - binding.toolbarMoment.setNavigationOnClickListener { - findNavController().popBackStack() - } - } - - private fun observeData() { - momentViewModel.isError.observe(viewLifecycleOwner) { isError -> - if (isError) { - showToast("스타카토를 불러올 수 없어요!") - findNavController().popBackStack() - } - } - momentViewModel.isDeleted.observe(viewLifecycleOwner) { isDeleted -> - if (isDeleted) { - sharedViewModel.setStaccatosHasUpdated() - findNavController().popBackStack() - } - } - } - - override fun onDeleteClicked() { - deleteDialog.show(parentFragmentManager, DeleteDialogFragment.TAG) - } - - override fun onUpdateClicked( - memoryId: Long, - memoryTitle: String, - ) { - val momentUpdateLauncher = (activity as MainActivity).staccatoUpdateLauncher - VisitUpdateActivity.startWithResultLauncher( - visitId = momentId, - memoryId = memoryId, - memoryTitle = memoryTitle, - context = requireContext(), - activityLauncher = momentUpdateLauncher, - ) - } - - companion object { - const val STACCATO_ID_KEY = "momentId" - const val DEFAULT_STACCATO_ID = -1L - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsFragment.kt deleted file mode 100644 index a791e97a7..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsFragment.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.on.staccato.presentation.moment.comments - -import android.os.Bundle -import android.view.View -import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE -import androidx.fragment.app.viewModels -import com.on.staccato.R -import com.on.staccato.databinding.FragmentMomentCommentsBinding -import com.on.staccato.presentation.base.BindingFragment -import com.on.staccato.presentation.moment.MomentFragment.Companion.DEFAULT_STACCATO_ID -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.util.showToast -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class MomentCommentsFragment : - BindingFragment(R.layout.fragment_moment_comments) { - private lateinit var commentsAdapter: CommentsAdapter - - private val momentId by lazy { arguments?.getLong(STACCATO_ID_KEY) ?: DEFAULT_STACCATO_ID } - private val commentsViewModel: MomentCommentsViewModel by viewModels() - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - commentsViewModel.setMemoryId(momentId) - setUpRecyclerView() - setUpBinding() - observeCommentsViewModel() - loadComments() - } - - private fun setUpRecyclerView() { - commentsAdapter = CommentsAdapter(commentsViewModel) - binding.rvMomentComments.adapter = commentsAdapter - binding.rvMomentComments.itemAnimator = null - } - - private fun setUpBinding() { - binding.viewModel = commentsViewModel - binding.commentHandler = commentsViewModel - } - - private fun loadComments() { - commentsViewModel.fetchComments() - } - - private fun observeCommentsViewModel() { - commentsViewModel.comments.observe(viewLifecycleOwner) { comments -> - commentsAdapter.updateComments(comments) - } - - commentsViewModel.isDeleteSuccess.observe(viewLifecycleOwner) { issDeleted -> - if (issDeleted) { - showToast(getString(R.string.moment_comment_has_been_deleted)) - } - } - - commentsViewModel.isLoading.observe(viewLifecycleOwner) { isLoading -> - if (isLoading) { - requireActivity().window.setFlags(FLAG_NOT_TOUCHABLE, FLAG_NOT_TOUCHABLE) - } else { - requireActivity().window.clearFlags(FLAG_NOT_TOUCHABLE) - } - } - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingUiModel.kt deleted file mode 100644 index a4857f805..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingUiModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.on.staccato.presentation.moment.feeling - -data class FeelingUiModel( - val feeling: String, - val colorSrc: Int?, - val graySrc: Int?, - val isSelected: Boolean = false, -) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionFragment.kt deleted file mode 100644 index be4479789..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionFragment.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.on.staccato.presentation.moment.feeling - -import android.os.Bundle -import android.view.View -import androidx.fragment.app.viewModels -import com.on.staccato.R -import com.on.staccato.databinding.FragmentMomentFeelingSelectionBinding -import com.on.staccato.presentation.base.BindingFragment -import com.on.staccato.presentation.moment.MomentFragment.Companion.DEFAULT_STACCATO_ID -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.moment.viewmodel.MomentViewModel -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class MomentFeelingSelectionFragment : - BindingFragment(R.layout.fragment_moment_feeling_selection) { - private lateinit var feelingSelectionAdapter: FeelingSelectionAdapter - private val momentViewModel: MomentViewModel by viewModels({ requireParentFragment() }) - private val momentFeelingSelectionViewModel: MomentFeelingSelectionViewModel by viewModels() - - private val momentId by lazy { arguments?.getLong(STACCATO_ID_KEY) ?: DEFAULT_STACCATO_ID } - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - momentFeelingSelectionViewModel.setMomentId(momentId) - initAdapter() - observeInitialFeeling() - observeFeelings() - } - - private fun initAdapter() { - feelingSelectionAdapter = FeelingSelectionAdapter(momentFeelingSelectionViewModel) - binding.rvMomentFeelingSelection.adapter = feelingSelectionAdapter - } - - private fun observeInitialFeeling() { - momentViewModel.feeling.observe(viewLifecycleOwner) { feeling -> - momentFeelingSelectionViewModel.setFeelings(feeling) - } - } - - private fun observeFeelings() { - momentFeelingSelectionViewModel.feelings.observe(viewLifecycleOwner) { feelings -> - feelingSelectionAdapter.updateFeelings(feelings) - } - } -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/model/MomentDetailUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/model/MomentDetailUiModel.kt deleted file mode 100644 index acc84981f..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/model/MomentDetailUiModel.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.on.staccato.presentation.moment.model - -import java.time.LocalDateTime - -sealed class MomentDetailUiModel { - data class MomentDefaultUiModel( - val id: Long, - val placeName: String, - val momentImageUrls: List, - val address: String, - val visitedAt: LocalDateTime, - ) : MomentDetailUiModel() - - data class CommentsUiModel( - val id: Long = 0, - val memberId: Long = 0, - val nickname: String, - val memberImageUrl: String, - val content: String, - ) : MomentDetailUiModel() -} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/viewmodel/MomentViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/viewmodel/MomentViewModel.kt deleted file mode 100644 index 0aed5c529..000000000 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/viewmodel/MomentViewModel.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.on.staccato.presentation.moment.viewmodel - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.on.staccato.domain.model.Feeling -import com.on.staccato.domain.repository.MomentRepository -import com.on.staccato.presentation.common.MutableSingleLiveData -import com.on.staccato.presentation.common.SingleLiveData -import com.on.staccato.presentation.mapper.toMomentDetailUiModel -import com.on.staccato.presentation.moment.comments.CommentUiModel -import com.on.staccato.presentation.moment.detail.MomentDetailUiModel -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import javax.inject.Inject - -@HiltViewModel -class MomentViewModel - @Inject - constructor( - private val momentRepository: MomentRepository, - ) : ViewModel() { - private val _momentDetail = MutableLiveData() - val momentDetail: LiveData get() = _momentDetail - - private val _comments = MutableLiveData>() - val comments: LiveData> get() = _comments - - private val _feeling = MutableLiveData() - val feeling: LiveData get() = _feeling - - private val _isDeleted = MutableSingleLiveData(false) - val isDeleted: SingleLiveData get() = _isDeleted - - private val _isError = MutableSingleLiveData(false) - val isError: SingleLiveData get() = _isError - - fun loadMoment(momentId: Long) { - fetchMomentData(momentId) - } - - fun deleteMoment(momentId: Long) = - viewModelScope.launch { - momentRepository.deleteMoment(momentId).onSuccess { - _isDeleted.postValue(true) - } - } - - private fun fetchMomentData(momentId: Long) { - viewModelScope.launch { - momentRepository.getMoment(momentId).onSuccess { moment -> - _momentDetail.value = moment.toMomentDetailUiModel() - _feeling.value = moment.feeling - }.onFailure { - _isError.postValue(true) - } - } - } - } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MemberProfileHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MemberProfileHandler.kt new file mode 100644 index 000000000..41e0411d1 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MemberProfileHandler.kt @@ -0,0 +1,5 @@ +package com.on.staccato.presentation.mypage + +interface MemberProfileHandler { + fun onCodeCopyClicked() +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageActivity.kt index d188dc003..277fff4d4 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageActivity.kt @@ -3,6 +3,8 @@ package com.on.staccato.presentation.mypage import android.content.ClipData import android.content.ClipboardManager import android.content.Intent +import android.content.Intent.ACTION_VIEW +import android.net.Uri import android.os.Build import android.os.Bundle import androidx.activity.viewModels @@ -29,8 +31,35 @@ class MyPageActivity : override fun initStartView(savedInstanceState: Bundle?) { initToolbar() initBindings() - loadMyProfile() + loadMemberProfile() observeCopyingUuidCode() + observeErrorMessage() + } + + override fun onPrivacyPolicyClicked() { + val intent = + Intent(this, WebViewActivity::class.java) + .putExtra(EXTRA_URL, PRIVACY_POLICY_URL) + .putExtra(EXTRA_TOOLBAR_TITLE, getString(R.string.mypage_privacy_policy)) + startActivity(intent) + } + + override fun onFeedbackClicked() { + val intent = Intent(ACTION_VIEW).apply { data = Uri.parse(FEEDBACK_GOOGLE_FORM_URL) } + if (intent.resolveActivity(packageManager) != null) { + startActivity(intent) + } else { + showToast(getString(R.string.mypage_error_not_found_browser)) + } + } + + override fun onInstagramClicked() { + val intent = Intent(ACTION_VIEW).apply { data = Uri.parse(STACCATO_INSTAGRAM_URL) } + if (intent.resolveActivity(packageManager) != null) { + startActivity(intent) + } else { + showToast(getString(R.string.mypage_error_can_not_open_instagram_page)) + } } private fun initToolbar() { @@ -43,11 +72,11 @@ class MyPageActivity : binding.lifecycleOwner = this binding.menuHandler = this binding.viewModel = myPageViewModel - binding.myPageHandler = myPageViewModel + binding.memberProfileHandler = myPageViewModel } - private fun loadMyProfile() { - myPageViewModel.fetchMyProfile() + private fun loadMemberProfile() { + myPageViewModel.fetchMemberProfile() } private fun observeCopyingUuidCode() { @@ -68,16 +97,20 @@ class MyPageActivity : } } - override fun onPrivacyPolicyClicked() { - val url = getString(R.string.mypage_privacy_policy_url) - val intent = - Intent(this, WebViewActivity::class.java) - .putExtra(EXTRA_URL, url) - .putExtra(EXTRA_TOOLBAR_TITLE, getString(R.string.mypage_privacy_policy)) - startActivity(intent) + private fun observeErrorMessage() { + myPageViewModel.errorMessage.observe(this) { errorMessage -> + finish() + showToast(errorMessage) + } } companion object { private const val UUID_CODE_LABEL = "uuidCode" + private const val PRIVACY_POLICY_URL = + "https://app.websitepolicies.com/policies/view/7jel2uwv" + private const val FEEDBACK_GOOGLE_FORM_URL = + "https://forms.gle/fuxgta7HxDNY5KvSA" + private const val STACCATO_INSTAGRAM_URL = + "https://www.instagram.com/staccato_team/profilecard/?igsh=Y241bHoybnZmZjA5" } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageMenuHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageMenuHandler.kt index 8b08f815e..bfdd9521d 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageMenuHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/MyPageMenuHandler.kt @@ -2,4 +2,8 @@ package com.on.staccato.presentation.mypage interface MyPageMenuHandler { fun onPrivacyPolicyClicked() + + fun onFeedbackClicked() + + fun onInstagramClicked() } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/viewmodel/MyPageViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/viewmodel/MyPageViewModel.kt index f85d66ada..4158fb4cb 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/viewmodel/MyPageViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/mypage/viewmodel/MyPageViewModel.kt @@ -1,6 +1,5 @@ package com.on.staccato.presentation.mypage.viewmodel -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -9,13 +8,11 @@ import com.on.staccato.data.ApiResponseHandler.onException import com.on.staccato.data.ApiResponseHandler.onServerError import com.on.staccato.data.ApiResponseHandler.onSuccess import com.on.staccato.data.dto.Status -import com.on.staccato.domain.model.AccountInformation +import com.on.staccato.domain.model.MemberProfile import com.on.staccato.domain.repository.MyPageRepository import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData -import com.on.staccato.presentation.mapper.toUiModel -import com.on.staccato.presentation.mypage.MyPageHandler -import com.on.staccato.presentation.mypage.model.AccountInformationUiModel +import com.on.staccato.presentation.mypage.MemberProfileHandler import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -25,10 +22,10 @@ class MyPageViewModel @Inject constructor(private val repository: MyPageRepository) : ViewModel(), - MyPageHandler { - private val _accountInformation = MutableLiveData() - val accountInformation: LiveData - get() = _accountInformation + MemberProfileHandler { + private val _memberProfile = MutableLiveData() + val memberProfile: LiveData + get() = _memberProfile private val _uuidCode = MutableSingleLiveData() val uuidCode: SingleLiveData @@ -38,21 +35,26 @@ class MyPageViewModel val errorMessage: SingleLiveData get() = _errorMessage - fun fetchMyProfile() { + override fun onCodeCopyClicked() { + val memberProfile = memberProfile.value + if (memberProfile != null) { + _uuidCode.setValue(memberProfile.uuidCode) + } else { + _errorMessage.setValue(ERROR_NO_MEMBER_PROFILE) + } + } + + fun fetchMemberProfile() { viewModelScope.launch { - val result = repository.getAccountInformation() + val result = repository.getMemberProfile() result.onException(::handleException) .onServerError(::handleError) - .onSuccess(::setMyProfile) + .onSuccess(::setMemberProfile) } } - private fun setMyProfile(accountInformation: AccountInformation) { - _accountInformation.value = accountInformation.toUiModel() - } - - override fun onCodeCopyClicked() { - accountInformation.value?.let { _uuidCode.setValue(it.uuidCode) } + private fun setMemberProfile(memberProfile: MemberProfile) { + _memberProfile.value = memberProfile } private fun handleError( @@ -60,19 +62,6 @@ class MyPageViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - when (status) { - is Status.Message -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.message}, message: $errorMessage", - ) - - is Status.Code -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.code}, message: $errorMessage", - ) - } } private fun handleException( @@ -80,9 +69,9 @@ class MyPageViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - Log.e( - this::class.java.simpleName, - "Exception Caught | throwable: $e, message: $errorMessage", - ) + } + + companion object { + private const val ERROR_NO_MEMBER_PROFILE = "프로필 정보를 조회할 수 없습니다.\n잠시 후에 다시 시도해주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/recovery/viewmodel/RecoveryViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/recovery/viewmodel/RecoveryViewModel.kt index ff78cc8c6..534e3962e 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/recovery/viewmodel/RecoveryViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/recovery/viewmodel/RecoveryViewModel.kt @@ -1,6 +1,5 @@ package com.on.staccato.presentation.recovery.viewmodel -import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -59,19 +58,6 @@ class RecoveryViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - when (status) { - is Status.Message -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.message}, message: $errorMessage", - ) - - is Status.Code -> - Log.e( - this::class.java.simpleName, - "Error Occurred | status: ${status.code}, message: $errorMessage", - ) - } } private fun handleException( @@ -79,9 +65,5 @@ class RecoveryViewModel errorMessage: String, ) { _errorMessage.postValue(errorMessage) - Log.e( - this::class.java.simpleName, - "Exception Caught | throwable: $e, message: $errorMessage", - ) } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoFragment.kt new file mode 100644 index 000000000..a8bc9a37e --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoFragment.kt @@ -0,0 +1,236 @@ +package com.on.staccato.presentation.staccato + +import android.os.Bundle +import android.view.View +import android.view.ViewTreeObserver +import android.widget.ScrollView +import androidx.core.os.bundleOf +import androidx.core.widget.NestedScrollView +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.google.android.material.snackbar.Snackbar +import com.google.android.material.tabs.TabLayoutMediator +import com.on.staccato.R +import com.on.staccato.databinding.FragmentStaccatoBinding +import com.on.staccato.presentation.base.BindingFragment +import com.on.staccato.presentation.common.DeleteDialogFragment +import com.on.staccato.presentation.main.MainActivity +import com.on.staccato.presentation.main.viewmodel.SharedViewModel +import com.on.staccato.presentation.staccato.comments.CommentsAdapter +import com.on.staccato.presentation.staccato.comments.StaccatoCommentsViewModel +import com.on.staccato.presentation.staccato.detail.ViewpagePhotoAdapter +import com.on.staccato.presentation.staccato.feeling.StaccatoFeelingSelectionFragment +import com.on.staccato.presentation.staccato.viewmodel.StaccatoViewModel +import com.on.staccato.presentation.staccatoupdate.StaccatoUpdateActivity +import com.on.staccato.presentation.util.showSnackBarWithAction +import com.on.staccato.presentation.util.showToast +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class StaccatoFragment : + BindingFragment(R.layout.fragment_staccato), StaccatoToolbarHandler { + private val sharedViewModel: SharedViewModel by activityViewModels() + private val staccatoViewModel: StaccatoViewModel by viewModels() + private val commentsViewModel: StaccatoCommentsViewModel by viewModels() + private val commentsAdapter: CommentsAdapter by lazy { CommentsAdapter(commentsViewModel) } + private val pagePhotoAdapter: ViewpagePhotoAdapter by lazy { ViewpagePhotoAdapter() } + private val deleteDialog = + DeleteDialogFragment { + staccatoViewModel.deleteStaccato(staccatoId) + } + private val staccatoId by lazy { arguments?.getLong(STACCATO_ID_KEY) ?: DEFAULT_STACCATO_ID } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle?, + ) { + setUpBinding() + setNavigationClickListener() + setUpViewPager() + setUpComments() + loadStaccato() + loadComments() + observeStaccatoViewModel() + observeCommentsViewModel() + setStaccatoFeelingFragment(savedInstanceState) + showErrorToast() + showExceptionSnackBar() + } + + override fun onDeleteClicked() { + deleteDialog.show(parentFragmentManager, DeleteDialogFragment.TAG) + } + + override fun onUpdateClicked( + memoryId: Long, + memoryTitle: String, + ) { + val staccatoUpdateLauncher = (activity as MainActivity).staccatoUpdateLauncher + StaccatoUpdateActivity.startWithResultLauncher( + staccatoId = staccatoId, + memoryId = memoryId, + memoryTitle = memoryTitle, + context = requireContext(), + activityLauncher = staccatoUpdateLauncher, + ) + } + + private fun setUpBinding() { + binding.lifecycleOwner = this + binding.toolbarHandler = this + binding.commentHandler = commentsViewModel + binding.staccatoViewModel = staccatoViewModel + binding.commentsViewModel = commentsViewModel + } + + private fun setNavigationClickListener() { + binding.toolbarStaccato.setNavigationOnClickListener { + findNavController().popBackStack() + } + } + + private fun setUpComments() { + binding.rvStaccatoComments.adapter = commentsAdapter + binding.rvStaccatoComments.itemAnimator = null + } + + private fun setUpViewPager() { + binding.vpStaccatoPhotoHorizontal.adapter = pagePhotoAdapter + TabLayoutMediator( + binding.tabStaccatoPhotoHorizontal, + binding.vpStaccatoPhotoHorizontal, + ) { _, _ -> }.attach() + } + + private fun loadStaccato() { + staccatoViewModel.loadStaccato(staccatoId) + } + + private fun loadComments() { + commentsViewModel.fetchComments(staccatoId) + } + + private fun observeStaccatoViewModel() { + observeStaccatoDetail() + observeStaccatoDelete() + } + + private fun observeStaccatoDetail() { + staccatoViewModel.staccatoDetail.observe(viewLifecycleOwner) { staccatoDetail -> + pagePhotoAdapter.submitList(staccatoDetail.staccatoImageUrls) + } + } + + private fun observeStaccatoDelete() { + staccatoViewModel.isDeleted.observe(viewLifecycleOwner) { isDeleted -> + if (isDeleted) { + sharedViewModel.setStaccatosHasUpdated() + findNavController().popBackStack() + } + } + } + + private fun observeCommentsViewModel() { + observeComments() + observeDeletingComment() + observeSendingComment() + } + + private fun observeComments() { + commentsViewModel.comments.observe(viewLifecycleOwner) { comments -> + commentsAdapter.updateComments(comments) + } + } + + private fun observeDeletingComment() { + commentsViewModel.isDeleteSuccess.observe(viewLifecycleOwner) { isDeleted -> + if (isDeleted) { + showToast(getString(R.string.staccato_comment_has_been_deleted)) + } + } + } + + private fun observeSendingComment() { + commentsViewModel.isSendingSuccess.observe(viewLifecycleOwner) { isSuccess -> + if (isSuccess) { + scrollToBottom() + } + } + } + + private fun scrollToBottom() { + with(binding.nsvStaccato) { + viewTreeObserver.addOnGlobalLayoutListener( + scrollableToBottomListener(), + ) + } + } + + private fun NestedScrollView.scrollableToBottomListener() = + object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + post { + fullScroll(ScrollView.FOCUS_DOWN) + viewTreeObserver.removeOnGlobalLayoutListener(this) + } + } + } + + private fun setStaccatoFeelingFragment(savedInstanceState: Bundle?) { + if (savedInstanceState == null) { + val staccatoFeelingSelectionFragment = createFeelingSelectionFragment() + addFeelingSelectionFragment(staccatoFeelingSelectionFragment) + } + } + + private fun createFeelingSelectionFragment(): StaccatoFeelingSelectionFragment { + val bundle = + bundleOf(STACCATO_ID_KEY to staccatoId) + val staccatoFeelingSelectionFragment = + StaccatoFeelingSelectionFragment().apply { + arguments = bundle + } + return staccatoFeelingSelectionFragment + } + + private fun addFeelingSelectionFragment(staccatoFeelingSelectionFragment: StaccatoFeelingSelectionFragment) { + childFragmentManager.beginTransaction() + .replace( + R.id.container_staccato_feeling_selection, + staccatoFeelingSelectionFragment, + ) + .commit() + } + + private fun showErrorToast() { + staccatoViewModel.errorMessage.observe(viewLifecycleOwner) { message -> + showToast(message) + findNavController().popBackStack() + } + commentsViewModel.errorMessage.observe(viewLifecycleOwner) { message -> + showToast(message) + } + } + + private fun showExceptionSnackBar() { + staccatoViewModel.exceptionMessage.observe(viewLifecycleOwner) { message -> + view?.showSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = ::onRetryAction, + Snackbar.LENGTH_INDEFINITE, + ) + } + } + + private fun onRetryAction() { + loadStaccato() + loadComments() + } + + companion object { + const val STACCATO_ID_KEY = "staccatoId" + const val DEFAULT_STACCATO_ID = -1L + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentToolbarHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoToolbarHandler.kt similarity index 58% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentToolbarHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoToolbarHandler.kt index 5f81e5aa8..38a248f2c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/MomentToolbarHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/StaccatoToolbarHandler.kt @@ -1,6 +1,6 @@ -package com.on.staccato.presentation.moment +package com.on.staccato.presentation.staccato -interface MomentToolbarHandler { +interface StaccatoToolbarHandler { fun onUpdateClicked( memoryId: Long, memoryTitle: String, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentHandler.kt similarity index 73% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentHandler.kt index 5a8ee42b6..7010a3e80 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentHandler.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.comments +package com.on.staccato.presentation.staccato.comments interface CommentHandler { fun onSendButtonClicked() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentUiModel.kt similarity index 75% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentUiModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentUiModel.kt index 552f898db..ad1a48a9a 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentUiModel.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.comments +package com.on.staccato.presentation.staccato.comments data class CommentUiModel( val id: Long = 0, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentViewHolder.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentViewHolder.kt similarity index 91% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentViewHolder.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentViewHolder.kt index 1fe94465a..594cd572d 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentViewHolder.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentViewHolder.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.comments +package com.on.staccato.presentation.staccato.comments import android.view.Gravity import android.view.View @@ -6,13 +6,13 @@ import android.widget.PopupMenu import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import com.on.staccato.R -import com.on.staccato.databinding.ItemMomentMyCommentBinding +import com.on.staccato.databinding.ItemStaccatoMyCommentBinding import com.on.staccato.presentation.common.DeleteDialogFragment import com.on.staccato.presentation.common.DialogHandler // Todo: 추후 나의 댓글, 다른 사용자의 댓글 구분하기 class CommentViewHolder( - private val binding: ItemMomentMyCommentBinding, + private val binding: ItemStaccatoMyCommentBinding, private val commentHandler: CommentHandler, ) : RecyclerView.ViewHolder(binding.root), DialogHandler { diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentsAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentsAdapter.kt similarity index 89% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentsAdapter.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentsAdapter.kt index ce90e73e7..b6ef8e0cd 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/CommentsAdapter.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/CommentsAdapter.kt @@ -1,10 +1,10 @@ -package com.on.staccato.presentation.moment.comments +package com.on.staccato.presentation.staccato.comments import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter -import com.on.staccato.databinding.ItemMomentMyCommentBinding +import com.on.staccato.databinding.ItemStaccatoMyCommentBinding class CommentsAdapter(private val commentHandler: CommentHandler) : ListAdapter(diffUtil) { @@ -13,7 +13,7 @@ class CommentsAdapter(private val commentHandler: CommentHandler) : viewType: Int, ): CommentViewHolder { val binding = - ItemMomentMyCommentBinding.inflate( + ItemStaccatoMyCommentBinding.inflate( LayoutInflater.from(parent.context), parent, false, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/StaccatoCommentsViewModel.kt similarity index 66% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsViewModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/StaccatoCommentsViewModel.kt index 89416a4cf..8d7ef3f3d 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/comments/MomentCommentsViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/comments/StaccatoCommentsViewModel.kt @@ -1,6 +1,5 @@ -package com.on.staccato.presentation.moment.comments +package com.on.staccato.presentation.staccato.comments -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -20,7 +19,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class MomentCommentsViewModel +class StaccatoCommentsViewModel @Inject constructor( private val commentRepository: CommentRepository, @@ -31,17 +30,21 @@ class MomentCommentsViewModel val isEmpty: LiveData = _comments.map { it.isEmpty() } - val commentInput = MutableLiveData("") + val commentInput = MutableLiveData("") private val _isDeleteSuccess = MutableSingleLiveData() val isDeleteSuccess: SingleLiveData get() = _isDeleteSuccess - private val _isLoading = MutableSingleLiveData(false) - val isLoading: SingleLiveData - get() = _isLoading + private val _isSendingSuccess = MutableSingleLiveData(false) + val isSendingSuccess: SingleLiveData + get() = _isSendingSuccess - private var momentId: Long = -1L + private val _errorMessage = MutableSingleLiveData() + val errorMessage: SingleLiveData + get() = _errorMessage + + private var staccatoId: Long = STACCATO_DEFAULT_ID override fun onSendButtonClicked() { viewModelScope.launch { @@ -50,14 +53,14 @@ class MomentCommentsViewModel } override fun onUpdateButtonClicked(commentId: Long) { - Log.d("hodu", "not implemented yet") + // TODO } override fun onDeleteButtonClicked(commentId: Long) { viewModelScope.launch { commentRepository.deleteComment(commentId) .onSuccess { - fetchComments() + fetchComments(staccatoId) _isDeleteSuccess.postValue(true) } .onServerError(::handleServerError) @@ -65,9 +68,10 @@ class MomentCommentsViewModel } } - fun fetchComments() { + fun fetchComments(id: Long) { + setStaccatoId(id) viewModelScope.launch { - commentRepository.fetchComments(momentId) + commentRepository.fetchComments(id) .onSuccess { comments -> setComments(comments.map { it.toCommentUiModel() }) } @@ -76,24 +80,21 @@ class MomentCommentsViewModel } } - fun setMemoryId(id: Long) { - momentId = id - } - - fun setComments(newComments: List) { - _comments.value = newComments + private fun setStaccatoId(id: Long) { + if (staccatoId == STACCATO_DEFAULT_ID) { + staccatoId = id + } } private fun sendComment() { commentInput.value?.let { - _isLoading.setValue(true) - val newComment = NewComment(momentId, it) + val newComment = NewComment(staccatoId, it) + commentInput.value = "" viewModelScope.launch { commentRepository.createComment(newComment) .onSuccess { - commentInput.value = "" - fetchComments() - _isLoading.postValue(false) + fetchComments(staccatoId) + _isSendingSuccess.postValue(true) } .onServerError(::handleServerError) .onException(::handleException) @@ -101,31 +102,25 @@ class MomentCommentsViewModel } } + private fun setComments(newComments: List) { + _comments.value = newComments + } + private fun handleServerError( status: Status, message: String, ) { - _isLoading.postValue(false) - when (status) { - is Status.Code -> - Log.e( - this.javaClass.simpleName, - "ServerError(${status.code}): $message", - ) - - is Status.Message -> - Log.e( - this.javaClass.simpleName, - "ServerError(${status.message}): $message", - ) - } + _errorMessage.postValue(message) } private fun handleException( e: Throwable, message: String, ) { - _isLoading.postValue(false) - Log.e(this.javaClass.simpleName, "Exception($e): $message") + _errorMessage.postValue(message) + } + + companion object { + const val STACCATO_DEFAULT_ID = -1L } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/MomentDetailUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/StaccatoDetailUiModel.kt similarity index 68% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/MomentDetailUiModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/StaccatoDetailUiModel.kt index aa6828840..51fb18b09 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/MomentDetailUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/StaccatoDetailUiModel.kt @@ -1,8 +1,8 @@ -package com.on.staccato.presentation.moment.detail +package com.on.staccato.presentation.staccato.detail import java.time.LocalDateTime -data class MomentDetailUiModel( +data class StaccatoDetailUiModel( val id: Long, val memoryId: Long, val memoryTitle: String, @@ -10,7 +10,7 @@ data class MomentDetailUiModel( val placeName: String, val latitude: Double, val longitude: Double, - val momentImageUrls: List, + val staccatoImageUrls: List, val address: String, val visitedAt: LocalDateTime, ) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoAdapter.kt similarity index 95% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoAdapter.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoAdapter.kt index 8359f6c10..6df73ee8c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoAdapter.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoAdapter.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.detail +package com.on.staccato.presentation.staccato.detail import android.view.LayoutInflater import android.view.ViewGroup diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoViewHolder.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoViewHolder.kt similarity index 85% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoViewHolder.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoViewHolder.kt index f99620f9e..bcd75c64e 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/detail/ViewpagePhotoViewHolder.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/detail/ViewpagePhotoViewHolder.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.detail +package com.on.staccato.presentation.staccato.detail import androidx.recyclerview.widget.RecyclerView import com.on.staccato.databinding.ItemViewpagePhotoBinding diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingHandler.kt similarity index 61% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingHandler.kt index 8f2bf21a7..eeaf999c3 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingHandler.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.moment.feeling +package com.on.staccato.presentation.staccato.feeling interface FeelingHandler { fun onFeelingClicked(selectedFeeling: FeelingUiModel) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingSelectionAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingSelectionAdapter.kt similarity index 88% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingSelectionAdapter.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingSelectionAdapter.kt index 41ebae8fd..d31f2c442 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/FeelingSelectionAdapter.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingSelectionAdapter.kt @@ -1,11 +1,11 @@ -package com.on.staccato.presentation.moment.feeling +package com.on.staccato.presentation.staccato.feeling import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.on.staccato.databinding.ItemMomentFeelingSelectionBinding +import com.on.staccato.databinding.ItemStaccatoFeelingSelectionBinding import com.on.staccato.domain.model.Feeling import com.on.staccato.presentation.mapper.toFeelingUiModel @@ -24,7 +24,7 @@ class FeelingSelectionAdapter(private val feelingHandler: FeelingHandler) : submitList(feelings) } - class FeelingSelectionViewHolder(private val binding: ItemMomentFeelingSelectionBinding) : + class FeelingSelectionViewHolder(private val binding: ItemStaccatoFeelingSelectionBinding) : RecyclerView.ViewHolder(binding.root) { fun bind( feelingUiModel: FeelingUiModel, @@ -40,7 +40,7 @@ class FeelingSelectionAdapter(private val feelingHandler: FeelingHandler) : viewType: Int, ): FeelingSelectionViewHolder { val binding = - ItemMomentFeelingSelectionBinding.inflate( + ItemStaccatoFeelingSelectionBinding.inflate( LayoutInflater.from(parent.context), parent, false, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingUiModel.kt new file mode 100644 index 000000000..ec7a6c344 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/FeelingUiModel.kt @@ -0,0 +1,10 @@ +package com.on.staccato.presentation.staccato.feeling + +import androidx.annotation.ColorRes + +data class FeelingUiModel( + val feeling: String, + @ColorRes val colorSrc: Int?, + @ColorRes val graySrc: Int?, + val isSelected: Boolean = false, +) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionFragment.kt new file mode 100644 index 000000000..f9c3682e1 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionFragment.kt @@ -0,0 +1,52 @@ +package com.on.staccato.presentation.staccato.feeling + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import com.on.staccato.R +import com.on.staccato.databinding.FragmentStaccatoFeelingSelectionBinding +import com.on.staccato.presentation.base.BindingFragment +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.DEFAULT_STACCATO_ID +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.STACCATO_ID_KEY +import com.on.staccato.presentation.staccato.viewmodel.StaccatoViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class StaccatoFeelingSelectionFragment : + BindingFragment(R.layout.fragment_staccato_feeling_selection) { + private lateinit var feelingSelectionAdapter: FeelingSelectionAdapter + private val staccatoViewModel: StaccatoViewModel by viewModels({ requireParentFragment() }) + private val staccatoFeelingSelectionViewModel: StaccatoFeelingSelectionViewModel by viewModels() + private val staccatoId by lazy { arguments?.getLong(STACCATO_ID_KEY) ?: DEFAULT_STACCATO_ID } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle?, + ) { + setStaccatoId() + initAdapter() + observeInitialFeeling() + observeFeelings() + } + + private fun setStaccatoId() { + staccatoFeelingSelectionViewModel.setStaccatoId(staccatoId) + } + + private fun initAdapter() { + feelingSelectionAdapter = FeelingSelectionAdapter(staccatoFeelingSelectionViewModel) + binding.rvStaccatoFeelingSelection.adapter = feelingSelectionAdapter + } + + private fun observeInitialFeeling() { + staccatoViewModel.feeling.observe(viewLifecycleOwner) { feeling -> + staccatoFeelingSelectionViewModel.setFeelings(feeling) + } + } + + private fun observeFeelings() { + staccatoFeelingSelectionViewModel.feelings.observe(viewLifecycleOwner) { feelings -> + feelingSelectionAdapter.updateFeelings(feelings) + } + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionViewModel.kt similarity index 83% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionViewModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionViewModel.kt index 130c15299..389a52057 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/moment/feeling/MomentFeelingSelectionViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/feeling/StaccatoFeelingSelectionViewModel.kt @@ -1,21 +1,21 @@ -package com.on.staccato.presentation.moment.feeling +package com.on.staccato.presentation.staccato.feeling import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.on.staccato.domain.model.Feeling -import com.on.staccato.domain.repository.MomentRepository +import com.on.staccato.domain.repository.StaccatoRepository import com.on.staccato.presentation.mapper.toFeelingUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class MomentFeelingSelectionViewModel +class StaccatoFeelingSelectionViewModel @Inject constructor( - private val momentRepository: MomentRepository, + private val staccatoRepository: StaccatoRepository, ) : ViewModel(), FeelingHandler { private val initialFeelings: List = Feeling.entries.filterNot { it.value == Feeling.NOTHING.value } @@ -26,14 +26,14 @@ class MomentFeelingSelectionViewModel private val _feelings = MutableLiveData>() val feelings: LiveData> get() = _feelings - private var momentId: Long = -1L + private var staccatoId: Long = -1L override fun onFeelingClicked(selectedFeeling: FeelingUiModel) { checkFeelingBeforeChange(selectedFeeling) } - fun setMomentId(id: Long) { - momentId = id + fun setStaccatoId(id: Long) { + staccatoId = id } fun setFeelings(selectedFeeling: Feeling) { @@ -61,7 +61,7 @@ class MomentFeelingSelectionViewModel private fun requestChangingFeeling(newFeeling: Feeling) { viewModelScope.launch { - momentRepository.updateFeeling(momentId, newFeeling.value) + staccatoRepository.updateFeeling(staccatoId, newFeeling.value) } } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/viewmodel/StaccatoViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/viewmodel/StaccatoViewModel.kt new file mode 100644 index 000000000..2c2c2d4bf --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccato/viewmodel/StaccatoViewModel.kt @@ -0,0 +1,83 @@ +package com.on.staccato.presentation.staccato.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.on.staccato.data.ApiResponseHandler.onException +import com.on.staccato.data.ApiResponseHandler.onServerError +import com.on.staccato.data.ApiResponseHandler.onSuccess +import com.on.staccato.data.dto.Status +import com.on.staccato.domain.model.Feeling +import com.on.staccato.domain.repository.StaccatoRepository +import com.on.staccato.presentation.common.MutableSingleLiveData +import com.on.staccato.presentation.common.SingleLiveData +import com.on.staccato.presentation.mapper.toStaccatoDetailUiModel +import com.on.staccato.presentation.staccato.comments.CommentUiModel +import com.on.staccato.presentation.staccato.detail.StaccatoDetailUiModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class StaccatoViewModel + @Inject + constructor( + private val staccatoRepository: StaccatoRepository, + ) : ViewModel() { + private val _staccatoDetail = MutableLiveData() + val staccatoDetail: LiveData get() = _staccatoDetail + + private val _comments = MutableLiveData>() + val comments: LiveData> get() = _comments + + private val _feeling = MutableLiveData() + val feeling: LiveData get() = _feeling + + private val _isDeleted = MutableSingleLiveData(false) + val isDeleted: SingleLiveData get() = _isDeleted + + private val _errorMessage = MutableSingleLiveData() + val errorMessage: SingleLiveData get() = _errorMessage + + private val _exceptionMessage: MutableSingleLiveData = MutableSingleLiveData() + val exceptionMessage: SingleLiveData get() = _exceptionMessage + + fun loadStaccato(staccatoId: Long) { + fetchStaccatoData(staccatoId) + } + + fun deleteStaccato(staccatoId: Long) = + viewModelScope.launch { + staccatoRepository.deleteStaccato(staccatoId) + .onSuccess { + _isDeleted.postValue(true) + }.onException(::handleException) + .onServerError(::handleServerError) + } + + private fun fetchStaccatoData(staccatoId: Long) { + viewModelScope.launch { + staccatoRepository.getStaccato(staccatoId) + .onSuccess { staccato -> + _staccatoDetail.value = staccato.toStaccatoDetailUiModel() + _feeling.value = staccato.feeling + }.onException(::handleException) + .onServerError(::handleServerError) + } + } + + private fun handleServerError( + status: Status, + errorMessage: String, + ) { + _errorMessage.postValue(errorMessage) + } + + private fun handleException( + e: Throwable, + message: String, + ) { + _exceptionMessage.postValue(message) + } + } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/CurrentLocationHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/CurrentLocationHandler.kt similarity index 57% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/CurrentLocationHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/CurrentLocationHandler.kt index eabb88ec2..1861e03df 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/CurrentLocationHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/CurrentLocationHandler.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation +package com.on.staccato.presentation.staccatocreation interface CurrentLocationHandler { fun onCurrentLocationClicked() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/OnUrisSelectedListener.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/OnUrisSelectedListener.kt similarity index 65% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/OnUrisSelectedListener.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/OnUrisSelectedListener.kt index 50b5d3d66..bf771f934 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/OnUrisSelectedListener.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/OnUrisSelectedListener.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation +package com.on.staccato.presentation.staccatocreation import android.net.Uri diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationActivity.kt similarity index 79% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationActivity.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationActivity.kt index de4803cfe..244726521 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationActivity.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation +package com.on.staccato.presentation.staccatocreation import android.content.Context import android.content.Intent @@ -21,8 +21,9 @@ import com.google.android.gms.location.LocationServices import com.google.android.gms.location.Priority import com.google.android.gms.tasks.Task import com.google.android.libraries.places.api.model.Place +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R -import com.on.staccato.databinding.ActivityVisitCreationBinding +import com.on.staccato.databinding.ActivityStaccatoCreationBinding import com.on.staccato.presentation.base.BindingActivity import com.on.staccato.presentation.common.CustomAutocompleteSupportFragment import com.on.staccato.presentation.common.GooglePlaceFragmentEventHandler @@ -31,15 +32,16 @@ import com.on.staccato.presentation.common.LocationPermissionManager.Companion.l import com.on.staccato.presentation.common.PhotoAttachFragment import com.on.staccato.presentation.main.viewmodel.SharedViewModel import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.momentcreation.adapter.PhotoAttachAdapter -import com.on.staccato.presentation.momentcreation.dialog.MemorySelectionFragment -import com.on.staccato.presentation.momentcreation.dialog.VisitedAtSelectionFragment -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel -import com.on.staccato.presentation.momentcreation.viewmodel.MomentCreationViewModel +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.STACCATO_ID_KEY +import com.on.staccato.presentation.staccatocreation.adapter.AttachedPhotoItemTouchHelperCallback +import com.on.staccato.presentation.staccatocreation.adapter.ItemDragListener +import com.on.staccato.presentation.staccatocreation.adapter.PhotoAttachAdapter +import com.on.staccato.presentation.staccatocreation.dialog.MemorySelectionFragment +import com.on.staccato.presentation.staccatocreation.dialog.VisitedAtSelectionFragment +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.viewmodel.StaccatoCreationViewModel +import com.on.staccato.presentation.util.getSnackBarWithAction import com.on.staccato.presentation.util.showToast -import com.on.staccato.presentation.visitcreation.adapter.AttachedPhotoItemTouchHelperCallback -import com.on.staccato.presentation.visitcreation.adapter.ItemDragListener import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -47,14 +49,14 @@ import java.time.LocalDate import java.time.LocalDateTime @AndroidEntryPoint -class MomentCreationActivity : +class StaccatoCreationActivity : GooglePlaceFragmentEventHandler, CurrentLocationHandler, OnUrisSelectedListener, - MomentCreationHandler, - BindingActivity() { - override val layoutResourceId = R.layout.activity_visit_creation - private val viewModel: MomentCreationViewModel by viewModels() + StaccatoCreationHandler, + BindingActivity() { + override val layoutResourceId = R.layout.activity_staccato_creation + private val viewModel: StaccatoCreationViewModel by viewModels() private val sharedViewModel: SharedViewModel by viewModels() private val memorySelectionFragment by lazy { MemorySelectionFragment() @@ -82,6 +84,7 @@ class MomentCreationActivity : private lateinit var permissionRequestLauncher: ActivityResultLauncher> private lateinit var fusedLocationProviderClient: FusedLocationProviderClient private lateinit var address: String + private var currentSnackBar: Snackbar? = null override fun initStartView(savedInstanceState: Bundle?) { viewModel.fetchMemoryCandidates(memoryId) @@ -95,6 +98,8 @@ class MomentCreationActivity : initVisitedAtSelectionFragment() observeViewModelData() initGooglePlaceSearch() + showWarningMessage() + handleError() } override fun onResume() { @@ -111,14 +116,14 @@ class MomentCreationActivity : } override fun onNewPlaceSelected( - placeId: String, + id: String, name: String, address: String, longitude: Double, latitude: Double, ) { viewModel.selectNewPlace( - placeId, + id, name, address, longitude, @@ -158,7 +163,7 @@ class MomentCreationActivity : override fun onCreateDoneClicked() { window.setFlags(FLAG_NOT_TOUCHABLE, FLAG_NOT_TOUCHABLE) - viewModel.createMoment() + viewModel.createStaccato() } private fun setupPermissionRequestLauncher() { @@ -230,7 +235,7 @@ class MomentCreationActivity : private fun initBinding() { binding.lifecycleOwner = this binding.viewModel = viewModel - binding.visitCreationHandler = this + binding.staccatoCreationHandler = this binding.currentLocationHandler = this } @@ -257,7 +262,7 @@ class MomentCreationActivity : } private fun initToolbar() { - binding.toolbarVisitCreation.setNavigationOnClickListener { + binding.toolbarStaccatoCreation.setNavigationOnClickListener { finish() } } @@ -291,8 +296,9 @@ class MomentCreationActivity : viewModel.fetchPhotosUrlsByUris(this) } viewModel.currentPhotos.observe(this) { photos -> + photoAttachFragment.setCurrentImageCount(StaccatoCreationViewModel.MAX_PHOTO_NUMBER - photos.size) photoAttachAdapter.submitList( - listOf(AttachedPhotoUiModel.addPhotoButton).plus(photos.attachedPhotos), + listOf(AttachedPhotoUiModel.addPhotoButton, *photos.attachedPhotos.toTypedArray()), ) } viewModel.memoryCandidates.observe(this) { @@ -310,24 +316,16 @@ class MomentCreationActivity : visitedAtSelectionFragment.initKeyWithSelectedValues(selectedVisitedAt) } } - viewModel.createdStaccatoId.observe(this) { createdMomentId -> + viewModel.createdStaccatoId.observe(this) { createdStaccatoId -> val resultIntent = Intent() - .putExtra(STACCATO_ID_KEY, createdMomentId) + .putExtra(STACCATO_ID_KEY, createdStaccatoId) .putExtra(MEMORY_ID_KEY, memoryId) .putExtra(MEMORY_TITLE_KEY, memoryTitle) setResult(RESULT_OK, resultIntent) window.clearFlags(FLAG_NOT_TOUCHABLE) finish() } - viewModel.errorMessage.observe(this) { message -> - handleError(message) - } - } - - private fun handleError(errorMessage: String) { - window.clearFlags(FLAG_NOT_TOUCHABLE) - showToast(errorMessage) } private fun fetchAddress(location: Location) { @@ -347,7 +345,7 @@ class MomentCreationActivity : } private fun updateAddressByCurrentAddress(location: Location) { - val geocoder = Geocoder(this@MomentCreationActivity) + val geocoder = Geocoder(this@StaccatoCreationActivity) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val geocodeListener = initGeocodeListener() geocoder.getFromLocation( @@ -372,7 +370,7 @@ class MomentCreationActivity : } override fun onError(errorMessage: String?) { - showToast(getString(R.string.moment_creation_not_found_address)) + showToast(getString(R.string.staccato_creation_not_found_address)) } } @@ -382,10 +380,53 @@ class MomentCreationActivity : autocompleteFragment.setPlaceFields(placeFields) lifecycleScope.launchWhenCreated { - autocompleteFragment.setHint(getString(R.string.visit_creation_place_search)) + autocompleteFragment.setHint(getString(R.string.staccato_creation_place_search)) + } + } + + private fun showWarningMessage() { + viewModel.warningMessage.observe(this) { message -> + window.clearFlags(FLAG_NOT_TOUCHABLE) + showToast(message) + } + } + + private fun handleError() { + viewModel.error.observe(this) { error -> + when (error) { + is StaccatoCreationError.MemoryCandidates -> handleMemoryCandidatesFail(error) + is StaccatoCreationError.StaccatoCreation -> handleStaccatoCreateFail(error) + } } } + private fun handleMemoryCandidatesFail(error: StaccatoCreationError.MemoryCandidates) { + finish() + showToast(error.message) + } + + private fun handleStaccatoCreateFail(error: StaccatoCreationError.StaccatoCreation) { + window.clearFlags(FLAG_NOT_TOUCHABLE) + showExceptionSnackBar(error.message) { reCreateStaccato() } + } + + private fun reCreateStaccato() { + viewModel.createStaccato() + } + + private fun showExceptionSnackBar( + message: String, + onRetryAction: () -> Unit, + ) { + currentSnackBar = + binding.root.getSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = onRetryAction, + length = Snackbar.LENGTH_INDEFINITE, + ).apply { show() } + } + companion object { const val MEMORY_TITLE_KEY = "memoryTitle" @@ -395,7 +436,7 @@ class MomentCreationActivity : context: Context, activityLauncher: ActivityResultLauncher, ) { - Intent(context, MomentCreationActivity::class.java).apply { + Intent(context, StaccatoCreationActivity::class.java).apply { putExtra(MEMORY_ID_KEY, memoryId) putExtra(MEMORY_TITLE_KEY, memoryTitle) activityLauncher.launch(this) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationError.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationError.kt new file mode 100644 index 000000000..4a028bfd1 --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationError.kt @@ -0,0 +1,7 @@ +package com.on.staccato.presentation.staccatocreation + +sealed interface StaccatoCreationError { + data class MemoryCandidates(val message: String) : StaccatoCreationError + + data class StaccatoCreation(val message: String) : StaccatoCreationError +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationHandler.kt similarity index 54% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationHandler.kt index d897d5e14..be44fd08c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/MomentCreationHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/StaccatoCreationHandler.kt @@ -1,6 +1,6 @@ -package com.on.staccato.presentation.momentcreation +package com.on.staccato.presentation.staccatocreation -interface MomentCreationHandler { +interface StaccatoCreationHandler { fun onMemorySelectionClicked() fun onVisitedAtSelectionClicked() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/AttachedPhotoItemTouchHelperCallback.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/AttachedPhotoItemTouchHelperCallback.kt similarity index 93% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/AttachedPhotoItemTouchHelperCallback.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/AttachedPhotoItemTouchHelperCallback.kt index 6125d0d38..733698d32 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/AttachedPhotoItemTouchHelperCallback.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/AttachedPhotoItemTouchHelperCallback.kt @@ -1,8 +1,7 @@ -package com.on.staccato.presentation.visitcreation.adapter +package com.on.staccato.presentation.staccatocreation.adapter import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import com.on.staccato.presentation.momentcreation.adapter.PhotoAttachViewHolder class AttachedPhotoItemTouchHelperCallback( private val moveListener: ItemMoveListener, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemDragListener.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemDragListener.kt similarity index 57% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemDragListener.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemDragListener.kt index ae3aa42e8..fd2130f3c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemDragListener.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemDragListener.kt @@ -1,7 +1,7 @@ -package com.on.staccato.presentation.visitcreation.adapter +package com.on.staccato.presentation.staccatocreation.adapter import androidx.recyclerview.widget.RecyclerView -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel interface ItemDragListener { fun onStartDrag(viewHolder: RecyclerView.ViewHolder) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemMoveListener.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemMoveListener.kt similarity index 65% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemMoveListener.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemMoveListener.kt index d6c8a283c..899f0b011 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitcreation/adapter/ItemMoveListener.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/ItemMoveListener.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.visitcreation.adapter +package com.on.staccato.presentation.staccatocreation.adapter interface ItemMoveListener { fun onItemMove( diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachAdapter.kt similarity index 92% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachAdapter.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachAdapter.kt index bd43722f7..1f0f6a55c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachAdapter.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachAdapter.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.adapter +package com.on.staccato.presentation.staccatocreation.adapter import android.view.LayoutInflater import android.view.ViewGroup @@ -7,9 +7,7 @@ import androidx.recyclerview.widget.ListAdapter import com.on.staccato.databinding.ItemAddPhotoBinding import com.on.staccato.databinding.ItemAttachedPhotoBinding import com.on.staccato.presentation.common.AttachedPhotoHandler -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel -import com.on.staccato.presentation.visitcreation.adapter.ItemDragListener -import com.on.staccato.presentation.visitcreation.adapter.ItemMoveListener +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel class PhotoAttachAdapter( private val dragListener: ItemDragListener, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachViewHolder.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachViewHolder.kt similarity index 89% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachViewHolder.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachViewHolder.kt index 16cd2925a..4ac984bf7 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/adapter/PhotoAttachViewHolder.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/adapter/PhotoAttachViewHolder.kt @@ -1,11 +1,11 @@ -package com.on.staccato.presentation.momentcreation.adapter +package com.on.staccato.presentation.staccatocreation.adapter import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView import com.on.staccato.databinding.ItemAddPhotoBinding import com.on.staccato.databinding.ItemAttachedPhotoBinding import com.on.staccato.presentation.common.AttachedPhotoHandler -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel sealed class PhotoAttachViewHolder(binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) { diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionFragment.kt similarity index 97% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionFragment.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionFragment.kt index 9fb1d0ff9..47a54da67 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionFragment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionFragment.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.dialog +package com.on.staccato.presentation.staccatocreation.dialog import android.os.Bundle import android.view.LayoutInflater diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionHandler.kt similarity index 71% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionHandler.kt index 0a6c63353..c3df2f614 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/MemorySelectionHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/MemorySelectionHandler.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.dialog +package com.on.staccato.presentation.staccatocreation.dialog import com.on.staccato.domain.model.MemoryCandidate diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionFragment.kt similarity index 98% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionFragment.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionFragment.kt index 61cef45f5..3e4336467 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionFragment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionFragment.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.dialog +package com.on.staccato.presentation.staccatocreation.dialog import android.os.Bundle import android.view.LayoutInflater @@ -66,7 +66,7 @@ class VisitedAtSelectionFragment : BottomSheetDialogFragment() { view: View, savedInstanceState: Bundle?, ) { - binding.items = years + binding.years = years setupPickers() setupPickerListeners() initConfirmButton() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionHandler.kt similarity index 67% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionHandler.kt index 3205e8a8c..e6129124f 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/dialog/VisitedAtSelectionHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/dialog/VisitedAtSelectionHandler.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.dialog +package com.on.staccato.presentation.staccatocreation.dialog import java.time.LocalDateTime diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotoUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotoUiModel.kt similarity index 63% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotoUiModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotoUiModel.kt index 26aace123..554aa2c51 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotoUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotoUiModel.kt @@ -1,8 +1,8 @@ -package com.on.staccato.presentation.momentcreation.model +package com.on.staccato.presentation.staccatocreation.model import android.net.Uri -import com.on.staccato.presentation.momentcreation.adapter.PhotoAttachAdapter.Companion.ADD_PHOTO_BUTTON_URI -import com.on.staccato.presentation.momentcreation.adapter.PhotoAttachAdapter.Companion.ADD_PHOTO_BUTTON_URL +import com.on.staccato.presentation.staccatocreation.adapter.PhotoAttachAdapter.Companion.ADD_PHOTO_BUTTON_URI +import com.on.staccato.presentation.staccatocreation.adapter.PhotoAttachAdapter.Companion.ADD_PHOTO_BUTTON_URL data class AttachedPhotoUiModel( val uri: Uri? = null, diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotosUiModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotosUiModel.kt similarity index 96% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotosUiModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotosUiModel.kt index 59dcfde21..b055f4c4a 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/model/AttachedPhotosUiModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/model/AttachedPhotosUiModel.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.model +package com.on.staccato.presentation.staccatocreation.model import android.net.Uri diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/viewmodel/MomentCreationViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/viewmodel/StaccatoCreationViewModel.kt similarity index 78% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/viewmodel/MomentCreationViewModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/viewmodel/StaccatoCreationViewModel.kt index 9f305c4b8..6a6de9630 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/momentcreation/viewmodel/MomentCreationViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatocreation/viewmodel/StaccatoCreationViewModel.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.momentcreation.viewmodel +package com.on.staccato.presentation.staccatocreation.viewmodel import android.content.Context import android.location.Location @@ -9,32 +9,36 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.on.staccato.data.ApiResponseHandler.onException +import com.on.staccato.data.ApiResponseHandler.onServerError import com.on.staccato.data.ApiResponseHandler.onSuccess +import com.on.staccato.data.dto.Status import com.on.staccato.data.image.ImageDefaultRepository import com.on.staccato.domain.model.MemoryCandidate import com.on.staccato.domain.model.MemoryCandidates -import com.on.staccato.domain.repository.MomentRepository +import com.on.staccato.domain.repository.StaccatoRepository import com.on.staccato.domain.repository.TimelineRepository import com.on.staccato.presentation.common.AttachedPhotoHandler import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel -import com.on.staccato.presentation.momentcreation.model.AttachedPhotosUiModel +import com.on.staccato.presentation.staccatocreation.StaccatoCreationError +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotosUiModel import com.on.staccato.presentation.util.convertExcretaFile import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Job +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.time.LocalDate import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel -class MomentCreationViewModel +class StaccatoCreationViewModel @Inject constructor( private val timelineRepository: TimelineRepository, - private val momentRepository: MomentRepository, + private val staccatoRepository: StaccatoRepository, private val imageRepository: ImageDefaultRepository, ) : AttachedPhotoHandler, ViewModel() { val staccatoTitle = ObservableField() @@ -73,9 +77,6 @@ class MomentCreationViewModel private val _createdStaccatoId = MutableSingleLiveData() val createdStaccatoId: SingleLiveData get() = _createdStaccatoId - private val _errorMessage = MutableSingleLiveData() - val errorMessage: SingleLiveData get() = _errorMessage - private val _isPosting = MutableLiveData(false) val isPosting: LiveData get() = _isPosting @@ -87,9 +88,15 @@ class MomentCreationViewModel private val _isPlaceSearchClicked = MutableLiveData(false) val isPlaceSearchClicked: LiveData get() = _isPlaceSearchClicked + private val _warningMessage = MutableSingleLiveData() + val warningMessage: SingleLiveData get() = _warningMessage + + private val _error = MutableSingleLiveData() + val error: SingleLiveData get() = _error + override fun onAddClicked() { if ((currentPhotos.value?.size ?: 0) == MAX_PHOTO_NUMBER) { - _errorMessage.postValue(MAX_PHOTO_NUMBER_MESSAGE) + _warningMessage.postValue(MAX_PHOTO_NUMBER_MESSAGE) } else { _isAddPhotoClicked.postValue(true) } @@ -153,7 +160,8 @@ class MomentCreationViewModel if (memoryCandidates.memoryCandidate.isNotEmpty()) { initSelectedMemoryAndVisitedAt(memoryId, memoryCandidates.memoryCandidate) } - } + }.onException(::handleMemoryCandidatesException) + .onServerError(::handleServerError) } } @@ -213,10 +221,10 @@ class MomentCreationViewModel } } - fun createMoment() = + fun createStaccato() = viewModelScope.launch { _isPosting.value = true - momentRepository.createMoment( + staccatoRepository.createStaccato( memoryId = selectedMemory.value!!.memoryId, staccatoTitle = staccatoTitle.get() ?: return@launch, placeName = placeName.value ?: return@launch, @@ -224,13 +232,11 @@ class MomentCreationViewModel longitude = longitude.value ?: return@launch, address = address.value ?: return@launch, visitedAt = selectedVisitedAt.value ?: return@launch, - momentImageUrls = currentPhotos.value!!.attachedPhotos.map { it.imageUrl!! }, + staccatoImageUrls = currentPhotos.value!!.attachedPhotos.map { it.imageUrl!! }, ).onSuccess { response -> - _createdStaccatoId.postValue(response.momentId) - }.onFailure { - _isPosting.value = false - _errorMessage.postValue(it.message ?: "방문을 생성할 수 없어요!") - } + _createdStaccatoId.postValue(response.staccatoId) + }.onException(::handleCreateException) + .onServerError(::handleServerError) } private fun createPhotoUploadJob( @@ -241,15 +247,15 @@ class MomentCreationViewModel imageRepository.convertImageFileToUrl(multiPartBody) .onSuccess { updatePhotoWithUrl(photo, it.imageUrl) + }.onException { e, message -> + if (this.isActive) handleException(e, message) } - .onException { _, message -> - _errorMessage.postValue(message) - } + .onServerError(::handleServerError) } private fun buildCoroutineExceptionHandler(): CoroutineExceptionHandler { return CoroutineExceptionHandler { _, throwable -> - _errorMessage.postValue(throwable.message ?: "이미지 업로드에 실패했습니다.") + _warningMessage.postValue(throwable.message ?: FAIL_IMAGE_UPLOAD_MESSAGE) } } @@ -261,9 +267,41 @@ class MomentCreationViewModel _currentPhotos.value = currentPhotos.value?.updateOrAppendPhoto(updatedPhoto) } + private fun handleServerError( + status: Status, + errorMessage: String, + ) { + _isPosting.value = false + _warningMessage.postValue(errorMessage) + } + + private fun handleException( + e: Throwable, + errorMessage: String, + ) { + _isPosting.value = false + _warningMessage.postValue(errorMessage) + } + + private fun handleMemoryCandidatesException( + e: Throwable, + message: String, + ) { + _error.setValue(StaccatoCreationError.MemoryCandidates(message)) + } + + private fun handleCreateException( + e: Throwable, + message: String, + ) { + _isPosting.value = false + _error.setValue(StaccatoCreationError.StaccatoCreation(message)) + } + companion object { const val MAX_PHOTO_NUMBER = 5 const val MAX_PHOTO_NUMBER_MESSAGE = "사진은 최대 ${MAX_PHOTO_NUMBER}장만 첨부할 수 있어요!" + const val FAIL_IMAGE_UPLOAD_MESSAGE = "이미지 업로드에 실패했습니다." const val FORM_DATA_NAME = "imageFile" } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateActivity.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateActivity.kt similarity index 77% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateActivity.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateActivity.kt index 971ce66bc..3f7059bd3 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateActivity.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateActivity.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.visitupdate +package com.on.staccato.presentation.staccatoupdate import android.content.Context import android.content.Intent @@ -21,8 +21,9 @@ import com.google.android.gms.location.LocationServices import com.google.android.gms.location.Priority import com.google.android.gms.tasks.Task import com.google.android.libraries.places.api.model.Place +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R -import com.on.staccato.databinding.ActivityVisitUpdateBinding +import com.on.staccato.databinding.ActivityStaccatoUpdateBinding import com.on.staccato.presentation.base.BindingActivity import com.on.staccato.presentation.common.CustomAutocompleteSupportFragment import com.on.staccato.presentation.common.GooglePlaceFragmentEventHandler @@ -32,17 +33,19 @@ import com.on.staccato.presentation.common.PhotoAttachFragment import com.on.staccato.presentation.main.viewmodel.SharedViewModel import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_TITLE_KEY -import com.on.staccato.presentation.moment.MomentFragment.Companion.STACCATO_ID_KEY -import com.on.staccato.presentation.momentcreation.CurrentLocationHandler -import com.on.staccato.presentation.momentcreation.OnUrisSelectedListener -import com.on.staccato.presentation.momentcreation.adapter.PhotoAttachAdapter -import com.on.staccato.presentation.momentcreation.dialog.MemorySelectionFragment -import com.on.staccato.presentation.momentcreation.dialog.VisitedAtSelectionFragment -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccato.StaccatoFragment.Companion.STACCATO_ID_KEY +import com.on.staccato.presentation.staccatocreation.CurrentLocationHandler +import com.on.staccato.presentation.staccatocreation.OnUrisSelectedListener +import com.on.staccato.presentation.staccatocreation.adapter.AttachedPhotoItemTouchHelperCallback +import com.on.staccato.presentation.staccatocreation.adapter.ItemDragListener +import com.on.staccato.presentation.staccatocreation.adapter.PhotoAttachAdapter +import com.on.staccato.presentation.staccatocreation.dialog.MemorySelectionFragment +import com.on.staccato.presentation.staccatocreation.dialog.VisitedAtSelectionFragment +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.viewmodel.StaccatoCreationViewModel +import com.on.staccato.presentation.staccatoupdate.viewmodel.StaccatoUpdateViewModel +import com.on.staccato.presentation.util.getSnackBarWithAction import com.on.staccato.presentation.util.showToast -import com.on.staccato.presentation.visitcreation.adapter.AttachedPhotoItemTouchHelperCallback -import com.on.staccato.presentation.visitcreation.adapter.ItemDragListener -import com.on.staccato.presentation.visitupdate.viewmodel.VisitUpdateViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -50,14 +53,14 @@ import java.time.LocalDate import java.time.LocalDateTime @AndroidEntryPoint -class VisitUpdateActivity : +class StaccatoUpdateActivity : GooglePlaceFragmentEventHandler, CurrentLocationHandler, OnUrisSelectedListener, - VisitUpdateHandler, - BindingActivity() { - override val layoutResourceId = R.layout.activity_visit_update - private val viewModel: VisitUpdateViewModel by viewModels() + StaccatoUpdateHandler, + BindingActivity() { + override val layoutResourceId = R.layout.activity_staccato_update + private val viewModel: StaccatoUpdateViewModel by viewModels() private val sharedViewModel: SharedViewModel by viewModels() private val memorySelectionFragment by lazy { MemorySelectionFragment() @@ -84,6 +87,7 @@ class VisitUpdateActivity : private lateinit var permissionRequestLauncher: ActivityResultLauncher> private lateinit var fusedLocationProviderClient: FusedLocationProviderClient private lateinit var address: String + private var currentSnackBar: Snackbar? = null override fun onNewPlaceSelected( placeId: String, @@ -133,7 +137,7 @@ class VisitUpdateActivity : override fun onUpdateDoneClicked() { window.setFlags(FLAG_NOT_TOUCHABLE, FLAG_NOT_TOUCHABLE) - viewModel.updateVisit(staccatoId) + viewModel.updateStaccato(staccatoId) } override fun initStartView(savedInstanceState: Bundle?) { @@ -147,6 +151,8 @@ class VisitUpdateActivity : initItemTouchHelper() observeViewModelData() initGooglePlaceSearch() + showWarningMessage() + handleError() viewModel.fetchTargetData(staccatoId, memoryId, memoryTitle) } @@ -224,7 +230,7 @@ class VisitUpdateActivity : private fun initBinding() { binding.lifecycleOwner = this binding.viewModel = viewModel - binding.visitUpdateHandler = this + binding.staccatoUpdateHandler = this binding.currentLocationHandler = this } @@ -251,7 +257,7 @@ class VisitUpdateActivity : } private fun initToolbar() { - binding.toolbarVisitUpdate.setNavigationOnClickListener { + binding.toolbarStaccatoUpdate.setNavigationOnClickListener { finish() } } @@ -288,8 +294,9 @@ class VisitUpdateActivity : viewModel.fetchPhotosUrlsByUris(this) } viewModel.currentPhotos.observe(this) { photos -> + photoAttachFragment.setCurrentImageCount(StaccatoCreationViewModel.MAX_PHOTO_NUMBER - photos.size) photoAttachAdapter.submitList( - listOf(AttachedPhotoUiModel.addPhotoButton).plus(photos.attachedPhotos), + listOf(AttachedPhotoUiModel.addPhotoButton, *photos.attachedPhotos.toTypedArray()), ) } viewModel.memoryCandidates.observe(this) { @@ -307,9 +314,6 @@ class VisitUpdateActivity : visitedAtSelectionFragment.initKeyWithSelectedValues(selectedVisitedAt) } } - viewModel.errorMessage.observe(this) { message -> - handleError(message) - } } private fun handleUpdateComplete(isUpdateCompleted: Boolean) { @@ -325,11 +329,6 @@ class VisitUpdateActivity : } } - private fun handleError(errorMessage: String) { - window.clearFlags(FLAG_NOT_TOUCHABLE) - showToast(errorMessage) - } - private fun fetchAddress(location: Location) { lifecycleScope.launch { val defaultDelayJob = @@ -347,7 +346,7 @@ class VisitUpdateActivity : } private fun updateAddressByCurrentAddress(location: Location) { - val geocoder = Geocoder(this@VisitUpdateActivity) + val geocoder = Geocoder(this@StaccatoUpdateActivity) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val geocodeListener = initGeocodeListener() geocoder.getFromLocation( @@ -372,7 +371,7 @@ class VisitUpdateActivity : } override fun onError(errorMessage: String?) { - showToast(getString(R.string.moment_creation_not_found_address)) + showToast(getString(R.string.staccato_creation_not_found_address)) } } @@ -382,20 +381,69 @@ class VisitUpdateActivity : autocompleteFragment.setPlaceFields(placeFields) lifecycleScope.launchWhenCreated { - autocompleteFragment.setHint(getString(R.string.visit_creation_place_search)) + autocompleteFragment.setHint(getString(R.string.staccato_creation_place_search)) + } + } + + private fun showWarningMessage() { + viewModel.warningMessage.observe(this) { message -> + window.clearFlags(FLAG_NOT_TOUCHABLE) + showToast(message) + } + } + + private fun handleError() { + viewModel.error.observe(this) { error -> + when (error) { + is StaccatoUpdateError.MemoryCandidates -> handleMemoryCandidatesFail(error) + is StaccatoUpdateError.StaccatoInitialize -> handleInitializeFail(error) + is StaccatoUpdateError.StaccatoUpdate -> handleStaccatoUpdateFail(error) + } } } + private fun handleMemoryCandidatesFail(error: StaccatoUpdateError.MemoryCandidates) { + finish() + showToast(error.message) + } + + private fun handleInitializeFail(error: StaccatoUpdateError.StaccatoInitialize) { + finish() + showToast(error.message) + } + + private fun handleStaccatoUpdateFail(error: StaccatoUpdateError.StaccatoUpdate) { + window.clearFlags(FLAG_NOT_TOUCHABLE) + showExceptionSnackBar(error.message) { reUpdateStaccato() } + } + + private fun reUpdateStaccato() { + viewModel.updateStaccato(staccatoId) + } + + private fun showExceptionSnackBar( + message: String, + onRetryAction: () -> Unit, + ) { + currentSnackBar = + binding.root.getSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = onRetryAction, + length = Snackbar.LENGTH_INDEFINITE, + ).apply { show() } + } + companion object { fun startWithResultLauncher( - visitId: Long, + staccatoId: Long, memoryId: Long, memoryTitle: String, context: Context, activityLauncher: ActivityResultLauncher, ) { - Intent(context, VisitUpdateActivity::class.java).apply { - putExtra(STACCATO_ID_KEY, visitId) + Intent(context, StaccatoUpdateActivity::class.java).apply { + putExtra(STACCATO_ID_KEY, staccatoId) putExtra(MEMORY_ID_KEY, memoryId) putExtra(MEMORY_TITLE_KEY, memoryTitle) activityLauncher.launch(this) diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateError.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateError.kt new file mode 100644 index 000000000..d02f38ebb --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateError.kt @@ -0,0 +1,9 @@ +package com.on.staccato.presentation.staccatoupdate + +sealed interface StaccatoUpdateError { + data class MemoryCandidates(val message: String) : StaccatoUpdateError + + data class StaccatoInitialize(val message: String) : StaccatoUpdateError + + data class StaccatoUpdate(val message: String) : StaccatoUpdateError +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateHandler.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateHandler.kt similarity index 55% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateHandler.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateHandler.kt index 733938c0d..a7253c41e 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/VisitUpdateHandler.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/StaccatoUpdateHandler.kt @@ -1,6 +1,6 @@ -package com.on.staccato.presentation.visitupdate +package com.on.staccato.presentation.staccatoupdate -interface VisitUpdateHandler { +interface StaccatoUpdateHandler { fun onUpdateDoneClicked() fun onMemorySelectionClicked() diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/viewmodel/VisitUpdateViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/viewmodel/StaccatoUpdateViewModel.kt similarity index 69% rename from android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/viewmodel/VisitUpdateViewModel.kt rename to android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/viewmodel/StaccatoUpdateViewModel.kt index 68331c36b..956cfd104 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/visitupdate/viewmodel/VisitUpdateViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/staccatoupdate/viewmodel/StaccatoUpdateViewModel.kt @@ -1,4 +1,4 @@ -package com.on.staccato.presentation.visitupdate.viewmodel +package com.on.staccato.presentation.staccatoupdate.viewmodel import android.content.Context import android.location.Location @@ -9,34 +9,39 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.on.staccato.data.ApiResponseHandler.onException +import com.on.staccato.data.ApiResponseHandler.onServerError import com.on.staccato.data.ApiResponseHandler.onSuccess +import com.on.staccato.data.dto.Status import com.on.staccato.domain.model.MemoryCandidate import com.on.staccato.domain.model.MemoryCandidates import com.on.staccato.domain.repository.ImageRepository -import com.on.staccato.domain.repository.MomentRepository +import com.on.staccato.domain.repository.StaccatoRepository import com.on.staccato.domain.repository.TimelineRepository import com.on.staccato.presentation.common.AttachedPhotoHandler import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData -import com.on.staccato.presentation.momentcreation.model.AttachedPhotoUiModel -import com.on.staccato.presentation.momentcreation.model.AttachedPhotosUiModel -import com.on.staccato.presentation.momentcreation.model.AttachedPhotosUiModel.Companion.createPhotosByUrls -import com.on.staccato.presentation.momentcreation.viewmodel.MomentCreationViewModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotoUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotosUiModel +import com.on.staccato.presentation.staccatocreation.model.AttachedPhotosUiModel.Companion.createPhotosByUrls +import com.on.staccato.presentation.staccatocreation.viewmodel.StaccatoCreationViewModel +import com.on.staccato.presentation.staccatocreation.viewmodel.StaccatoCreationViewModel.Companion.FAIL_IMAGE_UPLOAD_MESSAGE +import com.on.staccato.presentation.staccatoupdate.StaccatoUpdateError import com.on.staccato.presentation.util.convertExcretaFile import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Job import kotlinx.coroutines.async +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.time.LocalDateTime import javax.inject.Inject @HiltViewModel -class VisitUpdateViewModel +class StaccatoUpdateViewModel @Inject constructor( private val timelineRepository: TimelineRepository, - private val momentRepository: MomentRepository, + private val staccatoRepository: StaccatoRepository, private val imageRepository: ImageRepository, ) : AttachedPhotoHandler, ViewModel() { val staccatoTitle = ObservableField() @@ -77,9 +82,6 @@ class VisitUpdateViewModel private val _isUpdateCompleted = MutableLiveData(false) val isUpdateCompleted: LiveData get() = _isUpdateCompleted - private val _errorMessage = MutableSingleLiveData() - val errorMessage: SingleLiveData get() = _errorMessage - private val _isPosting = MutableLiveData(false) val isPosting: LiveData get() = _isPosting @@ -88,9 +90,15 @@ class VisitUpdateViewModel private val photoJobs = mutableMapOf() + private val _warningMessage = MutableSingleLiveData() + val warningMessage: SingleLiveData get() = _warningMessage + + private val _error = MutableSingleLiveData() + val error: SingleLiveData get() = _error + override fun onAddClicked() { - if ((currentPhotos.value?.size ?: 0) == MomentCreationViewModel.MAX_PHOTO_NUMBER) { - _errorMessage.postValue(MomentCreationViewModel.MAX_PHOTO_NUMBER_MESSAGE) + if ((currentPhotos.value?.size ?: 0) == StaccatoCreationViewModel.MAX_PHOTO_NUMBER) { + _warningMessage.postValue(StaccatoCreationViewModel.MAX_PHOTO_NUMBER_MESSAGE) } else { _isAddPhotoClicked.postValue(true) } @@ -176,21 +184,21 @@ class VisitUpdateViewModel } } - fun updateVisit(staccatoId: Long) { + fun updateStaccato(staccatoId: Long) { viewModelScope.launch { - val staccatoTitleValue = staccatoTitle.get() ?: return@launch handleError() - val placeNameValue = placeName.value ?: return@launch handleError() - val addressValue = address.value ?: return@launch handleError() - val latitudeValue = latitude.value ?: return@launch handleError() - val longitudeValue = longitude.value ?: return@launch handleError() - val visitedAtValue = selectedVisitedAt.value ?: return@launch handleError() - val memoryIdValue = selectedMemory.value?.memoryId ?: return@launch handleError() - val momentImageUrlsValue = + val staccatoTitleValue = staccatoTitle.get() ?: return@launch handleException() + val placeNameValue = placeName.value ?: return@launch handleException() + val addressValue = address.value ?: return@launch handleException() + val latitudeValue = latitude.value ?: return@launch handleException() + val longitudeValue = longitude.value ?: return@launch handleException() + val visitedAtValue = selectedVisitedAt.value ?: return@launch handleException() + val memoryIdValue = selectedMemory.value?.memoryId ?: return@launch handleException() + val staccatoImageUrlsValue = currentPhotos.value?.attachedPhotos?.map { it.imageUrl!! } ?: emptyList() _isPosting.value = true - momentRepository.updateMoment( - momentId = staccatoId, + staccatoRepository.updateStaccato( + staccatoId = staccatoId, staccatoTitle = staccatoTitleValue, placeName = placeNameValue, address = addressValue, @@ -198,18 +206,17 @@ class VisitUpdateViewModel longitude = longitudeValue, visitedAt = visitedAtValue, memoryId = memoryIdValue, - momentImageUrls = momentImageUrlsValue, + staccatoImageUrls = staccatoImageUrlsValue, ).onSuccess { _isUpdateCompleted.postValue(true) - }.onFailure { e -> - handleError(e.message) - } + }.onException(::handleUpdateException) + .onServerError(::handleServerError) } } private fun fetchStaccatoBy(staccatoId: Long) { viewModelScope.launch { - momentRepository.getMoment(momentId = staccatoId) + staccatoRepository.getStaccato(staccatoId = staccatoId) .onSuccess { staccato -> staccatoTitle.set(staccato.staccatoTitle) _address.value = staccato.address @@ -217,7 +224,7 @@ class VisitUpdateViewModel _longitude.value = staccato.longitude _selectedVisitedAt.value = staccato.visitedAt _placeName.value = staccato.placeName - _currentPhotos.value = createPhotosByUrls(staccato.momentImageUrls) + _currentPhotos.value = createPhotosByUrls(staccato.staccatoImageUrls) _selectedMemory.value = MemoryCandidate( staccato.memoryId, @@ -225,9 +232,8 @@ class VisitUpdateViewModel staccato.startAt, staccato.endAt, ) - }.onFailure { e -> - _errorMessage.postValue(e.message ?: "알 수 없는 오류가 발생했습니다.") - } + }.onException(::handleInitializeException) + .onServerError(::handleServerError) } } @@ -236,7 +242,8 @@ class VisitUpdateViewModel timelineRepository.getMemoryCandidates() .onSuccess { memoryCandidates -> _memoryCandidates.value = memoryCandidates - } + }.onException(::handleMemoryCandidatesException) + .onServerError(::handleServerError) } } @@ -248,20 +255,20 @@ class VisitUpdateViewModel convertExcretaFile( context, photo.uri, - MomentCreationViewModel.FORM_DATA_NAME, + StaccatoCreationViewModel.FORM_DATA_NAME, ) imageRepository.convertImageFileToUrl(multiPartBody) .onSuccess { updatePhotoWithUrl(photo, it.imageUrl) + }.onException { e, message -> + if (this.isActive) handleUpdatePhotoException(e, message) } - .onException { _, message -> - _errorMessage.postValue(message) - } + .onServerError(::handleServerError) } private fun buildCoroutineExceptionHandler(): CoroutineExceptionHandler { return CoroutineExceptionHandler { _, throwable -> - _errorMessage.postValue(throwable.message ?: "이미지 업로드에 실패했습니다.") + _warningMessage.postValue(throwable.message ?: FAIL_IMAGE_UPLOAD_MESSAGE) } } @@ -273,13 +280,53 @@ class VisitUpdateViewModel _currentPhotos.value = currentPhotos.value?.updateOrAppendPhoto(updatedPhoto) } - private fun handleError() { + private fun handleServerError( + status: Status, + message: String, + ) { + _isPosting.value = false + _warningMessage.setValue(message) + } + + private fun handleUpdatePhotoException( + e: Throwable = IllegalArgumentException(), + errorMessage: String = IMAGE_UPLOAD_ERROR_MESSAGE, + ) { + _warningMessage.setValue(errorMessage) + } + + private fun handleException( + e: Throwable = IllegalArgumentException(), + errorMessage: String = REQUIRED_VALUES_ERROR_MESSAGE, + ) { _isPosting.value = false - _errorMessage.postValue("알 수 없는 오류가 발생했습니다.") + _warningMessage.setValue(errorMessage) + } + + private fun handleMemoryCandidatesException( + e: Throwable, + message: String, + ) { + _error.setValue(StaccatoUpdateError.MemoryCandidates(message)) } - private fun handleError(errorMessage: String?) { + private fun handleInitializeException( + e: Throwable, + message: String, + ) { + _error.setValue(StaccatoUpdateError.StaccatoInitialize(message)) + } + + private fun handleUpdateException( + e: Throwable = IllegalArgumentException(), + message: String = REQUIRED_VALUES_ERROR_MESSAGE, + ) { _isPosting.value = false - _errorMessage.postValue(errorMessage ?: "알 수 없는 오류가 발생했습니다.") + _error.setValue(StaccatoUpdateError.StaccatoUpdate(message)) + } + + companion object { + private const val IMAGE_UPLOAD_ERROR_MESSAGE = "이미지 업로드에 실패했습니다." + private const val REQUIRED_VALUES_ERROR_MESSAGE = "필수 값을 모두 입력해 주세요." } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/TimelineFragment.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/TimelineFragment.kt index f8d0247c9..f3a3fc900 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/TimelineFragment.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/TimelineFragment.kt @@ -1,11 +1,14 @@ package com.on.staccato.presentation.timeline import android.os.Bundle +import android.view.Gravity import android.view.View +import android.widget.PopupMenu import androidx.core.os.bundleOf import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.google.android.material.snackbar.Snackbar import com.on.staccato.R import com.on.staccato.databinding.FragmentTimelineBinding import com.on.staccato.presentation.base.BindingFragment @@ -14,7 +17,9 @@ import com.on.staccato.presentation.main.viewmodel.SharedViewModel import com.on.staccato.presentation.memory.MemoryFragment.Companion.MEMORY_ID_KEY import com.on.staccato.presentation.memorycreation.MemoryCreationActivity import com.on.staccato.presentation.timeline.adapter.TimelineAdapter +import com.on.staccato.presentation.timeline.model.SortType import com.on.staccato.presentation.timeline.viewmodel.TimelineViewModel +import com.on.staccato.presentation.util.showSnackBarWithAction import com.on.staccato.presentation.util.showToast import dagger.hilt.android.AndroidEntryPoint @@ -49,7 +54,10 @@ class TimelineFragment : } override fun onSortClicked() { - showToast(getString(R.string.all_default_not_supported)) + val sortButton = binding.btnTimelineSortMemories + val popup = sortButton.inflateCreationMenu() + setUpCreationMenu(popup) + popup.show() } private fun setupBinding() { @@ -69,17 +77,53 @@ class TimelineFragment : private fun setUpObserving() { timelineViewModel.timeline.observe(viewLifecycleOwner) { timeline -> - adapter.updateTimeline(timeline) + adapter.updateTimeline(timeline) { + binding.rvTimeline.scrollToPosition(0) + } } timelineViewModel.errorMessage.observe(viewLifecycleOwner) { message -> showToast(message) } + timelineViewModel.exceptionMessage.observe(viewLifecycleOwner) { message -> + view?.showSnackBarWithAction( + message = message, + actionLabel = R.string.all_retry, + onAction = ::onRetryAction, + Snackbar.LENGTH_INDEFINITE, + ) + } + sharedViewModel.isTimelineUpdated.observe(viewLifecycleOwner) { isUpdated -> if (isUpdated) { timelineViewModel.loadTimeline() } } } + + private fun View.inflateCreationMenu(): PopupMenu { + val popup = + PopupMenu( + this.context, + this, + Gravity.END, + 0, + R.style.Theme_Staccato_AN_PopupMenu, + ) + popup.menuInflater.inflate(R.menu.menu_sort, popup.menu) + return popup + } + + private fun setUpCreationMenu(popup: PopupMenu) { + popup.setOnMenuItemClickListener { menuItem -> + val sortType: SortType = SortType.from(menuItem.itemId) + timelineViewModel.sortTimeline(sortType) + false + } + } + + private fun onRetryAction() { + timelineViewModel.loadTimeline() + } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/adapter/TimelineAdapter.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/adapter/TimelineAdapter.kt index aa0c2b6bc..dae0d260c 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/adapter/TimelineAdapter.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/adapter/TimelineAdapter.kt @@ -30,8 +30,11 @@ class TimelineAdapter(private val eventHandler: TimelineHandler) : holder.bind(currentList[position]) } - fun updateTimeline(newTimeline: List) { - submitList(newTimeline) + fun updateTimeline( + newTimeline: List, + commitCallback: Runnable?, + ) { + submitList(newTimeline, commitCallback) } companion object { diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/model/SortType.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/model/SortType.kt new file mode 100644 index 000000000..feb2815bf --- /dev/null +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/model/SortType.kt @@ -0,0 +1,19 @@ +package com.on.staccato.presentation.timeline.model + +import androidx.annotation.MenuRes +import com.on.staccato.R + +enum class SortType( + @MenuRes val menuId: Int, +) { + CREATION(R.id.creation_order), + LATEST(R.id.latest_order), + OLDEST(R.id.oldest_order), + WITH_PERIOD(R.id.with_period_order), + WITHOUT_PERIOD(R.id.without_period_order), + ; + + companion object { + fun from(menuId: Int): SortType = entries.first { it.menuId == menuId } + } +} diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/viewmodel/TimelineViewModel.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/viewmodel/TimelineViewModel.kt index 6fc1866c6..624a53251 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/viewmodel/TimelineViewModel.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/timeline/viewmodel/TimelineViewModel.kt @@ -14,6 +14,7 @@ import com.on.staccato.domain.repository.TimelineRepository import com.on.staccato.presentation.common.MutableSingleLiveData import com.on.staccato.presentation.common.SingleLiveData import com.on.staccato.presentation.mapper.toTimelineUiModel +import com.on.staccato.presentation.timeline.model.SortType import com.on.staccato.presentation.timeline.model.TimelineUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineExceptionHandler @@ -30,13 +31,19 @@ class TimelineViewModel val timeline: LiveData> get() = _timeline + private val _isTimelineLoading = MutableLiveData(false) + val isTimelineLoading: LiveData + get() = _isTimelineLoading + private val _errorMessage = MutableSingleLiveData() val errorMessage: SingleLiveData get() = _errorMessage - private val _isTimelineLoading = MutableLiveData(false) - val isTimelineLoading: LiveData - get() = _isTimelineLoading + private val _exceptionMessage = MutableSingleLiveData() + val exceptionMessage: SingleLiveData + get() = _exceptionMessage + + private var originalTimeline = listOf() private val coroutineExceptionHandler = CoroutineExceptionHandler { context, throwable -> @@ -60,36 +67,54 @@ class TimelineViewModel } } + fun sortTimeline(type: SortType) { + when (type) { + SortType.CREATION -> sortByCreation() + SortType.LATEST -> sortByLatest() + SortType.OLDEST -> sortByOldest() + SortType.WITH_PERIOD -> filterWithPeriod() + SortType.WITHOUT_PERIOD -> filterWithoutPeriod() + } + } + private fun setTimelineUiModels(timeline: Timeline) { _timeline.value = timeline.toTimelineUiModel() + originalTimeline = _timeline.value ?: emptyList() _isTimelineLoading.value = false } + private fun sortByCreation() { + _timeline.value = originalTimeline + } + + private fun sortByLatest() { + _timeline.value = originalTimeline.sortedByDescending { it.startAt } + } + + private fun sortByOldest() { + val memoriesSortedByOldest = originalTimeline.sortedWith(compareBy(nullsLast()) { it.startAt }) + _timeline.value = memoriesSortedByOldest + } + + private fun filterWithPeriod() { + _timeline.value = originalTimeline.filter { it.startAt != null }.sortedByDescending { it.startAt } + } + + private fun filterWithoutPeriod() { + _timeline.value = originalTimeline.filter { it.startAt == null } + } + private fun handleServerError( status: Status, errorMessage: String, ) { _errorMessage.postValue(errorMessage) - when (status) { - is Status.Code -> - Log.e( - "TimelineViewModel", - "An error occurred: ${status.code}, $errorMessage", - ) - - is Status.Message -> - Log.e( - "TimelineViewModel", - "An error occurred: ${status.message}, $errorMessage", - ) - } } private fun handleException( e: Throwable, errorMessage: String, ) { - _errorMessage.postValue(errorMessage) - Log.e("TimelineViewModel", "An exception occurred: $e, $errorMessage") + _exceptionMessage.postValue(errorMessage) } } diff --git a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/util/MessageUtils.kt b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/util/MessageUtils.kt index 47328701c..87bc011e8 100644 --- a/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/util/MessageUtils.kt +++ b/android/Staccato_AN/app/src/main/java/com/on/staccato/presentation/util/MessageUtils.kt @@ -3,6 +3,7 @@ package com.on.staccato.presentation.util import android.content.Context import android.view.View import android.widget.Toast +import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.google.android.material.snackbar.Snackbar @@ -17,3 +18,27 @@ fun Fragment.showToast(message: String) { fun View.showSnackBar(message: String) { Snackbar.make(this, message, Snackbar.LENGTH_SHORT).show() } + +fun View.showSnackBarWithAction( + message: String, + @StringRes actionLabel: Int, + onAction: () -> Unit, + length: Int, +) { + val snackBar = + Snackbar.make(this, message, length) + .setAction(actionLabel) { + onAction() + } + snackBar.show() +} + +fun View.getSnackBarWithAction( + message: String, + @StringRes actionLabel: Int, + onAction: () -> Unit, + length: Int, +): Snackbar = + Snackbar.make(this, message, length).setAction(actionLabel) { + onAction() + } diff --git a/android/Staccato_AN/app/src/main/res/drawable-night-xxxhdpi/icon_location_pin_3x.png b/android/Staccato_AN/app/src/main/res/drawable-night-xxxhdpi/icon_location_pin_3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e47bb7e3b4aad666d9a43f407aab0a1fee4af56e GIT binary patch literal 16654 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 z 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 literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable-xxxhdpi/icon_location_pin_3x.png b/android/Staccato_AN/app/src/main/res/drawable-xxxhdpi/icon_location_pin_3x.png new file mode 100644 index 0000000000000000000000000000000000000000..36025f711c7280d46dd353c9421406d5aea10360 GIT binary patch literal 16515 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 literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/feeling_angry_note_gray.png b/android/Staccato_AN/app/src/main/res/drawable/feeling_angry_note_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..a7d7c27d397018bb25c587f0c6e181caa2c5cedd GIT binary patch literal 59377 zcmeEO&?L*r8W?}1(_nN|V3iSDkgEQeMzM!yfdz_OK9mqkPSnn3tqj*W)48>ylotLuaQ z`w>5pZO)SsZ}q11kW?%VXe^~Y|{wg<(1 z&wh;r)SBq&w@R5Rym1zB*%==4KlUE?$`zm{!U^v*VQQ=M*w_Bg_cu$^Q2B=1xFP~=L!DN@O`a?s#ilMMMs<*nuG^k z4I~p^b$&>X+4gHvoQlaGf;@;2@Ql2}MQe=8l2rjuA0O&*f-cXbns%SR54Y~+n)y<@ ziwYyaF}*NH^qKt#f;NIR8oRTdo8cs$f89S9o5Fs6tVqcx>~cL?Y&1Z&;sgxFbmhR230FO6y925n z99+o7BhOXdJS)LM9K0ZT{m9{-m&Qq>qRLZRKQDE-Sb{fK;P^3bTl-Bv>5x@BX3rk~ z7}>3ue1E*w1n43!J{huqalG2O)0RV^G^-SRGO1>-535eWsz~Gwx+?uYpfJr zuqh$~^JY;pvP+oU>~HXN%M5x4!rUT8!KFfPdeuMU$1zZ%l+IT!jWI?#Ea`h zN#e{_83@FQkM2*$6k)b0&?0E$<>h$~xk`?jbZsEj>;3#G@!Un$vP#-JTI__A7;a(b zsJ0F+gbpUYiie*T>bn~8V`E>);l2_&j9zC7Bk^KJ`F>xBWW_?aR!W8K z$&X?4T(an?7I0BuFn#XP>xg1hgMW;?6d1I9GcH13X=(>|tEQCT{CNNMO-#(|Gv+>L0);+uwu zCdQ*HCYLM_^pm~⌽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�vXDpxcc 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 CFR+-)8X{9jR@pMK%ejA;^!&rLFx<2I3&LLqe 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

XKTyzQtbJx8}sFkBX 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 literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/feeling_happy_note_gray.png b/android/Staccato_AN/app/src/main/res/drawable/feeling_happy_note_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..3af89c5ecdffb886dcc7c59db4595f4f1f8499c6 GIT binary patch literal 60743 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 F{tq~>i97%R literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note.png b/android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note.png new file mode 100644 index 0000000000000000000000000000000000000000..8bfb759e8d4601b81437c192b735e001402d1de4 GIT binary patch literal 117936 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

yw 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

4|-gxes0T$(AGU(Ah< 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 literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note_gray.png b/android/Staccato_AN/app/src/main/res/drawable/feeling_sad_note_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8ebf6cb55b99891aa33d9a2f969c24e91f6f9f GIT binary patch literal 59665 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 z zN9K9`j~7tNe$KkWVyYYy!<6YIn0075rp&Iy;frffF>w-`%8J>}?7R|(Or0Thk5EE+ z5xw|Jh;tvZIqk5rmugllu`kt$Vc+t;6XA!1WHzT2LYu!vL1xie5oPpBpjl$Fwl#*d9`IJ$;xI`#B@EpG$a zj~4Lu3mW;+v$PmS@a1ZyF`Sn*>G7!yCiVD0@8n(Z8H7JKwu0Q7%#i0;8~MxguQ%?( zfd@iYE{*)ur&8Zjcw>=?n}L`QT4rlgy2Bm_0ZR1)zF zlO-l&kJAuXnkh%)t)P;FSf15fVr9tTs6)Iwm9jPR6a8J?MR065a zPHfuPj4d15v14l|w%2u`ttn%9Bo6EGdjq%e`3Vk!RIyisKLw=kwZLw*D!B;&)j%r0 zgveRIZWzNL(zXeBG`NMJY09og2;1o=9acD zEvrix^1f0Uy+fa>_Hck3A2&7AGdmLWR91PHVmLt2!dl0@OAn`i*o`SK-F4T2uZ~># z%kkw;*CrP}^+xn_Egj^nOcvuNP+3Rww@M`9+XVH(aok|SRMvJ*njgpZwQ)Ienoo4Puz9P<`dW6u1E z7&E>Kr4{8c_!b4k7!W;>6Sbf3dknovS6;3yK>HYHf9QoAHrJF*L??xGv#y?=M>gAXD*8od*11TlanGPGF2rmU!eFFEXgDTV;7?k8i0u`QjY&%M5( z=`tK-c<={RWB%};$VZx5@S)Bmj$$NdEQH7YkX1>-C`MAt2=Zh22#_fWC=r%O=l*`w zb%{)iq<7HmArXIcj6`GUJt1__R&W_tZG-e38Jtu(nji z|Gun=Y77uev6&(;T3F?NW5#&%&v!l1vH}Mo_|(#h>&H+0_cPhE_ch~!)-D{!L`)f* zv5r`VcSLIJ)YX`X)mQQ=Rmnurwwr-7>Y};pm~h%9h)r)uj%>#ZL1JXP97uA_i7Voh zj)4ULOxR@|LT5;26AHnEa@|bQ?-$bLD(AVv1m9EGoN#iJ>}W-zqupu4mbF}8uBR%LE4Kt8ZgB)sE6|t5?tiM~erVvipH3^e|Mm7o8@3rA z-Pu4sk;-B+_Y1)k4_R3VI<_w^aUnjzBeI5Grz?g!{!1 zf2MerBA|^DUQLAwf*V$>vJ!#(5HFFl;c$i*F)(?05te;$JdRs35hc}Q5iKc4BoaqH zgNN|$QbX>E{T(dOzp@%g8RvbLYi+VAYgJUbs{_f-4n}mc*xS&F*K3>b=IVAd?@yz% zEn|-as9Gh&pc12X;3#VJ09D?jCD=Q zpA*KE-c9CKBrNYFycxI}ny`Tkg7U@7pzXDt%P#J;FI!$r)*Uj%{KFA5=yONU$JV7w zS~{@Q+PX$JxdRZRir}1kZguspU9sYHd)iuJpG9P;v+a9cL<~~D-LeA&FyAq zSxGcC)`+(}@XGEkXjr?E|9Q>WvZl`L__bTe;SH_igt|S(r&3v3Nw}{hs(K{$3#}X@ ztenobeB?;TYCpm84aU6e`V;cWX89R00?g_2%n_O*ebc$v4C>2X&bqO&zrqN;3Q5kM2V$yJjF3ztJ$i2tv3E)$b z1jC9r0wjWZVM2Bu@zOz0Ux$X?@ed3Lf?F|2$3S=m>dk%kn$!fTAS%vag>U*xBL;0R zD<&HbnS{H>lw_ZZRmFCnd_uhCoXdA70c}WpAcJ5OW67-QY7|G8^b{^yM7x$Ak*vG% zj*d~Y-NJB#E{Aa!E2=d+D$8L;C#~C#4{vY8`;%!pn@tN=GSLyGs#pE6KF^KLQ01JT zun5T0Si#;fT*xW>Le7KKUkGkOeb0h=WJo49;w8i&*~>c#?FYOJQ15wpYj$fx&j>-Z zn4o529Mfi3;rMrq!;D!KsHm<$yrj(8->Ub!rGyo9uKWI8f%wAYi!1blqGw@|@44PQ z-&f>{yT57mB_20zzU-U(wBh8Yy9?dTO-OX5uz7nsHm+&M&aK_px2GG4PSbK4DVFld zl{Ku_7imBuBz{eg{~PCOBuX02Nf_zzU+)i`G^qcQa}XGaSVds@%tF51Yz2uCQ{V0) z2C6y-6oVvt(_ZjRl1amaG1-Tw){wjA)tKu(a#HJ_S!K{Gqz)2{YJ#IN_~0aF&Gm@g zy`ggEn*GtETDow2XE!~mGl}_GlazB;=dd>mcLfdLYGH`b5*Q$S2PkJtDNpbSnBE>% zrs^-J$8MY;=(CzX?(`Yz^G<$bcRmWq0bFNcj<6F!sB>mXeZwAY`{MSEqOFO3SIa=$ z==k!E($WZ~&MLvQnWb#{sthv@sl=2?l_;t#L#()hk)a6sxL(&^F3`<+s1Ph$uC1Zj ztW9n*Da(ksv$YdDw$x+GmJY0as~!7xB+%KOwKm42PD^pMBNEFN@a(&UmI#i^U)iUD zM_2f2Y1iPNsJVqyUvq9n0)%RjoTT~$O69=@SEM*D9qgQiMepZjA|^l0lF1Dusz*H* z6y!v#EvDl!>?$uID-WAx-v0hG$m?U!+;z+zHXWr6i4PiRiKr0@K5g|do3?s%gL%l# zy*PzUTfMs@ffF)WR56L;Z1G{K=$$Dlo9{@X#w4DT94bjO$@{uuUeFr_0iqnjFqG`%*N1qWqm*~3lPvOc>dQ)tnWN;mO|3W7cLh| zaQn=V4%9X}wyBb=@sW*?1D!4jNi;|l?1&79?39#6Fl|;bj#yNMstFaCc4!sGO{iwq zOA(Q5b>#F!Y^t3Nl$2GYP%o!`3zgh-hxo$C@gne6DxvV($N(fHF2L_2Sbl@BzD`cT z?fwJ#&sB-?RR}pfWqS>3+t*kwT+FPsyLYO)-MW|RN@DlkHZ(V+uxnQr>Na;^_x2<@ znls2`sN$%PhUhQC>WG{ZIl}`H()lT|oJ@aHu}D}L2MsVA2a3&f$Z;*q7_D10zP_8B@9sdZaS&l3ZAarE0q^MV|1ru}uc?~% z##Wry&}N*L&R{0f&{t+DNRSGx-UP_3PI67A(PJt0?IgAupyd1|X8sF}9B4rlo^6kmdq$uNygH@Z7I(cF?o^WHAh zu5HD(jooP8mqwyH8*tJWMr^{~rY|{mH`we&xZZ5R;8D!{q2!q4eb1b!DFf0gN!l6t zJ;U0*xE{KbxFi?gEY$M6k`s&I@aOnoBo&X6o#iF;wYgL1olEAESC2WQxq(ebCG>RE z!3|AtGk3PSdh+Q91}jp4r4GRCxNCTi{*JE zf1MNL!tX3_$X-SKN)uY1ikkv3Bmpe#$HgHX817IK!C|L3_Ak>73&R-|=P%q@VD|oauocx%oIzsN%Np5PE>kIjFEXPTF4~8*@F!*bP_?mJ)L4!IvFKjRs>Z!Zj zsxD`ZdK}(eDVZZXrksv14hx30ix)TTW5mYZ{Vq)+Xp0iG7RAk-M;~JT;jlS)apvr{ z`Y}M)F_$BwjfgddqeIa+z`*Tu)&M21uc?@J|Fe;g?rOj}T`4k$nxvSC`Y01u5$Xv% zS?jJ49O7MHHgKdlK~ljHVsYK1YgmK{wtokS+l1rlZ2vPcZs1S2<{ z9cZZUWK&UHSiimlo8Ia|!`?K~NfzFOqwe$a8|pX7_nl=(yTD3iBE^TE-4ww0&hqz= z>z$uu!*}i(#u50vVT;&vzGJw?#^okN^=%b+ma5tx_cKd_4<1R@nld)5rQc>rjBX!4 zhCZ=q8Xh}gAznRXX6xP~rX#6++Gxno1V>{)*l{OH{_=R$;+HqzLwlOZIf)cznkFfw z)N`;$9PNlBAl)suiQ|L92|FAFN2JT)cM@m`S1R&r!0y6)ds#W!DYyR=Q&yq_kvn?1 zlMNfKQ;A*4D_s-{!49}#^2~W9c;{(jv2gwvrsWxjSZM{KF>a?5RS3plfns1fpj>hE zlulSY`Qi#AH^>vtB{Z3=y+@R@t2f_9fo3xnbxO2#i^@1m5A_^(&O_ ze5-20_C_4i+(8%ZZX{>5bQ;HHG8n^zTGS#kh9lE$jfgrb^Pt%93^rszDqZsrpsj4? zjKeoNbO!N;bnbQ_eSMKI`wELVv4V<6?G;!R)ltklq8vvbI}UT_PC!}BWXV3Kx7|J9 zrwo1Dg(+7$LqWBAlXmWOEdycpXKi-Lck)grn5L#1$qHM}9VlR=~-_V6uYn!lr zV>g=irO?upMwhcklof@fXYdmbJDp(KxyXg6G_d!@HsRYQM1-U8S>)!bAM$-EPXi%@ zGI~pJVjSOm=z$7COzUPJC!_73CakA9`O19lmTwymL| zKocB|0fUpASAL7gD_h2tZr?$x+tQg?yY?9$+0__1FO|haIQ2{-GlnI+8NuP|XlhSs zg^ld;O08V?{VYY&2+)wrkiDO}+IcmKU>d|#ut3s25kJ9kH4;*){(QTMIen-+S~q=R zqKxQNjE!RaggBfDgCY7wB(!G<%;_uVPX8yBeM)ZwKt6SQ%)<&ZzM4_QE zKsbWSq_nwh)%EBcdk7l-_E1TJ$?T3jt;YLP89F_iMHvgpr>D5^;2(@wyh%HnBLdpmM#@eLvB zY=WB?c{rM*vymT^%fux+>|!=U(b~YB%4M)`cM|*dc4Nn;c1$~@5;Zj?7(1pIMI}Xu z7MCzGBn*>{(6aQ(I=4-W|9j+mre|`ZGRNRuno}PX)Gqm4yE)6b#d$WHMkd(}%BG+A zFW261Em$&(;fSr7?~A`Xn0mr>x_Sc9W4HuIUjhLwzHE&nwgp0isG&y%^xL z`k_Q7+i<66B~v7SJ;+5`ynAXoKuG-&?A|c|%R_X;UZFgQGaXBvC~|MO8K}!p%8WQ= zY5=ag1yi&=Dn~)QYdj1S5FL}o(!1F26LY4~*N&LevFE~XL;JMR=oK`<(HJy1T8#{o zV62WxFU?NVSiJ~F=28A#?@4zxT+G7NDM)cuyT=d5IpvmYIxU1Lqe+r zG>i<9z?tl1iTL7{{Q2;5<90QS)MWX#3E8Z5-Ar|%qoo~9%?WgNWEr^uI@{A|U{g`+ z)^?zoks7{z0@v1<8AfihP`|zVRR#O-`Q0Jjck-%KSoiNQ7lp`)CyD&txys02PjeH@ z9N$K+`oYi^r%*Lk;vGeNo=Llxg6vz#{}pLiZbb7Su9GY|J*U9AW-AsY^(8U-#$hw@ zkBi>f_S~XHNN6KsjlO_DLt_YF4XA&P_|qt_{OLc)#f@!|3%inJe%7R=7zBiMt$lbD z(&LtzT$Z(_+PAt)gLqmW5s{JwY2-^}+YHiEMje9Fn|BHg!=C3mJ@7e^(lP^6W)@-Y z+%n9bGY;dYk3;2{QdCzK!Qe*8Oq~yl{i`(n0821yMA2AXPM=sf&HVf4E@*#j z5gRe-{i8Jc3Qce{h789aQ8l}~97bz1`AOEq2QfSlI|>s@eJTVgjPz@%%?+aNVlD}L z@oW3)@W$H8Ha;d*ws9a3n{`PFnp{LDY|P&0hUsmKVQ=yoCnzq9Fl|m8OHQc7;d84| zRx=Lqk`lyi=ORDq)KIV^4ZZ^)G$A=P1)&`?35`Pz#0iaQ ze~3&5-H8+_iakaJ*$5eq{yICdU#&4e7=h|um$5FC+~+%fo< z;^yrzrB0VfnUfirdJu%?3(z(Q;#*tAOAM5i+k|KKykg9mU505BN>Nr_isH&D#LKEI z|1V+!LZv!VUJ*`y)G)#A8oUV&kGzmPUAE;t*t9pZG(`b1Z4EaZZrr>LudQpr{`wT! zS~AvB?v}<3I@|bElxf*1<;a+?pp+jkm@izul~Q>@+_)(X-_F2r;fY=`8ue(D9Q<7U6Xyh$V5B5ZW6B=s+R$E*D)&R!*tSD zNIPg?a?D;3CerZjzc$hY$B%K9=Gi~`ueQgJy#i_U6Yn{p>ig~8_;6>E%){WJu6BLP zY-kh|G{Mmr6f9X-eHEh!Uvf@oVHhFV6gZ~7o_4?#Yj9<<1810=Z%A(2-dF==0|SU(ZIKeoxe@oS94lhKOz9Ab+tXeS%iwB* z2xA3V%duX!wFN?^JB3778jbBKG_)kq(ZMt@omtE9w{b5!=k_w)?7SS5RVSiM+Z<7&qUl<6@!E~N~KM{1~3k6f>G5(yG;;xJvptZHcFDXO0H zYSWI~HO7gTN*Wqxid2wxJ1y$l4u#m;q`=vC&Gb}kuC|iWVcSBbS6~@wW&gEAB4~{p zxa+w$TfUnw{D+s0ThN`%T(!H2oaM$rP|jYhic%88;G)hwisHQ5w_9qVF{01}M`J)( zGQavJ{sWuT%)&6kB`=WN(hD6vyt%3Y@(Fo&apH6$&T4XL#I7!~321v{XJ@V*L@zt! zp$1>TA2Doaf~9OKtFkpX z2Ui(IB?2VfQ)bD8j>UbBlM&yvk{~hE_BBITdoYA&0*MP+hV_n}Pj9r6BVuga6Igz; z(Fj`789Xp+0)2jG6FEF$&>GVuM=(;e2qO%p&}@&!=;n0FczMd0?CTFc-}Xyr3>!4T z(dacS`x@X<>xAOl7$Jz=x4G1|M)wq9whz_?Q|d8^n3{3J(a?@dRM{m z!*R7Y*7ugDjNG_X=}9QpF&YG1@tPW)hijx#7j z6hv>n>qwxy7;mzf&skX$6(}&UvQC#3VM9j}|5!95^TfFE@!FsNxv32rLkdlBGKhxJKua#j!+T{3OLO5+;&QJ!%ssB{jFo+I5LXZTeo$Y6zCsaF1LI$WyQW_pudF z#PY{S6x9?o27;Q(>_0n`#tYpk@{iheEp^ZsG8B}ByhdSx6ProniWe|)!{@h`v%jSn zA@C`aY13!oqZfP=3XLwtV!U$35%&U={6^anSc3PhCZ1x&Y(g=vstDC%t8w9F*WkSK zFNc{;A=%l${`R4}bq|{Nyn?#TYp`)^J+|y<#jd?gXm06Xnw_j=>tUMSLhxhb#}_VKg!g@XIVR3IGiMkx zlR_%df-a`<-Mi%(yz%^9_|NnEuwi>Ux|60mc_fw?`zyYG$+%}Y8YC{VEss2fMfFg& z;NX47o`szV<7WsxepTDhm%7Bkp*2+HQ@N+2d;~%vV$x3AB!?fSe31Ou*q*qZ|ETw} zq0^&cb)xGy%E^%BPl^3SnMQS7bsR@87=yFVI0iG0ybyo8STYe*lLbatJCas}Qw(u;hScgTt2>bJzWCXm8wtruv;|-1R2vx4nQ@ z-rkKZJ3E>1?Y1>LS!YF$a53v>SG>+fY@bPd$#{gu{)fTqI>9D3Q#5q}kW7Jj-quge_YnVsoIPn1LzdOK{ZUNjUMu6EW$~r6{Wyi>fgb zQBpk(=~NmWon4j&XZ1_Z;M-rj5*odSVbHbXE9r|F6o2*c7x(Xj#(<#-P62_gM(n5y zs~?rG#Uiwr4VcE6l#EGdF%I50Gb0hKWAdjdYg#@bT-2`b{Yb!Z(8u?QnuP))HXNMX z9DDr9=o{=ki_A>Yn##%~ThQIM8}<8lp<&++H11i;rnBD0ORw+7_C1|Qrdi>!0+fjj z35iqQd_c1CbndDRNt2u5g}j1J><$?k4yu-hNEe0n#R7%juEbppB`G!RV{h8W;SydH zMA|gdVG>mKjLq*;WyZ*h(0xvNM^QJaWS=Q z8%SZoxMCbOrwR)XI~LPs9f^rkrlMxjp(v}K2_sqpBNDUz&1OhG$okJCFoa;T>OuDNTAKQnk5X$} zg=!QK=FXjucb$0_X3m<4vp(=C3r@;PS#n8<)5+;AR!&6Uq2wu%mansko*EecCHs@m>L#Vgb%ykoBJ-gL6Fo0$c~63 zPg-GF4SU|N$#Vz=@lSQR_lZY}?8C6ap*i2*TDj!JD;veDWlTb8xM1DR>L)R~X6@m{ z5o1$ORpn7kWSW|Zp^dFkw3 zLg*#Q>H%s@!IuwAO-U}5l&S!SYRF_pw)ygdNE1qeRJ*%qsv*^Kq~87zLXl*7rDp%x zzXVaHGUi)y%$Pb3vkzT_nbT@8ZSpuwnm!L>CLe{;F>DIT;944{UN+oaMh1-b`gM5e zxySIge?DT_>S*LfJW9WJ>$h9~ck%g1L8H&m1ZRk`WL9-`tdbs67Qx(>F7j(=C@3$D zVdf!=aQ=mt57LxW-@&J^vguAFyBd+`*oQrJuj1|3U%=YUjO;YGpryGP^-Z1V=+3xX z6j+ddywSO1v`R5Tyv73YXPRMtXy4~P{`aHdy9IDW|@ zHB3`e%BFy;%44XhF2Tg9voUM>1RQ_#d`v!cDN3qmAQCOM|6<&>CXS&5x6!%r`(L+? zHPH!2ah%>crrP}3!%w$A3ynTQ6PzIgCpRdI`lRgv-8g1LiC|9t8nv zB9&}IH=DxhYTbs;=55%r_Bp)r_AYF!YeP$07gDKiq?0Km(wy+Xn$j|<*FhD6&5d8< z;y?BR20Qf7_z)gRSloUsk4S`4^-gcfNg-;|<9#h+>U-Qy-<>@Y1jfJ5hPx_B(!=!D z>$F+~N}QgDYoT4S9}uhfywWrzcISU*e-UsJW39t-w2gc(u^7|Rl*A(_Es3I}q!d#o zjlrB5RXF*$d6<6WCr~wUF`Ig-bTl+0hxeUvr1jh0-f9^rYbelua{38PaE1^|7E~|C z2ybmr$armCGe!gW((_bTGrHS%p|hzD^*dg|y4Rn=OK&w|+nz4eHz$$Kn2vU*AP9~y zFePDAN|L`p_gXHhA72 z(}!Y)HE7_P7O_uSm`#gao@#lyH)wbUBZj?4n`NiN;^qeX6UP?g2sVf~X7MD7JQ` zbQn_Ssu-R4?t9ZGUgw=llaz}zx%ncwNsy6`ajBq=c8yB2hy}6#mm#z{fa^8e%ACVc z?JM?oi5Mhw>W+I89#a{|__0MeWLi0nSTqZB7B96(OpN`NR8B*2`9u^~OwR91sz7l2 z?{CEKe)VH?bfux;KogvPK@*%I0GoEX2ll>A1+_|Pq;cX2$KVTJ_#&z&FR@6@XoRJm zp{C6u%#7`8C)J5dFML1hw$@pGbqW9;{}BFLWCwFZ3Pf{p0vp7CoJWH|d^cU+K{7Ft z;-bELY6xE(N_c-5DSzHIdBX(i*wzq-a|!>B1wnGWDL4|CCF4i&xPgk&7{*q`P*oN~ zWknoQCzLWWQ_0%WQHYm~Loxd+EgOr{3iew*4rSF-n0BVbnzu4Y)S9m%M#M50E_8IZ zx1o(qRlWS;)7n{}gW@>ede3p$&n^FByEazp1ESCvR4kcSeJeD%3E-UbK90{^@g-|F z@Znk|H59OSHjG#uPbQPZnw8(h&;POp>o;scL4tZ_HqPvY*!0o0y`jjl^4B*#6*^Z# z;jZ$rS%u7a>|fL2eAaf>P8Y6fiHPSB+DXzd+`PLaia<&O9@!DZ%A}qj7&v=CI-Egd z#dX-{WZ7M9jS+-f6oPdb6s1K`R5Pv2M5dKlJf{kC7QPeXrYt~Fya@545|ovfqr9TZ z(#~*$U~U*}@Fm>b>7Mi3-{ssRjk1bL>uCIcQ>M8`*T?RW&=h7j$eP%nr`tlBvf^^ z?>VUB5Su>}kL(yCtbnlN;QMxo=Y(F$-53dZrl5$bc@dF#(@(@P9(K5h&?Gr=xfzmP zM4o|imXJ&Ch1^{urA-Lj$30SG$6-+FmXS{vRT$v!lFFE9?@Z&0%Rh~I^AE#>X^h;I zjkEsR zhNRf!dz4XINg}3Wgkr>-0per=F* zBs4?Bmj|I*0=zxoAzdQ=xhyBDz;*9A;cZy3C7bv;M5homIRX~JVN;#_@3ptKW7~dU z&dfbH;;54_dG@h57_epQR{Z~eNPXh`cVPYr7ooIjIt~=<-nAX~-~CrS;JBY3ZZKlgMhvp2 zIF?;sR*Ysgs;f3(RAn=?GHarg2Qeur;UhlQQAVh3cFcaMy<$i<@9_MzxKu^*w(IZm ziBJ-GtE+9MKvnvos8ZbPlA(+<6XS$%;*jHXB6J=xy)4O>)fp^TBjs&X;N_e;3L>ae zZQ@xeU#`L_lqHP-?!M-YG@W6@Z@2Mdo$V(i#4mhY$o84b-zY~0?Cp$6Z?R}8*t z#uVYR|NYfo6Pzdia~GR3G|=2;8$)wjyxQ8=piwwDu=JWE0LRzOY2dyJG%SqfRZ_WN zni+Jox8pazya9i?ePsMKvZ~Axs zX3|DkOP4XdtD8od=$6*@M^rVb~lCsoY+)UR9PO>fBK6*VW8lP z4LX{(;Nu^=z&hsxp&>xsjOzG__v@X;dksx+28iPpjrnB8q`zlUv9KIUj1Ue)a>J2m z+l}um|0*7OXn57;GLB!II_C1Ty52nY3Ix{AS|no?BQD*DtbY^nR0X14sj_%OOSWu( zXSTW{5vkZwADP|W9U0TwZqDpT8k4(HWKvg>%uJ<84I$h;90;54ia|_o5k+g_ZQw|~ z)klu~u0;yj;#>C!+9d#)h0-MpBuAcii(bcI_WI zA2+q@Tl&>jEy8g<`#X(w+4T-FDQD;VKz5da>}$4VK&%9$V;{<1-(GS^a~B!c*=45*O)5GP=9p9pRVkB{rZO1UoieJ-EJ_(`h?^!U&akPmtVxT_EGc1xAjT;TC6p5a zck0U`MK*azv;QKFX2|kM2Rk4qK3PW<6mhOoiD;SZH^t)SB!$rr7QaozvMfNxavGRL zj4`Q*Vpb#j@VWwLxrItIKR970c#3_4sOXYhYfvcIh zfbD46gJdd;5kej7#FwF;a7YBF3j76>mzc)>{&2lF$ockZ>@_>fyXqq8Xw`&lBvAyi zzd0LWWW{Lhpbq%up55*98_ndXRTP>Ql9DdAIRoV-K~lCa4M z(u}Nhvfr#h%`CMilbH60q!>|2M_w^rOw4<|S8|t^N!eE1wo8emU zaOBCK!1j7Df-`iQB8~je1ZMzf?!a6&YCH@FF*v#Tz`38W=Clta@Rd^B$=DFhrS}%K ztc6}y`*uqm1^|+OlE<|)`8GRVO6xlzk)FFwvX7^-zmM{R@$7sOf^O>_TrMk&(?F*d~wha%B<)L@zxVp2xCNQN;Dl8Ld{ zh)L2FC7I4lh9uKPM!Fyac^F~v z{hRpTs>dI~hIMaQ?Qt+{OGXNBzPSd!`@`UF*)Uw18-b$Y3dBn)g|Yo`tYTgCEwvk33U*~42`(e|BdrsV^U0iiT&_6ffC z*WA?B#C{%GGOxPCNnIu~Lk7a6+@W_HI1=)RTB)LnB5I zt604%XmT?c2+^PnD)|^r@NdOP4vYwP7zPf>WC}|zaBU<_ z%FFUMzx>h2PD$CQ+G@@rhoExo1Q^DF*BwlpG##J)(s!V7a6%KDe&7QqOqjTRaj z7N3t4n;d#($%5+3*!Nr+B`D9Bs6hcjtPte5@yFk{1}Vj*)%H|YS?@gg4kaw#0DiBK zeT3!A?*Ow8)aV;D!RZH5=)Ni%iM%5_I2Hm5dg~zBI+zyIz#@SWvfgGS%+ zzB7(QfnXUUH+9e$^>Du9?CU;Oe!)|3N3Kt%NI~y1d+q=Gy7fDCLMcA=+3WD3Ph5qO zM$~|{4MHN>fA`8`Gpy4!Z+g@=BCqZW)o0icdM?$YGuz{3rH>-hVNZ?-OA+ML@k z3b1Q`7ryhq*IVsks5}Vw7H5Cppn>m!6~-`V$hjpU^atmh_i}^Wy{n2L&#oPo13_-jGMtMEN=hqGQa;w* zQC-H|ndO)=z6AT5l7V|w0X(PL3)3Z~n@?peF27jt#>FMvae#h60#gb!ALNcATR$YlDql1ZwGv9%+ zlMCCSGxrJdz&(E*^bPR(iim*+D@*8I^QMqze|~SvW@sD~IDa`eKyF;OWI;98;@Iq( za_7;758+RTFJ|EFXYSnjIBnUPYCOpzkxvmMf-O?)q3B&i?MBu`LFX`q;wC}|&H{XD#Ry{VLCDPnqPa*rj;Ums(fBni4^%>-V?<;lv^KZ1) zF6;N!nHmQY7}>e(9fw!_CYdp2nI`4?Sa1JA$Ndc~`2o6lmB_&!3&PJ>|JD%D|vrQqJpd7Jz5?Z3vsjz2xH0jpjdycJX${evbr{eiuY&VZLC zz4`bLvGL_wG1B03+=Zy-?GGNj_pexb+KKqe5AMTAqBxE>E;uE#jQhBOhDI-N$q(8a z|N5WS-!S1M%`NfYcUpi+TKM_y-ZYeZ0MhcqX^aH0YHh)xJOkc(T@!-?D@oa4a z3IWT`cwe7M4)?di=iLhheB^k;_rC_y9P!=l?n|Wc!J>+4z1~5i&#<(8oaESlbr_{+ zYD?j}zguf*b@(6mt#dGdPuC6hyGA2;_UO6kbD_~EXoAxZ6pxF%(3K_|F+gxPW)N@->y)nIozyiq?d*nz zMnAyok29@#Syc&rw_)Hxj6yUsk|X@-@F^_b`QP*R-y@wE{=M^t3qxUtlr@pL=-AG; zq0uL3^?5(BWI^=`Hc52}1_-_ii7$J+@Z!&*5Wsz1JoWfP=xHO-LfTxDtHimlj*;9j z(;!H*68kRuyItGcXbdJ;Q#6h}tok&A;#2JSoQ#Q4y@Mq8qceZOVKAaamiP5*LsmzP zR&Wx>jjadW(3)TslPh}tWgnrJiH|V2Zx-Ij3x(kDyu9z+k7G1oTkT)4YW40BCpVD@ z{+G>)asL!|)UIvW1`Ult1R*eimX)U*S=pJ&lGihoEM|kNOEF5ZapQXHkArJ~%PZ~O z%P+X#lc*Xy0Y)T_(FRIQq`O;Or-*|IrciH>$Du8j`vFaG`iZzfcV#Kr%~Xd|FhHb| z?bx^dRZN_5G&Fh!A06>I?l&L#6@K^6_2^EFpwB!uvReIi%m1=Ys4(UlH4a!j{d(I= z?B}H=bE}si;`q#=Si=6V#wZ1E%UlD?F>A(TjH#K5NVM1@K80l8*AqCwdGWdbU?^Z1 zbWddwo`y!Bp{J<&iQB$`sVg3?{91FTaU}+b31f?J;kn1*;{W#mH1dNBMDD!rn*aVJ zMi?!u_0(#$vBpS(O_i^V7-T**X*ts(R^R{u-;RO%*y5Nxc`ArexZ5U*0oRaiOiHn$ zc0yz)bcI7T)3@N$M7!WkUDG+cQ67D-fBRBr<7eBO&_(l??Mc6W- zivB-MZZrx7SNx=X-7~c<=P=TJJq|GJ*|Q7pIBuaO8$Wc$bgX&fc@z>Fcf5d&&)tHd zLUkE_@%2xnzXpwdK@*$-;9ZB)+s0SX17`_9f#Qyze*u?$^n@YV3B4~UiqY$;%W-u+{mbi=HTeN)B*?m9A^06{H zhPkRSXRmWVL_$d$#;!1KqoUWPdaDmMW@(!WxC&iQKmI5ON>;jUxPU7Avs%W+>O=F9JRCXzolw(XmTb13$u1pt%e{Tm_>mnCpZ{i$=LlK+~*Kn z)ki^KoJpeIoieY#Gn4vkjrinn`{O^wIB7tI9JhdElPp|vovv30Z`f{+cERc;+WycE z=LB{=d}z%^Aj{+g)EI6*-mx1xE!~*tcyLcOSSE zvMFNW9M(8ApM!Dgv2?F6=M~Y6a0rgJ9H>5g12dMsqx~KuXSy$^QSUweuwLWrTl48*R(`XL zj_@)M%Tb>fpKVD`WlAn1yb<+9d=t_KsW*(KOiVpcWF?o9a32!_e?a-D%6G`p6bMHP2a9yIOcD`$(Wu)G;0TkDc|oKm5K(}O}VY`alaJh(lGCyrCZ zq|xH$&B2Q}b}f_So2ZK6OF0xj{h{UlkW7gsSib^cqe&@}FPNmjLHY$JF)5E8{lGVz z>JLRu&ue%Cs<}iRLQ!4tG%eEPt}KAuOjcU^sjp^IjyM@htMHBD45M5 z9|;XM)^MKc-`+iiIo35RLhJd=*HO^N#c2uk>)n9bEhZ22ec{5&Ch0hbzg0ZG?l-gc zI1tx+S10>LlYNB81;v<>w5O@z7|=N^uEKUS8@2lKwT0{%u*L0vV)vShRz6{DJ^C1` zA?Ap%sk=Xlgc^SW+{yL;^hs{kR)Q){nPpD{f&Rj)hbf1HDQTdDDR7Ux?62m!wlgso zFzzK`*Jh$#L#I^hoZIgzP(M1@=0r>IDmc2`9V$R~YP4qopJ*G0m?L_-nJQvmud=Xg zB9Ju@^cI*xZuerBb(M^JDcR>G=1W5ZxACY-d)BoP1Gmc@9S39H85c`RMAQ0)wtsPxD6fkQJkBbURoo0 z`m4OKkO)q~W8w1(nM%cxV+cO8{}&gN2I&2}W@p=$WbT1WulC14!U*z-$Jz^fkME#; z!F9>_09WTp!7G}pKNBxw(^FlmCuh%yyOL5W&-uFOslwXJ1Wnve(n%!#s2k*dybdNhJ2^hzTkJZ;S@O|F{MBx{nbn3ov8Q$%EVk0} z{Cg?=>$GLj;QGW^F0}DoFWsN3oYx{7pPW+nIe!lPK^$#qqdKF{%Sun$6PZ@erwH}3 z$tR4Lcy6Beki$t-=Uu?R%@<|(4s2xR`8|yK(f75FOilt{q&)jL7%2V?YQas>U8Fww z%M%3h#b{P=5Bj_EuF>`U0X1-erm3$eNZ)E$V25$CJxaD8cYc|%h~?(LN5Syfv*Q1SsY&Tj4kSjXM0h=%QeHjOmbTSQ9k$7=1RQw{jZM#A z`TBsSCmaGbArXsBt9mvH!X#A9b=(5>lZvwD@9VR<#;$G-4#Hy@)DYpd6{KrJbF?TJ z1{7K_n7^JR@0mvTL#de;zabiYbkzH$dTX%At!>Y0XL<+k(hYgQi_4NLlpmihvGnxr zldC(5zr7v&cwt&?=j3_@Cjn|}uY@_^?&^Y>eb)3P>6PCduW{&edzr>Z4cbnE9U>s{ z2p89vw}r3I#s`in3p=$3Lv~&Q<*KxVLLK1SShj{OErFFAGy}{p+{8_%r^ldJJiSe#`bIiXjVML9DM6 z``_iS`MeMf-gSt56V`s+wIczpvHAQWQuGD_a%~B_rF6&k_sfE~5QwKM=Je^;RY_W4 zk__4OpliypM=^yLw;dnNa3TYZH98mqE%e^CX`EN`78HnV^bN4d{&9;-Oa!{quK`uS zV4eQZs2pVFrkW42DVdL{V$Tmf8xsp@ci>-9?uR%${Z>gh&E`#_WH2AoqOMXYx05dgU}fJvv$xHi*RLrw-54IY5})F^PT{q>I}4h@<;XKNTCm$JYbMq5syluvc&)Rpv7H0wJCGP6w=vdOhHFh$VTEorB zC&ABy!&8$V{$>;KKV%yd-D)~7MSf&{xJe%u+;buE>S^~DVkk3%8Ea(TFNZxbJ5bt} zNy!1v{*+F~3(csg414G~ameN}aoaWDSd$O6sBY35aIBFQ)>YyO5i#Ye!uAc*;Au=F z;fWrM_)M~&!W%$Bxox|x<03Ps`{A`{+nghhPkfQ;sp7x*Iq6ffTkRZ6Vtu2)OKA2b zRozff@(~A97XPkgVP-e1OzHl;dWd`1k%{tjyM2tIs_@(Q6t`?Bq#LF)cHA`8A1;ho zsldX$v`JR+US@~4nOwVX;yass`k{*vKWh}qf8TU^*Jis+=A^7TxRZi9u@&v5(8_Eq zKBw_o9B#{USRP_QK2Z6j=(}eh_)Gt=n?nw#mYmIb0quXEWYG5&=8&jqJi>3Q*NEyH zRu(>Y(`1>opvCK7uE-B0mG+DshEa_3b=I0?cg)O*1an?6^M_Flq$E3iZ2QFdi$((eE2rtWu+w-r~5mY^{4du3w$G= z&5CwIeudcg<=MVYyu(j1D$M7BCj-@eS?oq|H)kedzM5DkuA6cU2HR23dMWJWsK4ho6{$E-XsV# zp231gKN#iR^YocH=ex$c?4a80)vMm6u<6@=75l7r;T@>1`(IKR_#fk57*Eng@|}Bq zIX-xKbSfz*=D@`w-BCekbpv1CCQw?PVbv1{;?zc$DHJ`Kzz)Pcg&*BHA9A(zyv%fH zGrZQ7d3rEX4tod$JTvW?Ua>K%L@7v8eC{t?57Cq6zok>4t?0m-cBUt(tz?C;yxJ1P zaz#>c77EBA$_M=?-$m^LHUD4+7tPfP&>9Sxt5`VY{qoa9YSehpwH8>0iIS38mCotOkQG&)gS^gmcabrkgt-p|NVUJQvd6#_LzqvMjR@0x z7TnvPS}{OsKOboxy}<)+LMTc`f+}$EDjtx6q043&$Ncm=yNCCup}7u1^A}&t{Gyy^k1bXJ4+=>_NbkBYNjhIl6Tf#&ppDB8 zquD@C%|#TyjuiA970QHMtr9#0S5o=>$FQiPN<)-AZ(wZP4WWogy|l6*JL7C*@uCdw z9WGBr1=WRMa=qLF-w&t73(nJh@s^<$S5_gSvTZWf-x}C(yB$?G);Aoxdr=as=kp8? zd9cM*Z|~G8IchVaHA96n3hVQRV8#krmX@WUg4A$i(+)$mS22Y86%cw}E8TK+#5ul; zJi2zJEasdi?kSR+$UQ@~Sy&HhpWc2&(dpUQMy?{~bw0`>RFmc z;ep>^Smm%xGc94b^W1o&!P4wkyA%3G?rC^1aEX(sIu@mLl{XaevC@zdohcT~Cbe$J z&r@dn$iaTZOPATnOq6$WzCTvS%a`3=ml154H)o%0ZS$G=Dq5bLW}&eGRcG&pk%#we zQq@e)>~v)h(*yTeBF6I7TV@+Jl1?*KGJp%WHtN);Qs1~IS5gzXRJ>KtCh?kwPY}ud z{At=#jv|2nzI0diT%N#ED-%Qz3s>Y1R84tDF(^6`kn?fY-7s-GuF z87mAH7Jkb>5aod;eW{f!_p()|+Wy>ZY<3W0|69lLbbUuMrL@sOpOFWH0^n^V``%YLvy@Kv2Ja_6Fm1Q%UW}IE9Y9 zn3Tw`=wnEG5&ztj$gR|#f4mpTYN756BD`nh!s)R^?`kPUB7Y!u8{&zQ=LtpenT(Yt zB?_BRDu2kCash!mV_yC5GqOU9Sr#~%L zuk6f)yj7sIdw699w>r|Fn0XSe@=SCUZ*s8+)mSWz1Uu1vx4-f^K1%n)kQntwTy&|X z3j8ODp0))RRyY#yUL>2ade26=^)Y|deC&P>^5p&Z<@&WvGtY}ZjY1E4jTE44!Y(f} zQgE>gf9IP1$hQ)H)iGiexbRmV6aTn?fF3B0h$Qc9`+cu{I!?~zX&>xc@n;G-xzJ%N zSzlaVetumZN0g^$y>HfoaMuIrf36Y8(-b*jPNjL>fp z^4q9#A=~n~l4tti2R$wh2NjgHA_2L5_*qziID|P>J*ZTc&c1)%F6O07k{eqPwS700 ze9z%*DWDc#6w1Ux!wnRB?{;59lP<|hGnNZ1Scq%tbZ*nqxfM* z!0(#jhW@``%FYCm7-eGLj0s16L>SSU!F$}gtUGa6ox~QeRb9Dj7WLR9pIv8;$uVn| zt-Hz3!}u9H3M%Ox;s&) z$IaiFM~d9G+lYDPWL9y z0$ef;yqAToQ3c8xN3*IW1ik+Hdgj6OZi*|FlfsnrD&M`k)sfjcfi-KZ09fM7e@kSC zBM-gP?=e2uy_s5yI#eYTa`QnIPfH$mROtcOpV8y~G7Z}~w{4x7 zgCJl{3>#Tz&6@~Kf^85cEm|ep_vw^=t!r-~=gn6>N+v-Li&!j+rT&lX3D_I}5Lr{J zavrRe9QR*kS=e>)Va>bMX3{?NdEMKeGGNl$YE)G4$@f)q=KF?3bG?SJ43w~k$I?9l z|KoNu03cxe7qwIHl&&!K#wEu7!8G|Qp?TtpZ8=k+&3E@o-;LG}!IPd}aIUo>76gPHWD(IS-di+zFCgRUt zaWu(soNWHkf!lY`8H1GdE|3@@r%kMA*GdWe8w3aG0)&Aku9!%ffK`<>Vyo2K z@rCT*4jvUT8|#x1Ak^$7DzcTDL#mlL6r*~JacNa>Bgz)>XRhV6@!Z+ZLNYO+$HJG7 zdlC+L<9>AFAKR#K>SKbzPdz@|BV_!GJIHYoBPrnBG+M8`oraFGJZ_b4?bAQ z@R{*Xm|6j~@LnDomlsNBfh4iB*cZf2e&6-J4D7L*h22C(CXkeak^G6ygN%2G11;MS zf#WSCgs00*#OTsSoEJwD9nSTF^ykdg)+>g3-ZZY^)%BjTZ0EfD8N_tD?0kwI{) zmg986qlSyI=kl3A4IpM*Z{UIznpt4DTX!KbN?P))!**!~_!A`|Pf$F^Uz_cpm|B#9V z1DYDW{LNagl6vcU&d}wGd7gMvYPJ4Ur7kp{PD2R11k0oX|tD?YtpsF4=Y7VMb? zQJOkpulJPJUO(Ss*KI-u2%=pS7krJ$){pQ(=g88aMsF$XS z?Zc{BGpd>ZW@T8MF1gtEp;}m+9#5UyfMyzBgsM<+R>5r+xHQd^1Rxg-z@4(NAVjmh z-#uG1NR)mnS5g>R9@oFp)BTr62$=!RV`Gkh&(0fo%&b#k8z(T#8@r_lbo^P^ohoOn zYKV!BND8tI`Ihk#SobZJuqw93ObMW zd9(7`X2uXpKaCEibIwN#CToNC@R*qpND=)S1Vn%jkSYM2(>YB&7!rEjryZ!7M zGu=jsI5aLU=)8Zn#9_eT3_u%7JzbvMs0ultU1if{5XI^4V3yeR{hVO+Ew8S2bz`=m zPPy)4OB;a~nhe}bZSK{)lX#j1a&7$3*QGng0A>WVJt4y*%R`4vvdoe;q$Bku32m@)u+R z4&mAUP?)Lm#I3$`^`u1BeA>KHuvpp!c^;jR_&443ecF>{*=QOrAI-twZ#w?=*m; z+dmotQcn$3O>Zcvde|M5f*On%OXQsu#EZ%rO&$nBV((R zB!I+@|B(2N)XAj>c`0K}fe>jwCt$87Xwg21)vSVDJe3&+5Xz4<@LgPynH&&%r6JUKqBviiO_8*!zo=y-#z zWUG*TkI&L&H>V!dZ6=Hr;n9CCxlSS$jJw10dHZ#1@mKsuo_qd}=bro7(uRl;I}1rz zxXfGPuUZn7`~)dDDx23_=_opW!O{DWI-fXRCs*S>_rJcR;i7DBRLFHiyebtC{mG#}mp`4T4le)x1Gr*cE3laQ!~IQoZwDicckZIAs& z>jbiy|KV?T-ONK2?1#qTdT4xqW9%a-VrKzr8bV?cKCXsWRp9TOrXS<6T1Q^eX%J+T zu{N)YhPSe{rRUmzmwOjx$Mz6AH#yP+{r0+r>!8!_ko}gKSB19p_>w=zIMyis=6ltL zkUlvseEWJx`s3t$pI87Q<<$9l?6XmlQjMwC$;12i2vv51NUdli;$@g!AJfv1^FHh# zy!K}+=y_PW=L1}DAtT-TFf6TSiPjb_Tga-}c2r0Yy-R)TBThS^5B)-T(&>ris7Z={ zxhv8J&*m}oLn+)9Zd3`UWcInuj}2BhLE9;(#G<)`8d;b{Hv<*p81Eg#^Id+gG9A6aUe(87L&BTt zjNn&%mbk=TO!Mln$!Q%`N*{67^r`^b+Qwb`zNNI3=UrJpI03(qj9LsfVT{{973Gl} zEV2Cnw$rcGQC74BQ1wqFz4;p_*hM$^IS|8t0~ZocH=arRe)l`LrK zRRp^Jsq&NN{a{s(G4k<6TId=>Hv*Iq`b1fO!<$(mP)^;$jvkK$Qc*`1U1So8*KDmB z{h9HRl>x6FfFvXgEm;P6uK>pG_cN?RYuS>~#3sD)eJaX+^fQxQk-UeU;^p^~4>egS zdlx;6uVRLg^)(h;Bp5<>thI`!mG!zRv{C3JvT2)%<7}_K>%Z-%xa9I9cDcJl+%4sC zJaYQ-KUw9yD$O$4oRqbmYS8<_)V6=J#qA5G@>eKQTFv~-t&Lq%IdyYODg~GA21P8F zxJF~ynQ46R4q%Q5 zPTq&u9Y^jF^i~0mdZ*a^`WDNN5NW@6`Hrb|^bcH|>bR zBqufcbJrL}J-^bZTS>mhim=|Nn>!FlIAr0kOb1Nyo`R>3R!jTZto%#XTn1ayw7;xg z*>U-4C%hKdo^6wKN2l*~P1o_V8r-^?PCFS7n^&e;X2F~ibw|>?L~|G4(;AxVw;L6l zs_4{33y*a4*e2$hT@Q{4gdN!V~l9CzV zh=572G0_-#cFQhP5u|U}d@cMQGPrF;|BiO2=%w9C(g7Nn>*J&P?13O%-s4A_zci~9 z;I#rVesOiztxZ4n+a^B&+I2Jut|)3(8a+RXA}t#_NG+BH$9(T|Q)fzP9A%f@8!5^T8( zR%a1~rv-bUL{O5{8^=S%8O+y}7Dl`sExB>S+FjTE4Sz2)Kg*dAEZZA2`>u}|zdKFh zE2t}h)YCc=wjYcUey^(JVh92>+BlFAX&K zgMYp0X?=byVGR9q;`Ls;Kmu&5%X8w3B`cK7B(Uw=Ut2&1g?)TwT=aAMvlz4F9CY68U<<}0;%zQ&Z7A{E`xp8=z2=V#`nzlQo~{Q=$hB@X zZP|nQ&r74604}D?+`{ISn)59v47T>|A628GP2OjI8u+QKd~4oA#~9#xAs7^tvw`+5 z@=S&&BOu{uu=b0a(5GEiR%|i6Sl3%@i_&#_>Oy=u_QsV6XO;}WOKJOO{5``(oazVa z#Ao)Xznc&6-%Q^EfJBU)Dv*s>$3LTE2wVavk}qpZp%*tb7O$Dd>_LS2IqFTjkg=u zFaGrJlYoK;#2s4((xvX#*_q07lc2w`hdWOe0fpMuUz6se~_F8kp2P% z$Kp2ftM#)1v#u0^Kb(B%!>9;Dze=c<%Dhsg%G`?+9*g-?DxH)?GvEw98DOF5F3zLw zrRr7AF}8IzPCjmRUwip__Yos-sIrQsg+*Q6Va)YqV$EsWM?_e3{;Ucw!-`Jvu9vk!57u?*45_WYkOG1+|Exn0MvMD#6H!=~dlY)$?()f=dvW%D z+W=2|`Z-mtKIm33eJJt<((ys&y1nvk0)q+ZQZV`BLD(Ky0*=;3BS@9dx85m4w=&rH z%tbH?E6O*AUdNcg$Ue+Hpyw@GT%G6I0r;2BAK=`4kMRPiFyhNvGb6cR1VPZBI+d`c z7XMD(J9_BPkdMA=HZeQq6h#42j=uvloFhS~$GyWUm$7sFVSvyKK>0-p1h~S?Gw3pvUi0#Kf|JUvRyBl=(ho6k8JW0ejv~msx-x#^i6j0ft}Qic zf(Zd*N9NJJfMu%#65x44JaMkrbX-uXt*Yuy?TCX?^q?(DpAFAGqv#|T7Cy-NOPG$b zjEje`9G}+_4p`3z*m?kvfCEs}m++KUp8Ii;pY*+EOzcLh#^_iIOw<_;EB3+ikU!{$ zLKODM5M7RlG0MD38Ob1rJ)CnnrpF`yxBN(5fTa@}ud?ww31ch+Sq7`$QAdr!QYVJA z!}lzeCB}XVD$ub--0=#8xL<)enSI0K6{f9Y8*l{o8U z({&hZ<2OnStzuYta5B1^SGEui^nf0OQKpWUe{~+Vd^Fvrz-AwTQJ{Z=F+nX}8`P~I zcfx+i6{;|#(4>^dTPqov literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/feeling_scared_note_gray.png b/android/Staccato_AN/app/src/main/res/drawable/feeling_scared_note_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..2913c6a8c0418a83be9ea47d611dedcf074e2f8f GIT binary patch literal 70147 zcmdp7Wm{Wau!Z7or8tD(ZpGb$7YW6SyF+lNxVuYnmjFddao1A3xVslAdh_1g1(1ve9Naqr*z*w;8TJcqt7aVR1I-zv>jnqM zs`TFjUn-hj3HuS=O+#J^u5OC_2=)chN>W7<4z4i)vN$;s0LunIv%l)!}}pyi730@CT>TU;w#=%!oiLT{Cnlv1CqUly*R zDnBji_e!nz%r&8)s3OGVLJ)2iz?E3JhgNyYyW`~S!aZ;0>HLQpc

;t@UDULvKD! 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 KQR^vD;(q`kD%%kN literal 0 HcmV?d00001 diff --git a/android/Staccato_AN/app/src/main/res/drawable/icon_instagram.xml b/android/Staccato_AN/app/src/main/res/drawable/icon_instagram.xml new file mode 100644 index 000000000..40b3c2876 --- /dev/null +++ b/android/Staccato_AN/app/src/main/res/drawable/icon_instagram.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/Staccato_AN/app/src/main/res/drawable/icon_send_disabled.png b/android/Staccato_AN/app/src/main/res/drawable/icon_send_disabled.png deleted file mode 100644 index 50b2032370245ee9572ed244b940af77e12d807c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13567 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 + + + diff --git a/android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.png b/android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.png deleted file mode 100644 index e7fd5ffd3f6f56610d4d9d66ccd7fe38d8e0fd8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6101 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 QUpd(jc|-Suwo~N)0U5}$5C8xG diff --git a/android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.xml b/android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.xml new file mode 100644 index 000000000..9778b4579 --- /dev/null +++ b/android/Staccato_AN/app/src/main/res/drawable/icon_send_enabled.xml @@ -0,0 +1,12 @@ + + + + diff --git a/android/Staccato_AN/app/src/main/res/drawable/icon_staccato_symbol_dark.png b/android/Staccato_AN/app/src/main/res/drawable/icon_staccato_symbol_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..e27d870987d46da0b691dff9a1801393dcede65e GIT binary patch literal 85909 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 pk4wIb4j - - + + diff --git a/android/Staccato_AN/app/src/main/res/drawable/shape_my_visit_log_12dp.xml b/android/Staccato_AN/app/src/main/res/drawable/shape_my_staccato_log_12dp.xml similarity index 100% rename from android/Staccato_AN/app/src/main/res/drawable/shape_my_visit_log_12dp.xml rename to android/Staccato_AN/app/src/main/res/drawable/shape_my_staccato_log_12dp.xml diff --git a/android/Staccato_AN/app/src/main/res/drawable/shape_others_visit_log_12dp.xml b/android/Staccato_AN/app/src/main/res/drawable/shape_others_staccato_log_12dp.xml similarity index 100% rename from android/Staccato_AN/app/src/main/res/drawable/shape_others_visit_log_12dp.xml rename to android/Staccato_AN/app/src/main/res/drawable/shape_others_staccato_log_12dp.xml diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_login.xml b/android/Staccato_AN/app/src/main/res/layout/activity_login.xml index 7d1aefbdd..4558fe24c 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_login.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_login.xml @@ -14,38 +14,40 @@ type="com.on.staccato.presentation.login.LoginHandler" /> - + android:background="@color/white"> + android:onClick="@{() -> handler.onScreenClicked()}" + android:paddingHorizontal="36dp"> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" + app:layout_constraintWidth_max="300dp" + app:layout_constraintWidth_percent="0.6" /> @@ -53,13 +55,14 @@ android:id="@+id/text_input_login_user_nickname" style="@style/TextInputLayoutStyle" app:counterMaxLength="20" + app:layout_constraintBottom_toTopOf="@id/btn_start_staccato" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/space_login_separating_logo_and_nickname_et"> + app:layout_constraintTop_toBottomOf="@id/space_login_logo_nickname" + app:layout_constraintWidth_max="500dp"> + app:layout_constraintWidth_max="500dp" + bind:loginButtonEnabled="@{viewModel.nickname}" /> - + - + - + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_main.xml b/android/Staccato_AN/app/src/main/res/layout/activity_main.xml index 3652b8abc..3bb769b88 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_main.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_main.xml @@ -38,7 +38,7 @@ android:layout_marginEnd="10dp" android:layout_marginBottom="75dp" android:clickable="true" - android:contentDescription="@string/all_image_content_description" + android:contentDescription="@string/main_staccato_creation_btn_description" android:focusable="true" android:onClick="@{() -> handler.onStaccatoCreationClicked()}" android:paddingTop="10dp" @@ -50,12 +50,13 @@ android:id="@+id/iv_main_mypage" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="12dp" - android:layout_marginTop="12dp" + android:layout_marginStart="4dp" + android:layout_marginTop="4dp" android:clickable="true" - android:contentDescription="@string/all_image_content_description" + android:contentDescription="@string/main_mypage_btn_description" android:focusable="true" android:onClick="@{() -> handler.onMyPageClicked()}" + android:padding="8dp" android:src="@drawable/icon_member_with_border" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -87,12 +88,11 @@ diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_memory_creation.xml b/android/Staccato_AN/app/src/main/res/layout/activity_memory_creation.xml index 3f15ac785..21a7b40e7 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_memory_creation.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_memory_creation.xml @@ -25,7 +25,7 @@ + bind:visibilityByEmptyThumbnailUri="@{viewModel.thumbnailUri}" + bind:visibilityByEmptyThumbnailUrl="@{viewModel.thumbnailUrl}" /> - + + @@ -152,11 +160,9 @@ app:layout_constraintTop_toBottomOf="@id/tv_memory_creation_description"> @@ -165,7 +171,7 @@ android:id="@+id/tv_memory_creation_period_title" style="@style/SubTitleStyle" android:layout_marginStart="24dp" - android:layout_marginTop="24dp" + android:layout_marginTop="25dp" android:text="@string/memory_creation_period_setting" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/text_input_memory_creation_description" /> @@ -189,35 +195,26 @@ + bind:startDate="@{viewModel.startDate}" + bind:visibleOrGone="@{viewModel.isPeriodActive}" /> + bind:isPhotoUploading="@{viewModel.isPhotoPosting}" + bind:memoryEndDate="@{viewModel.endDate}" + bind:memoryStartDate="@{viewModel.startDate}" + bind:memoryTitle="@{viewModel.title}" /> - + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_memory_update.xml b/android/Staccato_AN/app/src/main/res/layout/activity_memory_update.xml index 2e79d3523..5851b3c90 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_memory_update.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_memory_update.xml @@ -25,7 +25,7 @@ + app:layout_constraintWidth_max="500dp" + bind:coilRoundedCornerImageUri="@{viewModel.thumbnailUri}" + bind:coilRoundedCornerImageUrl="@{viewModel.thumbnailUrl}" + bind:coilRoundedCornerPlaceHolder="@{@drawable/shape_all_gray1_8dp}" + bind:coilRoundingRadius="@{12f}" /> - + + @@ -153,11 +161,9 @@ app:layout_constraintTop_toBottomOf="@id/tv_memory_update_description"> @@ -166,7 +172,7 @@ android:id="@+id/tv_memory_update_period_title" style="@style/SubTitleStyle" android:layout_marginStart="24dp" - android:layout_marginTop="24dp" + android:layout_marginTop="25dp" android:text="@string/memory_creation_period_setting" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/text_input_memory_update_description" /> @@ -190,36 +196,26 @@ + bind:startDate="@{viewModel.startDate}" + bind:visibleOrGone="@{viewModel.isPeriodActive}" /> + bind:isPhotoUploading="@{viewModel.isPhotoPosting}" + bind:memoryEndDate="@{viewModel.endDate}" + bind:memoryStartDate="@{viewModel.startDate}" + bind:memoryTitle="@{viewModel.title}" /> - + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_mypage.xml b/android/Staccato_AN/app/src/main/res/layout/activity_mypage.xml index a8679fa3e..0843fef33 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_mypage.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_mypage.xml @@ -11,8 +11,8 @@ type="com.on.staccato.presentation.mypage.viewmodel.MyPageViewModel" /> + name="memberProfileHandler" + type="com.on.staccato.presentation.mypage.MemberProfileHandler" /> - - - - - - - - - - - + + + + - - - - - + + + + app:layout_constraintTop_toBottomOf="@id/tv_mypage_profile_uuid" /> + + + + + + + + + + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_recovery.xml b/android/Staccato_AN/app/src/main/res/layout/activity_recovery.xml index 1bd381753..1bcabd92b 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_recovery.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_recovery.xml @@ -21,67 +21,76 @@ - + android:orientation="vertical" + app:layout_constraintGuide_begin="24dp" /> - + - + - + + + + + android:text="@={viewModel.recoveryCode}" /> - + - + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_visit_creation.xml b/android/Staccato_AN/app/src/main/res/layout/activity_staccato_creation.xml similarity index 64% rename from android/Staccato_AN/app/src/main/res/layout/activity_visit_creation.xml rename to android/Staccato_AN/app/src/main/res/layout/activity_staccato_creation.xml index fdf76298c..e795ceb1e 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_visit_creation.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_staccato_creation.xml @@ -10,15 +10,15 @@ + type="com.on.staccato.presentation.staccatocreation.viewmodel.StaccatoCreationViewModel" /> + name="staccatoCreationHandler" + type="com.on.staccato.presentation.staccatocreation.StaccatoCreationHandler" /> + type="com.on.staccato.presentation.staccatocreation.CurrentLocationHandler" /> + app:subtitle="@string/staccato_creation_toolbar_subtitle" + app:title="@string/staccato_creation_toolbar_title" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar_staccato_creation"> + tools:context=".presentation.staccatocreation.StaccatoCreationActivity"> @@ -83,50 +79,47 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_photo_title" - app:spanCount="2" + app:spanCount="@integer/staccato_span_count" tools:itemCount="2" tools:listitem="@layout/item_attached_photo" /> + app:layout_constraintBottom_toBottomOf="@id/tv_staccato_creation_place_name_title" + app:layout_constraintStart_toEndOf="@id/tv_staccato_creation_place_name_title" + app:layout_constraintTop_toTopOf="@id/tv_staccato_creation_place_name_title" /> + app:layout_constraintTop_toBottomOf="@id/tv_staccato_creation_place_name_title"> @@ -137,13 +130,13 @@ android:id="@+id/tv_place_name_title" style="@style/SubTitleStyle" android:layout_marginTop="20dp" - android:text="@string/visit_creation_place" + android:text="@string/staccato_creation_place" android:textAppearance="@style/Typography.Title2" - app:layout_constraintStart_toStartOf="@id/tv_visit_creation_place_name_title" - app:layout_constraintTop_toBottomOf="@id/text_input_visit_creation_title" /> + app:layout_constraintStart_toStartOf="@id/tv_staccato_creation_place_name_title" + app:layout_constraintTop_toBottomOf="@id/text_input_staccato_creation_title" /> @@ -166,28 +159,19 @@ android:id="@+id/tv_place_address_title" style="@style/SubTitleStyle" android:layout_marginTop="10dp" - android:text="@string/visit_creation_address" + android:text="@string/staccato_creation_address" android:textAppearance="@style/Typography.Title3" - app:layout_constraintStart_toStartOf="@id/tv_visit_creation_place_name_title" + app:layout_constraintStart_toStartOf="@id/tv_staccato_creation_place_name_title" app:layout_constraintTop_toBottomOf="@id/autocomplete_fragment" /> + bind:currentLocationButtonLoading="@{viewModel.isCurrentLocationLoading}" /> + bind:visibleOrGone="@{viewModel.isCurrentLocationLoading}" /> + bind:memoryCandidates="@{viewModel.memoryCandidates}" + bind:selectedMemory="@{viewModel.selectedMemory}" /> + bind:dateTimeWithAmPm="@{viewModel.selectedVisitedAt}" + bind:memoryCandidates="@{viewModel.memoryCandidates}" /> + bind:staccatoVisitedAt="@{viewModel.selectedVisitedAt}" /> - + diff --git a/android/Staccato_AN/app/src/main/res/layout/activity_visit_update.xml b/android/Staccato_AN/app/src/main/res/layout/activity_staccato_update.xml similarity index 65% rename from android/Staccato_AN/app/src/main/res/layout/activity_visit_update.xml rename to android/Staccato_AN/app/src/main/res/layout/activity_staccato_update.xml index 1ca8fb194..037d3939f 100644 --- a/android/Staccato_AN/app/src/main/res/layout/activity_visit_update.xml +++ b/android/Staccato_AN/app/src/main/res/layout/activity_staccato_update.xml @@ -10,15 +10,15 @@ + type="com.on.staccato.presentation.staccatoupdate.viewmodel.StaccatoUpdateViewModel" /> + name="staccatoUpdateHandler" + type="com.on.staccato.presentation.staccatoupdate.StaccatoUpdateHandler" /> + type="com.on.staccato.presentation.staccatocreation.CurrentLocationHandler" /> + app:subtitle="@string/staccato_update_toolbar_subtitle" + app:title="@string/staccato_update_toolbar_title" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar_staccato_update"> + tools:context=".presentation.staccatocreation.StaccatoCreationActivity"> @@ -83,50 +79,48 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_photo_title" - app:spanCount="2" - tools:itemCount="1" + app:spanCount="@integer/staccato_span_count" + tools:itemCount="2" tools:listitem="@layout/item_attached_photo" /> + app:layout_constraintBottom_toBottomOf="@id/tv_staccato_update_place_name_title" + app:layout_constraintStart_toEndOf="@id/tv_staccato_update_place_name_title" + app:layout_constraintTop_toTopOf="@id/tv_staccato_update_place_name_title" /> + app:layout_constraintTop_toBottomOf="@id/tv_staccato_update_place_name_title"> @@ -137,13 +131,13 @@ android:id="@+id/tv_place_name_title" style="@style/SubTitleStyle" android:layout_marginTop="20dp" - android:text="@string/visit_creation_place" + android:text="@string/staccato_creation_place" android:textAppearance="@style/Typography.Title2" - app:layout_constraintStart_toStartOf="@id/tv_visit_update_place_name_title" - app:layout_constraintTop_toBottomOf="@id/text_input_visit_update_title" /> + app:layout_constraintStart_toStartOf="@id/tv_staccato_update_place_name_title" + app:layout_constraintTop_toBottomOf="@id/text_input_staccato_update_title" /> + bind:currentLocationButtonLoading="@{viewModel.isCurrentLocationLoading}" /> - /> + bind:visibleOrGone="@{viewModel.isCurrentLocationLoading}" /> + bind:dateTimeWithAmPm="@{viewModel.selectedVisitedAt}" + bind:memoryCandidates="@{viewModel.memoryCandidates}" /> + bind:staccatoVisitedAt="@{viewModel.selectedVisitedAt}" /> - + diff --git a/android/Staccato_AN/app/src/main/res/layout/fragment_delete_impossibility_dialog.xml b/android/Staccato_AN/app/src/main/res/layout/fragment_delete_impossibility_dialog.xml index e4b81a728..29a5e0fdc 100644 --- a/android/Staccato_AN/app/src/main/res/layout/fragment_delete_impossibility_dialog.xml +++ b/android/Staccato_AN/app/src/main/res/layout/fragment_delete_impossibility_dialog.xml @@ -6,9 +6,7 @@ - + - \ No newline at end of file diff --git a/android/Staccato_AN/app/src/main/res/layout/fragment_memory.xml b/android/Staccato_AN/app/src/main/res/layout/fragment_memory.xml index ea9fbbb4c..a0b0f9276 100644 --- a/android/Staccato_AN/app/src/main/res/layout/fragment_memory.xml +++ b/android/Staccato_AN/app/src/main/res/layout/fragment_memory.xml @@ -56,7 +56,7 @@ android:id="@+id/iv_memory_thumbnail" android:layout_width="0dp" android:layout_height="0dp" - android:contentDescription="@string/all_image_content_description" + android:contentDescription="@string/all_memory_thumbnail_photo_description" android:scaleType="centerCrop" app:layout_constraintDimensionRatio="3:2" app:layout_constraintEnd_toEndOf="parent" @@ -83,7 +83,7 @@ android:layout_marginHorizontal="16dp" android:text="@{viewModel.memory.title}" android:textAppearance="@style/Typography.Title1" - android:textColor="@color/white" + android:textColor="@color/absolute_white" app:layout_constraintBottom_toTopOf="@id/tv_memory_period" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -96,7 +96,7 @@ android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:textAppearance="@style/Typography.Body4" - android:textColor="@color/white" + android:textColor="@color/absolute_white" app:layout_constraintBottom_toBottomOf="@id/iv_memory_thumbnail" app:layout_constraintStart_toStartOf="@id/tv_memory_title" bind:memoryEndAt="@{viewModel.memory.endAt}" @@ -159,49 +159,36 @@ app:layout_constraintTop_toBottomOf="@id/rv_memory_mates" /> + app:layout_constraintTop_toTopOf="@id/tv_memory_staccatos">