@shaykec/app-agent 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/ui-tester/SKILL.md +59 -0
- package/.cursor/skills/android-customizer/SKILL.md +50 -16
- package/.cursor/skills/appconfig-customization/SKILL.md +15 -0
- package/.cursor/skills/customization-planner/SKILL.md +17 -1
- package/.cursor/skills/ios-customizer/SKILL.md +54 -13
- package/.cursor/skills/mock-data-update/SKILL.md +11 -3
- package/.cursor/skills/ui-tester/SKILL.md +59 -0
- package/dist/cli.d.ts +18 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +134 -14
- package/dist/cli.js.map +1 -1
- package/dist/github.d.ts +5 -0
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +27 -0
- package/dist/github.js.map +1 -1
- package/dist/index.js +218 -24
- package/dist/index.js.map +1 -1
- package/dist/preview-generator.d.ts +35 -0
- package/dist/preview-generator.d.ts.map +1 -0
- package/dist/preview-generator.js +546 -0
- package/dist/preview-generator.js.map +1 -0
- package/package.json +4 -1
- package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/features/booking/BookingScreen.kt +5 -3
- package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/features/bookings/BookingsScreen.kt +7 -5
- package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/features/discovery/DiscoveryViewModel.kt +3 -2
- package/templates/android/BookTemplate/app/src/main/kotlin/com/appship/book/features/profile/ProfileScreen.kt +4 -2
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/AppConfig.kt +9 -0
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/data/DataRepository.kt +23 -0
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/data/DataSourceResolver.kt +23 -0
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/calls/CallsScreen.kt +4 -3
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/contacts/ContactsScreen.kt +3 -2
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/conversations/ChatScreen.kt +11 -10
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/conversations/ConversationsScreen.kt +5 -5
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/navigation/Navigation.kt +4 -2
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/features/settings/SettingsScreen.kt +6 -4
- package/templates/android/ChatTemplate/app/src/main/kotlin/com/appship/chat/mock/MockDataProvider.kt +7 -7
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/data/DataRepository.kt +46 -0
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/data/DataSourceResolver.kt +23 -0
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/alerts/AlertsScreen.kt +4 -3
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/dashboard/DashboardScreen.kt +3 -2
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/datasources/DataSourcesScreen.kt +3 -2
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/features/reports/ReportsScreen.kt +3 -2
- package/templates/android/DashTemplate/app/src/main/kotlin/com/appship/dash/mock/MockDataProvider.kt +16 -15
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/AppConfig.kt +9 -0
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/calendar/CalendarScreen.kt +5 -5
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/chores/ChoreBoardScreen.kt +3 -3
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/familyhub/FamilyHubScreen.kt +4 -4
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/gallery/GalleryScreen.kt +3 -3
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/members/MembersListScreen.kt +5 -5
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/rewards/RewardsScreen.kt +5 -5
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/features/settings/SettingsScreen.kt +3 -3
- package/templates/android/FamilyTemplate/app/src/main/java/com/appship/family/mock/MockDataProvider.kt +29 -32
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/AppConfig.kt +9 -0
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/data/DataRepository.kt +70 -0
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/data/DataSourceResolver.kt +23 -0
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/features/budgets/BudgetsScreen.kt +3 -2
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/features/goals/GoalsScreen.kt +5 -3
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/features/home/HomeScreen.kt +8 -7
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/features/settings/SettingsScreen.kt +0 -1
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/features/transactions/TransactionsScreen.kt +9 -4
- package/templates/android/FinanceTemplate/app/src/main/kotlin/com/appship/finance/mock/MockDataProvider.kt +103 -11
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/data/DataRepository.kt +19 -0
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/leaderboard/LeaderboardScreen.kt +2 -1
- package/templates/android/GameTemplate/app/src/main/kotlin/com/appship/game/features/results/ResultsScreen.kt +3 -2
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/data/DataRepository.kt +46 -0
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/data/DataSourceResolver.kt +23 -0
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/features/dashboard/DashboardScreen.kt +3 -2
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/features/profile/ProfileScreen.kt +3 -2
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/features/workouts/WorkoutListScreen.kt +3 -2
- package/templates/android/HealthTemplate/app/src/main/kotlin/com/appship/health/mock/MockDataProvider.kt +13 -13
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/AppConfig.kt +9 -0
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/data/DataRepository.kt +48 -0
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/data/DataSourceResolver.kt +23 -0
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/features/courses/CourseListScreen.kt +4 -3
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/features/leaderboard/LeaderboardScreen.kt +3 -2
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/features/profile/ProfileScreen.kt +3 -2
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/features/progress/ProgressDashboardScreen.kt +3 -2
- package/templates/android/LearnTemplate/app/src/main/kotlin/com/appship/learn/mock/MockDataProvider.kt +41 -11
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/data/DataSourceResolver.kt +11 -6
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/di/AppModule.kt +11 -2
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/favorites/FavoritesViewModel.kt +4 -4
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/map/MapViewModel.kt +4 -4
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/place/PlaceDetailViewModel.kt +5 -5
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/place/PlaceListViewModel.kt +4 -4
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/profile/ProfileViewModel.kt +5 -5
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/route/RouteViewModel.kt +3 -3
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/search/SearchViewModel.kt +3 -3
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/features/settings/SettingsViewModel.kt +3 -3
- package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/mock/MockDataProvider.kt +54 -41
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/AppConfig.kt +9 -0
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/features/browse/BrowseScreen.kt +2 -1
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/features/detail/DetailScreen.kt +3 -1
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/features/home/HomeScreen.kt +3 -2
- package/templates/android/MediaTemplate/app/src/main/kotlin/com/appship/media/mock/MockDataProvider.kt +63 -132
- package/templates/android/ReferenceTemplate/app/src/main/kotlin/com/appship/reference/AppConfig.kt +9 -0
- package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/features/home/HomeViewModel.kt +2 -1
- package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/features/products/ProductViewModels.kt +12 -7
- package/templates/android/ShopTemplate/app/src/main/kotlin/com/appship/shop/mock/MockDataProvider.kt +3 -3
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/data/DataRepository.kt +0 -1
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/createpost/CreatePostScreen.kt +3 -2
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/feed/CommentsScreen.kt +4 -3
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/feed/FeedScreen.kt +3 -2
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/messages/MessagesScreen.kt +9 -8
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/notifications/NotificationsScreen.kt +3 -2
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/profile/ProfileScreen.kt +5 -4
- package/templates/android/SocialTemplate/app/src/main/kotlin/com/appship/social/features/search/SearchScreen.kt +3 -2
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/AppConfig.kt +9 -0
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/data/DataRepository.kt +38 -0
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/data/DataSourceResolver.kt +23 -0
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/calendar/CalendarScreen.kt +0 -1
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/inbox/InboxScreen.kt +4 -2
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/kanban/KanbanBoardScreen.kt +5 -3
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/projects/ProjectDetailScreen.kt +9 -5
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/projects/ProjectListScreen.kt +6 -4
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/search/SearchScreen.kt +1 -1
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/features/tasks/TaskDetailScreen.kt +0 -1
- package/templates/android/TaskTemplate/app/src/main/kotlin/com/appship/task/mock/MockDataProvider.kt +13 -12
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/AppConfig.kt +9 -0
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/data/DataRepository.kt +34 -0
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/data/DataSourceResolver.kt +23 -0
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/features/achievements/AchievementsViewModel.kt +4 -2
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/features/dashboard/TodayViewModel.kt +4 -2
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/features/habits/HabitDetailViewModel.kt +4 -2
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/features/habits/HabitsListViewModel.kt +4 -2
- package/templates/android/TrackTemplate/app/src/main/kotlin/com/appship/track/mock/MockDataProvider.kt +13 -11
- package/templates/ios/ChatTemplate/ChatTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/ChatTemplate/ChatTemplate/Data/DataRepository.swift +43 -0
- package/templates/ios/ChatTemplate/ChatTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/DashTemplate/DashTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/DashTemplate/DashTemplate/Data/DataRepository.swift +53 -0
- package/templates/ios/DashTemplate/DashTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/FamilyTemplate/FamilyTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/FamilyTemplate/FamilyTemplate/App/FamilyTemplateApp.swift +4 -2
- package/templates/ios/FamilyTemplate/FamilyTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/FinanceTemplate/FinanceTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate/Data/DataRepository.swift +75 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Budgets/BudgetsView.swift +3 -1
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Goals/GoalsView.swift +3 -1
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Home/HomeView.swift +13 -6
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Settings/SettingsView.swift +6 -2
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Transactions/AddTransactionView.swift +4 -2
- package/templates/ios/FinanceTemplate/FinanceTemplate/Features/Transactions/TransactionsView.swift +3 -1
- package/templates/ios/FinanceTemplate/FinanceTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/GameTemplate/GameTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/GameTemplate/GameTemplate/Data/DataRepository.swift +30 -0
- package/templates/ios/GameTemplate/GameTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/GameTemplate/GameTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/HealthTemplate/HealthTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/HealthTemplate/HealthTemplate/Data/DataRepository.swift +60 -0
- package/templates/ios/HealthTemplate/HealthTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/LearnTemplate/LearnTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Courses/CourseDetailView.swift +3 -2
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Courses/CourseListView.swift +3 -2
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Flashcards/FlashcardView.swift +2 -1
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Leaderboard/LeaderboardView.swift +2 -1
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Lessons/LessonPlayerView.swift +4 -2
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Profile/ProfileView.swift +4 -2
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Progress/ProgressDashboardView.swift +3 -2
- package/templates/ios/LearnTemplate/LearnTemplate/Features/Quiz/QuizView.swift +2 -1
- package/templates/ios/LearnTemplate/LearnTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/MediaTemplate/MediaTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/MediaTemplate/MediaTemplate/Data/DataRepository.swift +52 -0
- package/templates/ios/MediaTemplate/MediaTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/MediaTemplate/MediaTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/Data/DataRepository.swift +28 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/ReferenceTemplate/ReferenceTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/TaskTemplate/TaskTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/TaskTemplate/TaskTemplate/Data/DataRepository.swift +38 -0
- package/templates/ios/TaskTemplate/TaskTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Calendar/CalendarView.swift +6 -2
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Inbox/InboxView.swift +2 -1
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Kanban/KanbanBoardView.swift +9 -3
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Projects/ProjectDetailView.swift +3 -1
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Projects/ProjectListView.swift +3 -1
- package/templates/ios/TaskTemplate/TaskTemplate/Features/Search/SearchView.swift +3 -1
- package/templates/ios/TaskTemplate/TaskTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/TrackTemplate/TrackTemplate/App/AppConfig.swift +9 -0
- package/templates/ios/TrackTemplate/TrackTemplate/Data/DataRepository.swift +29 -0
- package/templates/ios/TrackTemplate/TrackTemplate/Data/DataSourceResolver.swift +20 -0
- package/templates/ios/TrackTemplate/TrackTemplate/MockData/MockDataProvider.swift +1 -1
- package/templates/ios/TrackTemplate/TrackTemplate/Services/HabitManager.swift +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
package com.appship.learn.mock
|
|
2
2
|
|
|
3
3
|
import com.appship.learn.AppConfig
|
|
4
|
+
import com.appship.learn.data.DataRepository
|
|
4
5
|
import com.appship.learn.data.models.*
|
|
5
6
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
6
7
|
import kotlinx.coroutines.flow.StateFlow
|
|
7
8
|
import kotlinx.coroutines.flow.asStateFlow
|
|
8
9
|
|
|
9
10
|
// CUSTOMIZE:API - Replace mock data with real API calls
|
|
10
|
-
object MockDataProvider {
|
|
11
|
+
object MockDataProvider : DataRepository {
|
|
11
12
|
|
|
12
13
|
// MARK: - Default Seed Data
|
|
13
14
|
private val defaultCategories = listOf(
|
|
@@ -172,14 +173,14 @@ object MockDataProvider {
|
|
|
172
173
|
val userProgress: StateFlow<UserProgress> = _userProgress.asStateFlow()
|
|
173
174
|
|
|
174
175
|
// MARK: - CRUD Functions
|
|
175
|
-
fun getCourses(): List<Course> = _courses.value
|
|
176
|
-
fun getCourse(id: String): Course? = _courses.value.find { it.id == id }
|
|
177
|
-
fun getLessons(courseId: String): List<Lesson> = _courses.value.find { it.id == courseId }?.lessons ?: emptyList()
|
|
178
|
-
fun getFlashcardDecks(): List<FlashcardDeck> = _flashcardDecks.value
|
|
179
|
-
fun getLeaderboard(): List<LeaderboardEntry> = _leaderboardEntries.value.sortedBy { it.rank }
|
|
180
|
-
fun getProgress(): UserProgress = _userProgress.value
|
|
181
|
-
|
|
182
|
-
fun markLessonComplete(courseId: String, lessonId: String) {
|
|
176
|
+
override fun getCourses(): List<Course> = _courses.value
|
|
177
|
+
override fun getCourse(id: String): Course? = _courses.value.find { it.id == id }
|
|
178
|
+
override fun getLessons(courseId: String): List<Lesson> = _courses.value.find { it.id == courseId }?.lessons ?: emptyList()
|
|
179
|
+
override fun getFlashcardDecks(): List<FlashcardDeck> = _flashcardDecks.value
|
|
180
|
+
override fun getLeaderboard(): List<LeaderboardEntry> = _leaderboardEntries.value.sortedBy { it.rank }
|
|
181
|
+
override fun getProgress(): UserProgress = _userProgress.value
|
|
182
|
+
|
|
183
|
+
override fun markLessonComplete(courseId: String, lessonId: String) {
|
|
183
184
|
val courseIndex = _courses.value.indexOfFirst { it.id == courseId }
|
|
184
185
|
if (courseIndex >= 0) {
|
|
185
186
|
val course = _courses.value[courseIndex]
|
|
@@ -214,7 +215,7 @@ object MockDataProvider {
|
|
|
214
215
|
)
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
fun updateFlashcard(deckId: String, cardId: String, difficulty: FlashcardDifficulty) {
|
|
218
|
+
override fun updateFlashcard(deckId: String, cardId: String, difficulty: FlashcardDifficulty) {
|
|
218
219
|
val deckIndex = _flashcardDecks.value.indexOfFirst { it.id == deckId }
|
|
219
220
|
if (deckIndex >= 0) {
|
|
220
221
|
val deck = _flashcardDecks.value[deckIndex]
|
|
@@ -242,11 +243,40 @@ object MockDataProvider {
|
|
|
242
243
|
}
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
fun reset() {
|
|
246
|
+
override fun reset() {
|
|
246
247
|
_courses.value = defaultCourses
|
|
247
248
|
_flashcardDecks.value = defaultFlashcardDecks
|
|
248
249
|
_leaderboardEntries.value = defaultLeaderboardEntries
|
|
249
250
|
_userProgress.value = defaultUserProgress
|
|
250
251
|
_achievements.value = defaultAchievements
|
|
251
252
|
}
|
|
253
|
+
|
|
254
|
+
// Additional methods required by DataRepository interface
|
|
255
|
+
override fun getQuiz(lessonId: String): Quiz? {
|
|
256
|
+
// TODO: Implement quiz retrieval
|
|
257
|
+
return null
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
override fun updateProgress(progress: UserProgress) {
|
|
261
|
+
_userProgress.value = progress
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
override fun updateStreak() {
|
|
265
|
+
val progress = _userProgress.value
|
|
266
|
+
val newStreak = progress.currentStreak + 1
|
|
267
|
+
_userProgress.value = progress.copy(
|
|
268
|
+
currentStreak = newStreak,
|
|
269
|
+
longestStreak = maxOf(progress.longestStreak, newStreak),
|
|
270
|
+
totalXP = progress.totalXP + AppConfig.Business.XP_PER_STREAK
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
override fun unlockAchievement(achievementId: String) {
|
|
275
|
+
val achievements = _achievements.value.toMutableList()
|
|
276
|
+
val index = achievements.indexOfFirst { it.id == achievementId }
|
|
277
|
+
if (index >= 0 && !achievements[index].isUnlocked) {
|
|
278
|
+
achievements[index] = achievements[index].copy(isUnlocked = true)
|
|
279
|
+
_achievements.value = achievements
|
|
280
|
+
}
|
|
281
|
+
}
|
|
252
282
|
}
|
package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/data/DataSourceResolver.kt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.appship.map.data
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
3
4
|
import com.appship.map.AppConfig
|
|
4
5
|
import com.appship.map.mock.MockDataProvider
|
|
5
6
|
|
|
@@ -7,17 +8,21 @@ import com.appship.map.mock.MockDataProvider
|
|
|
7
8
|
* Resolves the active [DataRepository] implementation based on [AppConfig.DataSource.active].
|
|
8
9
|
* Screens use this to obtain the correct data source without knowing the concrete type.
|
|
9
10
|
*
|
|
11
|
+
* Note: For ViewModels, prefer injecting [DataRepository] via Hilt instead of using this resolver.
|
|
12
|
+
* This resolver is primarily for Views/Screens that don't use dependency injection.
|
|
13
|
+
*
|
|
10
14
|
* Usage:
|
|
11
|
-
* val repository = DataSourceResolver.
|
|
15
|
+
* val repository = DataSourceResolver.getRepository(context)
|
|
12
16
|
* val places = repository.places
|
|
13
17
|
*/
|
|
14
18
|
object DataSourceResolver {
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
fun getRepository(context: Context): DataRepository {
|
|
20
|
+
return when (AppConfig.DataSource.active) {
|
|
17
21
|
AppConfig.DataSource.SourceType.LOCAL_STORAGE -> {
|
|
18
|
-
// TODO: Return LocalStorageProvider once implemented
|
|
19
|
-
MockDataProvider
|
|
22
|
+
// TODO: Return LocalStorageProvider.getInstance(context) once implemented
|
|
23
|
+
MockDataProvider.getInstance(com.appship.map.data.LocalPersistence(context))
|
|
20
24
|
}
|
|
21
|
-
AppConfig.DataSource.SourceType.MOCK -> MockDataProvider
|
|
25
|
+
AppConfig.DataSource.SourceType.MOCK -> MockDataProvider.getInstance(com.appship.map.data.LocalPersistence(context))
|
|
22
26
|
}
|
|
27
|
+
}
|
|
23
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.appship.map.di
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import com.appship.map.data.DataRepository
|
|
4
5
|
import com.appship.map.data.LocalPersistence
|
|
5
6
|
import com.appship.map.data.NetworkMonitor
|
|
6
7
|
import com.appship.map.data.SyncManager
|
|
@@ -32,12 +33,20 @@ object AppModule {
|
|
|
32
33
|
return NetworkMonitor(context)
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
@Provides
|
|
37
|
+
@Singleton
|
|
38
|
+
fun provideDataRepository(
|
|
39
|
+
mockDataProvider: MockDataProvider
|
|
40
|
+
): DataRepository {
|
|
41
|
+
return mockDataProvider
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
@Provides
|
|
36
45
|
@Singleton
|
|
37
46
|
fun provideSyncManager(
|
|
38
47
|
networkMonitor: NetworkMonitor,
|
|
39
|
-
|
|
48
|
+
dataRepository: DataRepository
|
|
40
49
|
): SyncManager {
|
|
41
|
-
return SyncManager(networkMonitor,
|
|
50
|
+
return SyncManager(networkMonitor, dataRepository as MockDataProvider)
|
|
42
51
|
}
|
|
43
52
|
}
|
|
@@ -2,8 +2,8 @@ package com.appship.map.features.favorites
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.Place
|
|
6
|
-
import com.appship.map.mock.MockDataProvider
|
|
7
7
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
8
8
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
9
9
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
|
|
13
13
|
|
|
14
14
|
@HiltViewModel
|
|
15
15
|
class FavoritesViewModel @Inject constructor(
|
|
16
|
-
private val
|
|
16
|
+
private val repository: DataRepository
|
|
17
17
|
) : ViewModel() {
|
|
18
18
|
|
|
19
19
|
data class FavoritesUiState(
|
|
@@ -32,14 +32,14 @@ class FavoritesViewModel @Inject constructor(
|
|
|
32
32
|
kotlinx.coroutines.delay(300)
|
|
33
33
|
|
|
34
34
|
_uiState.value = _uiState.value.copy(
|
|
35
|
-
favorites =
|
|
35
|
+
favorites = repository.getFavoritePlaces(),
|
|
36
36
|
isLoading = false
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
fun removeFavorite(place: Place) {
|
|
42
|
-
|
|
42
|
+
repository.toggleFavorite(place)
|
|
43
43
|
loadFavorites() // Refresh
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -2,8 +2,8 @@ package com.appship.map.features.map
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.Place
|
|
6
|
-
import com.appship.map.mock.MockDataProvider
|
|
7
7
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
8
8
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
9
9
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
|
|
13
13
|
|
|
14
14
|
@HiltViewModel
|
|
15
15
|
class MapViewModel @Inject constructor(
|
|
16
|
-
private val
|
|
16
|
+
private val repository: DataRepository
|
|
17
17
|
) : ViewModel() {
|
|
18
18
|
|
|
19
19
|
data class MapUiState(
|
|
@@ -33,14 +33,14 @@ class MapViewModel @Inject constructor(
|
|
|
33
33
|
kotlinx.coroutines.delay(500)
|
|
34
34
|
|
|
35
35
|
_uiState.value = _uiState.value.copy(
|
|
36
|
-
places =
|
|
36
|
+
places = repository.places,
|
|
37
37
|
isLoading = false
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
fun toggleFavorite(place: Place) {
|
|
43
|
-
|
|
43
|
+
repository.toggleFavorite(place)
|
|
44
44
|
loadPlaces() // Refresh list
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -2,9 +2,9 @@ package com.appship.map.features.place
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.Place
|
|
6
7
|
import com.appship.map.data.Review
|
|
7
|
-
import com.appship.map.mock.MockDataProvider
|
|
8
8
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
9
9
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
10
10
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -14,7 +14,7 @@ import javax.inject.Inject
|
|
|
14
14
|
|
|
15
15
|
@HiltViewModel
|
|
16
16
|
class PlaceDetailViewModel @Inject constructor(
|
|
17
|
-
private val
|
|
17
|
+
private val repository: DataRepository
|
|
18
18
|
) : ViewModel() {
|
|
19
19
|
|
|
20
20
|
data class PlaceDetailUiState(
|
|
@@ -34,8 +34,8 @@ class PlaceDetailViewModel @Inject constructor(
|
|
|
34
34
|
// CUSTOMIZE:API - Replace with real API call
|
|
35
35
|
kotlinx.coroutines.delay(300)
|
|
36
36
|
|
|
37
|
-
val place =
|
|
38
|
-
val reviews = place?.let {
|
|
37
|
+
val place = repository.getPlace(placeId)
|
|
38
|
+
val reviews = place?.let { repository.getReviews(it.id) } ?: emptyList()
|
|
39
39
|
|
|
40
40
|
_uiState.value = _uiState.value.copy(
|
|
41
41
|
place = place,
|
|
@@ -46,7 +46,7 @@ class PlaceDetailViewModel @Inject constructor(
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
fun toggleFavorite(place: Place) {
|
|
49
|
-
|
|
49
|
+
repository.toggleFavorite(place)
|
|
50
50
|
loadPlace(place.id) // Refresh
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -2,8 +2,8 @@ package com.appship.map.features.place
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.Place
|
|
6
|
-
import com.appship.map.mock.MockDataProvider
|
|
7
7
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
8
8
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
9
9
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
|
|
13
13
|
|
|
14
14
|
@HiltViewModel
|
|
15
15
|
class PlaceListViewModel @Inject constructor(
|
|
16
|
-
private val
|
|
16
|
+
private val repository: DataRepository
|
|
17
17
|
) : ViewModel() {
|
|
18
18
|
|
|
19
19
|
data class PlaceListUiState(
|
|
@@ -33,14 +33,14 @@ class PlaceListViewModel @Inject constructor(
|
|
|
33
33
|
kotlinx.coroutines.delay(500)
|
|
34
34
|
|
|
35
35
|
_uiState.value = _uiState.value.copy(
|
|
36
|
-
places =
|
|
36
|
+
places = repository.places,
|
|
37
37
|
isLoading = false
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
fun toggleFavorite(place: Place) {
|
|
43
|
-
|
|
43
|
+
repository.toggleFavorite(place)
|
|
44
44
|
loadPlaces() // Refresh list
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -2,8 +2,8 @@ package com.appship.map.features.profile
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.User
|
|
6
|
-
import com.appship.map.mock.MockDataProvider
|
|
7
7
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
8
8
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
9
9
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
|
|
13
13
|
|
|
14
14
|
@HiltViewModel
|
|
15
15
|
class ProfileViewModel @Inject constructor(
|
|
16
|
-
private val
|
|
16
|
+
private val repository: DataRepository
|
|
17
17
|
) : ViewModel() {
|
|
18
18
|
|
|
19
19
|
data class ProfileUiState(
|
|
@@ -28,13 +28,13 @@ class ProfileViewModel @Inject constructor(
|
|
|
28
28
|
|
|
29
29
|
fun loadProfile() {
|
|
30
30
|
viewModelScope.launch {
|
|
31
|
-
val user =
|
|
32
|
-
val favorites =
|
|
31
|
+
val user = repository.currentUser
|
|
32
|
+
val favorites = repository.getFavoritePlaces()
|
|
33
33
|
|
|
34
34
|
_uiState.value = _uiState.value.copy(
|
|
35
35
|
user = user,
|
|
36
36
|
favoriteCount = favorites.size,
|
|
37
|
-
reviewCount =
|
|
37
|
+
reviewCount = repository.reviews.values.sumOf { it.size }
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -3,8 +3,8 @@ package com.appship.map.features.route
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
5
|
import com.appship.map.data.Coordinate
|
|
6
|
+
import com.appship.map.data.DataRepository
|
|
6
7
|
import com.appship.map.data.Route
|
|
7
|
-
import com.appship.map.mock.MockDataProvider
|
|
8
8
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
9
9
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
10
10
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -14,7 +14,7 @@ import javax.inject.Inject
|
|
|
14
14
|
|
|
15
15
|
@HiltViewModel
|
|
16
16
|
class RouteViewModel @Inject constructor(
|
|
17
|
-
private val
|
|
17
|
+
private val repository: DataRepository
|
|
18
18
|
) : ViewModel() {
|
|
19
19
|
|
|
20
20
|
data class RouteUiState(
|
|
@@ -33,7 +33,7 @@ class RouteViewModel @Inject constructor(
|
|
|
33
33
|
// CUSTOMIZE:API - Replace with real API call
|
|
34
34
|
kotlinx.coroutines.delay(500)
|
|
35
35
|
|
|
36
|
-
val route =
|
|
36
|
+
val route = repository.getRoute(origin, destination)
|
|
37
37
|
|
|
38
38
|
_uiState.value = _uiState.value.copy(
|
|
39
39
|
route = route,
|
|
@@ -2,8 +2,8 @@ package com.appship.map.features.search
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.Place
|
|
6
|
-
import com.appship.map.mock.MockDataProvider
|
|
7
7
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
8
8
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
9
9
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
|
|
13
13
|
|
|
14
14
|
@HiltViewModel
|
|
15
15
|
class SearchViewModel @Inject constructor(
|
|
16
|
-
private val
|
|
16
|
+
private val repository: DataRepository
|
|
17
17
|
) : ViewModel() {
|
|
18
18
|
|
|
19
19
|
data class SearchUiState(
|
|
@@ -37,7 +37,7 @@ class SearchViewModel @Inject constructor(
|
|
|
37
37
|
// CUSTOMIZE:API - Replace with real API call
|
|
38
38
|
kotlinx.coroutines.delay(300)
|
|
39
39
|
|
|
40
|
-
val results =
|
|
40
|
+
val results = repository.searchPlaces(query)
|
|
41
41
|
_uiState.value = _uiState.value.copy(
|
|
42
42
|
results = results,
|
|
43
43
|
isLoading = false
|
|
@@ -2,7 +2,7 @@ package com.appship.map.features.settings
|
|
|
2
2
|
|
|
3
3
|
import androidx.lifecycle.ViewModel
|
|
4
4
|
import androidx.lifecycle.viewModelScope
|
|
5
|
-
import com.appship.map.
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
6
6
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
7
7
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
8
8
|
import kotlinx.coroutines.flow.StateFlow
|
|
@@ -12,7 +12,7 @@ import javax.inject.Inject
|
|
|
12
12
|
|
|
13
13
|
@HiltViewModel
|
|
14
14
|
class SettingsViewModel @Inject constructor(
|
|
15
|
-
private val
|
|
15
|
+
private val repository: DataRepository
|
|
16
16
|
) : ViewModel() {
|
|
17
17
|
|
|
18
18
|
data class SettingsUiState(
|
|
@@ -37,7 +37,7 @@ class SettingsViewModel @Inject constructor(
|
|
|
37
37
|
|
|
38
38
|
fun resetData() {
|
|
39
39
|
viewModelScope.launch {
|
|
40
|
-
|
|
40
|
+
repository.reset()
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
package/templates/android/MapTemplate/app/src/main/kotlin/com/appship/map/mock/MockDataProvider.kt
CHANGED
|
@@ -2,6 +2,7 @@ package com.appship.map.mock
|
|
|
2
2
|
|
|
3
3
|
import com.appship.map.AppConfig
|
|
4
4
|
import com.appship.map.data.*
|
|
5
|
+
import com.appship.map.data.DataRepository
|
|
5
6
|
import com.appship.map.data.LocalPersistence
|
|
6
7
|
import java.util.Date
|
|
7
8
|
import java.util.Random
|
|
@@ -11,15 +12,27 @@ import javax.inject.Singleton
|
|
|
11
12
|
@Singleton
|
|
12
13
|
class MockDataProvider @Inject constructor(
|
|
13
14
|
private val persistence: LocalPersistence
|
|
14
|
-
) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
var currentUser: User = defaultCurrentUser
|
|
15
|
+
) : DataRepository {
|
|
16
|
+
override val places: List<Place> get() = _places
|
|
17
|
+
override val reviews: Map<String, List<Review>> get() = _reviews.mapValues { it.value.toList() }
|
|
18
|
+
override val routes: List<Route> get() = _routes
|
|
19
|
+
override var currentUser: User = defaultCurrentUser
|
|
20
|
+
|
|
21
|
+
private var _places: MutableList<Place> = mutableListOf()
|
|
22
|
+
private var _reviews: MutableMap<String, MutableList<Review>> = mutableMapOf()
|
|
23
|
+
private var _routes: MutableList<Route> = mutableListOf()
|
|
19
24
|
|
|
20
25
|
companion object {
|
|
26
|
+
@Volatile
|
|
27
|
+
private var INSTANCE: MockDataProvider? = null
|
|
21
28
|
private val random = Random()
|
|
22
29
|
|
|
30
|
+
fun getInstance(persistence: LocalPersistence): MockDataProvider {
|
|
31
|
+
return INSTANCE ?: synchronized(this) {
|
|
32
|
+
INSTANCE ?: MockDataProvider(persistence).also { INSTANCE = it }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
val defaultCurrentUser = User(
|
|
24
37
|
id = "current",
|
|
25
38
|
name = "John Doe",
|
|
@@ -401,60 +414,60 @@ class MockDataProvider @Inject constructor(
|
|
|
401
414
|
// Load persisted places if available, otherwise use defaults
|
|
402
415
|
val savedPlaces = persistence.load<List<Place>>("mockdata_places")
|
|
403
416
|
if (savedPlaces != null) {
|
|
404
|
-
|
|
417
|
+
_places = savedPlaces.toMutableList()
|
|
405
418
|
} else {
|
|
406
|
-
|
|
419
|
+
_places = makeDefaultPlaces().toMutableList()
|
|
407
420
|
// Set favorites based on current user
|
|
408
421
|
for (placeId in currentUser.favoritePlaces) {
|
|
409
|
-
|
|
422
|
+
_places.find { it.id == placeId }?.isFavorite = true
|
|
410
423
|
}
|
|
411
424
|
}
|
|
412
425
|
|
|
413
426
|
// Load persisted reviews if available
|
|
414
427
|
val savedReviews = persistence.load<Map<String, List<Review>>>("mockdata_reviews")
|
|
415
428
|
if (savedReviews != null) {
|
|
416
|
-
|
|
429
|
+
_reviews = savedReviews.mapValues { it.value.toMutableList() }.toMutableMap()
|
|
417
430
|
} else {
|
|
418
431
|
// Initialize default reviews for each place
|
|
419
|
-
for (place in
|
|
420
|
-
|
|
432
|
+
for (place in _places) {
|
|
433
|
+
_reviews[place.id] = makeDefaultReviews(place.id).toMutableList()
|
|
421
434
|
}
|
|
422
435
|
}
|
|
423
436
|
|
|
424
437
|
// Initialize routes
|
|
425
|
-
|
|
438
|
+
_routes = makeDefaultRoutes().toMutableList()
|
|
426
439
|
}
|
|
427
440
|
|
|
428
441
|
// MARK: - CRUD Operations
|
|
429
442
|
|
|
430
|
-
fun getPlace(id: String): Place? {
|
|
431
|
-
return
|
|
443
|
+
override fun getPlace(id: String): Place? {
|
|
444
|
+
return _places.find { it.id == id }
|
|
432
445
|
}
|
|
433
446
|
|
|
434
|
-
fun getReviews(placeId: String): List<Review> {
|
|
435
|
-
return
|
|
447
|
+
override fun getReviews(placeId: String): List<Review> {
|
|
448
|
+
return _reviews[placeId] ?: emptyList()
|
|
436
449
|
}
|
|
437
450
|
|
|
438
|
-
fun addReview(review: Review, placeId: String) {
|
|
439
|
-
if (
|
|
440
|
-
|
|
451
|
+
override fun addReview(review: Review, placeId: String) {
|
|
452
|
+
if (_reviews[placeId] == null) {
|
|
453
|
+
_reviews[placeId] = mutableListOf()
|
|
441
454
|
}
|
|
442
|
-
|
|
455
|
+
_reviews[placeId]?.add(0, review)
|
|
443
456
|
|
|
444
457
|
// Update place rating (simplified average)
|
|
445
|
-
|
|
446
|
-
val placeReviews =
|
|
458
|
+
_places.find { it.id == placeId }?.let { place ->
|
|
459
|
+
val placeReviews = _reviews[placeId] ?: emptyList()
|
|
447
460
|
val avgRating = placeReviews.map { it.rating }.average()
|
|
448
461
|
place.rating = avgRating
|
|
449
462
|
place.reviewCount = placeReviews.size
|
|
450
463
|
}
|
|
451
464
|
|
|
452
|
-
persistence.save(
|
|
453
|
-
persistence.save(
|
|
465
|
+
persistence.save(_reviews, "mockdata_reviews")
|
|
466
|
+
persistence.save(_places, "mockdata_places")
|
|
454
467
|
}
|
|
455
468
|
|
|
456
|
-
fun toggleFavorite(place: Place) {
|
|
457
|
-
|
|
469
|
+
override fun toggleFavorite(place: Place) {
|
|
470
|
+
_places.find { it.id == place.id }?.let { foundPlace ->
|
|
458
471
|
foundPlace.isFavorite = !foundPlace.isFavorite
|
|
459
472
|
|
|
460
473
|
if (foundPlace.isFavorite) {
|
|
@@ -465,18 +478,18 @@ class MockDataProvider @Inject constructor(
|
|
|
465
478
|
currentUser.favoritePlaces = currentUser.favoritePlaces.filter { it != place.id }
|
|
466
479
|
}
|
|
467
480
|
|
|
468
|
-
persistence.save(
|
|
481
|
+
persistence.save(_places, "mockdata_places")
|
|
469
482
|
}
|
|
470
483
|
}
|
|
471
484
|
|
|
472
|
-
fun getFavoritePlaces(): List<Place> {
|
|
473
|
-
return
|
|
485
|
+
override fun getFavoritePlaces(): List<Place> {
|
|
486
|
+
return _places.filter { it.isFavorite }
|
|
474
487
|
}
|
|
475
488
|
|
|
476
489
|
// MARK: - Filtering
|
|
477
490
|
|
|
478
|
-
fun filterPlaces(criteria: FilterCriteria): List<Place> {
|
|
479
|
-
var filtered =
|
|
491
|
+
override fun filterPlaces(criteria: FilterCriteria): List<Place> {
|
|
492
|
+
var filtered = _places.toList()
|
|
480
493
|
|
|
481
494
|
// Category filter
|
|
482
495
|
if (criteria.categories.isNotEmpty()) {
|
|
@@ -510,11 +523,11 @@ class MockDataProvider @Inject constructor(
|
|
|
510
523
|
return filtered
|
|
511
524
|
}
|
|
512
525
|
|
|
513
|
-
fun searchPlaces(query: String): List<Place> {
|
|
514
|
-
if (query.isEmpty()) return
|
|
526
|
+
override fun searchPlaces(query: String): List<Place> {
|
|
527
|
+
if (query.isEmpty()) return _places.toList()
|
|
515
528
|
|
|
516
529
|
val lowercasedQuery = query.lowercase()
|
|
517
|
-
return
|
|
530
|
+
return _places.filter { place ->
|
|
518
531
|
place.name.lowercase().contains(lowercasedQuery) ||
|
|
519
532
|
place.description.lowercase().contains(lowercasedQuery) ||
|
|
520
533
|
place.category.name.lowercase().contains(lowercasedQuery) ||
|
|
@@ -524,7 +537,7 @@ class MockDataProvider @Inject constructor(
|
|
|
524
537
|
|
|
525
538
|
// MARK: - Route Operations
|
|
526
539
|
|
|
527
|
-
fun getRoute(origin: Coordinate, destination: Coordinate): Route? {
|
|
540
|
+
override fun getRoute(origin: Coordinate, destination: Coordinate): Route? {
|
|
528
541
|
// In a real app, this would call a directions API
|
|
529
542
|
// For now, return a mock route
|
|
530
543
|
return Route(
|
|
@@ -540,13 +553,13 @@ class MockDataProvider @Inject constructor(
|
|
|
540
553
|
}
|
|
541
554
|
|
|
542
555
|
// MARK: - Reset
|
|
543
|
-
fun reset() {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
for (place in
|
|
547
|
-
|
|
556
|
+
override fun reset() {
|
|
557
|
+
_places = makeDefaultPlaces().toMutableList()
|
|
558
|
+
_reviews = mutableMapOf()
|
|
559
|
+
for (place in _places) {
|
|
560
|
+
_reviews[place.id] = makeDefaultReviews(place.id).toMutableList()
|
|
548
561
|
}
|
|
549
|
-
|
|
562
|
+
_routes = makeDefaultRoutes().toMutableList()
|
|
550
563
|
currentUser = defaultCurrentUser
|
|
551
564
|
|
|
552
565
|
// Clear persistence
|
|
@@ -74,4 +74,13 @@ object AppConfig {
|
|
|
74
74
|
)
|
|
75
75
|
)
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
// CUSTOMIZE:DATASOURCE - Data source configuration
|
|
79
|
+
object DataSource {
|
|
80
|
+
enum class SourceType {
|
|
81
|
+
LOCAL_STORAGE, // Room — real local database (DEFAULT)
|
|
82
|
+
MOCK // In-memory seed data — for development/testing only
|
|
83
|
+
}
|
|
84
|
+
val active: SourceType = SourceType.MOCK
|
|
85
|
+
}
|
|
77
86
|
}
|
|
@@ -13,7 +13,8 @@ import androidx.compose.ui.unit.dp
|
|
|
13
13
|
fun BrowseScreen(
|
|
14
14
|
onItemClick: (String) -> Unit
|
|
15
15
|
) {
|
|
16
|
-
val
|
|
16
|
+
val repository = remember { com.appship.media.data.DataSourceResolver.repository }
|
|
17
|
+
val categories = repository.categories
|
|
17
18
|
|
|
18
19
|
LazyVerticalGrid(
|
|
19
20
|
columns = GridCells.Fixed(2),
|
|
@@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Download
|
|
|
6
6
|
import androidx.compose.material.icons.filled.PlaylistAdd
|
|
7
7
|
import androidx.compose.material3.*
|
|
8
8
|
import androidx.compose.runtime.Composable
|
|
9
|
+
import androidx.compose.runtime.remember
|
|
9
10
|
import androidx.compose.ui.Modifier
|
|
10
11
|
import androidx.compose.ui.platform.testTag
|
|
11
12
|
import androidx.compose.ui.unit.dp
|
|
@@ -16,7 +17,8 @@ fun DetailScreen(
|
|
|
16
17
|
onBackClick: () -> Unit,
|
|
17
18
|
onPlayClick: () -> Unit
|
|
18
19
|
) {
|
|
19
|
-
val
|
|
20
|
+
val repository = remember { com.appship.media.data.DataSourceResolver.repository }
|
|
21
|
+
val item = repository.mediaItem(itemId) ?: return
|
|
20
22
|
|
|
21
23
|
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
|
|
22
24
|
Text(item.title, style = MaterialTheme.typography.titleLarge)
|