Is there a way to make a scrollable calendar - list

I have this calendar I'm working on in jetpack compose. I have gotten some help with placement in rows and stuff like that using weight. The problem is though that I'm trying to make an item of a month in the calendar and place that in a LazyRow but i think it has to do with that lazy rows are scrollable so the weight function for the box with the text in it makes it so that no text shows up if the code looks like this...
fun CalendarRowItem(calendarSize: Int, initWeekday: Int, textColor: Color, clickedColor: Color){
var dayCounter: Int = 1
var week: Int = 1
var _initWeekday = initWeekday
Column() {
while(dayCounter <= calendarSize){
Row(modifier = Modifier.fillMaxWidth().padding(5.dp)) {
if(initWeekday > 0){
repeat(initWeekday){
Spacer(modifier = Modifier.weight(1f))
}
}
for (i in week..(7 - _initWeekday)){
if(dayCounter <= 31){
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(10.dp)
.background(clickedColor, CircleShape)
.clickable { }
) {
Text(text = dayCounter++.toString(), color = textColor )
}
}else{
Spacer(modifier = Modifier.weight(1f))
}
_initWeekday = 0
}
}
}
}
}
but without the weight i cant place the dates correctly plus i have no clue how i would make it so that only one item is visible in the screen at once?

I think using HorizontalPager instead of LazyRow may suit better in this case: it has pagination, as you probably don't need your scroll to stop in between the month, and won't have such a problem out of the box, as same modifier as I suggest you below in applied by the component.
Below is a general answer to the problem, as you still may face it in other cases.
That indeed happens because the parent is horizontally scrollable.
In such case Modifier.fillMaxWidth, as well as Modifier.weight with fill parameter set to true (it's default value) has no effect, as parent width constraint is equal to infinity.
You need to restrict parent width. In this case Modifier.fillParentMaxWidth() can be used on the container: it'll make the view width be equal to the LazyRow width - the part of scroll view which takes exactly "one screen".
As this modifier is defined on LazyItemScope, you have two options to apply it:
Define CalendarRowItem on the scope, in this case CalendarRowItem will only be available to use from lazy view item.
fun LazyItemScope.CalendarRowItem(/* ... */) {
// ...
Column(Modifier.fillParentMaxWidth()) {
// ...
}
}
Add a modifier parameter for CalendarRowItem and pass Modifier.fillParentMaxWidth from item scope:
fun CalendarRowItem(/* ... */, modifier: Modifier) {
// ...
Column(modifier) {
// ...
}
}
items(yourItems) { item ->
CalendarRowItem(
/* ... */,
modifier = Modifier.fillParentMaxWidth()
)
}

Related

Calendar and dropdopwn connections

I am making a calendar and have a dropdown with all the months in so you can pick a month from the dropdown and the lazyrow should go to that index. Now my question is how would you go about doing it the other way around so that the dropdown changes when you swipe in the calendar would you update it every time you touch the lazy row or would you do it in a side effect?
So would you do it this way
LazyRow(state = calendarViewModel.listState, modifier = Modifier.fillMaxWidth()) {
calendarYears.forEach {
items(it.months.count()) { index ->
calendarViewModel.onEvent(CalendarEvent.setMonth(index))
CalendarRowItem(
modifier = Modifier.fillParentMaxWidth(),
calendarSize = it.months[index].amountOfDays,
initWeekday = it.months[index].startDayOfMonth.ordinal,
textColor = MaterialTheme.colors.secondaryVariant,
clickedColor = MaterialTheme.colors.primary,
textStyle = MaterialTheme.typography.body1
)
}
}
}
or would you do it by a side effect and can someone in that case give me an example of how to do that?

First Visible Row in Codenameone

I tried this code to get the first visible row in a scrolling Table inside a BorderLayout.CENTER, but it didn't work, seems the points returned do not reflect the visible cells, unless I am missing a sort of calculation,
thank you for your insights,
#Override
protected void onScrollY(int scrollY) {
super.onScrollY(scrollY); //To change body of generated methods, choose Tools | Templates.
Component c=getComponentAt(50, scrollY);
if (c instanceof Table){
System.err.println("table "+getWidth()+" "+getHeight()+" s "+scrollY);
return;
}
Button b=(Button) c;
System.err.println("c: "+b.getText());
}
getComponentAt(x,y) takes absolute (screen) coordinates. The scrollY value is a relative coordinate in that container.
So what you want is something like:
Component c = getComponentAt(getAbsoluteX()+50, getAbsoluteY() + scrollY)
Also worth nothing that getComponentAt(x,y) will only return components that are focusable or have been set to grab pointer events. If you just want to find the first paintable immediate child of this container, and you're using a BoxLayout.Y_AXIS layout, then you might be better to just iterate through the children until you find one where y is at least the scrollY.
e.g.
Component c = null;
for (Component child : this) {
if (child.getY() + child.getHeight() > scrollY) {
c = child;
break;
}
}
....

Chart.js - make barchart element blink

I'm reading docs but there seems to be no parameters to do what i need: I have a plain bar chart and I need to make some bars blink depending on threshold configuration. Is there any plugin or secret parameter to obtain this?
As far as I understand, you want to have a blinking bar.
So what you can do is create the bar and then dynamically update its background-color from 'transparent' to the original color periodically using a timer.
This will create a blinking effect.
Ok, so if you want the first bar to blink:
let count = 0;
setInterval(() => {
if(count % 2 === 0) {
myChart.data.datasets[0].backgroundColor[0] = 'transparent';
myChart.update();
}
else {
myChart.data.datasets[0].backgroundColor[0] = '#FFC857';
myChart.update();
}
count++;
}, 2000);
I don't know if there is a better solution for it, but this is the first thing that came to my mind.

QListView: how to automatically scroll the view and keep current selection on correct items in view when removing items from the top

I have a list view with a custom model. The model allows me to add text to the bottom of the list (using 'addText(const QString&)') and to remove items from the top of the list (using 'removeItemsFromTop(int _iCount)').
What is the best way to add text to the view and keep the model size under some maximum (lets say 'MAX_LIST_SIZE'), while always maintaining the view (i.e. current selection and items in view should not change when items are removed).
The solution should preferably be a function that I can use wherever I'm using my custom model.
I have looked at indexAt(...), scrollTo(...), currentIndex(...) and setCurrentIndex(...) methods on QListView, but I can't figure out how to put all of this together.
So far I have (for auto scrolling the view)
// add items here ...
// cleanup
QModelIndex indexViewTop = listView->indexAt(QPoint(8, 8));
if (listModel->rowCount() > MAX_SIZE)
{
int iRemoveCount = (listModel->rowCount() - MAX_SIZE) + MAX_SIZE/10;
listModel->clearTextFromFront(iRemoveCount);
listView->scrollTo(indexViewTop.sibling(indexViewTop.row() - iRemoveCount, 0), QAbstractItemView::PositionAtTop);
}
This is supposed to scroll the list view as items are removed to keep the view consistent, but indexAt(...) always returns an invalid index.
For keeping the selection consistent I tried:
// add items her ...
// cleanup
if (listModel->rowCount() > MAX_SIZE)
{
int iCurrentViewIndex = listView->currentIndex().row();
int iRemoveCount = (listModel->rowCount() - MAX_SIZE) + MAX_SIZE/10;
listModel->clearTextFromFront(iRemoveCount);
listView->setCurrentIndex(listModel->index(iCurrentViewIndex - iRemoveCount, 0));
}
This seems to work, but I'm still stuck on the auto scrolling.
I did a queue-like table model implementation. I think it is similar for QAbstractItemModel. Best way would be to use QQueue to store data.
Now, this is a snipped for QAbstractTableModel (which is subclass of QAbstractItemModel so it should work; mEvents is QQueue):
// custom table for inserting events
void EventPreviewTableModel::insertEvent(const DeviceEvent &event) {
beginInsertRows(QModelIndex(), 0, 0);
mEvents.enqueue(event);
endInsertRows();
if (mEvents.size() > SIZE) {
beginRemoveRows(QModelIndex(), mEvents.size(), mEvents.size());
mEvents.dequeue();
endRemoveRows();
}
}
And also override data() and rowCount() to serve correct data.
For second part using ItemIsSelected flag for items you want to have selected is done through: Qt::ItemFlags QAbstractItemModel::flags(const QModelIndex & index)
This is my current approach and it seems to work well:
void addTitlesToList(Model *model, QListView *view, std::vector<Object*> &items)
{
QScrollBar *pVerticalScrollBar = view->verticalScrollBar();
bool bScrolledToBottom = pVerticalScrollBar->value() == pVerticalScrollBar->maximum();
QModelIndex indexViewTop = view->indexAt(QPoint(8, 8));
// add to model
model->pushItems(items);
// cleanup if model gets too big
if (model->rowCount() > model->maxListSize())
{
int iCurrentViewIndex = view->currentIndex().row();
int iRemoveCount = (int)(model->rowCount() - model->maxListSize()) + (int)model->maxListSize()/10;
model->removeItemsFromFront(iRemoveCount);
// scrolls to maintain view on items
if (bScrolledToBottom == false)
{
_pView->scrollTo(indexViewTop.sibling(indexViewTop.row() - iRemoveCount, 0), QAbstractItemView::PositionAtTop);
}
// maintain selection
if (iCurrentViewIndex >= iRemoveCount)
{
view->setCurrentIndex(_pModel->index(iCurrentViewIndex - iRemoveCount, 0));
}
else
{
view->setCurrentIndex(QModelIndex());
}
}
// move scroll bar to keep new items in view (if scrolled to the bottom)
if (bScrolledToBottom == true)
{
view->scrollToBottom();
}
}
One issue I had with indexAt(QPoint(...)) is that I was calling it after adding the items to the list, which seems to cause it to always return an invalid index. Calling indexAt before anything is added to the model seems to work.
I also added automatic 'scroll to bottom' if already there (i.e. the view either stays fixed on specific items or sticks to the latest items if scrolled all the way to the bottom).

Sitecore Set the Number of Components

Is it possible to set the number of components in placeholder?
We can add as many as components in placeholder by using "Add to here" in gray box even the component has been already added.
I'd like to say that
In plcaceholder named 'bodyArea', you can set only one component in 'bodyArea' placeholder and you will not add any other component additionally.
Is there anyway how to do this??
There could be many ways, but this is what I used before.
// Check the number of renderings in placeholder
public static bool numberOfRenderings(string placeholderName)
{
bool rendering = true;
var renderingReferences = Sitecore.Context.Item.Visualization.GetRenderings(Sitecore.Context.Device, true);
int renderingsInPlaceholder = renderingReferences.Where(r => r.Placeholder.EndsWith('/' + placeholderName, StringComparison.OrdinalIgnoreCase)).Count();
if (renderingsInPlaceholder > 1)
{
return rendering = false;
}
return rendering;
}
In View.cshtml
if (#yourObject.numberOfRenderings("your-placeholder-key")) {
#Html.Sitecore().Placeholder("your-placeholder-key")
}
else
{
#Html.Raw("<div>Only one rendering item is available in this placeholder.</div>")
}
here is a blog where is describing how to restrict number of allowed controls :
http://www.newguid.net/sitecore/2014/restricting-the-number-of-components-in-the-sitecore-page-editor/
Other solution is using rules :
http://dotnetmafia.com/blogs/kevin/archive/2013/07/10/placeholder-settings-rules.aspx