Skip to content
Open
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: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ android {
versionName = libs.versions.versionName.get()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

targetSdk = 35
targetSdk = 36

buildConfigs(rootDir) {
string(name = "S3_BASE_URL", key = "s3.url")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.into.websoso.core.common.navigator.NavigatorProvider
import com.into.websoso.ui.login.LoginActivity
import com.into.websoso.ui.main.MainActivity
import com.into.websoso.ui.normalExplore.NormalExploreActivity
import com.into.websoso.ui.notificationSetting.NotificationSettingActivity
import com.into.websoso.ui.novelDetail.NovelDetailActivity
import com.into.websoso.ui.onboarding.OnboardingActivity
import com.into.websoso.ui.userStorage.UserStorageActivity
Expand Down Expand Up @@ -66,6 +67,11 @@ internal class WebsosoNavigator
val intent = NormalExploreActivity.getIntent(context)
startActivity(intent)
}

override fun navigateToNotificationSettingActivity(startActivity: (Intent) -> Unit) {
val intent = NotificationSettingActivity.getIntent(context)
startActivity(intent)
}
}

@Module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class LibraryFragment : Fragment() {
navigateToNovelDetailActivity = { novelId ->
websosoNavigator.navigateToNovelDetailActivity(novelId, ::startActivity)
},
navigateToNotificationSettingActivity = {
websosoNavigator.navigateToNotificationSettingActivity(::startActivity)
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun NovelNotificationEmptyView(
modifier = modifier.fillMaxSize(),
horizontalAlignment = CenterHorizontally,
) {
Spacer(modifier = Modifier.weight(1f))
Spacer(modifier = Modifier.weight(2f))
Image(
imageVector = ImageVector.vectorResource(id = ic_storage_null),
contentDescription = null,
Expand All @@ -64,7 +64,7 @@ fun NovelNotificationEmptyView(
color = Primary100,
)
}
Spacer(modifier = Modifier.weight(2f))
Spacer(modifier = Modifier.weight(3f))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ package com.into.websoso.ui.novelNotification.component

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
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.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Alignment.Companion.CenterEnd
import androidx.compose.ui.Alignment.Companion.CenterStart
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale.Companion.FillHeight
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign.Companion.Center
import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.into.websoso.core.common.util.clickableWithoutRipple
Expand All @@ -30,6 +33,10 @@ import com.into.websoso.domain.model.NovelNotificationType
import com.into.websoso.domain.model.NovelNotificationType.COMPLETION
import com.into.websoso.domain.model.NovelNotificationType.HIATUS_RETURN
import com.into.websoso.ui.novelNotification.novelNotificationTitleRes
import androidx.compose.ui.Alignment.Companion.Center as CenterAlignment

// 뒤로가기(6 + 44)와 액션 영역을 침범하지 않도록 제목이 쓸 수 있는 좌우 여백
private val TITLE_HORIZONTAL_MARGIN = 70.dp

@Composable
fun NovelNotificationListAppBar(
Expand All @@ -42,55 +49,62 @@ fun NovelNotificationListAppBar(
onDeleteButtonClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Row(
Box(
modifier = modifier
.background(White)
.fillMaxWidth()
.padding(start = 6.dp, end = 20.dp)
.height(44.dp),
verticalAlignment = CenterVertically,
) {
Image(
painter = painterResource(id = ic_notification_back),
contentDescription = null,
contentScale = FillHeight,
modifier = Modifier
.align(CenterStart)
.padding(start = 6.dp)
.size(44.dp)
.clickableWithoutRipple { onBackButtonClick() },
)
// 뒤로가기/액션 유무와 무관하게 제목이 화면 정중앙에 오도록 Box 위에 겹쳐 배치한다
Text(
text = stringResource(notificationType.novelNotificationTitleRes()),
style = WebsosoTheme.typography.title2,
color = Black,
textAlign = Center,
maxLines = 1,
overflow = Ellipsis,
modifier = Modifier
.weight(1f)
.padding(start = 24.dp),
.align(CenterAlignment)
.padding(horizontal = TITLE_HORIZONTAL_MARGIN),
)
if (isActionVisible) {
NovelNotificationListAppBarAction(
isEditing = isEditing,
isDeletable = isDeletable,
onEditButtonClick = onEditButtonClick,
onDeleteButtonClick = onDeleteButtonClick,
modifier = Modifier
.align(CenterEnd)
.padding(end = 20.dp),
)
}
}
}

@Composable
private fun NovelNotificationListAppBarAction(
private fun BoxScope.NovelNotificationListAppBarAction(
isEditing: Boolean,
isDeletable: Boolean,
onEditButtonClick: () -> Unit,
onDeleteButtonClick: () -> Unit,
modifier: Modifier = Modifier,
) {
when (isEditing) {
true -> Text(
text = stringResource(novel_notification_delete),
style = WebsosoTheme.typography.title2,
color = if (isDeletable) Gray300 else Gray200,
modifier = Modifier.clickableWithoutRipple {
modifier = modifier.clickableWithoutRipple {
if (isDeletable) onDeleteButtonClick()
},
)
Expand All @@ -99,7 +113,7 @@ private fun NovelNotificationListAppBarAction(
text = stringResource(novel_notification_edit),
style = WebsosoTheme.typography.title2,
color = Gray300,
modifier = Modifier.clickableWithoutRipple { onEditButtonClick() },
modifier = modifier.clickableWithoutRipple { onEditButtonClick() },
)
}
}
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/res/layout/activity_notification_setting.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="2dp"
android:contentDescription="@null"
android:padding="10dp"
android:src="@drawable/btn_setting_back"
Expand All @@ -42,8 +41,8 @@
<TextView
android:id="@+id/tv_notification_setting_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingVertical="20dp"
android:layout_height="44dp"
android:gravity="center"
android:text="@string/setting_notification"
android:textAppearance="@style/title2"
android:textColor="@color/black"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

androidExtension.apply {
compileSdk = 35
compileSdk = 36

defaultConfig {
minSdk = 30
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ interface NavigatorProvider {
)

fun navigateToNormalExploreActivity(startActivity: (Intent) -> Unit)

fun navigateToNotificationSettingActivity(startActivity: (Intent) -> Unit)
}

@EntryPoint
Expand Down
2 changes: 1 addition & 1 deletion core/resource/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {

android {
namespace = "com.into.websoso.core.resource"
compileSdk = 35
compileSdk = 36

defaultConfig {
minSdk = 30
Expand Down
10 changes: 10 additions & 0 deletions core/resource/src/main/res/drawable/ic_library_notification.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="15dp"
android:viewportWidth="12"
android:viewportHeight="15">
<path
android:pathData="M6.75,0.75C6.75,0.336 6.414,0 6,0C5.586,0 5.25,0.336 5.25,0.75V0.803C2.706,1.167 0.75,3.355 0.75,6V10.5C0.336,10.5 0,10.836 0,11.25C0,11.664 0.336,12 0.75,12H1.5H2.25H3C3,13.657 4.343,15 6,15C7.657,15 9,13.657 9,12H9.75H10.5H11.25C11.664,12 12,11.664 12,11.25C12,10.836 11.664,10.5 11.25,10.5V6C11.25,3.355 9.294,1.167 6.75,0.803V0.75ZM6,2.25C3.929,2.25 2.25,3.929 2.25,6V10.5H9.75V6C9.75,3.929 8.071,2.25 6,2.25ZM6,13.5C5.172,13.5 4.5,12.828 4.5,12H7.5C7.5,12.828 6.828,13.5 6,13.5Z"
android:fillColor="#C7C7D0"
android:fillType="evenOdd"/>
</vector>
4 changes: 2 additions & 2 deletions core/resource/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@
<string name="notification_setting_description">댓글, 좋아요 등 알림</string>
<string name="notification_setting_completion_title">완결 알림</string>
<string name="notification_setting_completion_description">작품이 완결나면 알림을 드려요</string>
<string name="notification_setting_hiatus_return_title">휴재 복귀, 외전 알림</string>
<string name="notification_setting_hiatus_return_description">휴재가 끝나거나 새로운 회차가 생기면 알림을 드려요</string>
<string name="notification_setting_hiatus_return_title">휴재 복귀 알림</string>
<string name="notification_setting_hiatus_return_description">새로운 회차가 생기면 알림을 드려요</string>

<!-- 작품 알림 뷰 -->
<string name="novel_detail_notification_content_description">작품 알림 설정</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.into.websoso.feature.library

import android.view.HapticFeedbackConstants
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
Expand All @@ -23,6 +26,7 @@ import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.paging.LoadState.Loading
Expand Down Expand Up @@ -57,6 +61,7 @@ fun LibraryScreen(
navigateToNormalExploreActivity: () -> Unit,
navigateToNovelDetailActivity: (novelId: Long) -> Unit,
libraryViewModel: LibraryViewModel,
navigateToNotificationSettingActivity: (() -> Unit)? = null,
) {
val scope = rememberCoroutineScope()
val uiState by libraryViewModel.uiState.collectAsStateWithLifecycle()
Expand Down Expand Up @@ -134,6 +139,7 @@ fun LibraryScreen(
onItemClick = { navigateToNovelDetailActivity(it.novelId) },
onSearchClick = navigateToNormalExploreActivity,
onExploreClick = navigateToNormalExploreActivity,
onNotificationManageClick = navigateToNotificationSettingActivity,
onInterestClick = libraryViewModel::updateInterestedNovels,
onAttractivePointClick = libraryViewModel::updateAttractivePoints,
onReadStatusClick = libraryViewModel::updateReadStatus,
Expand All @@ -148,6 +154,19 @@ fun LibraryScreen(
)
}

// 당겨서 새로고침은 중첩 스크롤로 동작해 스크롤 가능한 자식이 없으면 제스처가 전달되지 않는다.
// 빈 화면은 스크롤할 내용이 없으므로 화면 높이만큼 차지하는 항목 하나로 감싸 제스처만 살린다.
@Composable
private fun RefreshableContainer(content: @Composable () -> Unit) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
item {
Box(modifier = Modifier.fillParentMaxSize()) {
content()
}
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun LibraryScreen(
Expand Down Expand Up @@ -182,7 +201,10 @@ private fun LibraryScreen(
onKeywordClick: (String) -> Unit,
onResetClick: () -> Unit,
onFilterSearchClick: () -> Unit,
onNotificationManageClick: (() -> Unit)?,
) {
val view = LocalView.current

Column(
modifier = Modifier
.fillMaxSize()
Expand All @@ -192,8 +214,6 @@ private fun LibraryScreen(

LibraryTopBar(onSearchClick = onSearchClick)

Spacer(modifier = Modifier.height(9.dp))

LibraryFilterTopBar(
libraryFilterUiModel = uiState.libraryFilterUiModel,
totalCount = uiState.novelTotalCount,
Expand All @@ -202,19 +222,25 @@ private fun LibraryScreen(
onSortClick = onSortClick,
onToggleViewType = onToggleViewType,
onInterestClick = onInterestClick,
onNotificationManageClick = onNotificationManageClick,
)

PullToRefreshBox(
isRefreshing = isNovelsRefreshing,
onRefresh = novels::refresh,
onRefresh = {
view.performHapticFeedback(HapticFeedbackConstants.CONFIRM)
novels.refresh()
},
) {
when {
novels.itemCount == 0 &&
novels.loadState.refresh !is Loading -> {
if (uiState.libraryFilterUiModel.isFilterApplied) {
LibraryFilterEmptyView()
} else {
LibraryEmptyView(onExploreClick = onExploreClick)
RefreshableContainer {
if (uiState.libraryFilterUiModel.isFilterApplied) {
LibraryFilterEmptyView()
} else {
LibraryEmptyView(onExploreClick = onExploreClick)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal fun LibraryGridList(
columns = GridCells.Fixed(3),
state = gridState,
modifier = modifier.fillMaxSize(),
contentPadding = PaddingValues(horizontal = 20.dp),
contentPadding = PaddingValues(start = 20.dp, top = 16.dp, end = 20.dp, bottom = 20.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalArrangement = Arrangement.spacedBy(18.dp),
) {
Expand Down
Loading
Loading