From 8323ced08b3d8645f0e07e0bb2194e8550c06751 Mon Sep 17 00:00:00 2001 From: m6z1 Date: Sun, 29 Dec 2024 16:41:28 +0900 Subject: [PATCH 1/4] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 03f3cfa6939604318d1f46b00a7aa58856e0a310 Merge: 2b3a096f 533a5f4b Author: Son Myeongji <114990782+m6z1@users.noreply.github.com> Date: Sat Dec 28 19:49:17 2024 +0900 Merge branch 'release/1.0.6' into release_wss commit 533a5f4b2dc40ac426e3a8685f968f46898dca04 Author: m6z1 Date: Sat Dec 28 19:47:38 2024 +0900 build: 버전 1.0.6 업데이트 commit e966b626bb78475b01da9fd7b291ff0a26b9b9d4 Merge: 122407a0 d2d1bb46 Author: Son Myeongji <114990782+m6z1@users.noreply.github.com> Date: Sat Dec 28 19:44:39 2024 +0900 Merge pull request #502 from Team-WSS/feat/497 feat: 비로그인 로직을 제거 commit 2b3a096ff9796c718fbd2204f69f0b5318029c6d Author: Son Myeongji <114990782+m6z1@users.noreply.github.com> Date: Sat Dec 28 19:33:36 2024 +0900 Revert "Merge branch 'release/1.0.6' into release_" This reverts commit e9b835506a4d5c5eb5d134f243000c22d203575d, reversing changes made to a37629dcc2dbf406735de37fac4217558657b4f2. commit d2d1bb46a9934aea667389e50dc4bf34130b45ee Author: m6z1 Date: Sat Dec 28 19:22:21 2024 +0900 feat: 비로그인 둘러보기 버튼 제거 commit e9b835506a4d5c5eb5d134f243000c22d203575d Merge: a37629dc 61e33f08 Author: librarywon Date: Fri Dec 27 23:15:57 2024 +0900 Merge branch 'release/1.0.6' into release_ commit 61e33f08af3495ca2aea330b7caa86988eb17dfc Author: librarywon Date: Fri Dec 27 23:15:28 2024 +0900 🚀 Release 1.0.6 commit a37629dcc2dbf406735de37fac4217558657b4f2 Merge: 7710b89a 122407a0 Author: librarywon Date: Fri Dec 27 23:08:58 2024 +0900 Merge remote-tracking branch 'origin/develop' into release_ commit 7710b89a92fa4d6875df48007e795ba7399c52f1 Merge: b69f9c58 16e0e1b8 Author: librarywon Date: Fri Dec 27 23:06:28 2024 +0900 Merge remote-tracking branch 'origin/release/1.0.5' into release_ commit 122407a01e987127abc42ae6c052ca4db50fe02d Merge: e6ce3cec 35f15030 Author: YeonJeen <144861180+yeonjeen@users.noreply.github.com> Date: Fri Dec 27 14:28:29 2024 +0900 Merge pull request #500 from Team-WSS/feat/499 feat: 앱 내 공지 하이퍼링크 구현 commit 35f15030c9d359ef65cc3205a768e2fe705c33c5 Author: yeonjeen Date: Fri Dec 27 14:27:08 2024 +0900 refactor: import로 코드 정리 commit 903f9483f01620a55f913b9c8637f5232f9be76a Author: yeonjeen Date: Thu Dec 26 10:32:36 2024 +0900 feat: 공지 텍스트뷰 내 하이퍼링크 구현 commit e2444c1fe39ab293d36f44fa292be8a45ddf1880 Author: yeonjeen Date: Thu Dec 26 10:31:36 2024 +0900 feat: 텍스트뷰 링크 활성화 commit e6ce3cecbb6aad98c31b77428c61ade2fb04ecf1 Merge: 5385b664 d05e3d9b Author: YeonJeen <144861180+yeonjeen@users.noreply.github.com> Date: Thu Dec 26 10:15:41 2024 +0900 Merge pull request #491 from Team-WSS/feat/478 feat: 최소버전 강제 업데이트 구현 commit d05e3d9bd4ae414c4c92c205987bb0e7682c207b Author: yeonjeen Date: Wed Dec 25 18:17:27 2024 +0900 refactor: 불필요한 코드 제거 commit 98f8b2c299a5c09c0537422763d7dfc19f1ba9a8 Author: yeonjeen Date: Wed Dec 25 17:19:09 2024 +0900 refactor: 버전네임 형식으로 최소버전 비교 commit c1ec4c29f63a95d3cc63e81efc8a1a0f2983d395 Author: yeonjeen Date: Wed Dec 25 13:07:46 2024 +0900 feat: 스플래쉬에서 강제업데이트 다이얼로그 구현 commit 21aa8ab3a669ea221ff6d94db9caa32a0bb288df Author: yeonjeen Date: Wed Dec 25 13:07:13 2024 +0900 refactor: 강제업데이트 스플래쉬에서 처리를 위한 홈 불필요한 코드 삭제 commit 2add763be3751861ffc99d696ee7f18d7bc571bd Author: yeonjeen Date: Wed Dec 25 13:06:36 2024 +0900 refactor: 버전처리 및 운영체제 값 처리 commit 3bb10cdd411c6f5cab623edf2bb7081fa56d3b43 Author: yeonjeen Date: Wed Dec 25 13:05:59 2024 +0900 refactor: 운영체제 값 레포지터리에서 처리 commit 41f2a84e5864fb3a20c27f504edade860cca67f0 Author: yeonjeen Date: Wed Dec 25 13:05:01 2024 +0900 refactor: 다이얼로그 패키지 변경 commit e7fbc6012ef958c0732c1163997e86f56db04df1 Author: yeonjeen Date: Wed Dec 25 13:04:43 2024 +0900 refactor: 업데이트 날짜 삭제 commit 463b096d80a486bb7fee99aacf31bfdc95380897 Author: yeonjeen Date: Wed Dec 25 13:02:25 2024 +0900 refactor: 플레이스토어 링크 deepLinks.xml로 이동 commit 5385b66403f0bf7bcdc43ae3134521fb103ac2f0 Merge: 09dc75ea 4c71d8ff Author: YeonJeen <144861180+yeonjeen@users.noreply.github.com> Date: Tue Dec 24 16:06:46 2024 +0900 Merge pull request #495 from Team-WSS/feat/492 feat: 마이페이지 스티키헤더 스크롤 문제 해결 commit 09dc75eae7f8a20f45b487145b70108ed5e5e939 Merge: aeacd884 82ee7499 Author: GongBaek <127238018+junseo511@users.noreply.github.com> Date: Mon Dec 23 17:01:54 2024 +0900 Merge pull request #494 from Team-WSS/feat/493 commit aeacd8845213d247c4942ad8272b93bcdabc7d5f Merge: 16e0e1b8 d49cf085 Author: Jaewon Seo <52442547+librarywon@users.noreply.github.com> Date: Mon Dec 23 16:52:39 2024 +0900 Merge pull request #498 from Team-WSS/feat/477 feat: 앰플리튜드 이벤트 트래커 도입 commit d49cf085f88b84007b7cc09e6bf09d9b52d5c76f Author: librarywon Date: Mon Dec 23 16:11:45 2024 +0900 refactor: util의 하위로 패키지 이동 commit 697efbfce56ebe45a8c0778097dfceeb7946985f Author: librarywon Date: Fri Dec 20 17:26:03 2024 +0900 feat: amplitude 이벤트 트래킹 추가 commit c6b342f05702c5de4e4266f5fde391e245299d1a Author: librarywon Date: Thu Dec 19 16:07:49 2024 +0900 feat: 유저차단 이벤트 트래킹 추가 commit 5978dba47dfb5c459960faab6cbc58efeec1191d Author: librarywon Date: Thu Dec 19 16:07:31 2024 +0900 feat: 유저정보 이벤트 트래킹 추가 commit 83b66bee7621eeea657393a3f1bd83d4303a30c5 Author: librarywon Date: Thu Dec 19 16:06:43 2024 +0900 feat: 키워드 추가 문의하기 이벤트 트래킹 추가 commit b18a1fe4eb83d0f32f881633254078712c456f0f Author: librarywon Date: Thu Dec 19 16:06:22 2024 +0900 feat: 탐색 이벤트 트래킹 추가 commit c43fe28e9c539a9a17246cb0d2fe02e72dade698 Author: librarywon Date: Thu Dec 19 15:36:43 2024 +0900 feat: 탐색 이벤트 트래킹 추가 commit 08b178384bd7685aa5daa6c87ff9c944fe2abd6d Author: librarywon Date: Thu Dec 19 15:28:56 2024 +0900 feat: 홈 이벤트 트래킹 추가 commit 140587148e3e3971d8484355d10bb7ad36c5b2aa Author: librarywon Date: Thu Dec 19 15:28:27 2024 +0900 feat: 일반 검색 진입 이벤트 트래킹 추가 commit 4268cf1690d3ad3f656f46c09bd5062b91db48c4 Author: librarywon Date: Thu Dec 19 14:33:16 2024 +0900 feat: 타유저 마이페이지 진입 이벤트 트래킹 추가 commit 4c71d8ff78bf9b18f622a99dec18edeea9226d74 Author: yeonjeen Date: Wed Dec 18 16:35:16 2024 +0900 feat: 3줄 이상 자기소개 입력 막아두기 구현 commit 82ee749992a7a7d592be9c7aed51215b6b232815 Author: junseo511 Date: Wed Dec 18 15:46:15 2024 +0900 refactor: 툴팁 윈도우 안정성 향상 commit 42c2ace87375ae78a28476e54f15b5d7bcdadb4c Author: yeonjeen Date: Wed Dec 18 15:41:48 2024 +0900 fix: CollapsingToolbarLayout height 고정값 설정 commit fe56d675975264b090f5f398a75079f68148f974 Author: yeonjeen Date: Wed Dec 18 15:41:13 2024 +0900 fix: CollapsingToolbarLayout height 고정값 설정 commit 6e8fd8bdb4521a0239a7a67c9924ac387a1f9681 Author: librarywon Date: Sun Dec 15 16:58:51 2024 +0900 feat: AmplitudeTracker 구현 commit 86475ca6b25e3f5ff53064c219415d99bd68698d Author: librarywon Date: Sun Dec 15 14:57:22 2024 +0900 feat: amplitude 의존성 추가 commit 61ae58085b915321f00505b7a22531bc037e3fff Author: yeonjeen Date: Wed Dec 18 03:27:23 2024 +0900 refactor: 불필요한 변수 선언 수정 commit 3e001f0702f4deffe74483294e4d096320b5267a Author: yeonjeen Date: Wed Dec 18 03:19:23 2024 +0900 feat: 홈에서 최소버전 강제 업데이트 팝업 호출 commit d879e751b99fb5d67697cd59706c3cff4fdc9ef7 Author: yeonjeen Date: Wed Dec 18 03:18:24 2024 +0900 feat: 최소버전 강제 업데이트 팝업 프레그먼트 구현 commit bc8fed9e99c0c84e04d66d24379f759575534a40 Author: yeonjeen Date: Wed Dec 18 03:16:49 2024 +0900 feat: 업데이트 플레이스토어 url 스트링 추출 commit f83c976ab76aaa62d4f30030e3d750c6d20d291b Author: yeonjeen Date: Wed Dec 18 03:10:23 2024 +0900 feat: 최소버전과 현재 버전 비교 후 업데이트 여부 구현 commit 18db1a279e5241e3c62b800241d94987efa01e16 Author: yeonjeen Date: Wed Dec 18 03:05:30 2024 +0900 feat: 최소버전 Entity 매핑 commit ef58e24b7b98c1d22b2e61bf5c5c47d4869dece5 Author: yeonjeen Date: Wed Dec 18 03:05:06 2024 +0900 feat: 최소버전 팝업 스트링 추출 commit d6d1dd41076d7e68287b20f4cf4100090d6534ce Author: yeonjeen Date: Wed Dec 18 03:04:21 2024 +0900 feat: 최소버전 팝업 xml 구현 commit e8d9235ce1037ecd4e656925056a6d3b5f5cb704 Author: yeonjeen Date: Wed Dec 18 03:02:55 2024 +0900 feat: 최소버전 api 연결 --- app/build.gradle.kts | 9 ++- .../websoso/common/util/tracker/Tracker.kt | 8 ++ .../tracker/amplitude/AmplitudeTracker.kt | 30 ++++++++ .../common/util/tracker/di/TrackerModule.kt | 24 ++++++ .../com/into/websoso/data/di/ApiModule.kt | 5 ++ .../into/websoso/data/di/RepositoryModule.kt | 8 +- .../into/websoso/data/mapper/VersionMapper.kt | 9 +++ .../data/model/MinimumVersionEntity.kt | 5 ++ .../websoso/data/remote/api/VersionApi.kt | 12 +++ .../response/MinimumVersionResponseDto.kt | 12 +++ .../data/repository/VersionRepository.kt | 40 ++++++++++ .../ui/accountInfo/AccountInfoActivity.kt | 7 ++ .../ui/createFeed/CreateFeedActivity.kt | 7 ++ .../CreateFeedSearchNovelBottomSheetDialog.kt | 8 +- .../keyword/DetailExploreKeywordFragment.kt | 6 ++ .../DetailExploreResultKeywordFragment.kt | 6 ++ .../ui/feedDetail/FeedDetailActivity.kt | 18 ++++- .../ui/main/explore/ExploreFragment.kt | 11 +++ .../into/websoso/ui/main/feed/FeedFragment.kt | 9 +++ .../feed/dialog/FeedReportDialogFragment.kt | 7 ++ .../into/websoso/ui/main/home/HomeFragment.kt | 36 ++++++++- .../websoso/ui/main/myPage/MyPageFragment.kt | 6 ++ .../ui/normalExplore/NormalExploreActivity.kt | 7 ++ .../ui/noticeDetail/NoticeDetailActivity.kt | 15 ++++ .../ui/novelDetail/NovelDetailActivity.kt | 74 +++++++++++-------- .../websoso/ui/novelInfo/NovelInfoFragment.kt | 6 ++ .../ui/novelRating/NovelRatingActivity.kt | 7 ++ .../otherUserPage/BlockUserDialogFragment.kt | 11 ++- .../ui/otherUserPage/OtherUserPageActivity.kt | 6 ++ .../ui/profileEdit/ProfileEditActivity.kt | 21 ++++++ .../into/websoso/ui/splash/SplashActivity.kt | 23 +++++- .../into/websoso/ui/splash/SplashViewModel.kt | 14 ++++ .../dialog/MinimumVersionDialogFragment.kt | 38 ++++++++++ app/src/main/res/layout/activity_login.xml | 1 + .../res/layout/activity_notice_detail.xml | 2 + .../res/layout/activity_other_user_page.xml | 2 +- .../main/res/layout/activity_profile_edit.xml | 3 +- .../dialog_minimum_version_popup_menu.xml | 71 ++++++++++++++++++ app/src/main/res/layout/fragment_my_page.xml | 2 +- app/src/main/res/values/deepLinks.xml | 1 + app/src/main/res/values/strings.xml | 5 ++ 41 files changed, 545 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/into/websoso/common/util/tracker/Tracker.kt create mode 100644 app/src/main/java/com/into/websoso/common/util/tracker/amplitude/AmplitudeTracker.kt create mode 100644 app/src/main/java/com/into/websoso/common/util/tracker/di/TrackerModule.kt create mode 100644 app/src/main/java/com/into/websoso/data/mapper/VersionMapper.kt create mode 100644 app/src/main/java/com/into/websoso/data/model/MinimumVersionEntity.kt create mode 100644 app/src/main/java/com/into/websoso/data/remote/api/VersionApi.kt create mode 100644 app/src/main/java/com/into/websoso/data/remote/response/MinimumVersionResponseDto.kt create mode 100644 app/src/main/java/com/into/websoso/data/repository/VersionRepository.kt create mode 100644 app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt create mode 100644 app/src/main/res/layout/dialog_minimum_version_popup_menu.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 898e2306d..44b24f949 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,12 +18,14 @@ android { applicationId = "com.into.websoso" minSdk = 30 targetSdk = 34 - versionCode = 10005 - versionName = "1.0.5" + versionCode = 10006 + versionName = "1.0.6" buildConfigField("String", "BASE_URL", gradleLocalProperties(rootDir).getProperty("base.url")) buildConfigField("String", "S3_BASE_URL", gradleLocalProperties(rootDir).getProperty("s3.url")) buildConfigField("String", "KAKAO_APP_KEY", gradleLocalProperties(rootDir).getProperty("kakao.app.key")) + buildConfigField("String", "AMPLITUDE_KEY", gradleLocalProperties(rootDir).getProperty("amplitude.key")) + manifestPlaceholders["kakaoAppKey"] = gradleLocalProperties(rootDir) .getProperty("kakao.app.key").replace("\"", "") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -116,4 +118,7 @@ dependencies { // Firebase implementation(platform("com.google.firebase:firebase-bom:33.7.0")) implementation("com.google.firebase:firebase-analytics") + + // Amplitude + implementation("com.amplitude:analytics-android:1.+") } \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/common/util/tracker/Tracker.kt b/app/src/main/java/com/into/websoso/common/util/tracker/Tracker.kt new file mode 100644 index 000000000..681aa7efc --- /dev/null +++ b/app/src/main/java/com/into/websoso/common/util/tracker/Tracker.kt @@ -0,0 +1,8 @@ +package com.into.websoso.common.util.tracker + +interface Tracker { + fun trackEvent( + eventName: String, + properties: Map = emptyMap(), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/common/util/tracker/amplitude/AmplitudeTracker.kt b/app/src/main/java/com/into/websoso/common/util/tracker/amplitude/AmplitudeTracker.kt new file mode 100644 index 000000000..8bd7d9f77 --- /dev/null +++ b/app/src/main/java/com/into/websoso/common/util/tracker/amplitude/AmplitudeTracker.kt @@ -0,0 +1,30 @@ +package com.into.websoso.common.util.tracker.amplitude + +import android.content.Context +import com.amplitude.android.Amplitude +import com.amplitude.android.Configuration +import com.amplitude.android.autocaptureOptions +import com.into.websoso.common.util.tracker.Tracker + +class AmplitudeTracker(context: Context, apiKey: String) : Tracker { + private val amplitude = + Amplitude( + Configuration( + apiKey = apiKey, + context = context, + autocapture = + autocaptureOptions { + +sessions + +appLifecycles + +screenViews + }, + ), + ) + + override fun trackEvent( + eventName: String, + properties: Map, + ) { + amplitude.track(eventName, properties) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/common/util/tracker/di/TrackerModule.kt b/app/src/main/java/com/into/websoso/common/util/tracker/di/TrackerModule.kt new file mode 100644 index 000000000..c778877c9 --- /dev/null +++ b/app/src/main/java/com/into/websoso/common/util/tracker/di/TrackerModule.kt @@ -0,0 +1,24 @@ +package com.into.websoso.common.util.tracker.di + +import android.content.Context +import com.into.websoso.BuildConfig +import com.into.websoso.common.util.tracker.Tracker +import com.into.websoso.common.util.tracker.amplitude.AmplitudeTracker +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object TrackerModule { + @Provides + @Singleton + fun provideTracker( + @ApplicationContext context: Context, + ): Tracker { + return AmplitudeTracker(context, BuildConfig.AMPLITUDE_KEY) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/data/di/ApiModule.kt b/app/src/main/java/com/into/websoso/data/di/ApiModule.kt index 7b0e525f0..b9c654e57 100644 --- a/app/src/main/java/com/into/websoso/data/di/ApiModule.kt +++ b/app/src/main/java/com/into/websoso/data/di/ApiModule.kt @@ -10,6 +10,7 @@ import com.into.websoso.data.remote.api.NoticeApi import com.into.websoso.data.remote.api.NovelApi import com.into.websoso.data.remote.api.UserApi import com.into.websoso.data.remote.api.UserNovelApi +import com.into.websoso.data.remote.api.VersionApi import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -52,4 +53,8 @@ object ApiModule { @Provides @Singleton fun provideAvatarApi(@Secured retrofit: Retrofit): AvatarApi = retrofit.create(AvatarApi::class.java) + + @Provides + @Singleton + fun provideVersionApi(@Secured retrofit: Retrofit): VersionApi = retrofit.create(VersionApi::class.java) } diff --git a/app/src/main/java/com/into/websoso/data/di/RepositoryModule.kt b/app/src/main/java/com/into/websoso/data/di/RepositoryModule.kt index 49275ed29..5ef5ec948 100644 --- a/app/src/main/java/com/into/websoso/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/into/websoso/data/di/RepositoryModule.kt @@ -7,10 +7,12 @@ import com.into.websoso.data.remote.api.AuthApi import com.into.websoso.data.remote.api.FeedApi import com.into.websoso.data.remote.api.NovelApi import com.into.websoso.data.remote.api.UserApi +import com.into.websoso.data.remote.api.VersionApi import com.into.websoso.data.repository.AuthRepository import com.into.websoso.data.repository.FeedRepository import com.into.websoso.data.repository.NovelRepository import com.into.websoso.data.repository.UserRepository +import com.into.websoso.data.repository.VersionRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -42,4 +44,8 @@ object RepositoryModule { authApi: AuthApi, preferences: SharedPreferences, ): AuthRepository = AuthRepository(authApi, preferences) -} + + @Provides + @Singleton + fun provideVersionRepository(versionApi: VersionApi): VersionRepository = VersionRepository(versionApi) +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/data/mapper/VersionMapper.kt b/app/src/main/java/com/into/websoso/data/mapper/VersionMapper.kt new file mode 100644 index 000000000..a1b9f1e62 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/mapper/VersionMapper.kt @@ -0,0 +1,9 @@ +package com.into.websoso.data.mapper + +import com.into.websoso.data.model.MinimumVersionEntity +import com.into.websoso.data.remote.response.MinimumVersionResponseDto + +fun MinimumVersionResponseDto.toData(): MinimumVersionEntity = + MinimumVersionEntity( + minimumVersion = minimumVersion, + ) \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/data/model/MinimumVersionEntity.kt b/app/src/main/java/com/into/websoso/data/model/MinimumVersionEntity.kt new file mode 100644 index 000000000..713d9e5fb --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/model/MinimumVersionEntity.kt @@ -0,0 +1,5 @@ +package com.into.websoso.data.model + +data class MinimumVersionEntity( + val minimumVersion: String, +) diff --git a/app/src/main/java/com/into/websoso/data/remote/api/VersionApi.kt b/app/src/main/java/com/into/websoso/data/remote/api/VersionApi.kt new file mode 100644 index 000000000..2959e1355 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/remote/api/VersionApi.kt @@ -0,0 +1,12 @@ +package com.into.websoso.data.remote.api + +import com.into.websoso.data.remote.response.MinimumVersionResponseDto +import retrofit2.http.GET +import retrofit2.http.Query + +interface VersionApi { + @GET("minimum-version") + suspend fun getMinimumVersion( + @Query("os") os: String, + ): MinimumVersionResponseDto +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/data/remote/response/MinimumVersionResponseDto.kt b/app/src/main/java/com/into/websoso/data/remote/response/MinimumVersionResponseDto.kt new file mode 100644 index 000000000..7b140f2a8 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/remote/response/MinimumVersionResponseDto.kt @@ -0,0 +1,12 @@ +package com.into.websoso.data.remote.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class MinimumVersionResponseDto ( + @SerialName("minimumVersion") + val minimumVersion: String, + @SerialName("updateDate") + val updateDate: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/data/repository/VersionRepository.kt b/app/src/main/java/com/into/websoso/data/repository/VersionRepository.kt new file mode 100644 index 000000000..70e1ff9b3 --- /dev/null +++ b/app/src/main/java/com/into/websoso/data/repository/VersionRepository.kt @@ -0,0 +1,40 @@ +package com.into.websoso.data.repository + +import com.into.websoso.BuildConfig +import com.into.websoso.data.mapper.toData +import com.into.websoso.data.model.MinimumVersionEntity +import com.into.websoso.data.remote.api.VersionApi +import javax.inject.Inject + +class VersionRepository @Inject constructor( + private val versionApi: VersionApi, +) { + suspend fun isUpdateRequired(): Boolean { + val currentVersion = BuildConfig.VERSION_NAME + val minVersion = fetchMinimumVersion().minimumVersion + + return compareVersions(parseVersionName(currentVersion), parseVersionName(minVersion)) + } + + private suspend fun fetchMinimumVersion(): MinimumVersionEntity { + return versionApi.getMinimumVersion(os = OS).toData() + } + + private fun parseVersionName(version: String): List { + return version.split(".").map { it.toIntOrNull() ?: 0 } + } + + private fun compareVersions(currentVersionParts: List, minVersionParts: List): Boolean { + for (i in 0 until maxOf(currentVersionParts.size, minVersionParts.size)) { + val current = currentVersionParts.getOrNull(i) ?: 0 + val min = minVersionParts.getOrNull(i) ?: 0 + if (current < min) return true + if (current > min) return false + } + return false + } + + companion object { + private const val OS = "android" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoActivity.kt b/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoActivity.kt index 93ed028d3..20584636b 100644 --- a/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoActivity.kt @@ -11,15 +11,20 @@ import com.into.websoso.R.string.change_user_info_message import com.into.websoso.common.ui.base.BaseActivity import com.into.websoso.common.ui.model.ResultFrom.ChangeUserInfo import com.into.websoso.common.util.showWebsosoSnackBar +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityAccountInfoBinding import com.into.websoso.ui.blockedUsers.BlockedUsersActivity import com.into.websoso.ui.changeUserInfo.ChangeUserInfoActivity import com.into.websoso.ui.withdraw.first.WithdrawFirstActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class AccountInfoActivity : BaseActivity(R.layout.activity_account_info) { + @Inject + lateinit var tracker: Tracker + private val accountInfoViewModel: AccountInfoViewModel by viewModels() private val startActivityLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() @@ -62,6 +67,7 @@ class AccountInfoActivity : private fun onWithDrawButtonClick() { binding.clAccountInfoWithdraw.setOnClickListener { + tracker.trackEvent("withdraw") val intent = WithdrawFirstActivity.getIntent(this) startActivity(intent) } @@ -75,6 +81,7 @@ class AccountInfoActivity : private fun onChangeUserInfoButtonClick() { binding.clAccountInfoChangeUserInfo.setOnClickListener { + tracker.trackEvent("logout") val intent = ChangeUserInfoActivity.getIntent(this) startActivityLauncher.launch(intent) } diff --git a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedActivity.kt b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedActivity.kt index 552459aad..9403794d5 100644 --- a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedActivity.kt @@ -23,13 +23,18 @@ import com.into.websoso.common.ui.model.ResultFrom.CreateFeed import com.into.websoso.common.util.SingleEventHandler import com.into.websoso.common.util.getAdaptedParcelableExtra import com.into.websoso.common.util.toFloatPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityCreateFeedBinding import com.into.websoso.ui.createFeed.model.CreatedFeedCategoryModel import com.into.websoso.ui.feedDetail.model.EditFeedModel import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class CreateFeedActivity : BaseActivity(activity_create_feed) { + @Inject + lateinit var tracker: Tracker + private val createFeedViewModel: CreateFeedViewModel by viewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } @@ -48,6 +53,7 @@ class CreateFeedActivity : BaseActivity(activity_crea bindViewModel() setupObserver() createFeedViewModel.categories.setupCategoryChips() + tracker.trackEvent("write") } private fun setupView() { @@ -100,6 +106,7 @@ class CreateFeedActivity : BaseActivity(activity_crea else -> createFeedViewModel.editFeed(editFeedModel.feedId) } + tracker.trackEvent("write_feed") setResult(CreateFeed.RESULT_OK) if (!isFinishing) finish() } diff --git a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt index 9fb2b71ba..579dc51b3 100644 --- a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt +++ b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt @@ -12,14 +12,19 @@ import com.into.websoso.R.layout.dialog_create_feed_search_novel import com.into.websoso.common.ui.base.BaseBottomSheetDialog import com.into.websoso.common.util.InfiniteScrollListener import com.into.websoso.common.util.SingleEventHandler +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.DialogCreateFeedSearchNovelBinding import com.into.websoso.ui.createFeed.adapter.SearchNovelAdapter import com.into.websoso.ui.createFeed.adapter.SearchNovelItemType.Loading import com.into.websoso.ui.createFeed.adapter.SearchNovelItemType.Novels import com.into.websoso.ui.createFeed.model.SearchNovelUiState +import javax.inject.Inject class CreateFeedSearchNovelBottomSheetDialog : BaseBottomSheetDialog(dialog_create_feed_search_novel) { + @Inject + lateinit var tracker: Tracker + private val createFeedViewModel: CreateFeedViewModel by activityViewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val searchNovelAdapter: SearchNovelAdapter by lazy { SearchNovelAdapter(::onNovelClick) } @@ -119,9 +124,10 @@ class CreateFeedSearchNovelBottomSheetDialog : } private fun setupNavigateToInquireNovel() { + tracker.trackEvent("contact_novel_connect") val inquireUrl = getString(R.string.inquire_link) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(inquireUrl)) - binding.tvCreateFeedAddNovelInquireButton.setOnClickListener{ + binding.tvCreateFeedAddNovelInquireButton.setOnClickListener { startActivity(intent) } } diff --git a/app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.kt b/app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.kt index 83e959f39..6a32f64ee 100644 --- a/app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/detailExplore/keyword/DetailExploreKeywordFragment.kt @@ -17,6 +17,7 @@ import com.into.websoso.common.ui.model.CategoriesModel.CategoryModel.KeywordMod import com.into.websoso.common.ui.model.CategoriesModel.Companion.findKeywordByName import com.into.websoso.common.util.SingleEventHandler import com.into.websoso.common.util.toFloatPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentDetailExploreKeywordBinding import com.into.websoso.ui.detailExplore.DetailExploreViewModel import com.into.websoso.ui.detailExplore.keyword.adapter.DetailExploreKeywordAdapter @@ -24,10 +25,14 @@ import com.into.websoso.ui.detailExplore.keyword.model.DetailExploreKeywordUiSta import com.into.websoso.ui.detailExploreResult.DetailExploreResultActivity import com.into.websoso.ui.detailExploreResult.model.DetailExploreFilteredModel import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class DetailExploreKeywordFragment : BaseFragment(R.layout.fragment_detail_explore_keyword) { + @Inject + lateinit var tracker: Tracker + private val detailExploreViewModel: DetailExploreViewModel by activityViewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val detailExploreKeywordAdapter: DetailExploreKeywordAdapter by lazy { @@ -54,6 +59,7 @@ class DetailExploreKeywordFragment : private fun onDetailExploreKeywordButtonClick() = object : DetailExploreClickListener { override fun onNovelInquireButtonClick() { + tracker.trackEvent("contact_keyword") val inquireUrl = getString(R.string.inquire_link) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(inquireUrl)) startActivity(intent) diff --git a/app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.kt b/app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.kt index f1a00d56b..1fddc05fc 100644 --- a/app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/detailExploreResult/DetailExploreResultKeywordFragment.kt @@ -17,15 +17,20 @@ import com.into.websoso.common.ui.model.CategoriesModel.CategoryModel.KeywordMod import com.into.websoso.common.ui.model.CategoriesModel.Companion.findKeywordByName import com.into.websoso.common.util.SingleEventHandler import com.into.websoso.common.util.toFloatPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentDetailExploreResultKeywordBinding import com.into.websoso.ui.detailExplore.keyword.DetailExploreClickListener import com.into.websoso.ui.detailExplore.keyword.adapter.DetailExploreKeywordAdapter import com.into.websoso.ui.detailExploreResult.model.DetailExploreResultUiState import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class DetailExploreResultKeywordFragment : BaseFragment(R.layout.fragment_detail_explore_result_keyword) { + @Inject + lateinit var tracker: Tracker + private val detailExploreResultViewModel: DetailExploreResultViewModel by activityViewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val detailExploreKeywordAdapter: DetailExploreKeywordAdapter by lazy { @@ -41,6 +46,7 @@ class DetailExploreResultKeywordFragment : setupSearchKeyword() setupWebsosoSearchEditListener() setupBackButtonListener() + tracker.trackEvent("seek_result") } private fun bindViewModel() { diff --git a/app/src/main/java/com/into/websoso/ui/feedDetail/FeedDetailActivity.kt b/app/src/main/java/com/into/websoso/ui/feedDetail/FeedDetailActivity.kt index 740909970..bed683552 100644 --- a/app/src/main/java/com/into/websoso/ui/feedDetail/FeedDetailActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/feedDetail/FeedDetailActivity.kt @@ -42,6 +42,7 @@ import com.into.websoso.common.util.hideKeyboard import com.into.websoso.common.util.showWebsosoSnackBar import com.into.websoso.common.util.toFloatPxFromDp import com.into.websoso.common.util.toIntPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityFeedDetailBinding import com.into.websoso.databinding.DialogRemovePopupMenuBinding import com.into.websoso.databinding.DialogReportPopupMenuBinding @@ -67,9 +68,13 @@ import com.into.websoso.ui.novelDetail.NovelDetailActivity import com.into.websoso.ui.otherUserPage.BlockUserDialogFragment.Companion.USER_NICKNAME import com.into.websoso.ui.otherUserPage.OtherUserPageActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class FeedDetailActivity : BaseActivity(activity_feed_detail) { + @Inject + lateinit var tracker: Tracker + private enum class MenuType { COMMENT, FEED } private val feedId: Long by lazy { intent.getLongExtra(FEED_ID, DEFAULT_FEED_ID) } @@ -108,6 +113,7 @@ class FeedDetailActivity : BaseActivity(activity_feed view.isSelected = !view.isSelected singleEventHandler.debounce(coroutineScope = lifecycleScope) { + tracker.trackEvent("feed_detail_like") feedDetailViewModel.updateLike(view.isSelected, updatedLikeCount) } } @@ -258,7 +264,10 @@ class FeedDetailActivity : BaseActivity(activity_feed private fun setupReportingSpoilerComment(commentId: Long) { showDialog( menuType = SPOILER_COMMENT.name, - event = { feedDetailViewModel.updateReportedSpoilerComment(commentId) }, + event = { + tracker.trackEvent("alert_comment_spoiler") + feedDetailViewModel.updateReportedSpoilerComment(commentId) + }, ) } @@ -272,7 +281,10 @@ class FeedDetailActivity : BaseActivity(activity_feed private fun setupReportingImpertinenceComment(commentId: Long) { showDialog( menuType = IMPERTINENCE_COMMENT.name, - event = { feedDetailViewModel.updateReportedImpertinenceComment(commentId) }, + event = { + tracker.trackEvent("alert_feed_abuse") + feedDetailViewModel.updateReportedImpertinenceComment(commentId) + }, ) } @@ -300,6 +312,7 @@ class FeedDetailActivity : BaseActivity(activity_feed setupObserver() onFeedDetailClick() refreshView() + tracker.trackEvent("feed_detail") } private fun refreshView() { @@ -356,6 +369,7 @@ class FeedDetailActivity : BaseActivity(activity_feed binding.ivFeedDetailCommentRegister.setOnClickListener { if (binding.etFeedDetailInput.text.isNullOrBlank().not()) { binding.etFeedDetailInput.run { + tracker.trackEvent("write_comment") when (feedDetailViewModel.commentId == DEFAULT_FEED_ID) { true -> feedDetailViewModel.dispatchComment(text.toString()) false -> feedDetailViewModel.modifyComment(text.toString()) diff --git a/app/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.kt b/app/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.kt index 625d5be89..541fa2a10 100644 --- a/app/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/explore/ExploreFragment.kt @@ -6,15 +6,20 @@ import androidx.fragment.app.viewModels import com.into.websoso.R import com.into.websoso.common.ui.base.BaseFragment import com.into.websoso.common.util.SingleEventHandler +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentExploreBinding import com.into.websoso.ui.detailExplore.DetailExploreDialogBottomSheet import com.into.websoso.ui.main.explore.adapter.SosoPickAdapter import com.into.websoso.ui.normalExplore.NormalExploreActivity import com.into.websoso.ui.novelDetail.NovelDetailActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class ExploreFragment : BaseFragment(R.layout.fragment_explore) { + @Inject + lateinit var tracker: Tracker + private val sosoPickAdapter: SosoPickAdapter by lazy { SosoPickAdapter(::navigateToNovelDetail) } private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val exploreViewModel: ExploreViewModel by viewModels() @@ -27,6 +32,7 @@ class ExploreFragment : BaseFragment(R.layout.fragment_e onDetailExploreButtonClick() onReloadPageButtonClick() setupObserver() + tracker.trackEvent("search") } private fun initSosoPickAdapter() { @@ -35,12 +41,17 @@ class ExploreFragment : BaseFragment(R.layout.fragment_e } private fun navigateToNovelDetail(novelId: Long) { + tracker.trackEvent( + eventName = "soso_pick", + properties = mapOf("novelId" to novelId) + ) val intent = NovelDetailActivity.getIntent(requireContext(), novelId) startActivity(intent) } private fun onNormalSearchButtonClick() { binding.clExploreNormalSearch.setOnClickListener { + tracker.trackEvent("general_search") val intent = NormalExploreActivity.getIntent(requireContext()) startActivity(intent) } diff --git a/app/src/main/java/com/into/websoso/ui/main/feed/FeedFragment.kt b/app/src/main/java/com/into/websoso/ui/main/feed/FeedFragment.kt index 3410c7e4d..d116c7f19 100644 --- a/app/src/main/java/com/into/websoso/ui/main/feed/FeedFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/feed/FeedFragment.kt @@ -43,6 +43,7 @@ import com.into.websoso.common.util.SingleEventHandler import com.into.websoso.common.util.showWebsosoSnackBar import com.into.websoso.common.util.toFloatPxFromDp import com.into.websoso.common.util.toIntPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.DialogRemovePopupMenuBinding import com.into.websoso.databinding.DialogReportPopupMenuBinding import com.into.websoso.databinding.FragmentFeedBinding @@ -67,9 +68,13 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.Serializable +import javax.inject.Inject @AndroidEntryPoint class FeedFragment : BaseFragment(fragment_feed) { + @Inject + lateinit var tracker: Tracker + private var _popupBinding: MenuFeedPopupBinding? = null private val popupBinding: MenuFeedPopupBinding get() = _popupBinding ?: error("FeedFragment") private val feedViewModel: FeedViewModel by viewModels() @@ -106,6 +111,7 @@ class FeedFragment : BaseFragment(fragment_feed) { @SuppressLint("CutPasteId") override fun onLikeButtonClick(view: View, id: Long) { + tracker.trackEvent("feed_like") val likeCount: Int = view.findViewById(tv_feed_thumb_up_count).text.toString().toInt() val updatedLikeCount: Int = when (view.isSelected) { @@ -250,6 +256,7 @@ class FeedFragment : BaseFragment(fragment_feed) { initView() setupObserver() refreshView() + tracker.trackEvent("feed_all") } private fun refreshView() { @@ -322,6 +329,7 @@ class FeedFragment : BaseFragment(fragment_feed) { } private fun navigateToFeedWriting() { + tracker.trackEvent("feed_write_floating_btn") activityResultCallback.launch(CreateFeedActivity.getIntent(requireContext())) } @@ -372,6 +380,7 @@ class FeedFragment : BaseFragment(fragment_feed) { if (binding.wcgFeed.children.toList().isEmpty()) category.setUpChips() val selectedCategory = category.find { it.isSelected } ?: category.first() + tracker.trackEvent("feed_${selectedCategory.category.enTitle}") binding.wcgFeed.children.forEach { val chip = it as Chip diff --git a/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt b/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt index cd8a52f80..884eae44a 100644 --- a/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt @@ -9,15 +9,20 @@ import com.into.websoso.R.string.report_popup_menu_spoiling_comment import com.into.websoso.R.string.report_popup_menu_spoiling_feed import com.into.websoso.common.ui.base.BaseDialogFragment import com.into.websoso.common.util.SingleEventHandler +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.DialogReportPopupMenuBinding import com.into.websoso.ui.main.feed.FeedFragment.FeedDialogClickListener import com.into.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT import com.into.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_FEED import com.into.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_COMMENT import com.into.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_FEED +import javax.inject.Inject class FeedReportDialogFragment : BaseDialogFragment(R.layout.dialog_report_popup_menu) { + @Inject + lateinit var tracker: Tracker + private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val menuType: String? by lazy { arguments?.getString(MENU_TYPE) } private val onReportClick: FeedDialogClickListener by lazy { @@ -56,6 +61,7 @@ class FeedReportDialogFragment : ) binding.tvReportPopupMenuReport.setOnClickListener { singleEventHandler.throttleFirst { + tracker.trackEvent("alert_feed_abuse") onReportClick() FeedReportDoneDialogFragment .newInstance(IMPERTINENCE_COMMENT.name) { dismiss() } @@ -68,6 +74,7 @@ class FeedReportDialogFragment : binding.tvReportPopupMenuTitle.text = getString(report_popup_menu_spoiling_feed) binding.tvReportPopupMenuReport.setOnClickListener { singleEventHandler.throttleFirst { + tracker.trackEvent("alert_feed_spoiler") onReportClick() FeedReportDoneDialogFragment .newInstance(SPOILER_FEED.name) { dismiss() } diff --git a/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt b/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt index 6ce5ce63f..5e066da8f 100644 --- a/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/home/HomeFragment.kt @@ -13,6 +13,7 @@ import com.into.websoso.common.ui.model.ResultFrom.FeedDetailRemoved import com.into.websoso.common.ui.model.ResultFrom.NormalExploreBack import com.into.websoso.common.ui.model.ResultFrom.NovelDetailBack import com.into.websoso.common.ui.model.ResultFrom.ProfileEditSuccess +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentHomeBinding import com.into.websoso.ui.feedDetail.FeedDetailActivity import com.into.websoso.ui.main.MainViewModel @@ -25,26 +26,30 @@ import com.into.websoso.ui.notice.NoticeActivity import com.into.websoso.ui.novelDetail.NovelDetailActivity import com.into.websoso.ui.profileEdit.ProfileEditActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class HomeFragment : BaseFragment(R.layout.fragment_home) { + @Inject + lateinit var tracker: Tracker + private val homeViewModel: HomeViewModel by viewModels() private val mainViewModel: MainViewModel by activityViewModels() private val popularNovelsAdapter: PopularNovelsAdapter by lazy { - PopularNovelsAdapter(::navigateToNovelDetail) + PopularNovelsAdapter(::onPopularNovelClick) } private val popularFeedsAdapter: PopularFeedsAdapter by lazy { - PopularFeedsAdapter(::navigateToFeedDetail) + PopularFeedsAdapter(::onPopularFeedClick) } private val userInterestFeedAdapter: UserInterestFeedAdapter by lazy { - UserInterestFeedAdapter(::navigateToNovelDetail) + UserInterestFeedAdapter(::onUserInterestNovelFeedClick) } private val recommendedNovelsByUserTasteAdapter: RecommendedNovelsByUserTasteAdapter by lazy { - RecommendedNovelsByUserTasteAdapter(::navigateToNovelDetail) + RecommendedNovelsByUserTasteAdapter(::onRecommendedNovelClick) } private val startActivityLauncher = registerForActivityResult( @@ -75,6 +80,7 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { onPostInterestNovelClick() onSettingPreferenceGenreClick() onNoticeButtonClick() + tracker.trackEvent("home") } private fun bindViewModel() { @@ -182,6 +188,21 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { binding.dotsIndicatorHome.attachTo(binding.vpHomePopularFeed) } + private fun onPopularNovelClick(novelId: Long) { + tracker.trackEvent("home_today_ranking") + navigateToNovelDetail(novelId) + } + + private fun onUserInterestNovelFeedClick(novelId: Long) { + tracker.trackEvent("home_love_feedlist") + navigateToNovelDetail(novelId) + } + + private fun onRecommendedNovelClick(novelId: Long) { + tracker.trackEvent("home_prefer_novellist") + navigateToNovelDetail(novelId) + } + private fun navigateToNovelDetail(novelId: Long) { startActivityLauncher.launch( NovelDetailActivity.getIntent( @@ -191,6 +212,11 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { ) } + private fun onPopularFeedClick(feedId: Long) { + tracker.trackEvent("home_hot_feedlist") + navigateToFeedDetail(feedId) + } + private fun navigateToFeedDetail(feedId: Long) { startActivityLauncher.launch( FeedDetailActivity.getIntent( @@ -202,6 +228,7 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { private fun onPostInterestNovelClick() { binding.clHomeInterestFeed.setOnClickListener { + tracker.trackEvent("home_to_love_btn") startActivityLauncher.launch( NormalExploreActivity.getIntent( requireContext(), @@ -212,6 +239,7 @@ class HomeFragment : BaseFragment(R.layout.fragment_home) { private fun onSettingPreferenceGenreClick() { binding.clHomeRecommendNovel.setOnClickListener { + tracker.trackEvent("home_to_prefer_btn") startActivityLauncher.launch( ProfileEditActivity.getIntent( requireContext(), diff --git a/app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt b/app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt index 448c08a41..dfae1edab 100644 --- a/app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/myPage/MyPageFragment.kt @@ -13,15 +13,20 @@ import com.into.websoso.R import com.into.websoso.common.ui.base.BaseFragment import com.into.websoso.common.ui.model.ResultFrom.ProfileEditSuccess import com.into.websoso.common.util.getS3ImageUrl +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentMyPageBinding import com.into.websoso.ui.main.MainViewModel import com.into.websoso.ui.main.myPage.adapter.MyPageViewPagerAdapter import com.into.websoso.ui.profileEdit.ProfileEditActivity import com.into.websoso.ui.setting.SettingActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class MyPageFragment : BaseFragment(R.layout.fragment_my_page) { + @Inject + lateinit var tracker: Tracker + private val myPageViewModel: MyPageViewModel by activityViewModels() private val mainViewModel: MainViewModel by activityViewModels() private val viewPagerAdapter by lazy { MyPageViewPagerAdapter(this) } @@ -45,6 +50,7 @@ class MyPageFragment : BaseFragment(R.layout.fragment_my_ onSettingButtonClick() setupObserver() onProfileEditClick() + tracker.trackEvent("mypage") } override fun onResume() { diff --git a/app/src/main/java/com/into/websoso/ui/normalExplore/NormalExploreActivity.kt b/app/src/main/java/com/into/websoso/ui/normalExplore/NormalExploreActivity.kt index 5533ff3ae..d83a976d3 100644 --- a/app/src/main/java/com/into/websoso/ui/normalExplore/NormalExploreActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/normalExplore/NormalExploreActivity.kt @@ -13,6 +13,7 @@ import com.into.websoso.common.ui.base.BaseActivity import com.into.websoso.common.ui.model.ResultFrom.NormalExploreBack import com.into.websoso.common.util.InfiniteScrollListener import com.into.websoso.common.util.SingleEventHandler +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityNormalExploreBinding import com.into.websoso.ui.normalExplore.adapter.NormalExploreAdapter import com.into.websoso.ui.normalExplore.adapter.NormalExploreItemType.Header @@ -21,10 +22,14 @@ import com.into.websoso.ui.normalExplore.adapter.NormalExploreItemType.Novels import com.into.websoso.ui.normalExplore.model.NormalExploreUiState import com.into.websoso.ui.novelDetail.NovelDetailActivity import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class NormalExploreActivity : BaseActivity(R.layout.activity_normal_explore) { + @Inject + lateinit var tracker: Tracker + private val normalExploreAdapter: NormalExploreAdapter by lazy { NormalExploreAdapter(::navigateToNovelDetail) } private val normalExploreViewModel: NormalExploreViewModel by viewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } @@ -92,6 +97,7 @@ class NormalExploreActivity : override fun onSearchButtonClick() { singleEventHandler.throttleFirst { + tracker.trackEvent("click_search_result") normalExploreViewModel.updateSearchResult(isSearchButtonClick = true) binding.etNormalExploreSearchContent.clearFocus() hideKeyboard() @@ -106,6 +112,7 @@ class NormalExploreActivity : } override fun onNovelInquireButtonClick() { + tracker.trackEvent("contact_novel_search") val inquireUrl = getString(R.string.inquire_link) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(inquireUrl)) startActivity(intent) diff --git a/app/src/main/java/com/into/websoso/ui/noticeDetail/NoticeDetailActivity.kt b/app/src/main/java/com/into/websoso/ui/noticeDetail/NoticeDetailActivity.kt index cb82bbee6..edbfa5153 100644 --- a/app/src/main/java/com/into/websoso/ui/noticeDetail/NoticeDetailActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/noticeDetail/NoticeDetailActivity.kt @@ -3,6 +3,8 @@ package com.into.websoso.ui.noticeDetail import android.content.Context import android.content.Intent import android.os.Bundle +import android.text.Html +import android.text.method.LinkMovementMethod import androidx.activity.addCallback import com.into.websoso.R import com.into.websoso.common.ui.base.BaseActivity @@ -20,6 +22,7 @@ class NoticeDetailActivity : onBackButtonClick() handleBackPressed() + setupHyperlink(noticeItem?.noticeContent) } private fun onBackButtonClick() { @@ -34,6 +37,18 @@ class NoticeDetailActivity : } } + private fun setupHyperlink(noticeContent: String?) { + binding.tvNoticeDetailContent.apply { + movementMethod = LinkMovementMethod.getInstance() + text = noticeContent?.let { content -> + Html.fromHtml( + content, + Html.FROM_HTML_MODE_LEGACY, + ) + } + } + } + companion object { const val NOTICE_DETAIL_KEY = "NOTICE_DETAIL_KEY" diff --git a/app/src/main/java/com/into/websoso/ui/novelDetail/NovelDetailActivity.kt b/app/src/main/java/com/into/websoso/ui/novelDetail/NovelDetailActivity.kt index 9015e756a..c8af72b01 100644 --- a/app/src/main/java/com/into/websoso/ui/novelDetail/NovelDetailActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/novelDetail/NovelDetailActivity.kt @@ -26,6 +26,7 @@ import com.into.websoso.common.util.getS3ImageUrl import com.into.websoso.common.util.showWebsosoSnackBar import com.into.websoso.common.util.toFloatPxFromDp import com.into.websoso.common.util.toIntPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityNovelDetailBinding import com.into.websoso.databinding.ItemNovelDetailTooltipBinding import com.into.websoso.databinding.MenuNovelDetailPopupBinding @@ -39,10 +40,14 @@ import com.into.websoso.ui.novelInfo.NovelInfoViewModel import com.into.websoso.ui.novelRating.NovelRatingActivity import com.into.websoso.ui.novelRating.model.ReadStatus import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class NovelDetailActivity : BaseActivity(R.layout.activity_novel_detail) { + @Inject + lateinit var tracker: Tracker + private val novelDetailViewModel by viewModels() private val novelInfoViewModel by viewModels() private val novelFeedViewModel by viewModels() @@ -91,6 +96,7 @@ class NovelDetailActivity : setupViewPager() novelDetailViewModel.updateNovelDetail(novelId) handleBackPressed() + tracker.trackEvent("novel_info") } private fun bindViewModel() { @@ -107,6 +113,7 @@ class NovelDetailActivity : } private fun navigateToReportError() { + tracker.trackEvent("contact_error") val inquireUrl = getString(R.string.inquire_link) val intent = Intent(Intent.ACTION_VIEW, Uri.parse(inquireUrl)) startActivity(intent) @@ -126,6 +133,7 @@ class NovelDetailActivity : } private fun deleteUserNovel() { + tracker.trackEvent("rate_delete") novelDetailViewModel.deleteUserNovel(novelId) novelInfoViewModel.updateNovelInfoWithDelay(novelId) @@ -199,41 +207,46 @@ class NovelDetailActivity : } private fun setupTooltipBottomFramePosition() { - binding.ctlNovelDetail.viewTreeObserver.addOnGlobalLayoutListener(object : - ViewTreeObserver.OnGlobalLayoutListener { - override fun onGlobalLayout() { - val layoutParams = - binding.viewNovelDetailTooltipFrameBottom.layoutParams as ConstraintLayout.LayoutParams + binding.ctlNovelDetail.viewTreeObserver.addOnPreDrawListener(object : + ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + binding.ctlNovelDetail.viewTreeObserver.removeOnPreDrawListener(this) + + val layoutParams = binding.viewNovelDetailTooltipFrameBottom.layoutParams as ConstraintLayout.LayoutParams layoutParams.topMargin = binding.ctlNovelDetail.height binding.viewNovelDetailTooltipFrameBottom.layoutParams = layoutParams - binding.ctlNovelDetail.viewTreeObserver.removeOnGlobalLayoutListener(this) + + return true } }) } private fun showTooltipWindow() { - tooltipPopupWindow = PopupWindow( - novelDetailToolTipBinding.root, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - true, - ).apply { - novelDetailToolTipBinding.root.measure( - View.MeasureSpec.UNSPECIFIED, - View.MeasureSpec.UNSPECIFIED, - ) - val anchorViewWidth = binding.tgNovelDetailReadStatus.measuredWidth - val popupWidth = novelDetailToolTipBinding.root.measuredWidth - - val xOffset = (anchorViewWidth - popupWidth) / 2 - val yOffset = 6.toIntPxFromDp() - - showAsDropDown(binding.tgNovelDetailReadStatus, xOffset, yOffset) - - novelDetailToolTipBinding.root.setOnClickListener { dismiss() } - this.setOnDismissListener { - novelDetailViewModel.updateIsFirstLaunched() - binding.tgNovelDetailReadStatus.clearChecked() + binding.tgNovelDetailReadStatus.post { + tooltipPopupWindow = PopupWindow( + novelDetailToolTipBinding.root, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + true, + ).apply { + novelDetailToolTipBinding.root.measure( + View.MeasureSpec.UNSPECIFIED, + View.MeasureSpec.UNSPECIFIED, + ) + + val anchorViewWidth = binding.tgNovelDetailReadStatus.measuredWidth + val popupWidth = novelDetailToolTipBinding.root.measuredWidth + val xOffset = (anchorViewWidth - popupWidth) / 2 + val yOffset = 6.toIntPxFromDp() + + showAsDropDown(binding.tgNovelDetailReadStatus, xOffset, yOffset) + + novelDetailToolTipBinding.root.setOnClickListener { dismiss() } + + this.setOnDismissListener { + novelDetailViewModel.updateIsFirstLaunched() + binding.tgNovelDetailReadStatus.clearChecked() + } } } } @@ -292,10 +305,12 @@ class NovelDetailActivity : showLoginRequestDialog() return } + tracker.trackEvent("novel_write_btn") val editFeedModel = EditFeedModel( novelId = novelId, novelTitle = binding.tvNovelDetailTitle.text.toString(), - feedCategory = novelDetailViewModel.novelDetailModel.value?.novel?.getGenres ?: emptyList(), + feedCategory = novelDetailViewModel.novelDetailModel.value?.novel?.getGenres + ?: emptyList(), ) val intent = CreateFeedActivity.getIntent(this@NovelDetailActivity, editFeedModel) novelDetailResultLauncher.launch(intent) @@ -306,6 +321,7 @@ class NovelDetailActivity : showLoginRequestDialog() return } + tracker.trackEvent("rate_love") novelDetailViewModel.updateUserInterest(novelId) } } diff --git a/app/src/main/java/com/into/websoso/ui/novelInfo/NovelInfoFragment.kt b/app/src/main/java/com/into/websoso/ui/novelInfo/NovelInfoFragment.kt index ca3adf850..695b867b7 100644 --- a/app/src/main/java/com/into/websoso/ui/novelInfo/NovelInfoFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/novelInfo/NovelInfoFragment.kt @@ -15,6 +15,7 @@ import com.into.websoso.R import com.into.websoso.common.ui.base.BaseFragment import com.into.websoso.common.ui.custom.WebsosoChip import com.into.websoso.common.util.getS3ImageUrl +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.FragmentNovelInfoBinding import com.into.websoso.ui.novelInfo.model.ExpandTextUiModel import com.into.websoso.ui.novelInfo.model.KeywordModel @@ -22,9 +23,13 @@ import com.into.websoso.ui.novelInfo.model.PlatformModel import com.into.websoso.ui.novelInfo.model.UnifiedReviewCountModel import com.into.websoso.ui.novelRating.model.ReadStatus import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class NovelInfoFragment : BaseFragment(R.layout.fragment_novel_info) { + @Inject + lateinit var tracker: Tracker + private val novelInfoViewModel by activityViewModels() private val novelId: Long by lazy { arguments?.getLong(NOVEL_ID) ?: 0L } @@ -46,6 +51,7 @@ class NovelInfoFragment : BaseFragment(R.layout.fragme } private fun navigateToWebView(url: String) { + tracker.trackEvent("direct_novel") val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) startActivity(intent) } diff --git a/app/src/main/java/com/into/websoso/ui/novelRating/NovelRatingActivity.kt b/app/src/main/java/com/into/websoso/ui/novelRating/NovelRatingActivity.kt index 5cb35ae79..1720fd682 100644 --- a/app/src/main/java/com/into/websoso/ui/novelRating/NovelRatingActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/novelRating/NovelRatingActivity.kt @@ -17,6 +17,7 @@ import com.into.websoso.common.util.getAdaptedSerializableExtra import com.into.websoso.common.util.showWebsosoSnackBar import com.into.websoso.common.util.showWebsosoToast import com.into.websoso.common.util.toFloatPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityNovelRatingBinding import com.into.websoso.ui.novelDetail.NovelAlertDialogFragment import com.into.websoso.ui.novelDetail.model.NovelAlertModel @@ -26,10 +27,14 @@ import com.into.websoso.ui.novelRating.model.NovelRatingUiState import com.into.websoso.ui.novelRating.model.RatingDateModel import com.into.websoso.ui.novelRating.model.ReadStatus import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class NovelRatingActivity : BaseActivity(R.layout.activity_novel_rating) { + @Inject + lateinit var tracker: Tracker + private val novelRatingViewModel: NovelRatingViewModel by viewModels() private val charmPoints: List = CharmPoint.entries.toList() private val novelId: Long by lazy { intent.getLongExtra(NOVEL_ID, 0) } @@ -42,6 +47,7 @@ class NovelRatingActivity : setupCharmPointChips() setupWebsosoLoadingLayout() setupBackPressCallback() + tracker.trackEvent("rate") } private fun bindView() { @@ -70,6 +76,7 @@ class NovelRatingActivity : } override fun onSaveClick() { + tracker.trackEvent("rate_novel") novelRatingViewModel.updateUserNovelRating(novelId, binding.rbNovelRating.rating) } diff --git a/app/src/main/java/com/into/websoso/ui/otherUserPage/BlockUserDialogFragment.kt b/app/src/main/java/com/into/websoso/ui/otherUserPage/BlockUserDialogFragment.kt index f1584e4a2..9a638ec23 100644 --- a/app/src/main/java/com/into/websoso/ui/otherUserPage/BlockUserDialogFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/otherUserPage/BlockUserDialogFragment.kt @@ -8,12 +8,17 @@ import com.into.websoso.R import com.into.websoso.common.ui.base.BaseDialogFragment import com.into.websoso.common.ui.model.ResultFrom.BlockUser import com.into.websoso.common.util.SingleEventHandler +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.DialogBlockUserBinding import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class BlockUserDialogFragment : BaseDialogFragment(R.layout.dialog_block_user) { + @Inject + lateinit var tracker: Tracker + private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } private val otherUserPageViewModel: OtherUserPageViewModel by activityViewModels() @@ -36,6 +41,7 @@ class BlockUserDialogFragment : private fun onBlockButtonClick() { binding.tvBlockUserButton.setOnClickListener { singleEventHandler.throttleFirst { + tracker.trackEvent("other_block") otherUserPageViewModel.updateBlockedUser() } } @@ -45,7 +51,10 @@ class BlockUserDialogFragment : otherUserPageViewModel.uiState.observe(viewLifecycleOwner) { uiState -> if (uiState.isBlockedCompleted) { val intent = Intent().apply { - putExtra(USER_NICKNAME, otherUserPageViewModel.uiState.value?.otherUserProfile?.nickname) + putExtra( + USER_NICKNAME, + otherUserPageViewModel.uiState.value?.otherUserProfile?.nickname + ) } activity?.setResult(BlockUser.RESULT_OK, intent) dismiss() diff --git a/app/src/main/java/com/into/websoso/ui/otherUserPage/OtherUserPageActivity.kt b/app/src/main/java/com/into/websoso/ui/otherUserPage/OtherUserPageActivity.kt index 9f5de868c..0e60f5142 100644 --- a/app/src/main/java/com/into/websoso/ui/otherUserPage/OtherUserPageActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/otherUserPage/OtherUserPageActivity.kt @@ -21,14 +21,19 @@ import com.into.websoso.common.util.SingleEventHandler import com.into.websoso.common.util.getS3ImageUrl import com.into.websoso.common.util.toFloatPxFromDp import com.into.websoso.common.util.toIntPxFromDp +import com.into.websoso.common.util.tracker.Tracker import com.into.websoso.databinding.ActivityOtherUserPageBinding import com.into.websoso.databinding.MenuOtherUserPagePopupBinding import com.into.websoso.ui.otherUserPage.adapter.OtherUserPageViewPagerAdapter import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class OtherUserPageActivity : BaseActivity(R.layout.activity_other_user_page) { + @Inject + lateinit var tracker: Tracker + private var _popupBinding: MenuOtherUserPagePopupBinding? = null private val popupBinding: MenuOtherUserPagePopupBinding get() = _popupBinding ?: error("OtherUserPageActivity") @@ -48,6 +53,7 @@ class OtherUserPageActivity : onBackButtonClick() onMoreButtonClick() handleBackPressed() + tracker.trackEvent("other_mypage") } private fun updateUserId() { diff --git a/app/src/main/java/com/into/websoso/ui/profileEdit/ProfileEditActivity.kt b/app/src/main/java/com/into/websoso/ui/profileEdit/ProfileEditActivity.kt index cb7d13747..ced5b45ce 100644 --- a/app/src/main/java/com/into/websoso/ui/profileEdit/ProfileEditActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/profileEdit/ProfileEditActivity.kt @@ -3,6 +3,7 @@ package com.into.websoso.ui.profileEdit import android.content.Context import android.content.Intent import android.os.Bundle +import android.text.InputFilter import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -45,6 +46,7 @@ class ProfileEditActivity : setupGenreChips() onNicknameEditTextChange() onIntroductionEditTextChange() + setupProfileIntroductionMaxLines() } private fun bindViewModel() { @@ -240,10 +242,29 @@ class ProfileEditActivity : profileEditViewModel.updateAvatarThumbnail(updatedAvatarThumbnail) } + private fun setupProfileIntroductionMaxLines() { + binding.etProfileEditIntroduction.filters = + arrayOf(InputFilter { source, start, end, dest, dstart, dend -> + + val newText = dest.toString().substring(0, dstart) + + source.toString().substring(start, end) + + dest.toString().substring(dend) + + if (newText.length > MAX_LENGTH || newText.lines().size > MAX_LINES) { + "" + } else { + null + } + }) + } + companion object { private const val PROFILE_EDIT_CHARACTER_BOTTOM_SHEET_DIALOG = "PROFILE_EDIT_CHARACTER_BOTTOM_SHEET_DIALOG" + private const val MAX_LENGTH = 50 + private const val MAX_LINES = 2 + fun getIntent( context: Context, ): Intent { diff --git a/app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt b/app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt index 0283dcd11..fe7a5247a 100644 --- a/app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt +++ b/app/src/main/java/com/into/websoso/ui/splash/SplashActivity.kt @@ -8,6 +8,7 @@ import com.into.websoso.common.ui.base.BaseActivity import com.into.websoso.databinding.ActivityLoginBinding import com.into.websoso.ui.login.LoginActivity import com.into.websoso.ui.main.MainActivity +import com.into.websoso.ui.splash.dialog.MinimumVersionDialogFragment import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -27,9 +28,15 @@ class SplashActivity : BaseActivity(R.layout.activity_spla splashViewModel.isAutoLogin.observe(this) { isAutoLogin -> lifecycleScope.launch { delay(1000L) - when (isAutoLogin) { - true -> navigateToMainActivity() - false -> navigateToLoginActivity() + splashViewModel.updateMinimumVersion { isUpdateRequired -> + if (isUpdateRequired) { + showMinimumVersionDialog() + } else { + when (isAutoLogin) { + true -> navigateToMainActivity() + false -> navigateToLoginActivity() + } + } } } } @@ -44,4 +51,14 @@ class SplashActivity : BaseActivity(R.layout.activity_spla startActivity(LoginActivity.getIntent(this)) finish() } + + private fun showMinimumVersionDialog() { + val dialog = MinimumVersionDialogFragment.newInstance() + dialog.isCancelable = false + dialog.show(supportFragmentManager, MINIMUM_VERSION_TAG) + } + + companion object { + private const val MINIMUM_VERSION_TAG = "MinimumVersionDialog" + } } diff --git a/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt b/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt index 2f17e7f79..a6e062e51 100644 --- a/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt +++ b/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.into.websoso.data.repository.AuthRepository +import com.into.websoso.data.repository.VersionRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -12,6 +13,7 @@ import javax.inject.Inject @HiltViewModel class SplashViewModel @Inject constructor( private val authRepository: AuthRepository, + private val versionRepository: VersionRepository, ) : ViewModel() { private var _isAutoLogin = MutableLiveData(false) @@ -32,4 +34,16 @@ class SplashViewModel @Inject constructor( } } } + + fun updateMinimumVersion(onUpdateRequired: (Boolean) -> Unit) { + viewModelScope.launch { + runCatching { + versionRepository.isUpdateRequired() + }.onSuccess { isUpdateRequired -> + onUpdateRequired(isUpdateRequired) + }.onFailure { + onUpdateRequired(false) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt b/app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt new file mode 100644 index 000000000..a3af4fefb --- /dev/null +++ b/app/src/main/java/com/into/websoso/ui/splash/dialog/MinimumVersionDialogFragment.kt @@ -0,0 +1,38 @@ +package com.into.websoso.ui.splash.dialog + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.View +import com.into.websoso.R +import com.into.websoso.common.ui.base.BaseDialogFragment +import com.into.websoso.databinding.DialogMinimumVersionPopupMenuBinding + +class MinimumVersionDialogFragment : + BaseDialogFragment(R.layout.dialog_minimum_version_popup_menu) { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + onMinimumVersionUpdateButtonClick() + } + + private fun onMinimumVersionUpdateButtonClick() { + binding.tvMinimumVersionPopupMenuUpdate.setOnClickListener { + navigateToPlayStore() + } + } + + private fun navigateToPlayStore() { + val intent = Intent( + Intent.ACTION_VIEW, + Uri.parse(getString(R.string.minimum_version_popup_menu_url)), + ) + startActivity(intent) + } + + companion object { + fun newInstance(): MinimumVersionDialogFragment { + return MinimumVersionDialogFragment() + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 9f92ba992..8025e0df3 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -63,6 +63,7 @@ android:text="@string/login_browse_without_signup" android:textAppearance="@style/title1" android:textColor="@color/primary_100_6A5DFD" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/layout/activity_notice_detail.xml b/app/src/main/res/layout/activity_notice_detail.xml index f68ff74d2..43ceb5a43 100644 --- a/app/src/main/res/layout/activity_notice_detail.xml +++ b/app/src/main/res/layout/activity_notice_detail.xml @@ -74,11 +74,13 @@ app:layout_constraintTop_toBottomOf="@id/tv_notice_detail_notice_date" /> diff --git a/app/src/main/res/layout/activity_profile_edit.xml b/app/src/main/res/layout/activity_profile_edit.xml index d335efc3a..d4784b695 100644 --- a/app/src/main/res/layout/activity_profile_edit.xml +++ b/app/src/main/res/layout/activity_profile_edit.xml @@ -240,8 +240,7 @@ android:background="@null" android:gravity="top" android:hint="@string/edit_profile_introduction_hint" - android:maxLength="50" - android:maxLines="4" + android:inputType="textMultiLine" android:minHeight="44dp" android:text="@{viewModel.profileEditUiState.profile.introduction}" android:textAppearance="@style/body2" diff --git a/app/src/main/res/layout/dialog_minimum_version_popup_menu.xml b/app/src/main/res/layout/dialog_minimum_version_popup_menu.xml new file mode 100644 index 000000000..2e8fd72dc --- /dev/null +++ b/app/src/main/res/layout/dialog_minimum_version_popup_menu.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_my_page.xml b/app/src/main/res/layout/fragment_my_page.xml index 707ecc091..f3cabdcad 100644 --- a/app/src/main/res/layout/fragment_my_page.xml +++ b/app/src/main/res/layout/fragment_my_page.xml @@ -29,7 +29,7 @@ diff --git a/app/src/main/res/values/deepLinks.xml b/app/src/main/res/values/deepLinks.xml index dff02cb31..76a1fd97d 100644 --- a/app/src/main/res/values/deepLinks.xml +++ b/app/src/main/res/values/deepLinks.xml @@ -4,4 +4,5 @@ https://www.instagram.com/websoso_official/ https://websoso.notion.site/143600bd74688050be18f4da31d9403e?pvs=4 https://websoso.notion.site/143600bd746880668556fb005fcef491?pvs=4 + https://play.google.com/store/apps/details?id=com.into.websoso \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65799ce08..fe155568a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -401,4 +401,9 @@ 스포일러 신고 부적절한 표현 신고 작성한 글이 없어요 + + + 업데이트 알림 + 웹소소 세계에 변화가 생겼어요!\n지금 업데이트해보세요. + 업데이트 From eb629d9ec4a7c9baae026a66dfc37aba2bdb9749 Mon Sep 17 00:00:00 2001 From: Son Myeongji <114990782+m6z1@users.noreply.github.com> Date: Wed, 1 Jan 2025 22:53:40 +0900 Subject: [PATCH 2/4] =?UTF-8?q?build:=201.0.7=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20(#507)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 44b24f949..3ff36892e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,8 +18,8 @@ android { applicationId = "com.into.websoso" minSdk = 30 targetSdk = 34 - versionCode = 10006 - versionName = "1.0.6" + versionCode = 10007 + versionName = "1.0.7" buildConfigField("String", "BASE_URL", gradleLocalProperties(rootDir).getProperty("base.url")) buildConfigField("String", "S3_BASE_URL", gradleLocalProperties(rootDir).getProperty("s3.url")) From 79ee73a46aff834c652885bcbfe55d31df6ed339 Mon Sep 17 00:00:00 2001 From: m6z1 Date: Sat, 4 Jan 2025 17:15:28 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20dialogfragment=20=EC=97=90=20android?= =?UTF-8?q?=20entry=20point=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt | 2 ++ .../websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt index 579dc51b3..09daa87fb 100644 --- a/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt +++ b/app/src/main/java/com/into/websoso/ui/createFeed/CreateFeedSearchNovelBottomSheetDialog.kt @@ -18,8 +18,10 @@ import com.into.websoso.ui.createFeed.adapter.SearchNovelAdapter import com.into.websoso.ui.createFeed.adapter.SearchNovelItemType.Loading import com.into.websoso.ui.createFeed.adapter.SearchNovelItemType.Novels import com.into.websoso.ui.createFeed.model.SearchNovelUiState +import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject +@AndroidEntryPoint class CreateFeedSearchNovelBottomSheetDialog : BaseBottomSheetDialog(dialog_create_feed_search_novel) { @Inject diff --git a/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt b/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt index 884eae44a..6c560d034 100644 --- a/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/main/feed/dialog/FeedReportDialogFragment.kt @@ -16,8 +16,10 @@ import com.into.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_COMMENT import com.into.websoso.ui.main.feed.dialog.ReportMenuType.IMPERTINENCE_FEED import com.into.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_COMMENT import com.into.websoso.ui.main.feed.dialog.ReportMenuType.SPOILER_FEED +import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject +@AndroidEntryPoint class FeedReportDialogFragment : BaseDialogFragment(R.layout.dialog_report_popup_menu) { @Inject From b1ebf2e82e24a8a8bf8f7b662731fd836c5d56a8 Mon Sep 17 00:00:00 2001 From: m6z1 Date: Sat, 4 Jan 2025 17:18:49 +0900 Subject: [PATCH 4/4] =?UTF-8?q?build:=201.0.8=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3ff36892e..d9e6f5935 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,8 +18,8 @@ android { applicationId = "com.into.websoso" minSdk = 30 targetSdk = 34 - versionCode = 10007 - versionName = "1.0.7" + versionCode = 10008 + versionName = "1.0.8" buildConfigField("String", "BASE_URL", gradleLocalProperties(rootDir).getProperty("base.url")) buildConfigField("String", "S3_BASE_URL", gradleLocalProperties(rootDir).getProperty("s3.url"))