Daehan Lim

Header Project Icon

Cubadebate 뉴스 앱

📝 개요

📌 앱 소개: 맞춤형 콘텐츠 제공 및 오프라인 저장 기능을 갖춘 뉴스 앱
🕒 기간: 2021.03.15 ~ 2021.06.30 (3.5개월)
📱 플랫폼: 안드로이드 네이티브 앱
🏢 회사명: Desoft (쿠바 국영 소프트웨어 개발사)
👥 개발 인원: 1명
💼 역할: UI/UX 설계 및 전체 안드로이드 앱 개발 담당
🛠️ 사용 기술: Android Kotlin Coroutines MVVM Room Retrofit Moshi Navigation Material Design Glide Lottie ViewBinding
🔗 GitHub: daehan-lim/cubadebate-app

Cubadebate news feed screen Cubadebate news article screen Cubadebate replies screen Cubadebate categories screen Cubadebate topics screen Cubadebate SMS screen Cubadebate search screen Cubadebate saved articles screen

📖 프로젝트 배경

🛠️ Tech Stack

Kotlin MVVM Room Coroutines Retrofit Moshi Material Design Navigation ViewBinding DataBinding Glide JSoup Material Dialogs

📋 프로젝트 구조

├── database/                        # 로컬 데이터베이스 관련 클래스
│   ├── CubadebateDatabase.kt        # Room 데이터베이스 메인 클래스
│   ├── converters/                  # 데이터 타입 변환기
│   ├── dao/                         # 데이터 액세스 객체
│   │   ├── PostDao.kt               # 게시글 관련 데이터 액세스
│   │   ├── RecentCategoryDao.kt     # 최근 카테고리 데이터 액세스
│   │   └── TagDao.kt                # 태그 관련 데이터 액세스
│   └── model/                       # 데이터베이스 엔티티 모델
│       ├── post/                    # 게시글 관련 엔티티
│       │   ├── DatabasePost.kt      # 게시글 메인 엔티티
│       │   ├── DatabaseCategory.kt  # 카테고리 엔티티
│       │   └── ...(기타 게시글 관련 엔티티)
│       ├── savedpost/               # 저장된 게시글 관련 엔티티
│       │   ├── SavedPost.kt         # 저장된 게시글 메인 엔티티
│       │   ├── SavedCategory.kt     # 저장된 게시글 카테고리
│       │   └── ...(기타 저장된 게시글 관련 엔티티)
│       ├── ...(기타 엔티티들)
│
├── model/                           # 데이터 모델 클래스
│   ├── api/                         # API 응답 모델
│   │   ├── comment/                 # 댓글 API 모델
│   │   │   ├── Content.kt           # 댓글 내용
│   │   │   └── ResponseComment.kt   # 댓글 응답 모델
│   │   ├── post/                    # 게시글 API 모델
│   │   │   ├── NetworkPost.kt       # 네트워크 게시글 모델
│   │   │   └── ...(기타 API 모델들)
│   ├── categories/                  # 카테고리 관련 모델
│   │   └── MyCategoriesGridViewItem.kt
│   ├── comment/                     # 댓글 도메인 모델
│   │   └── Comment.kt               # 댓글 정보
│   └── post/                        # 게시글 도메인 모델
│       ├── Post.kt                  # 게시글 메인 모델
│       ├── Category.kt              # 카테고리 모델
│       └── ...(기타 게시글 관련 모델)
│
├── network/                         # 네트워크 통신 관련 클래스
│   └── CubadebateApiService.kt      # Retrofit API 서비스 인터페이스
│
├── repository/                      # 데이터 저장소 (Repository 패턴)
│   ├── PostRepository.kt            # 게시글 데이터 관리
│   ├── RecentCategoryRepository.kt  # 최근 카테고리 데이터 관리
│   └── TagRepository.kt             # 태그 데이터 관리
│
├── ui/                              # 사용자 인터페이스 관련 클래스
│   ├── CoroutineBaseViewModel.kt    # 코루틴 기반 베이스 뷰모델
│   ├── PostsViewModel.kt            # 게시글 공통 뷰모델
│   ├── HeadingsAdapter.kt           # 게시글 목록 어댑터
│   ├── EndlessRecyclerViewScrollListener.kt  # 무한 스크롤 리스너

│   ├── main/                        # 메인 화면 관련 클래스
│   │   ├── MainActivity.kt          # 메인 액티비티
│   │   ├── MainActivityViewModel.kt # 메인 액티비티 뷰모델
│   ├── categories/                  # 카테고리별 화면
│   │   ├── BaseCategoryFragment.kt  # 카테고리 베이스 프래그먼트
│   │   ├── HomeFragment.kt          # 홈 프래그먼트
│   ├── details/                     # 게시글 상세 화면
│   ├── comments/                    # 댓글 관련 화면
│   │   ├── CommentsActivity.kt      # 댓글 액티비티
│   │   ├── CommentsFragment.kt      # 댓글 프래그먼트
│   │   ├── RepliesFragment.kt       # 댓글 답글 프래그먼트
│   │   └── ...(ViewModels 및 기타 클래스)
│   ├── search/                      # 검색 관련 화면
│   ├── saved/                       # 저장된 게시글 화면
│   ├── forme/                       # 개인화 추천 화면
│   │   ├── ForMeFragment.kt         # 추천 메인 프래그먼트
│   │   ├── MyCategoriesFragment.kt  # 내 카테고리 프래그먼트
│   │   ├── MyTopicsFragment.kt      # 내 토픽 프래그먼트
│   │   └── ...(ViewModels 및 기타 클래스)
│   │
│   ├── headingspertag/              # 태그별 게시글 화면
│   ├── subscription/                # 구독 관련 화면
│   └── settings/                    # 설정 관련 화면
│       ├── categories/              # 카테고리 관리
│       └── topics/                  # 토픽 관리
│
└── util/                            # 유틸리티 클래스 및 헬퍼 함수
    ├── ActivityUtils.kt             # 액티비티 관련 유틸리티
    ├── BindingUtils.kt              # 데이터 바인딩 관련 유틸리티
    ├── MappingUtils.kt              # 데이터 매핑 유틸리티
    ├── PostUtils.kt                 # 게시글 관련 유틸리티
    ├── PreferenceManager.kt         # 설정 관리 유틸리티
    └── Util.kt                      # 일반 유틸리티 함수

🌟 수행 내용 및 성과

🧭 기술적 의사결정

1. 오프라인 저장 아키텍처 선택

@Entity(tableName = "posts")
data class DatabasePost(
    @PrimaryKey val id: Long,
    val title: String,
    val content: String,
    val imageUrl: String?,
    val publishedDate: String,
    val isSaved: Boolean = false
)

2. MVVM 아키텍처 도입

class PostRepository(private val database: CubadebateDatabase) {
    suspend fun getPosts(categoryId: Long?): MutableList<Post> {
        return withContext(Dispatchers.IO) {
            try {
                // 네트워크에서 최신 데이터 가져오기 시도
                val networkPosts = when(categoryId) {
                    null -> CubadebateApi.retrofitService.getPostsAsync()
                    else -> CubadebateApi.retrofitService.getPostsByCategoryAsync(categoryId)
                }.await()
                
                // 로컬 DB에 저장 후 반환
                networkPosts.map { it.mapToPost() }
            } catch (e: Exception) {
                // 네트워크 실패 시 로컬 데이터 반환
                getPostsFromDb(categoryId)
            }
        }
    }
}

🌱 문제 해결

1. 사용자 중심의 콘텐츠 탐색 개선

🎞️ 시연 영상

Watch the Video