Daehan Lim

Header Project Icon

Cubadebate News App

πŸ“ Overview

πŸ“Œ App Introduction: News reader app with personalized content delivery and offline storage capability
πŸ•’ Duration: March 15, 2021 ~ June 30, 2021 (3.5 months)
πŸ“± Platform: Native Android app
🏒 Company: Desoft (Cuba’s national software development company)
πŸ‘₯ Team Size: 1 developer
πŸ’Ό Role: UI/UX design and complete Android app development
πŸ› οΈ Key Technologies: 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

πŸ“– Project Background

πŸ› οΈ Tech Stack

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

πŸ“‹ Project Structure

β”œβ”€β”€ database/                        # Local database related classes
β”‚   β”œβ”€β”€ CubadebateDatabase.kt        # Room database main class
β”‚   β”œβ”€β”€ converters/                  # Data type converters
β”‚   β”œβ”€β”€ dao/                         # Data access objects
β”‚   β”‚   β”œβ”€β”€ PostDao.kt               # Post-related data access
β”‚   β”‚   β”œβ”€β”€ RecentCategoryDao.kt     # Recent category data access
β”‚   β”‚   └── TagDao.kt                # Tag-related data access
β”‚   └── model/                       # Database entity models
β”‚       β”œβ”€β”€ post/                    # Post-related entities
β”‚       β”‚   β”œβ”€β”€ DatabasePost.kt      # Post main entity
β”‚       β”‚   β”œβ”€β”€ DatabaseCategory.kt  # Category entity
β”‚       β”‚   └── ...(other post entities)
β”‚       β”œβ”€β”€ savedpost/               # Saved post entities
β”‚       β”‚   β”œβ”€β”€ SavedPost.kt         # Saved post main entity
β”‚       β”‚   β”œβ”€β”€ SavedCategory.kt     # Saved post category
β”‚       β”‚   └── ...(other saved post entities)
β”‚       β”œβ”€β”€ ...(other entities)
β”‚
β”œβ”€β”€ model/                           # Data model classes
β”‚   β”œβ”€β”€ api/                         # API response models
β”‚   β”‚   β”œβ”€β”€ comment/                 # Comment API models
β”‚   β”‚   β”‚   β”œβ”€β”€ Content.kt           # Comment content
β”‚   β”‚   β”‚   └── ResponseComment.kt   # Comment response model
β”‚   β”‚   β”œβ”€β”€ post/                    # Post API models
β”‚   β”‚   β”‚   β”œβ”€β”€ NetworkPost.kt       # Network post model
β”‚   β”‚   β”‚   └── ...(other API models)
β”‚   β”œβ”€β”€ categories/                  # Category-related models
β”‚   β”‚   └── MyCategoriesGridViewItem.kt
β”‚   β”œβ”€β”€ comment/                     # Comment domain models
β”‚   β”‚   └── Comment.kt               # Comment information
β”‚   └── post/                        # Post domain models
β”‚       β”œβ”€β”€ Post.kt                  # Post main model
β”‚       β”œβ”€β”€ Category.kt              # Category model
β”‚       └── ...(other post models)
β”‚
β”œβ”€β”€ network/                         # Network communication classes
β”‚   └── CubadebateApiService.kt      # Retrofit API service interface
β”‚
β”œβ”€β”€ repository/                      # Data repository (Repository pattern)
β”‚   β”œβ”€β”€ PostRepository.kt            # Post data management
β”‚   β”œβ”€β”€ RecentCategoryRepository.kt  # Recent category data management
β”‚   └── TagRepository.kt             # Tag data management
β”‚
β”œβ”€β”€ ui/                              # User interface classes
β”‚   β”œβ”€β”€ CoroutineBaseViewModel.kt    # Coroutine-based base view model
β”‚   β”œβ”€β”€ PostsViewModel.kt            # Common post view model
β”‚   β”œβ”€β”€ HeadingsAdapter.kt           # Post list adapter
β”‚   β”œβ”€β”€ EndlessRecyclerViewScrollListener.kt  # Infinite scroll listener

β”‚   β”œβ”€β”€ main/                        # Main screen classes
β”‚   β”‚   β”œβ”€β”€ MainActivity.kt          # Main activity
β”‚   β”‚   β”œβ”€β”€ MainActivityViewModel.kt # Main activity view model
β”‚   β”œβ”€β”€ categories/                  # Category screens
β”‚   β”‚   β”œβ”€β”€ BaseCategoryFragment.kt  # Category base fragment
β”‚   β”‚   β”œβ”€β”€ HomeFragment.kt          # Home fragment
β”‚   β”œβ”€β”€ details/                     # Post detail screen
β”‚   β”œβ”€β”€ comments/                    # Comment-related screens
β”‚   β”‚   β”œβ”€β”€ CommentsActivity.kt      # Comments activity
β”‚   β”‚   β”œβ”€β”€ CommentsFragment.kt      # Comments fragment
β”‚   β”‚   β”œβ”€β”€ RepliesFragment.kt       # Comment replies fragment
β”‚   β”‚   └── ...(ViewModels and other classes)
β”‚   β”œβ”€β”€ search/                      # Search screens
β”‚   β”œβ”€β”€ saved/                       # Saved posts screen
β”‚   β”œβ”€β”€ forme/                       # Personalized recommendation screen
β”‚   β”‚   β”œβ”€β”€ ForMeFragment.kt         # Recommendation main fragment
β”‚   β”‚   β”œβ”€β”€ MyCategoriesFragment.kt  # My categories fragment
β”‚   β”‚   β”œβ”€β”€ MyTopicsFragment.kt      # My topics fragment
β”‚   β”‚   └── ...(ViewModels and other classes)
β”‚   β”‚
β”‚   β”œβ”€β”€ headingspertag/              # Posts by tag screen
β”‚   β”œβ”€β”€ subscription/                # Subscription screens
β”‚   └── settings/                    # Settings screens
β”‚       β”œβ”€β”€ categories/              # Category management
β”‚       └── topics/                  # Topic management
β”‚
└── util/                            # Utility classes and helper functions
    β”œβ”€β”€ ActivityUtils.kt             # Activity utilities
    β”œβ”€β”€ BindingUtils.kt              # Data binding utilities
    β”œβ”€β”€ MappingUtils.kt              # Data mapping utilities
    β”œβ”€β”€ PostUtils.kt                 # Post utilities
    β”œβ”€β”€ PreferenceManager.kt         # Settings management utilities
    └── Util.kt                      # General utility functions

🌟 Implementation & Achievements

🧭 Technical Decision-Making

1. Offline Storage Architecture Selection

@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 Architecture Implementation

class PostRepository(private val database: CubadebateDatabase) {
    suspend fun getPosts(categoryId: Long?): MutableList<Post> {
        return withContext(Dispatchers.IO) {
            try {
                // Attempt to fetch latest data from network
                val networkPosts = when(categoryId) {
                    null -> CubadebateApi.retrofitService.getPostsAsync()
                    else -> CubadebateApi.retrofitService.getPostsByCategoryAsync(categoryId)
                }.await()
                
                // Save to local DB and return
                networkPosts.map { it.mapToPost() }
            } catch (e: Exception) {
                // Return local data on network failure
                getPostsFromDb(categoryId)
            }
        }
    }
}

🌱 Problem Solving

1. User-Centric Content Discovery Enhancement

🎞️ Video

Watch the Video