Skip to content

Commit 9d6eb7d

Browse files
committed
Improve the UI of DataExportDialogBox and DataImportDialogBox
1 parent f845c39 commit 9d6eb7d

File tree

5 files changed

+204
-19
lines changed

5 files changed

+204
-19
lines changed

app/src/main/java/com/sakethh/linkora/data/local/export/ExportImpl.kt

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,24 @@ class ExportImpl @Inject constructor(
9797
)
9898
} else {
9999

100-
ExportRequestInfo.updateState(ExportRequestState.GATHERING_DATA)
100+
ExportRequestInfo.totalLinksFromSavedLinks.intValue =
101+
linksRepo.getAllSavedLinksAsList().size
102+
ExportRequestInfo.totalLinksFromArchivedLinksTable.intValue = archivedLinksTable.size
103+
ExportRequestInfo.totalLinksFromImpLinksTable.intValue = importantLinksTable.size
104+
ExportRequestInfo.totalLinksFromHistoryLinksTable.intValue = historyLinksTable.size
105+
ExportRequestInfo.totalRegularFoldersAndItsLinks.intValue =
106+
foldersRepo.getAllRootFoldersList().size
107+
ExportRequestInfo.totalArchivedFoldersAndItsLinks.intValue =
108+
foldersRepo.getAllArchiveFoldersV10AsList().size
109+
110+
ExportRequestInfo.currentIterationOfLinksFromSavedLinks.intValue = 0
111+
ExportRequestInfo.currentIterationOfLinksFromArchivedLinksTable.intValue = 0
112+
ExportRequestInfo.currentIterationOfLinksFromImpLinksTable.intValue = 0
113+
ExportRequestInfo.currentIterationOfLinksFromHistoryLinksTable.intValue = 0
114+
ExportRequestInfo.currentIterationOfRegularFoldersAndItsLinks.intValue = 0
115+
ExportRequestInfo.currentIterationOfArchivedFoldersAndItsLinks.intValue = 0
116+
117+
101118
var htmlFileRawText = ""
102119

103120
// Saved Links :
@@ -107,7 +124,7 @@ class ExportImpl @Inject constructor(
107124
val savedLinksAsync = async {
108125
linksRepo.getAllSavedLinksAsList().forEach { savedLink ->
109126
savedLinks += dtA(linkTitle = savedLink.title, link = savedLink.webURL)
110-
linkoraLog("saved link in ${savedLink.id}")
127+
++ExportRequestInfo.currentIterationOfLinksFromSavedLinks.intValue
111128
}
112129
}
113130

@@ -118,7 +135,7 @@ class ExportImpl @Inject constructor(
118135
val impLinksAsync = async {
119136
importantLinksTable.forEach { impLink ->
120137
impLinks += dtA(linkTitle = impLink.title, link = impLink.webURL)
121-
linkoraLog("imp link in ${impLink.id}")
138+
++ExportRequestInfo.currentIterationOfLinksFromImpLinksTable.intValue
122139
}
123140
}
124141

@@ -149,6 +166,7 @@ class ExportImpl @Inject constructor(
149166
val historyLinksAsync = async {
150167
historyLinksTable.forEach { historyLink ->
151168
historyLinks += dtA(linkTitle = historyLink.title, link = historyLink.webURL)
169+
++ExportRequestInfo.currentIterationOfLinksFromHistoryLinksTable.intValue
152170
}
153171
}
154172

@@ -159,6 +177,7 @@ class ExportImpl @Inject constructor(
159177
val archivedLinksAsync = async {
160178
archivedLinksTable.forEach { archivedLink ->
161179
archivedLinks += dtA(linkTitle = archivedLink.title, link = archivedLink.webURL)
180+
++ExportRequestInfo.currentIterationOfLinksFromArchivedLinksTable.intValue
162181
}
163182
}
164183

@@ -233,6 +252,13 @@ class ExportImpl @Inject constructor(
233252
linkoraLog("folder in ${childFolder.id}")
234253
val nestedFolderHTML = foldersSectionInHtml(childFolder.id, forArchiveFolders)
235254
foldersSection += currentFolderDTH3 + dlP(folderLinksDTA + nestedFolderHTML)
255+
if (childFolder.parentFolderID == null) {
256+
if (forArchiveFolders) {
257+
++ExportRequestInfo.currentIterationOfArchivedFoldersAndItsLinks.intValue
258+
} else {
259+
++ExportRequestInfo.currentIterationOfRegularFoldersAndItsLinks.intValue
260+
}
261+
}
236262
}
237263
return foldersSection
238264
}

app/src/main/java/com/sakethh/linkora/data/local/export/ExportRequestInfo.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.sakethh.linkora.data.local.export
22

3+
import androidx.compose.runtime.mutableIntStateOf
4+
import androidx.compose.runtime.mutableStateOf
35
import kotlinx.coroutines.flow.MutableStateFlow
46
import kotlinx.coroutines.flow.asStateFlow
57

@@ -9,6 +11,23 @@ sealed class ExportRequestInfo {
911
private val _state = MutableStateFlow(ExportRequestState.IDLE)
1012
val state = _state.asStateFlow()
1113

14+
val isHTMLBasedRequest = mutableStateOf(false)
15+
16+
17+
val totalLinksFromSavedLinks = mutableIntStateOf(0)
18+
val totalLinksFromArchivedLinksTable = mutableIntStateOf(0)
19+
val totalLinksFromImpLinksTable = mutableIntStateOf(0)
20+
val totalLinksFromHistoryLinksTable = mutableIntStateOf(0)
21+
val totalRegularFoldersAndItsLinks = mutableIntStateOf(0)
22+
val totalArchivedFoldersAndItsLinks = mutableIntStateOf(0)
23+
24+
val currentIterationOfLinksFromSavedLinks = mutableIntStateOf(0)
25+
val currentIterationOfLinksFromArchivedLinksTable = mutableIntStateOf(0)
26+
val currentIterationOfLinksFromImpLinksTable = mutableIntStateOf(0)
27+
val currentIterationOfLinksFromHistoryLinksTable = mutableIntStateOf(0)
28+
val currentIterationOfRegularFoldersAndItsLinks = mutableIntStateOf(0)
29+
val currentIterationOfArchivedFoldersAndItsLinks = mutableIntStateOf(0)
30+
1231
suspend fun updateState(exportRequestState: ExportRequestState) {
1332
_state.emit(exportRequestState)
1433
}
Lines changed: 150 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,48 @@
11
package com.sakethh.linkora.ui.screens.settings.specific.data
22

33
import androidx.compose.animation.animateContentSize
4+
import androidx.compose.foundation.BorderStroke
45
import androidx.compose.foundation.background
6+
import androidx.compose.foundation.layout.Box
57
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.Row
9+
import androidx.compose.foundation.layout.Spacer
10+
import androidx.compose.foundation.layout.fillMaxSize
611
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.layout.height
13+
import androidx.compose.foundation.layout.navigationBarsPadding
714
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.wrapContentHeight
816
import androidx.compose.foundation.rememberScrollState
917
import androidx.compose.foundation.shape.RoundedCornerShape
1018
import androidx.compose.foundation.verticalScroll
19+
import androidx.compose.material.icons.Icons
20+
import androidx.compose.material.icons.outlined.Info
1121
import androidx.compose.material3.AlertDialogDefaults
1222
import androidx.compose.material3.BasicAlertDialog
23+
import androidx.compose.material3.Card
24+
import androidx.compose.material3.CardDefaults
1325
import androidx.compose.material3.ExperimentalMaterial3Api
26+
import androidx.compose.material3.Icon
1427
import androidx.compose.material3.LinearProgressIndicator
1528
import androidx.compose.material3.MaterialTheme
1629
import androidx.compose.material3.Text
30+
import androidx.compose.material3.contentColorFor
1731
import androidx.compose.runtime.Composable
1832
import androidx.compose.runtime.LaunchedEffect
33+
import androidx.compose.runtime.mutableLongStateOf
1934
import androidx.compose.runtime.mutableStateOf
2035
import androidx.compose.runtime.saveable.rememberSaveable
36+
import androidx.compose.ui.Alignment
2137
import androidx.compose.ui.Modifier
2238
import androidx.compose.ui.draw.clip
39+
import androidx.compose.ui.text.style.TextAlign
2340
import androidx.compose.ui.unit.dp
2441
import androidx.compose.ui.unit.sp
2542
import androidx.compose.ui.window.DialogProperties
43+
import androidx.lifecycle.ViewModel
2644
import androidx.lifecycle.compose.collectAsStateWithLifecycle
45+
import androidx.lifecycle.viewmodel.compose.viewModel
2746
import com.sakethh.linkora.data.local.export.ExportRequestInfo
2847
import com.sakethh.linkora.data.local.export.ExportRequestState
2948
import com.sakethh.linkora.ui.theme.LinkoraTheme
@@ -46,36 +65,151 @@ fun DataExportDialogBox() {
4665
LinkoraTheme {
4766
BasicAlertDialog(
4867
modifier = Modifier
49-
.animateContentSize(),
68+
.animateContentSize()
69+
.then(if (ExportRequestInfo.isHTMLBasedRequest.value) Modifier.fillMaxSize() else Modifier),
5070
onDismissRequest = {},
5171
properties = DialogProperties(
72+
dismissOnClickOutside = false,
5273
dismissOnBackPress = false,
53-
usePlatformDefaultWidth = false
74+
usePlatformDefaultWidth = !ExportRequestInfo.isHTMLBasedRequest.value
5475
)
5576
) {
5677
Column(
5778
modifier = Modifier
58-
.fillMaxWidth()
59-
.padding(20.dp)
60-
.clip(
61-
RoundedCornerShape(15.dp)
79+
.then(
80+
if (ExportRequestInfo.isHTMLBasedRequest.value) Modifier.fillMaxSize() else Modifier.clip(
81+
RoundedCornerShape(15.dp)
82+
)
6283
)
84+
.fillMaxWidth()
6385
.background(AlertDialogDefaults.containerColor)
6486
.padding(20.dp)
6587
.verticalScroll(rememberScrollState())
88+
.animateContentSize()
6689
) {
67-
Text(
68-
text = exportRequestResult.value.name,
69-
style = MaterialTheme.typography.titleMedium,
70-
fontSize = 20.sp
71-
)
72-
LinearProgressIndicator(
73-
modifier = Modifier
74-
.fillMaxWidth()
75-
.padding(top = 15.dp)
76-
)
90+
if (!ExportRequestInfo.isHTMLBasedRequest.value) {
91+
Text(
92+
text = exportRequestResult.value.name,
93+
style = MaterialTheme.typography.titleMedium,
94+
fontSize = 20.sp
95+
)
96+
LinearProgressIndicator(
97+
modifier = Modifier
98+
.fillMaxWidth()
99+
.padding(top = 15.dp)
100+
)
101+
} else {
102+
Text(
103+
text = "Collecting the data for exporting...",
104+
style = MaterialTheme.typography.titleMedium,
105+
fontSize = 20.sp
106+
)
107+
val dataExportDialogBoxVM: DataExportDialogBoxVM = viewModel()
108+
dataExportDialogBoxVM.dataExportSection().forEach {
109+
if (it.totalDetectedSize <= 0) return@forEach
110+
Spacer(Modifier.height(10.dp))
111+
Text(
112+
it.itemType,
113+
style = MaterialTheme.typography.titleMedium
114+
)
115+
Spacer(Modifier.height(10.dp))
116+
LinearProgressIndicator(modifier = Modifier.fillMaxWidth(), progress = {
117+
if (it.currentIterationCount.value.toInt() != 0 && it.totalDetectedSize.toInt() != 0
118+
) {
119+
it.currentIterationCount.value.toFloat() / it.totalDetectedSize
120+
} else {
121+
0f
122+
}
123+
})
124+
Spacer(Modifier.height(10.dp))
125+
Text(
126+
"${it.currentIterationCount.value}/${it.totalDetectedSize}",
127+
style = MaterialTheme.typography.titleMedium
128+
)
129+
Spacer(Modifier.height(10.dp))
130+
Spacer(Modifier.height(10.dp))
131+
}
132+
Card(
133+
border = BorderStroke(
134+
1.dp,
135+
contentColorFor(MaterialTheme.colorScheme.surface)
136+
),
137+
colors = CardDefaults.cardColors(containerColor = AlertDialogDefaults.containerColor),
138+
modifier = Modifier
139+
.fillMaxWidth()
140+
.navigationBarsPadding()
141+
) {
142+
Row(
143+
modifier = Modifier
144+
.fillMaxWidth()
145+
.wrapContentHeight()
146+
.padding(
147+
top = 10.dp, bottom = 10.dp
148+
),
149+
verticalAlignment = Alignment.CenterVertically
150+
) {
151+
Box(
152+
contentAlignment = Alignment.CenterStart
153+
) {
154+
Icon(
155+
imageVector = Icons.Outlined.Info,
156+
contentDescription = null,
157+
modifier = Modifier
158+
.padding(
159+
start = 10.dp, end = 10.dp
160+
)
161+
)
162+
}
163+
Text(
164+
text = "Please keep the app open. Data is still being processed. Linkora will save it once the modification is complete. Closing the app or removing it from the background will cancel this operation.",
165+
style = MaterialTheme.typography.titleSmall,
166+
fontSize = 14.sp,
167+
lineHeight = 18.sp,
168+
textAlign = TextAlign.Start,
169+
modifier = Modifier
170+
.padding(end = 10.dp)
171+
)
172+
}
173+
}
174+
}
77175
}
78176
}
79177
}
80178
}
179+
}
180+
181+
class DataExportDialogBoxVM : ViewModel() {
182+
183+
fun dataExportSection() = listOf(
184+
DataImportDialogBox(
185+
itemType = "READING_SAVED_LINKS",
186+
totalDetectedSize = ExportRequestInfo.totalLinksFromSavedLinks.intValue.toLong(),
187+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfLinksFromSavedLinks.intValue.toLong())
188+
),
189+
DataImportDialogBox(
190+
itemType = "READING_IMPORTANT_LINKS",
191+
totalDetectedSize = ExportRequestInfo.totalLinksFromImpLinksTable.intValue.toLong(),
192+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfLinksFromImpLinksTable.intValue.toLong())
193+
),
194+
DataImportDialogBox(
195+
itemType = "READING_HISTORY_LINKS",
196+
totalDetectedSize = ExportRequestInfo.totalLinksFromHistoryLinksTable.intValue.toLong(),
197+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfLinksFromHistoryLinksTable.intValue.toLong())
198+
),
199+
DataImportDialogBox(
200+
itemType = "READING_ARCHIVED_LINKS",
201+
totalDetectedSize = ExportRequestInfo.totalLinksFromArchivedLinksTable.intValue.toLong(),
202+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfLinksFromArchivedLinksTable.intValue.toLong())
203+
),
204+
DataImportDialogBox(
205+
itemType = "READING_REGULAR_FOLDERS",
206+
totalDetectedSize = ExportRequestInfo.totalRegularFoldersAndItsLinks.intValue.toLong(),
207+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfRegularFoldersAndItsLinks.intValue.toLong())
208+
),
209+
DataImportDialogBox(
210+
itemType = "READING_ARCHIVED_FOLDERS",
211+
totalDetectedSize = ExportRequestInfo.totalArchivedFoldersAndItsLinks.intValue.toLong(),
212+
currentIterationCount = mutableLongStateOf(ExportRequestInfo.currentIterationOfArchivedFoldersAndItsLinks.intValue.toLong())
213+
)
214+
)
81215
}

