diff --git a/presentation/src/main/java/daily/dayo/presentation/fragment/policy/PolicyFragment.kt b/presentation/src/main/java/daily/dayo/presentation/fragment/policy/PolicyFragment.kt deleted file mode 100644 index fdde426a..00000000 --- a/presentation/src/main/java/daily/dayo/presentation/fragment/policy/PolicyFragment.kt +++ /dev/null @@ -1,72 +0,0 @@ -package daily.dayo.presentation.fragment.policy - -import android.os.Bundle -import android.view.KeyEvent -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.webkit.WebViewClient -import androidx.navigation.fragment.findNavController -import androidx.navigation.fragment.navArgs -import daily.dayo.presentation.BuildConfig -import daily.dayo.presentation.R -import daily.dayo.presentation.common.autoCleared -import daily.dayo.presentation.common.setOnDebounceClickListener -import daily.dayo.presentation.databinding.FragmentPolicyBinding -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class PolicyFragment : Fragment() { - private var binding by autoCleared() - private val args by navArgs() - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentPolicyBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initActionbar() - showPolicy(args.informationType) - setWebViewBackClickListener() - } - - private fun initActionbar() { - binding.btnPolicyActionBarBack.setOnDebounceClickListener { - findNavController().navigateUp() - } - binding.tvPolicyActionBarTitle.text = - if (args.informationType == "privacy") getString(R.string.policy_privacy) - else getString(R.string.policy_terms) - } - - private fun showPolicy(informationType: String) { - with(binding.webviewPolicyContents) { - visibility = View.VISIBLE - apply { - webViewClient = WebViewClient() - settings.javaScriptEnabled = false - } - loadUrl("${BuildConfig.BASE_URL}/$informationType.html") - } - binding.webviewPolicyContents.visibility = View.VISIBLE - } - - private fun setWebViewBackClickListener() { - binding.webviewPolicyContents.setOnKeyListener( - View.OnKeyListener { v, keyCode, event -> - if (event.action !== KeyEvent.ACTION_DOWN) return@OnKeyListener true - if (keyCode == KeyEvent.KEYCODE_BACK) { - findNavController().navigateUp() - return@OnKeyListener true - } - false - } - ) - } -} \ No newline at end of file diff --git a/presentation/src/main/java/daily/dayo/presentation/fragment/setting/SettingFragment.kt b/presentation/src/main/java/daily/dayo/presentation/fragment/setting/SettingFragment.kt index 0d57e8c3..78cc93fe 100644 --- a/presentation/src/main/java/daily/dayo/presentation/fragment/setting/SettingFragment.kt +++ b/presentation/src/main/java/daily/dayo/presentation/fragment/setting/SettingFragment.kt @@ -79,10 +79,6 @@ class SettingFragment : Fragment() { private fun setInformationButtonClickListener() { binding.layoutSettingInformation.setOnDebounceClickListener { - findNavController().navigateSafe( - currentDestinationId = R.id.SettingFragment, - action = R.id.action_settingFragment_to_informationFragment - ) } } diff --git a/presentation/src/main/java/daily/dayo/presentation/fragment/setting/information/InformationFragment.kt b/presentation/src/main/java/daily/dayo/presentation/fragment/setting/information/InformationFragment.kt deleted file mode 100644 index 0e53565f..00000000 --- a/presentation/src/main/java/daily/dayo/presentation/fragment/setting/information/InformationFragment.kt +++ /dev/null @@ -1,70 +0,0 @@ -package daily.dayo.presentation.fragment.setting.information - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.navigation.fragment.findNavController -import daily.dayo.presentation.BuildConfig -import daily.dayo.presentation.R -import daily.dayo.presentation.common.autoCleared -import daily.dayo.presentation.common.extension.navigateSafe -import daily.dayo.presentation.common.setOnDebounceClickListener -import daily.dayo.presentation.databinding.FragmentInformationBinding -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class InformationFragment : Fragment() { - private var binding by autoCleared() - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentInformationBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setBackButtonClickListener() - setTermsClickListener() - setPrivacyClickListener() - setAppVersion() - } - - private fun setBackButtonClickListener() { - binding.btnInformationBack.setOnDebounceClickListener { - findNavController().navigateUp() - } - } - - private fun setTermsClickListener() { - binding.layoutInformationContentsPolicyTerms.setOnDebounceClickListener { - findNavController().navigateSafe( - currentDestinationId = R.id.InformationFragment, - action = R.id.action_informationFragment_to_policyFragment, - args = InformationFragmentDirections.actionInformationFragmentToPolicyFragment( - informationType = "terms" - ).arguments - ) - } - } - - private fun setPrivacyClickListener() { - binding.layoutInformationContentsPolicyPrivacy.setOnDebounceClickListener { - findNavController().navigateSafe( - currentDestinationId = R.id.InformationFragment, - action = R.id.action_informationFragment_to_policyFragment, - args = InformationFragmentDirections.actionInformationFragmentToPolicyFragment( - informationType = "privacy" - ).arguments - ) - } - } - - private fun setAppVersion() { - binding.versionName = requireActivity().packageManager.getPackageInfo(requireActivity().packageName, 0).versionName - } -} \ No newline at end of file diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/main/MainNavigator.kt b/presentation/src/main/java/daily/dayo/presentation/screen/main/MainNavigator.kt index c14420f3..422fc83c 100644 --- a/presentation/src/main/java/daily/dayo/presentation/screen/main/MainNavigator.kt +++ b/presentation/src/main/java/daily/dayo/presentation/screen/main/MainNavigator.kt @@ -23,10 +23,13 @@ import daily.dayo.presentation.screen.notice.navigateNoticeDetail import daily.dayo.presentation.screen.post.navigatePost import daily.dayo.presentation.screen.post.navigatePostLikeUsers import daily.dayo.presentation.screen.profile.navigateProfile +import daily.dayo.presentation.screen.rules.RuleType +import daily.dayo.presentation.screen.rules.navigateRules import daily.dayo.presentation.screen.search.navigateSearch import daily.dayo.presentation.screen.search.navigateSearchPostHashtag import daily.dayo.presentation.screen.search.navigateSearchResult import daily.dayo.presentation.screen.settings.navigateChangePassword +import daily.dayo.presentation.screen.settings.navigateInformation import daily.dayo.presentation.screen.settings.navigateSettings import daily.dayo.presentation.screen.settings.navigateSettingsNotification import daily.dayo.presentation.screen.write.navigateWrite @@ -79,6 +82,14 @@ class MainNavigator( navController.navigateNoticeDetail(noticeId = noticeId) } + fun navigateInformation() { + navController.navigateInformation() + } + + fun navigateRules(ruleType: RuleType) { + navController.navigateRules(ruleType) + } + fun navigateSettings() { navController.navigateSettings() } diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/main/MainScreen.kt b/presentation/src/main/java/daily/dayo/presentation/screen/main/MainScreen.kt index ee3cec13..1499f2c2 100644 --- a/presentation/src/main/java/daily/dayo/presentation/screen/main/MainScreen.kt +++ b/presentation/src/main/java/daily/dayo/presentation/screen/main/MainScreen.kt @@ -225,6 +225,8 @@ internal fun MainScreen( onPasswordChangeClick = { navigator.navigateChangePassword() }, onSettingNotificationClick = { navigator.navigateSettingsNotification() }, onNoticesClick = { navigator.navigateNotices() }, + onInformationClick = { navigator.navigateInformation() }, + onRulesClick = { ruleType -> navigator.navigateRules(ruleType) }, onBackClick = { navigator.popBackStack() } ) noticeNavGraph( diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/rules/RuleScreen.kt b/presentation/src/main/java/daily/dayo/presentation/screen/rules/RuleScreen.kt index 1238bb9c..292e35a7 100644 --- a/presentation/src/main/java/daily/dayo/presentation/screen/rules/RuleScreen.kt +++ b/presentation/src/main/java/daily/dayo/presentation/screen/rules/RuleScreen.kt @@ -58,6 +58,7 @@ fun RuleScreen( WebView(context).apply { webViewClient = WebViewClient() settings.javaScriptEnabled = false + overScrollMode = View.OVER_SCROLL_NEVER loadUrl("${BuildConfig.BASE_URL}/${ruleType.fileName}.html") setOnKeyListener( diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/settings/AppInformationScreen.kt b/presentation/src/main/java/daily/dayo/presentation/screen/settings/AppInformationScreen.kt new file mode 100644 index 00000000..cb4b2e68 --- /dev/null +++ b/presentation/src/main/java/daily/dayo/presentation/screen/settings/AppInformationScreen.kt @@ -0,0 +1,173 @@ +package daily.dayo.presentation.screen.settings + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import daily.dayo.presentation.R +import daily.dayo.presentation.screen.rules.RuleType +import daily.dayo.presentation.theme.Dark +import daily.dayo.presentation.theme.DayoTheme +import daily.dayo.presentation.theme.Gray4_C5CAD2 +import daily.dayo.presentation.theme.Primary_23C882 +import daily.dayo.presentation.view.NoRippleIconButton +import daily.dayo.presentation.view.TopNavigation +import daily.dayo.presentation.view.TopNavigationAlign + +@Composable +fun AppInformationScreen( + onBackClick: () -> Unit = {}, + onRulesClick: (RuleType) -> Unit = {}, +) { + Scaffold( + topBar = { AppInformationTopBar(onBackClick = onBackClick) }, + ) { paddingValues -> + AppInformationContent( + modifier = Modifier.padding(paddingValues), + onRulesClick = onRulesClick, + ) + } +} + +@Composable +fun AppInformationTopBar( + onBackClick: () -> Unit, +) { + TopNavigation( + leftIcon = { + NoRippleIconButton( + onClick = { onBackClick() }, + iconContentDescription = stringResource(R.string.back_sign), + iconPainter = painterResource(id = R.drawable.ic_arrow_left), + ) + }, + title = stringResource(R.string.information_title), + titleAlignment = TopNavigationAlign.CENTER + ) +} + +@Composable +fun AppInformationContent( + modifier: Modifier = Modifier, + onRulesClick: (RuleType) -> Unit = {}, +) { + val context = LocalContext.current + val appVersion = getAppVersion(context) + + Column( + modifier = modifier + .fillMaxSize() + .padding(vertical = 8.dp, horizontal = 20.dp), + ) { + AppInformationItem( + title = stringResource(R.string.rules_terms_and_conditions), + onClick = { onRulesClick(RuleType.TERMS_AND_CONDITIONS) }, + ) + Spacer(modifier = Modifier.height(2.dp)) + AppInformationItem( + title = stringResource(R.string.rules_privacy_policy_title), + onClick = { onRulesClick(RuleType.PRIVACY_POLICY) }, + ) + Spacer(modifier = Modifier.height(2.dp)) + AppInformationItem( + title = stringResource(R.string.app_version), + description = "DAYO $appVersion", + ) + } +} + +@Composable +fun AppInformationItem( + title: String, + description: String? = null, + onClick: () -> Unit = {}, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(48.dp) + .clickable { onClick() }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = title, + style = DayoTheme.typography.b4, + color = Dark, + ) + Spacer(modifier = Modifier.weight(1f)) + if (!description.isNullOrBlank()) { + Text( + text = description, + style = DayoTheme.typography.b4, + color = DayoTheme.colorScheme.primary, + modifier = Modifier + .padding(end = 4.dp) + .wrapContentSize(), + ) + } else { + Icon( + modifier = Modifier + .padding(end = 4.dp) + .size(20.dp), + painter = painterResource(id = R.drawable.ic_chevron_r), + contentDescription = null, + tint = DayoTheme.colorScheme.outline, + ) + } + } +} + +private fun getAppVersion(context: Context): String { + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.packageManager.getPackageInfo( + context.packageName, + PackageManager.PackageInfoFlags.of(0) + ).versionName + } else { + context.packageManager.getPackageInfo(context.packageName, 0).versionName + } ?: "" + } catch (e: PackageManager.NameNotFoundException) { + "" + } +} + +@Preview(showBackground = true) +@Composable +fun PreviewAppInformationContent() { + DayoTheme { + AppInformationContent() + } +} + +@Preview(showBackground = true) +@Composable +fun PreviewSettingsListItem() { + DayoTheme { + Column { + AppInformationItem(title = "이용약관") + AppInformationItem(title = "개인정보처리방침") + AppInformationItem(title = "앱 버전", description = "DAYO 1.0.0") + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsNavigation.kt b/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsNavigation.kt index 1d770cc4..6c96d98c 100644 --- a/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsNavigation.kt +++ b/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsNavigation.kt @@ -4,6 +4,8 @@ import androidx.compose.material3.SnackbarHostState import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable +import daily.dayo.presentation.screen.rules.RuleRoute +import daily.dayo.presentation.screen.rules.RuleType import kotlinx.coroutines.CoroutineScope fun NavController.navigateSettings() { @@ -18,6 +20,10 @@ fun NavController.navigateSettingsNotification() { navigate(SettingsRoute.notification) } +fun NavController.navigateInformation() { + navigate(SettingsRoute.information) +} + fun NavGraphBuilder.settingsNavGraph( coroutineScope: CoroutineScope, snackBarHostState: SnackbarHostState, @@ -27,6 +33,8 @@ fun NavGraphBuilder.settingsNavGraph( onSettingNotificationClick: () -> Unit, onPasswordChangeClick: () -> Unit, onNoticesClick: () -> Unit, + onInformationClick: () -> Unit, + onRulesClick: (RuleType) -> Unit, ) { composable(SettingsRoute.route) { SettingsScreen( @@ -36,6 +44,7 @@ fun NavGraphBuilder.settingsNavGraph( onBlockUsersClick = onBlockUsersClick, onSettingNotificationClick = onSettingNotificationClick, onNoticesClick = onNoticesClick, + onInformationClick = onInformationClick ) } @@ -52,6 +61,27 @@ fun NavGraphBuilder.settingsNavGraph( onBackClick = onBackClick, ) } + + composable(SettingsRoute.information) { + AppInformationScreen( + onBackClick = onBackClick, + onRulesClick = onRulesClick, + ) + } + + composable(route = RuleRoute.privacyPolicy) { + RuleRoute( + onBackClick = onBackClick, + ruleType = RuleType.PRIVACY_POLICY + ) + } + + composable(route = RuleRoute.termsAndConditions) { + RuleRoute( + onBackClick = onBackClick, + ruleType = RuleType.TERMS_AND_CONDITIONS + ) + } } object SettingsRoute { @@ -59,4 +89,5 @@ object SettingsRoute { const val changePassword = "${route}/changePassword" const val notification = "${route}/notification" + const val information = "${route}/information" } \ No newline at end of file diff --git a/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt b/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt index cc8ad657..efce96dc 100644 --- a/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt +++ b/presentation/src/main/java/daily/dayo/presentation/screen/settings/SettingsScreen.kt @@ -63,6 +63,7 @@ fun SettingsScreen( onBlockUsersClick: () -> Unit, onSettingNotificationClick: () -> Unit, onNoticesClick: () -> Unit, + onInformationClick: () -> Unit = {}, profileViewModel: ProfileViewModel = hiltViewModel() ) { val profileInfo = profileViewModel.profileInfo.observeAsState() @@ -78,7 +79,8 @@ fun SettingsScreen( onSettingNotificationClick = onSettingNotificationClick, onPasswordChangeClick = onPasswordChangeClick, onNoticesClick = onNoticesClick, - onBlockUsersClick = onBlockUsersClick + onBlockUsersClick = onBlockUsersClick, + onInformationClick = onInformationClick, ) } @@ -91,6 +93,7 @@ private fun SettingsScreen( onPasswordChangeClick: () -> Unit, onNoticesClick: () -> Unit = {}, onBlockUsersClick: () -> Unit, + onInformationClick: () -> Unit = {}, ) { Scaffold( topBar = { @@ -130,7 +133,7 @@ private fun SettingsScreen( SettingItem(R.string.setting_menu_notification, R.drawable.ic_notification, onClickMenu = onSettingNotificationClick), null, // Divider SettingItem(R.string.setting_menu_notice, R.drawable.ic_setting_notice, onClickMenu = onNoticesClick), - SettingItem(R.string.setting_menu_information, R.drawable.ic_setting_information, onClickMenu = {}, description = appVersion), + SettingItem(R.string.setting_menu_information, R.drawable.ic_setting_information, onClickMenu = onInformationClick, description = appVersion), SettingItem(R.string.setting_menu_contact, R.drawable.ic_setting_contact, onClickMenu = {}), null // Divider ) @@ -284,7 +287,8 @@ private fun PreviewSettingsScreen() { onPasswordChangeClick = {}, onSettingNotificationClick = {}, onNoticesClick = {}, - onBlockUsersClick = {} + onBlockUsersClick = {}, + onInformationClick = {} ) } } diff --git a/presentation/src/main/res/drawable/ic_chevron_r.xml b/presentation/src/main/res/drawable/ic_chevron_r.xml new file mode 100644 index 00000000..c8f4923b --- /dev/null +++ b/presentation/src/main/res/drawable/ic_chevron_r.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/presentation/src/main/res/layout/fragment_information.xml b/presentation/src/main/res/layout/fragment_information.xml deleted file mode 100644 index 1222bd81..00000000 --- a/presentation/src/main/res/layout/fragment_information.xml +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/layout/fragment_policy.xml b/presentation/src/main/res/layout/fragment_policy.xml deleted file mode 100644 index 3459062e..00000000 --- a/presentation/src/main/res/layout/fragment_policy.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/navigation/nav_graph.xml b/presentation/src/main/res/navigation/nav_graph.xml index caa99baa..4e136945 100644 --- a/presentation/src/main/res/navigation/nav_graph.xml +++ b/presentation/src/main/res/navigation/nav_graph.xml @@ -537,14 +537,6 @@ app:exitAnim="@anim/translate_to_left_out" app:popEnterAnim="@anim/translate_from_left_in" app:popExitAnim="@anim/translate_to_right_out" /> - - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 0db2453f..ba182b9b 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -86,10 +86,6 @@ 개인정보 취급방침 이용약관 - - 이용약관 - 개인정보 취급방침 - DAYO PICK New