-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loading resources from workbook #453
Changes from 10 commits
ae8c405
8ecb547
4244e27
7c205dc
7eb8b87
d786c37
15eacbd
bd153c9
1859e29
40137eb
38e7f3d
c0e87f1
18427cf
0da196f
6717545
7b74f9b
a1d91b9
6732ddd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package org.wycliffeassociates.otter.jvm.app.ui.resources.view | ||
|
||
import org.wycliffeassociates.otter.jvm.app.ui.mainscreen.view.MainScreenStyles | ||
import org.wycliffeassociates.otter.jvm.app.widgets.workbookheader.workbookheader | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.styles.ResourceListStyles | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.view.ResourceListView | ||
import org.wycliffeassociates.otter.jvm.app.ui.resources.viewmodel.ResourcesViewModel | ||
import tornadofx.* | ||
|
||
class ResourceListFragment : Fragment() { | ||
val viewModel: ResourcesViewModel by inject() | ||
|
||
init { | ||
importStylesheet<MainScreenStyles>() | ||
importStylesheet<ResourceListStyles>() | ||
} | ||
override val root = vbox { | ||
|
||
addClass(MainScreenStyles.main) | ||
|
||
add( | ||
workbookheader { | ||
labelText = viewModel.chapter.title + " Resources" | ||
filterText = "Hide Completed" | ||
aunger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
) | ||
add( | ||
ResourceListView(viewModel.resourceGroups) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package org.wycliffeassociates.otter.jvm.app.ui.resources.viewmodel | ||
|
||
import javafx.application.Platform | ||
import javafx.beans.property.SimpleObjectProperty | ||
import javafx.beans.property.SimpleStringProperty | ||
import javafx.collections.FXCollections | ||
import javafx.collections.ObservableList | ||
import org.wycliffeassociates.otter.common.data.workbook.* | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model.ResourceCardItem | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model.ResourceGroupCardItem | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model.resourceGroupCardItem | ||
import tornadofx.* | ||
|
||
class ResourcesViewModel : ViewModel() { | ||
val activeWorkbookProperty = SimpleObjectProperty<Workbook>() | ||
val workbook: Workbook | ||
get() = activeWorkbookProperty.value | ||
|
||
val activeChapterProperty = SimpleObjectProperty<Chapter>() | ||
val chapter: Chapter | ||
get() = activeChapterProperty.value | ||
|
||
val activeResourceSlugProperty = SimpleStringProperty() | ||
val resourceSlug: String | ||
get() = activeResourceSlugProperty.value | ||
|
||
var resourceGroups: ObservableList<ResourceGroupCardItem> = FXCollections.observableArrayList() | ||
|
||
fun loadResourceGroups() { | ||
chapter.chunks.map { chunk -> | ||
resourceGroupCardItem(chunk, resourceSlug) { navigateToTakesPage(it) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RxJava2 Observables will crash on null elements.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe better than Maybe :
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second one requires that |
||
}.startWith( | ||
resourceGroupCardItem(chapter, resourceSlug) { navigateToTakesPage(it) } | ||
).buffer(2).subscribe { // Buffering by 2 prevents the list UI from jumping while groups are loading | ||
aunger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Platform.runLater { | ||
resourceGroups.addAll(it) | ||
} | ||
} | ||
} | ||
|
||
private fun navigateToTakesPage(resource: Resource) { | ||
// TODO use navigator | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,33 @@ | ||
package org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model | ||
|
||
data class ResourceCardItem( | ||
val title: String | ||
) | ||
import javafx.beans.property.DoubleProperty | ||
import javafx.beans.property.SimpleDoubleProperty | ||
import org.wycliffeassociates.otter.common.data.workbook.AssociatedAudio | ||
import org.wycliffeassociates.otter.common.data.workbook.Resource | ||
import org.commonmark.parser.Parser | ||
import org.commonmark.renderer.text.TextContentRenderer | ||
|
||
data class ResourceCardItem(val resource: Resource, val onSelect: () -> Unit) { | ||
val title: String = getTitleTextContent() | ||
val titleProgressProperty: DoubleProperty = resource.titleAudio.progressProperty() | ||
val bodyProgressProperty: DoubleProperty? = resource.bodyAudio?.progressProperty() | ||
val hasBodyAudio: Boolean = resource.bodyAudio != null | ||
|
||
private fun AssociatedAudio.progressProperty(): DoubleProperty { | ||
val progressProperty = SimpleDoubleProperty(0.0) | ||
this.selected.subscribe { | ||
progressProperty.set( if (it.value != null) 1.0 else 0.0) | ||
} | ||
return progressProperty | ||
aunger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
companion object { | ||
val parser: Parser = Parser.builder().build() | ||
val renderer: TextContentRenderer = TextContentRenderer.builder().build() | ||
} | ||
|
||
private fun getTitleTextContent(): String { | ||
val document = parser.parse(resource.title.text) | ||
return renderer.render(document) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not really a getter, so I'd rename this to something like "renderTitleAsHtml". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not needed yet, but the second time you need to transform MD to HTML, you should probably pull this commonmark stuff out into an dagger-injectable MarkdownToHtml singleton. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good points. I'm actually just rendering the title as plain text though and saving html rendering for the body when it appears on the takes page. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SarabiaJ I would like to talk to you about dagger-injectable components like this, as opposed to an object in common, like ParseMd.kt. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to keep dagger to injection in the framework classes (Android Activities/Fragments, TornadoFX Views/ Fragments, maybe viewmodels) for a component like this, I'd rather you just pass the dependency into the constructor rather than make dagger do it for you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. In this case, it seems like this can be solved without passing a dependency into the constructor. I think I can just create a MarkdownToHtml object like ParseMd that basically just holds static functions to do what I need. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,40 @@ | ||
package org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model | ||
|
||
import io.reactivex.Observable | ||
import org.wycliffeassociates.otter.common.data.workbook.* | ||
|
||
data class ResourceGroupCardItem( | ||
val title: String, | ||
val resources: Observable<ResourceCardItem> | ||
) | ||
) | ||
|
||
fun resourceGroupCardItem(element: BookElement, slug: String, onSelect: (Resource) -> Unit): ResourceGroupCardItem? { | ||
return findResourceGroup(element, slug)?.let { rg -> | ||
ResourceGroupCardItem( | ||
getGroupTitle(element), | ||
getResourceCardItems(rg, onSelect) | ||
) | ||
} | ||
} | ||
|
||
private fun findResourceGroup(element: BookElement, slug: String): ResourceGroup? { | ||
return element.resources.firstOrNull { | ||
it.info.slug == slug | ||
} | ||
} | ||
|
||
private fun getGroupTitle(element: BookElement): String { | ||
return when (element) { | ||
is Chapter -> "Chapter " + element.title | ||
is Chunk -> "Chunk " + element.title | ||
aunger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else -> element.title | ||
} | ||
} | ||
|
||
private fun getResourceCardItems(rg: ResourceGroup, onSelect: (Resource) -> Unit): Observable<ResourceCardItem> { | ||
return rg.resources.map { | ||
ResourceCardItem(it) { | ||
onSelect(it) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.styles | ||
|
||
import javafx.scene.paint.Color | ||
import tornadofx.* | ||
|
||
typealias LinearU = Dimension<Dimension.LinearUnits> | ||
|
||
class ResourceListStyles : Stylesheet() { | ||
|
||
companion object { | ||
val resourceGroupList by cssclass() | ||
} | ||
|
||
init { | ||
resourceGroupList { | ||
borderColor += box(Color.TRANSPARENT) // Necessary for border under status bar banner to stay visible | ||
padding = box(0.px, 0.px, 0.px, 80.px) // Left "margin" | ||
scrollBar { | ||
+margin(0.px, 0.px, 0.px, 80.px) // Margin between scrollbar and right side of cards | ||
} | ||
|
||
listCell { | ||
// Add space between the cards (top margin) | ||
// But need to make the "margin" at least as large as the dropshadow offsets | ||
+margin(30.px, 4.px, 0.px, 0.px) | ||
} | ||
} | ||
} | ||
|
||
private fun margin(top: LinearU, right: LinearU, bottom: LinearU, left: LinearU) = mixin { | ||
padding = box(top, right, bottom, left) | ||
backgroundInsets += box(top, right, bottom, left) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.view | ||
|
||
import javafx.collections.ObservableList | ||
import javafx.scene.control.ListView | ||
import javafx.scene.layout.Priority | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.model.ResourceGroupCardItem | ||
import org.wycliffeassociates.otter.jvm.app.widgets.resourcecard.styles.ResourceListStyles | ||
import tornadofx.* | ||
|
||
class ResourceListView(items: ObservableList<ResourceGroupCardItem>): ListView<ResourceGroupCardItem>(items) { | ||
init { | ||
vgrow = Priority.ALWAYS // This needs to be here | ||
jsarabia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
cellFormat { | ||
graphic = cache(it.title) { | ||
resourcegroupcard(it) | ||
} | ||
} | ||
isFocusTraversable = false | ||
addClass(ResourceListStyles.resourceGroupList) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uses the BSD 2-clause license. Should be fine, but I'm not sure where/how we're keeping track of licenses.