app/src/main/java/com/sakethh/linkora/ui/screens/settings/specific/data/DataImportDialogBox.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Spacer
1010
import androidx.compose.foundation.layout.fillMaxSize
1111
import androidx.compose.foundation.layout.fillMaxWidth
1212
import androidx.compose.foundation.layout.height
13+
import androidx.compose.foundation.layout.navigationBarsPadding
1314
import androidx.compose.foundation.layout.padding
1415
import androidx.compose.foundation.layout.wrapContentHeight
1516
import androidx.compose.foundation.rememberScrollState
@@ -71,6 +72,7 @@ fun DataImportDialogBox() {
7172

7273
},
7374
properties = DialogProperties(
75+
dismissOnClickOutside = false,
7476
dismissOnBackPress = false,
7577
usePlatformDefaultWidth = importRequestState.value == ImportRequestState.PARSING || importRequestState.value == ImportRequestState.ADDING_TO_DATABASE
7678
)
@@ -135,6 +137,7 @@ fun DataImportDialogBox() {
135137
modifier = Modifier
136138
.fillMaxWidth()
137139
.padding(top = 15.dp)
140+
.navigationBarsPadding()
138141
) {
139142
Row(
140143
modifier = Modifier

app/src/main/java/com/sakethh/linkora/ui/screens/settings/specific/data/DataSettingsScreen.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import com.sakethh.linkora.LocalizedStrings.data
6363
import com.sakethh.linkora.LocalizedStrings.deleteEntireDataPermanently
6464
import com.sakethh.linkora.LocalizedStrings.deleteEntireDataPermanentlyDesc
6565
import com.sakethh.linkora.LocalizedStrings.deletedEntireDataFromTheLocalDatabase
66+
import com.sakethh.linkora.data.local.export.ExportRequestInfo
6667
import com.sakethh.linkora.ui.CommonUiEvent
6768
import com.sakethh.linkora.ui.commonComposables.DataDialogBoxType
6869
import com.sakethh.linkora.ui.commonComposables.DeleteDialogBox
@@ -205,6 +206,7 @@ fun DataSettingsScreen(navController: NavController, settingsScreenVM: SettingsS
205206
isSwitchNeeded = false,
206207
isSwitchEnabled = SettingsPreference.shouldFollowDynamicTheming,
207208
onSwitchStateChange = {
209+
ExportRequestInfo.isHTMLBasedRequest.value = false
208210
settingsScreenVM.exportDataToAFile(
209211
context = context,
210212
isDialogBoxVisible = isPermissionDialogBoxVisible,
@@ -227,6 +229,7 @@ fun DataSettingsScreen(navController: NavController, settingsScreenVM: SettingsS
227229
isSwitchNeeded = false,
228230
isSwitchEnabled = SettingsPreference.shouldFollowDynamicTheming,
229231
onSwitchStateChange = {
232+
ExportRequestInfo.isHTMLBasedRequest.value = true
230233
settingsScreenVM.exportDataToAFile(
231234
context = context,
232235
isDialogBoxVisible = isPermissionDialogBoxVisible,

0 commit comments

Comments
 (0)