Skip to content

Commit 3cdae19

Browse files
committed
feat: add selecting and deleting comics [#66]
* add a viewmodel list to contain the selected comic filenames * change how the list of comics is passed to the list view
1 parent d462844 commit 3cdae19

26 files changed

Lines changed: 435 additions & 50 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@ To achieve these goals, the project will:
3333

3434

3535
# Credits
36+
37+
[Reshot](https://www.reshot.com/free-svg-icons/) - for toolbar icons.

androidVariant/src/main/java/org/comixedproject/variant/android/view/HomeView.kt

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ import org.comixedproject.variant.android.view.comics.ComicBookView
3636
import org.comixedproject.variant.android.view.reading.ReadingView
3737
import org.comixedproject.variant.android.view.server.ServerView
3838
import org.comixedproject.variant.android.view.settings.SettingsView
39+
import org.comixedproject.variant.platform.Log
3940
import org.comixedproject.variant.viewmodel.VariantViewModel
4041
import org.koin.androidx.compose.koinViewModel
4142

43+
private const val TAG = "HomeView"
44+
4245
@Composable
4346
fun HomeView() {
4447
val variantViewModel: VariantViewModel = koinViewModel()
4548
var currentDestination by remember { mutableStateOf(AppDestination.COMICS) }
4649
val coroutineScope = rememberCoroutineScope()
50+
val comicBookList by variantViewModel.comicBookList.collectAsState()
51+
val selectionMode by variantViewModel.selectionMode.collectAsState()
52+
val selectionList by variantViewModel.selectionList.collectAsState()
4753
val comicBook by variantViewModel.comicBook.collectAsState()
4854

4955
Scaffold(
@@ -72,8 +78,29 @@ fun HomeView() {
7278
)
7379
} else {
7480
ComicBookView(
75-
onReadComicBook = { comicBook ->
76-
variantViewModel.readComicBook(comicBook)
81+
comicBookList,
82+
selectionMode,
83+
selectionList,
84+
onSetSelectionMode = {
85+
Log.info(TAG, "Setting selection mode: ${it}")
86+
variantViewModel.setSelectMode(it)
87+
},
88+
onComicBookClicked = { comicBook ->
89+
if (selectionMode) {
90+
Log.info(
91+
TAG,
92+
"Toggling comic book selection: ${comicBook.path}"
93+
)
94+
variantViewModel.updateSelectionList(comicBook.path)
95+
} else {
96+
Log.info(TAG, "Reading comic book: ${comicBook.filename}")
97+
variantViewModel.readComicBook(comicBook)
98+
}
99+
},
100+
onDeleteComics = {
101+
coroutineScope.launch(Dispatchers.IO) {
102+
variantViewModel.deleteSelections()
103+
}
77104
},
78105
modifier = Modifier.padding(padding)
79106
)

androidVariant/src/main/java/org/comixedproject/variant/android/view/comics/ComicBookListItemView.kt

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.comixedproject.variant.android.view.comics
22

33
import android.graphics.BitmapFactory
4+
import androidx.compose.foundation.ExperimentalFoundationApi
45
import androidx.compose.foundation.Image
5-
import androidx.compose.foundation.clickable
6+
import androidx.compose.foundation.border
7+
import androidx.compose.foundation.combinedClickable
68
import androidx.compose.foundation.layout.Column
79
import androidx.compose.foundation.layout.fillMaxWidth
810
import androidx.compose.material3.CardDefaults
@@ -17,10 +19,12 @@ import androidx.compose.runtime.remember
1719
import androidx.compose.runtime.rememberCoroutineScope
1820
import androidx.compose.runtime.setValue
1921
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.graphics.Color
2023
import androidx.compose.ui.graphics.asImageBitmap
2124
import androidx.compose.ui.res.painterResource
2225
import androidx.compose.ui.text.style.TextOverflow
2326
import androidx.compose.ui.tooling.preview.Preview
27+
import androidx.compose.ui.unit.dp
2428
import kotlinx.coroutines.Dispatchers
2529
import kotlinx.coroutines.launch
2630
import org.comixedproject.variant.adaptor.ArchiveAPI
@@ -33,23 +37,34 @@ import org.comixedproject.variant.platform.Log
3337

3438
private val TAG = "ComicBookListItemView"
3539

40+
@OptIn(ExperimentalFoundationApi::class)
3641
@Composable
3742
fun ComicBookListItemView(
3843
comicBook: ComicBook,
44+
selected: Boolean,
3945
onClick: (ComicBook) -> Unit,
4046
modifier: Modifier = Modifier
4147
) {
4248
var coverContent by remember { mutableStateOf<ByteArray?>(null) }
4349
val coroutineScope = rememberCoroutineScope()
50+
val borderWidth = when (selected) {
51+
true -> 5.dp
52+
false -> 0.dp
53+
}
4454

4555
ElevatedCard(
4656
colors = CardDefaults.cardColors(containerColor = colorScheme.surface),
4757
modifier = modifier
4858
.fillMaxWidth()
59+
.border(borderWidth, Color.Red)
4960
) {
5061
val title = MetadataAPI.displayableTitle(comicBook)
5162

52-
Column(modifier = Modifier.clickable(onClick = { onClick(comicBook) })) {
63+
Column(
64+
modifier = Modifier.combinedClickable(
65+
onClick = { onClick(comicBook) }
66+
)
67+
) {
5368
comicBook.pages.firstOrNull()?.let { cover ->
5469
if (coverContent == null) {
5570
Image(
@@ -91,5 +106,21 @@ fun ComicBookListItemView(
91106
@Composable
92107
@Preview
93108
fun ComicBookListItemViewPreview() {
94-
VariantTheme { ComicBookListItemView(comicBook = COMIC_BOOK_LIST.get(0), onClick = {}) }
109+
VariantTheme {
110+
ComicBookListItemView(
111+
comicBook = COMIC_BOOK_LIST.get(0),
112+
false,
113+
onClick = {})
114+
}
115+
}
116+
117+
@Composable
118+
@Preview
119+
fun ComicBookListItemViewSelectedPreview() {
120+
VariantTheme {
121+
ComicBookListItemView(
122+
comicBook = COMIC_BOOK_LIST.get(0),
123+
true,
124+
onClick = {})
125+
}
95126
}

androidVariant/src/main/java/org/comixedproject/variant/android/view/comics/ComicBookListView.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ private val TAG = "ComicBookListView"
4141
@Composable
4242
fun ComicBookListView(
4343
comicBookList: List<ComicBook>,
44+
selectionList: List<String>,
4445
onClick: (ComicBook) -> Unit,
4546
modifier: Modifier = Modifier
4647
) {
@@ -61,11 +62,13 @@ fun ComicBookListView(
6162
items(comicBookList) { comicBook ->
6263
ComicBookListItemView(
6364
comicBook,
64-
onClick = { onClick(it) },
65-
modifier = Modifier.padding(padding)
65+
selectionList.contains(comicBook.path),
66+
onClick = { onClick(it) }
6667
)
6768
}
68-
})
69+
},
70+
modifier = modifier.padding(padding)
71+
)
6972
}
7073
}, modifier = modifier.padding(8.dp)
7174
)
@@ -75,6 +78,6 @@ fun ComicBookListView(
7578
@Preview
7679
fun ComicBookListViewPreview() {
7780
VariantTheme {
78-
ComicBookListView(COMIC_BOOK_LIST, onClick = {})
81+
ComicBookListView(COMIC_BOOK_LIST, emptyList(), onClick = {})
7982
}
8083
}

androidVariant/src/main/java/org/comixedproject/variant/android/view/comics/ComicBookView.kt

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,105 @@
1818

1919
package org.comixedproject.variant.android.view.comics
2020

21+
import androidx.compose.foundation.layout.padding
22+
import androidx.compose.material.icons.Icons
23+
import androidx.compose.material.icons.filled.Delete
24+
import androidx.compose.material3.BottomAppBar
25+
import androidx.compose.material3.Icon
26+
import androidx.compose.material3.IconButton
27+
import androidx.compose.material3.Scaffold
2128
import androidx.compose.runtime.Composable
22-
import androidx.compose.runtime.collectAsState
23-
import androidx.compose.runtime.getValue
2429
import androidx.compose.ui.Modifier
30+
import androidx.compose.ui.res.painterResource
31+
import androidx.compose.ui.res.stringResource
2532
import androidx.compose.ui.tooling.preview.Preview
33+
import org.comixedproject.variant.android.COMIC_BOOK_LIST
34+
import org.comixedproject.variant.android.R
2635
import org.comixedproject.variant.android.VariantTheme
2736
import org.comixedproject.variant.model.library.ComicBook
28-
import org.comixedproject.variant.viewmodel.VariantViewModel
29-
import org.koin.androidx.compose.koinViewModel
37+
import org.comixedproject.variant.platform.Log
3038

3139
private val TAG = "ComicBookView"
3240

3341
@Composable
34-
fun ComicBookView(onReadComicBook: (ComicBook) -> Unit, modifier: Modifier = Modifier) {
35-
val variantViewModel: VariantViewModel = koinViewModel()
36-
val comicBookList by variantViewModel.comicBookList.collectAsState()
42+
fun ComicBookView(
43+
comicBookList: List<ComicBook>,
44+
selectionMode: Boolean,
45+
selectionList: List<String>,
46+
onSetSelectionMode: (Boolean) -> Unit,
47+
onComicBookClicked: (ComicBook) -> Unit,
48+
onDeleteComics: () -> Unit,
49+
modifier: Modifier = Modifier
50+
) {
51+
Scaffold(
52+
content = { padding ->
53+
ComicBookListView(
54+
comicBookList,
55+
selectionList,
56+
onClick = { onComicBookClicked(it) },
57+
modifier = modifier.padding(padding)
58+
)
59+
},
60+
bottomBar = {
61+
BottomAppBar(
62+
actions = {
63+
if (selectionMode) {
64+
IconButton(onClick = { onSetSelectionMode(false) }) {
65+
Icon(
66+
painterResource(id = R.drawable.ic_selection_mode_on),
67+
contentDescription = stringResource(R.string.markReadLabel)
68+
)
69+
}
70+
} else {
71+
IconButton(onClick = { onSetSelectionMode(true) }) {
72+
Icon(
73+
painterResource(id = R.drawable.ic_selection_mode_off),
74+
contentDescription = stringResource(R.string.markReadLabel)
75+
)
76+
}
77+
}
78+
if (!selectionList.isEmpty()) {
79+
IconButton(enabled = !selectionList.isEmpty(), onClick = {
80+
Log.info(TAG, "Deleting ${selectionList.size} comic book(s)")
81+
onDeleteComics()
82+
}) {
83+
Icon(
84+
Icons.Filled.Delete,
85+
contentDescription = stringResource(R.string.deleteSelectionsLabel)
86+
)
87+
}
88+
}
3789

38-
ComicBookListView(comicBookList, onClick = { onReadComicBook(it) }, modifier = modifier)
90+
}
91+
)
92+
}
93+
)
3994
}
4095

4196
@Composable
4297
@Preview
4398
fun ComicBookViewPreview() {
44-
VariantTheme { ComicBookView(onReadComicBook = { }) }
99+
VariantTheme {
100+
ComicBookView(
101+
COMIC_BOOK_LIST,
102+
false,
103+
emptyList(),
104+
onSetSelectionMode = { _ -> },
105+
onComicBookClicked = { _ -> },
106+
onDeleteComics = { })
107+
}
108+
}
109+
110+
@Composable
111+
@Preview
112+
fun ComicBookViewWithSelectionsPreview() {
113+
VariantTheme {
114+
ComicBookView(
115+
COMIC_BOOK_LIST,
116+
true,
117+
listOf(COMIC_BOOK_LIST.get(0).path),
118+
onSetSelectionMode = { _ -> },
119+
onComicBookClicked = { _ -> },
120+
onDeleteComics = { })
121+
}
45122
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="22"
5+
android:viewportHeight="12"
6+
android:tint="#333333"
7+
android:alpha="0.6">
8+
<group android:scaleY="0.54545456"
9+
android:translateY="2.7272727">
10+
<path
11+
android:fillColor="#FF000000"
12+
android:pathData="M12,6a6,6 0,1 0,-6 6A6.006,6.006 0,0 0,12 6Z"/>
13+
<path
14+
android:fillColor="#FF000000"
15+
android:pathData="M18,2H11.736a6.957,6.957 0,0 1,0.969 2H18a2,2 0,0 1,0 4H12.705a6.957,6.957 0,0 1,-0.969 2H18a4,4 0,0 0,0 -8Z"/>
16+
</group>
17+
</vector>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="22"
5+
android:viewportHeight="12"
6+
android:tint="#333333"
7+
android:alpha="0.6">
8+
<group android:scaleY="0.54545456"
9+
android:translateY="2.7272727">
10+
<path
11+
android:fillColor="#FF000000"
12+
android:pathData="M16,0a6,6 0,1 0,6 6A6.006,6.006 0,0 0,16 0Z"/>
13+
<path
14+
android:fillColor="#FF000000"
15+
android:pathData="M4,4H9.3a6.957,6.957 0,0 1,0.969 -2H4a4,4 0,0 0,0 8h6.264A6.957,6.957 0,0 1,9.3 8H4A2,2 0,0 1,4 4Z"/>
16+
</group>
17+
</vector>
532 Bytes
Loading
520 Bytes
Loading
355 Bytes
Loading

0 commit comments

Comments
 (0)