Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/alarm/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ dependencies {
implementation(projects.core.util)

implementation(projects.core.amplitude)
implementation(projects.core.datastore)
implementation(libs.datastore)
implementation(libs.amplitude.analytics)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.teambrake.brake.core.alarm.notification
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.datastore.core.DataStore
import com.amplitude.android.Amplitude
import com.amplitude.core.events.Identify
import com.teambrake.brake.core.alarm.scheduler.AlarmSchedulerImpl
import com.teambrake.brake.core.amplitude.AmplitudeEventHelper
import com.teambrake.brake.core.common.AlarmAction
import com.teambrake.brake.core.datastore.model.DatastoreFeedback
import com.teambrake.brake.core.model.accessibility.IntentConfig
import com.teambrake.brake.core.model.app.AppGroup
import com.teambrake.brake.core.model.app.AppGroupState
Expand All @@ -20,7 +22,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject

@AndroidEntryPoint
Expand All @@ -38,6 +39,9 @@ class NotificationReceiver : BroadcastReceiver() {
@Inject
lateinit var amplitude: Amplitude

@Inject
lateinit var feedbackDataStore: DataStore<DatastoreFeedback>

private val serviceJob = SupervisorJob()
private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)

Expand Down Expand Up @@ -69,8 +73,6 @@ class NotificationReceiver : BroadcastReceiver() {
* 3. 알람 스케줄러 시작 - 차단이 완료되면 알람 스케줄러를 시작
* */
private suspend fun startBlocking(context: Context, appGroup: AppGroup) {
Timber.i("ID: ${appGroup.id} 차단이 시작되었습니다")

val broadcastIntent = Intent().apply {
action = IntentConfig.RECEIVER_IDENTITY
setPackage(context.packageName)
Expand All @@ -88,7 +90,6 @@ class NotificationReceiver : BroadcastReceiver() {
}

private suspend fun stopBlocking(context: Context, appGroup: AppGroup) {
Timber.i("ID: ${appGroup.id} 차단이 해제되었습니다")
resetAppGroupUsecase(appGroup)

withContext(Dispatchers.IO) {
Expand Down Expand Up @@ -128,6 +129,10 @@ class NotificationReceiver : BroadcastReceiver() {
}
},
)

feedbackDataStore.updateData { current ->
current.copy(sessionCount = current.sessionCount + 1)
}
}

val broadcastIntent = Intent().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,42 @@ object AmplitudeEventHelper {
)

/**
* 17. total_group_count User Property 생성
* 17. view_coffeechat_popup 이벤트 생성
*/
fun createViewCoffeechatPopupEvent(
triggerSource: CoffeechatTriggerSource,
): AmplitudeEvent = AmplitudeEvent(
eventName = EventName.VIEW_COFFEECHAT_POPUP,
parameters = mapOf(
EventParameter.TRIGGER_SOURCE to triggerSource.value,
),
)

/**
* 18. click_coffeechat_popup 이벤트 생성
*/
fun createClickCoffeechatPopupEvent(
actionType: CoffeechatActionType,
): AmplitudeEvent = AmplitudeEvent(
eventName = EventName.CLICK_COFFEECHAT_POPUP,
parameters = mapOf(
EventParameter.ACTION_TYPE to actionType.value,
),
)

/**
* coffeechat_status User Property 설정
*/
fun setCoffeechatStatus(
status: String,
): AmplitudeUserProperty = AmplitudeUserProperty(
properties = mapOf(
"coffeechat_status" to status,
),
)

/**
* 20. total_group_count User Property 생성
* @param count 총 그룹 개수
* @return User Property 맵
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ enum class EventName(val eventName: String) {
CLICK_SNOOZE("click_snooze"),
END_BRAKE_SESSION("end_brake_session"),
VIEW_COOLDOWN("view_cooldown"),
VIEW_COFFEECHAT_POPUP("view_coffeechat_popup"),
CLICK_COFFEECHAT_POPUP("click_coffeechat_popup"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum class EventParameter(val parameterName: String) {
SNOOZE_NTH("snooze_nth"),
SNOOZE_COUNT("snooze_count"),
IS_EARLY_EXIT("is_early_exit"),
ACTION_TYPE("action_type"),
}

/**
Expand Down Expand Up @@ -48,3 +49,20 @@ enum class StepDetail(val value: String) {
NOTIFICATION("notification"),
ACCESSIBILITY("accessibility"),
}

/**
* Event Parameter Values for ACTION_TYPE (coffeechat popup)
*/
enum class CoffeechatActionType(val value: String) {
ACCEPT("accept"),
LATER("later"),
REJECT("reject"),
}

/**
* Event Parameter Values for TRIGGER_SOURCE (coffeechat popup)
*/
enum class CoffeechatTriggerSource(val value: String) {
APP_OPEN("app_open"),
SESSION_END("session_end"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import com.teambrake.brake.core.datastore.model.DatastoreAuthCode
import com.teambrake.brake.core.datastore.model.DatastoreFeedback
import com.teambrake.brake.core.datastore.model.DatastoreOnboarding
import com.teambrake.brake.core.datastore.model.DatastoreUserInfo
import com.teambrake.brake.core.datastore.model.DatastoreUserToken
import com.teambrake.brake.core.datastore.serializer.AuthSerializer
import com.teambrake.brake.core.datastore.serializer.FeedbackSerializer
import com.teambrake.brake.core.datastore.serializer.OnboardingSerializer
import com.teambrake.brake.core.datastore.serializer.UserInfoSerializer
import com.teambrake.brake.core.datastore.serializer.UserSerializer
Expand Down Expand Up @@ -42,6 +44,11 @@ object DatastoreModule {
serializer = OnboardingSerializer,
)

private val Context.FeedbackDataStore: DataStore<DatastoreFeedback> by dataStore(
fileName = "feedback",
serializer = FeedbackSerializer,
)

@Provides
@Singleton
fun provideUserTokenDataStore(
Expand All @@ -65,4 +72,10 @@ object DatastoreModule {
fun provideOnboardingDataStore(
@ApplicationContext context: Context,
): DataStore<DatastoreOnboarding> = context.OnboardingDataStore

@Provides
@Singleton
fun provideFeedbackDataStore(
@ApplicationContext context: Context,
): DataStore<DatastoreFeedback> = context.FeedbackDataStore
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.teambrake.brake.core.datastore.model

import kotlinx.serialization.Serializable

@Serializable
data class DatastoreFeedback(
val sessionCount: Int = 0,
val status: String = "",
val lastShownAt: Long = 0L,
) {
companion object {
val Default = DatastoreFeedback()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.teambrake.brake.core.datastore.serializer

import com.teambrake.brake.core.datastore.model.DatastoreFeedback

internal val FeedbackSerializer = DataSerializer(
DatastoreFeedback.Companion.serializer(),
DatastoreFeedback.Companion.Default,
"Feedback Datastore 읽기 실패",
)
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ fun BaseDialog(
onDismissRequest: () -> Unit,
confirmButton: (@Composable () -> Unit)? = null,
dismissButton: (@Composable () -> Unit)? = null,
dismissOnClickOutside: Boolean = true,
content: @Composable () -> Unit = { },
) {
Dialog(
properties = DialogProperties(),
properties = DialogProperties(dismissOnClickOutside = dismissOnClickOutside),
onDismissRequest = onDismissRequest,
) {
Box(
Expand Down Expand Up @@ -123,10 +124,12 @@ fun TwoButtonDialog(
onDismissRequest: () -> Unit,
onConfirmButtonClick: () -> Unit,
onDismissButtonClick: () -> Unit = onDismissRequest,
dismissOnClickOutside: Boolean = true,
content: @Composable () -> Unit,
) {
BaseDialog(
onDismissRequest = onDismissRequest,
dismissOnClickOutside = dismissOnClickOutside,
dismissButton = {
DialogButton(
text = dismissButtonText,
Expand Down
2 changes: 2 additions & 0 deletions presentation/home/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ android {
dependencies {
implementation(projects.core.util)
implementation(projects.core.appscanner)
implementation(projects.core.datastore)
implementation(libs.datastore)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.teambrake.brake.presentation.home

internal object FeedbackConfig {
const val FORM_URL = "https://forms.gle/jZQLtJyZSGh4ACfe8"
const val REQUIRED_SESSION_COUNT = 5
const val LATER_COOLDOWN_DAYS = 3
const val ACCEPTED_COOLDOWN_DAYS = 7
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.teambrake.brake.core.designsystem.theme.LinerGradient
import com.teambrake.brake.core.navigation.compositionlocal.LocalMainAction
import com.teambrake.brake.core.navigation.compositionlocal.LocalNavigatorAction
import android.content.Intent
import android.net.Uri
import com.teambrake.brake.presentation.home.component.FeedbackDialog
import com.teambrake.brake.presentation.home.component.StopUsingDialog
import com.teambrake.brake.presentation.home.contract.HomeEvent
import com.teambrake.brake.presentation.home.contract.HomeModalState
Expand Down Expand Up @@ -155,6 +158,8 @@ private fun ModalContent(
homeModalState: HomeModalState,
viewModel: HomeViewModel,
) {
val context = LocalContext.current

when (homeModalState) {
HomeModalState.Nothing -> {}
is HomeModalState.StopUsingDialog -> {
Expand All @@ -166,5 +171,19 @@ private fun ModalContent(
onDismissRequest = viewModel::dismiss,
)
}

HomeModalState.FeedbackDialog -> {
FeedbackDialog(
onAccept = {
viewModel.onFeedbackAccept()
context.startActivity(
Intent(Intent.ACTION_VIEW, Uri.parse(FeedbackConfig.FORM_URL)),
)
},
onLater = viewModel::onFeedbackLater,
onReject = viewModel::onFeedbackReject,
onDismissRequest = viewModel::onFeedbackLater,
)
}
}
}
Loading
Loading