I have poured over this for hours and I can say with 99% certainty that I know what is breaking but I don't know why or how to fix it.
#State private var timeSet = false {
willSet {
if newValue {
flyingHours = timeMachine.calculateTotalFlightHours()
}
}
}
The code above stops working when I use
AddSortie().environment(\.managedObjectContext, self.moc)
with the button to trigger the popover. timeSet never becomes true, or if it does it very quickly resets to false.
However, by leaving off the .environment
AddSortie()
timeSet does become true at the appropriate time and the app works as expected... Except without .environmtnt I can not save to CoreData.
Any ideas?
For what it's worth I am working in XCode 12 Beta 2
Thanks
Related
I need to be able to undo / redo the colors that are picked with the new SwiftUI ColorPicker ( on the iPad : it's presented as a floating window )
The thing that makes it very difficult is that there is apparently no way to know that the user has indeed chosen a color ( and therefore closed the panel )
Instead, the behavior of ColorPicker is that it will keep updating the binded color as the user is manipulating the color controls. This is very helpful to show a live preview, but you don't want to register all these color variations for undo / redo purposes : you only want the color that was finally picked.
Therefore there is no logical distinction between the colors that the user tried, and the one that was selected
And I looked everywhere : there aren't any modifiers / notifications related to that.
I know SwiftUI hasn't been there for long, but this seems like a crucial functionality that's missing?
Has anyone found a workaround?
Undo is always tricky. One size does not fit all. In this case a good solution is to throttle the number of events that come into the UndoManager. You can do so by comparing the current time to the time you last commit.
Create a view model that represents your Source of Truth, and conform to ObservableObject to publish events. It will own the UndoManager. It will have a computed property that gets/sets to the internal data, and check the current time against the time of last commit.
class EditViewModel: ObservableObject {
var commitTime = Date.now
let undoManager = UndoManager()
private var _color: Color = .red {
didSet {
objectWillChange.send()
}
}
var color: Color {
get { _color }
set {
let oldValue = color
let now = Date.now
if now.timeIntervalSince(commitTime) > 1 {
undoManager.registerUndo(withTarget: self) {
$0.color = oldValue
}
}
self.commitTime = now
_color = newValue
}
}
}
Now all that's left to do is create your view and pass in the binding. The implementation details are opaque to the View since it is managed by the ViewModel.
struct EditView: View {
#StateObject var vm = EditViewModel()
var body: some View {
Form {
ColorPicker("Color", selection: $vm.color)
}
}
}
If you need even more control, you can additionally compare the last committed color to the new value and only commit if there is a significant change.
I will also agree that a data-driven approach like SwiftUI's can make undo more tricky. For example, when you need to coalesce multiple operations together into one undo group. By its very nature an undo group is procedural-- the user did one thing after the other, and finally terminates on some condition. But I'm sure there is some way to encapsulate this step-wise operation in a transaction object of some kind.
Undo is hard!
I am working on web application. In which i am stuck with some issue.
When i call some server function it will take time to get response. When response have high number of data. It will get data, process on that data and update GUI in background.
Upto that my application GUI freeze. I can not click on any part. I see some where that ActionScript support multithreading. I found some tutorial for that which is here. But, it is for desktop application only.
Is there any way i can handle this freezing of application/GUI in web application. It will decrease my application performance and looks very bad.
Example:
If i have list of data with checkbox and on checkbox click there is some process. Now, there is one button called "Select All". Now, if i click on "select all" then all check box selected and process on check selection is going and freeze the application upto process done.
like: I have following list
<s:List id="tempList" itemRenderer="CustomItemRenderer"
dataProvider="{someList}" useVirtualLayout="false"/>
ItemRenderer have label and checkbox as following.
<s:CheckBox id="cCheckId" selected="{data.selected}"
change="onChangeHandler(event)" />
<s:Label id="lblTest" />
protected function onChangeHandler(event:Event):void
{
data.selected = !data.selected;
}
Now, on button Select all will select all check box.
<s:Button id="btnSelectAll" label="Select All" click="selectAllHandler(event)" />
protected function selectAllHandler(event:MouseEvent):void
{
for(var i:int = 0;i<someList.length;i++)
{
someList[i].selected = true;
}
}
Now, if someList have lots of data then it will freeze the screen.
Any help is greatly appreciated.
The main idea behind the list and itemrenderers that you have a list (or datagrid) that displays like 30 items and then you can scroll to see the rest. Then you will only have 30 Itemrenderers that would be updated at once.
If you don't want to scroll you will need to distribute your item selection over several frames, something like that (untested, but you get the idea)
private static const ITEMS_AT_ONCE:int = 5000;
private var _currentIndex:int;
protected function selectAllHandler(event:MouseEvent):void
{
_currentIndex = 0;
addEventListener(Event.ENTER_FRAME, onEnterFrame); // this will call the onEnterFrame method on each frame rendered
}
private function onEnterFrame(e:Event):void
{
// make sure we don't run out of bounds of the dataprovider's length
var maxIndex:int = Math.min(_currentIndex + ITEMS_AT_ONCE, someList.length);
// set selection for the current bunch
for (var i:int = _currentIndex; i < maxIndex; i++)
{
someList[i].selected = true;
}
if (maxIndex == someList.length)
{
// We are done, remove enterframe listener
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
// I'm not sure but don't you need to refresh the dataprovider to reflect the changes in the ItemRenderers ?
// (someList.dataProvider as ArrayCollection).refresh();
}
else
{
// update the _currentindex so we continue after this item on the next frame
_currentIndex = maxIndex;
}
Another possible solution - if you display all of them anyways - you might try to switch to a VGroup that will hold custom UIComponents (without MXML) for the items - this should speed up the rendering.
I have played around with the AlloyUI Scheduler, and it seems to be the by far best calendar out there. While poking it, a few questions have risen. I am not particularly experienced with YUI, so my questions might be caused by lack of experience with the kind of thinking that goes with YUI. Nevertheless, here are the problems I haven't managed to overcome:
First, I tried loading 500+ events into it, and the result is that every action (adding events, deleting events, switching between views, switching between weeks/months) happens with a delay. Is this expected? 500 events doesn't sound like much, even for a relatively short period.
Can I limit the hours displayed in Day or Month view? I.e., instead of 00:00 - 23:59 I'd prefer to only display 08:00 - 17:59.
I've managed to translate bits of the UI, such as "Today", "Day", "Week", "Month", "Agenda", "Delete", "Save", "Cancel", "e.g., Dinner at Brian's". But how can I translate the days (e.g., "Monday", "Tuesday" etc)?
I've found a way to replace the default buttons of the EventRecorder's toolbar. But is there a way to keep the originals ("Save", "Cancel", "Delete") and add a few custom ones?
var eventRecorder = new Y.SchedulerEventRecorder({
toolbar: {
children: [
[
{
label: 'Details',
on: {
click: function () {
alert("Yeah!");
}
}
},
]
]
}
});
Is there a way to disable some periods of time for event creation? I'd imagine this could be achieved by interrupting the event creation by some way. Something in the lines of
scheduler.on({
'scheduler-events:add': function (event) {
return isEventAllowed();
}
});
What is the correct way for accessing the calendar event data in the case of events such as "scheduler-event:change", "scheduler-event-recorder:edit" or similar? I currently use scheduler.getEvents()[event.index]._state.data and eventRecorder.getUpdatedSchedulerEvent()._state.data, respectively. But using these smells funny.
What would be a recommended way for adding a detailed editing view for events? I currently hacked it with something in the lines of
scheduler.on({
'scheduler-base:click': function(event) {
var toolbar = $(".aui-scheduler-event-recorder-overlay .yui3-widget-ft .aui-toolbar-content .aui-btn-group");
if (!toolbar.data("custom-processed")) {
var button = $('<button class="aui-btn">Details</button>');
toolbar.append(button);
button.click(function (event) {
event.preventDefault();
var eventData = (eventRecorder.get("event") || eventRecorder.clone())._state.data;
// Creating my detailed editing window here
$(".aui-scheduler-event-recorder-overlay").addClass("yui3-overlay-hidden");
});
toolbar.data("custom-processed", true);
}
}
});
Thanks,
This was just working perfectly fine 5 minutes ago... I can't for the life of me figure out why this is happening. Basically, I start on a page, with a layout (== 'default'), no where in the controller code do I change the layout, in fact, no where in the application do I change the layout, but for some reason when I hit this certain action named 'addQuestion', it renders the view without a layout...
<?php
// medicalCasesController.php
public function addQuestion($caseId) {
if ($this->request->is('post')) {
$this->MedicalCase->Question->create();
if ($this->MedicalCase->Question->saveAll($this->request->data)) {
$this->request->data['Question']['id'] = $this->MedicalCase->Question->getLastInsertId();
$this->MedicalCase->Question->Image->processData($this->request->data);
$this->Session->setFlash(__('The question has been saved successfully.', true), 'flash/success');
$this->redirect(array('action' => 'addAnother', $caseId));
} else {
$this->Session->setFlash(__('There was a problem saving the question.', true), 'flash/failure');
}
}
$this->MedicalCase->id = $caseId;
$this->MedicalCase->contain(array('Question'));
$mc = $this->MedicalCase->read();
$count = $this->MedicalCase->getQuestions('count') + 1;
// mc, count, caseId
$this->set(compact('mc', 'count', 'caseId'));
}
?>
Keep in mind that I see the issue without POST data.. before the form is submitted. Let me know what else you need from me as I'm not quite sure how to diagnose/debug this issue.
Thanks
-Andrew
Figured it out, there was an error in a hidden divide.
Silly me..
Ok, I'm working on my final dilemna for my project. The project is an IPv4 endpoint updater for TunnelBroker's IPv6 tunnel. I have everything working, except for the timer. It works, however if the user disables the "automatic update" and reenables it, the application crashes. I need the timer to be on an thread outside of the EDT (in such a way that it can be destroyed and recreated when the user unchecks/checks the automatic update feature or changes the amount of time between updates).
What I'm pasting here is the code for the checkbox that handles automatic updates, and the timer class. Hopefully this will be enough to get an answer on how to do this (I'm thinking either it needs to be a worker, or use multi-threading--even though only one timer will be active).
private void jCheckBox1ItemStateChanged(java.awt.event.ItemEvent evt) {
// TODO add your handling code here:
// if selected, then run timer for auto update
// set time textbox to setEditable(true) and get the time from it.
// else cancel timer. Try doing this on different
// class to prevent errors from happening on reselect.
int updateAutoTime = 0;
if (jCheckBox1.isSelected())
{
updateAutoTime = Integer.parseInt(jTextField4.getText())*60*1000;
if (updateAutoTime < 3600000)
{
updateAutoTime = 3600000;
jTextField4.setText(new Integer(updateAutoTime/60/1000).toString());
}
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run()
{
// Task here ...
if (jRadioButton1.isSelected())
{
newIPAddress = GetIP.getIPAddress();
}
else
{
newIPAddress = jTextField3.getText();
}
strUsername = jTextField1.getText();
jPasswordField1.selectAll();
strPassword = jPasswordField1.getSelectedText().toString();
strTunnelID = jTextField2.getText();
strIPAddress = newIPAddress;
if (!newIPAddress.equals(oldIPAddress))
{
//fire the tunnelbroker updater class
updateIP.setIPAddress(strUsername, strPassword, strTunnelID, strIPAddress);
oldIPAddress = newIPAddress;
jLabel8.setText(newIPAddress);
serverStatus = updateIP.getStatus().toString();
jLabel6.setText(serverStatus);
}
else
{
serverStatus = "No IP Update was needed.";
jLabel6.setText(serverStatus);
}
}
}, 0, updateAutoTime);
}
else
{
updateTimer.cancel();
System.out.println("Timer cancelled");
System.out.println("Purged {updateTimer.purge()} tasks.");
}
}
As I mentioned, this works once. But if the user deselects the checkbox, it won't work again. And the user can't change the value in jTextField4 after they select the checkbox.
So, what I'm looking for is this:
How to make this so that user can select and deselect the checkbox as they want (even if it's multiple times in a row).
How to make this so the user can change the value in jTextField4, and have it automatically cancel the current timer, and start a new one with the new value (I haven't done anything with the jTextField4 at all, so I'll have to create an event to cover it later).
Thanks, and have a great day:)
Patrick.
Perhaps this task would be better suited to a javax.swing.Timer. See Timer.restart() for details.
Note that Timer is relatively inaccurate over long time periods. One way to account for that is to have it repeat frequently but perform it's assigned task only one a certain time has been reached or passed.
Would I be able to wrap everything in the "task" portion of the call to Swing Timer, or do I have to create another class that handles the task?
You might want to wrap the grunt work in a SwingWorker to ensure the EDT is not blocked.
..I'm assuming that I would have to create the timer as a class-level declaration .. correct?
Yes, that is what I was thinking.