-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from GalievBulat/html-import-export
Added import/export to html functionality
- Loading branch information
Showing
15 changed files
with
329 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
app/src/main/java/com/amrdeveloper/linkhub/data/ImportExportFileType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.amrdeveloper.linkhub.data | ||
|
||
enum class ImportExportFileType(val mimeType: String, val extension: String, val fileTypeName: String) { | ||
JSON( "application/json",".json", "Json"), | ||
HTML("text/html", ".html", "HTML") | ||
} |
117 changes: 117 additions & 0 deletions
117
app/src/main/java/com/amrdeveloper/linkhub/data/parser/HtmlImportExportFileParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package com.amrdeveloper.linkhub.data.parser | ||
|
||
import com.amrdeveloper.linkhub.data.DataPackage | ||
import com.amrdeveloper.linkhub.data.Folder | ||
import com.amrdeveloper.linkhub.data.FolderColor | ||
import com.amrdeveloper.linkhub.data.ImportExportFileType | ||
import com.amrdeveloper.linkhub.data.Link | ||
import com.amrdeveloper.linkhub.data.source.FolderRepository | ||
import com.amrdeveloper.linkhub.data.source.LinkRepository | ||
import com.amrdeveloper.linkhub.util.UiPreferences | ||
import org.jsoup.Jsoup | ||
import org.jsoup.nodes.Document | ||
import org.jsoup.select.Selector | ||
|
||
class HtmlImportExportFileParser: ImportExportFileParser { | ||
override fun getFileType(): ImportExportFileType = ImportExportFileType.HTML | ||
|
||
override suspend fun importData(data: String, folderRepository: FolderRepository, linkRepository: LinkRepository): Result<DataPackage?> { | ||
try { | ||
val doc: Document = Jsoup.parse(data) | ||
val folders = doc.select("h3") | ||
for (i in folders.indices) { | ||
val folder = Folder(folders[i].text()).apply { | ||
folderColor = FolderColor.BLUE | ||
} | ||
//the default case - no folder id | ||
var folderId = -1 | ||
val getFolderRes = folderRepository.getFolderByName(folder.name) | ||
//a case when a folder does already exists | ||
if (getFolderRes.isSuccess && getFolderRes.getOrNull() != null) { | ||
val existingFolder = getFolderRes.getOrNull()!! | ||
folderId = existingFolder.id | ||
} else { | ||
//a case when a folder does not exists | ||
val addFolderRes = folderRepository.insertFolder(folder) | ||
if (addFolderRes.isSuccess) { | ||
folderId = addFolderRes.getOrDefault(-1).toInt() | ||
} | ||
} | ||
|
||
val folderLinks = mutableListOf<Link>() | ||
val nextDL = folders[i].nextElementSibling() | ||
val links = nextDL.select("a") | ||
for (j in links.indices) { | ||
val link = links[j] | ||
val title = link.text() | ||
val url = link.attr("href") | ||
//subtitle = title = link name | ||
folderLinks.add(Link(title, title, url, folderId = folderId)) | ||
} | ||
linkRepository.insertLinks(folderLinks) | ||
} | ||
// If there are bookmarks without a folder, add then individually | ||
val rootDL = doc.select("dl").firstOrNull() | ||
val folderLinks = mutableListOf<Link>() | ||
if (rootDL != null) { | ||
val individualBookmarks = rootDL.select("> dt > a") | ||
if (individualBookmarks.isNotEmpty()) { | ||
for (bookmarkElement in individualBookmarks) { | ||
val title = bookmarkElement.text() | ||
val url = bookmarkElement.attr("href") | ||
folderLinks.add(Link(title, title, url)) | ||
} | ||
} | ||
} | ||
linkRepository.insertLinks(folderLinks) | ||
return Result.success(null) | ||
} catch (e: Selector.SelectorParseException){ | ||
return Result.failure(e) | ||
} | ||
} | ||
override suspend fun exportData( | ||
folderRepository: FolderRepository, | ||
linkRepository: LinkRepository, | ||
uiPreferences: UiPreferences | ||
): Result<String> { | ||
val foldersResult = folderRepository.getFolderList() | ||
if (foldersResult.isSuccess) { | ||
val folders = foldersResult.getOrDefault(listOf()) | ||
val htmlString = buildString { | ||
appendLine("<!DOCTYPE NETSCAPE-Bookmark-file-1>\n") | ||
appendLine("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n") | ||
appendLine("<TITLE>Bookmarks</TITLE>\n") | ||
appendLine("<H1>Bookmarks</H1>\n") | ||
appendLine("<DL><p>\n") | ||
|
||
folders.forEach { | ||
val linksGetResult = linkRepository.getSortedFolderLinkList(it.id) | ||
appendLine("<DT><H3>${it.name}</H3>\n") | ||
if (linksGetResult.isSuccess) { | ||
val links = linksGetResult.getOrDefault(listOf()) | ||
appendLine("<DL><p>\n") | ||
links.forEach { link -> | ||
appendLine("<DT><A HREF=\"${link.url}\">${link.title}</A>\n") | ||
} | ||
appendLine("</DL><p>\n") | ||
} | ||
|
||
} | ||
|
||
val bookmarks: List<Link> = linkRepository.getSortedFolderLinkList(-1).getOrDefault( | ||
listOf() | ||
) | ||
if (bookmarks.isNotEmpty()) { | ||
bookmarks.forEach { link -> | ||
appendLine("<DT><A HREF=\"${link.url}\">${link.title}</A>\n") | ||
} | ||
} | ||
appendLine("</DL><p>\n") | ||
|
||
} | ||
return Result.success(htmlString) | ||
} | ||
return Result.failure(Throwable()) | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
app/src/main/java/com/amrdeveloper/linkhub/data/parser/ImportExportFileParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.amrdeveloper.linkhub.data.parser | ||
|
||
import com.amrdeveloper.linkhub.data.DataPackage | ||
import com.amrdeveloper.linkhub.data.ImportExportFileType | ||
import com.amrdeveloper.linkhub.data.source.FolderRepository | ||
import com.amrdeveloper.linkhub.data.source.LinkRepository | ||
import com.amrdeveloper.linkhub.util.UiPreferences | ||
|
||
interface ImportExportFileParser { | ||
|
||
companion object { | ||
fun getDataParser(fileType: ImportExportFileType): ImportExportFileParser { | ||
return when (fileType) { | ||
ImportExportFileType.JSON -> JsonImportExportFileParser() | ||
ImportExportFileType.HTML -> HtmlImportExportFileParser() | ||
} | ||
} | ||
} | ||
suspend fun importData(data: String, folderRepository: FolderRepository, linkRepository: LinkRepository): Result<DataPackage?> | ||
suspend fun exportData( | ||
folderRepository: FolderRepository, | ||
linkRepository: LinkRepository, | ||
uiPreferences: UiPreferences | ||
): Result<String> | ||
fun getFileType(): ImportExportFileType | ||
} |
54 changes: 54 additions & 0 deletions
54
app/src/main/java/com/amrdeveloper/linkhub/data/parser/JsonImportExportFileParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.amrdeveloper.linkhub.data.parser | ||
|
||
import com.amrdeveloper.linkhub.data.DataPackage | ||
import com.amrdeveloper.linkhub.data.FolderColor | ||
import com.amrdeveloper.linkhub.data.ImportExportFileType | ||
import com.amrdeveloper.linkhub.data.source.FolderRepository | ||
import com.amrdeveloper.linkhub.data.source.LinkRepository | ||
import com.amrdeveloper.linkhub.util.UiPreferences | ||
import com.google.gson.Gson | ||
import com.google.gson.JsonSyntaxException | ||
|
||
class JsonImportExportFileParser: ImportExportFileParser { | ||
override fun getFileType(): ImportExportFileType = ImportExportFileType.JSON | ||
override suspend fun importData( | ||
data: String, | ||
folderRepository: FolderRepository, | ||
linkRepository: LinkRepository | ||
): Result<DataPackage?> { | ||
try{ | ||
val dataPackage = Gson().fromJson(data, DataPackage::class.java) | ||
|
||
val folders = dataPackage.folders | ||
// This code should be removed after found why it not serialized on some devices (see Issue #23) | ||
// folderColor field is declared as non nullable type but in this case GSON will break the null safty feature | ||
folders.forEach { if (it.folderColor == null) it.folderColor = FolderColor.BLUE } | ||
folderRepository.insertFolders(folders) | ||
|
||
linkRepository.insertLinks(dataPackage.links) | ||
return Result.success(dataPackage) | ||
} catch (e : JsonSyntaxException) { | ||
return Result.failure(e) | ||
} | ||
} | ||
override suspend fun exportData( | ||
folderRepository: FolderRepository, | ||
linkRepository: LinkRepository, | ||
uiPreferences: UiPreferences | ||
): Result<String>{ | ||
val foldersResult = folderRepository.getFolderList() | ||
val linksResult = linkRepository.getLinkList() | ||
if (foldersResult.isSuccess && linksResult.isSuccess) { | ||
val folders = foldersResult.getOrDefault(listOf()) | ||
val links = linksResult.getOrDefault(listOf()) | ||
val showClickCounter = uiPreferences.isClickCounterEnabled() | ||
val autoSaving = uiPreferences.isAutoSavingEnabled() | ||
val lastTheme = uiPreferences.getThemeType() | ||
val dataPackage = DataPackage(folders, links, showClickCounter, autoSaving, lastTheme) | ||
return Result.success(Gson().toJson(dataPackage)) | ||
} else { | ||
return Result.failure(Throwable()); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.