Completion Events9:54 with Craig Dennis
When a timeline completes, you will probably want something to happen. We do, so let's add an Event Handler to take care of the onFinished property.
So we know that when that clock hits zero, we want some stuff to happen. 0:00 Let's go look at how to know the attempt is completed, and 0:04 then figure out how to, and what stuff we should do. 0:08 First, let's clean up that to do. 0:12 We definitely wanna stop the existing timelines from running, so 0:13 that seems like we wanna do that. 0:17 Every time we create or 0:19 prepare a new attempt, we wanna wipe out that existing timeline permanently. 0:21 So, let's take a look. 0:26 Let's think this through a little bit. 0:28 Let's come up here. 0:29 It seems like right about here, right? 0:31 So, there's gonna be a chance that mTimeLine's not set. 0:34 So, we're gonna have to say, like, it hasn't started yet. 0:38 So if it's not equal to null, 0:42 that's always a good thing to do to check otherwise. 0:44 When you go to access a property, like, we wanna see if it's running, right? 0:48 We wanna see if the thing's running. 0:52 So we're gonna say, get status. 0:53 And if I didn't check for that null, what would happen when I called this, 0:55 we would get a null pointer exception. 0:58 And those are no fun. 1:00 So you'll always want to check the state of things. 1:01 So then we're gonna say if the status, and 1:03 this status returns an enumeration of animation.status.running. 1:07 That is a long looking line, isn't it. 1:17 So if it's not null and it is running, we should just stop it. 1:22 So we'll say mTimeLine.stop[};, okay? 1:27 So that will stop it from playing into the future. 1:30 Cool, we got that taken care of, but you know what? 1:33 Those first couple of lines there, they kind of look like they belong together in 1:35 some sort of method, don't they? 1:39 When stuff starts feeling like that, 1:41 like that doesn't really feel like it's very succinct. 1:42 Like if I just look at this like what is going on there? 1:44 Why don't we refactor this into a single method and that way it will be cleaner as 1:47 to what's happening, as well as the method could be called elsewhere. 1:50 So, when you get this feeling, a nice thing to do is you come in here like this, 1:54 and you right click it and choose Refactor, Refactor, 1:58 and we're gonna choose extract, and let's extract that one more time. 2:02 Extract, and we're gonna extract a method okay? 2:08 Private is fine, let's call that something that makes sense for both of those. 2:16 We kinda want to reset things, right? 2:21 So let's call that reset doesn't take any types, and click OK. 2:22 Okay, awesome. 2:28 So what it did is it took those and put them into this new method down here, cool. 2:31 That's much cleaner now, I think. 2:34 We come in, we prepare the new attempt, we reset the board. 2:36 So anything that we need to do that resets the way that that screen looks, 2:38 we just put that function now. 2:41 And if we need to call that elsewhere, we can also call it elsewhere. 2:43 Or if it makes sense at a higher level, we could put that above that, make sense? 2:46 Great, now what we were doing? 2:51 Oh yeah. 2:53 Let's take a peek back over here at the board. 2:54 So we still can't complete this one yet, right? 2:56 Because as a user, I should know what state I'm in. 2:58 If it's focus/break, we have that going on. 3:01 We don't have paused yet, so we're kinda blocked on that. 3:03 I guess we should start this one. 3:07 As a user in a Pomodoro attempt, I should be notified when the attempt completes, so 3:08 that I'm aware of what my next step should be, break or focus, okay. 3:12 That's cool, we can do that. 3:16 And while we're in here, why don't we take a look at this one. 3:18 As a user, I should be able to detail what my Pomodoro was about so 3:21 I can keep track of what's happened for future planning. 3:24 So let's drag that over. 3:27 Okay, so we've got three of them. 3:29 We better get cranking on some of these. 3:30 We aren't actually going to save anything, but let's mock it out. 3:33 So, let's flip back. 3:38 Okay, so, we want something to happen when the timeline finishes. 3:41 You know, when all the pages have gone through. 3:46 Well the good news is that an event is fired when the timeline completes. 3:48 And it exposes a way for you to register an event handler when it completes. 3:52 So let's do that. 3:55 And it's called setOnFinished. 4:01 And it expects an event handler which means we can pass in a lambda like we have 4:04 been, which takes an event and let's make it a multi-line. 4:09 I'm gonna do a couple things in here. 4:13 So, here is one of those weird cases where a ternary might actually make sense. 4:15 Do you remember what ternaries are? 4:19 So, it's when you have the option to go between two different things. 4:21 So, we want to prepare an attempt, and we want to prepare the next attempt, right? 4:25 But how do we know what that is? 4:29 So, if we say that we get the current attempt, 4:31 we get the kind of attempt that it is. 4:35 That's equal to focus, well then the next one we know is break. 4:39 [INAUDIBLE] is right over, my typing's bad there. 4:49 It's hard to see. 4:53 AttemptKind.BREAK, otherwise it's a FOCUS. 4:54 Does that make sense? 5:04 So it's saying, if the current Kind is FOCUS, then switch it to break. 5:10 Otherwise, switch it to focus. 5:18 Make sense? 5:20 So that should take care of that first ticket that we looked at. 5:21 Now the second one. 5:24 So we want to save the current attempt. 5:25 So we should probably do that before we prepare the attempt right. 5:29 So let's come in here and let's make a method. 5:32 I feel like we might be calling this a couple more times. 5:35 So we're going to say save CurrentAttempt, 5:37 it's a method we that haven't declared yet. 5:41 So, let's just go ahead and have it build one for us, awesome. 5:43 You don't really have anything set up on our actual model to save. 5:48 So, let's just make a mock method. 5:53 So let's do that. 5:56 We'll just have it print out what we're going to save or 5:57 what it is that it's saving. 5:59 So let's so that. So let's say mCurrentAttempt.save. 6:00 And of course, that method doesn't exist. 6:04 Let's go create it, okay. 6:07 So here let's print out Saving, cuz we don't have a database set up and 6:10 it's kinda out of the scope of where we're at here. 6:16 But it would save if this method existed. 6:19 And this is typically what it is called on a model as you save it up to the database. 6:22 So we wanna print out the current object. 6:26 And the way that you do that is with the keyword this, right? 6:29 That's referring to this instance, make sense? 6:32 Oh yeah, you know what? 6:37 That reminds me we should generate one of those toStrings methods and 6:38 this IDE will do it for us so we're gonna generate to string, and 6:41 yeah all that stuff, let's generate it all. 6:46 Cool, okay, now one thing that we need to remember 6:50 is that we need to get the value out of that message field. 6:54 Do you remember that we had the message field at the bottom? 6:57 We could bind to that right. 7:00 So we could bind to it and 7:01 say every time that that field changes, update the message. 7:02 But that seems like a little overkill. 7:06 Think if we just have this save current attempt method and write right before we 7:07 save it, we go and get that value if we say mCurrentAttempt.setMessage. 7:11 You know what, why don't you go ahead and pause me? 7:18 I want you to pull the value out of the message field. 7:22 Now, the message field isn't over here yet in the controller. 7:25 How do we get that over here, can you figure that out? 7:28 Pause me and come back. 7:30 Okay, did you get it? 7:33 Cool, so over at home.xml if we look down here, this text area has an ID of message. 7:35 So let's flip back over here. 7:42 We will say @fxml that is a private text area. 7:46 Be very careful not to get the java awt It's a common, common error, so 7:53 this TextArea here is the one that we want, and it is called message;. 7:57 Cool, so then if we come back to where we were, sorry, 8:02 I am scrolling all over the place, save message, 8:05 we wanna get message.getText cool, right? 8:10 Let's see how we did. 8:16 Two tickets, let's see if we did two at once. 8:18 So, oh you know what though? 8:20 We don't have the play and the pause button that's wound up. 8:22 I know, what if we change the temp, 8:25 temporarily we change the time that was required on the first focus. 8:27 Then it would just switch over to break and we'd make sure that we did it right. 8:31 So, let's go into our AttemptKind here. 8:34 And we'll go into our definition of AttemptKind. 8:37 And let's change the Focus time just temporarily. 8:40 Change that to three so we'll just count down from three, all right. 8:44 Let's run it and see what happens. 8:48 So, we bound this button. 8:51 This restart button. 8:53 So it will go to three. 8:54 Two, one, boom. 8:54 Oh cool, and look. 8:58 Not only did it switch to break, but it also saved and, 8:59 it doesn't have the message but let's see if we can make it, 9:02 Have the message, because we didn't have one there awesome. 9:09 It pulled the message and the remaining seconds is zero. 9:13 So we can actually probably use that save in a different way, right? 9:17 Whenever that restart was called, we could do it. 9:21 Let's think about that. 9:25 Awesome job. 9:26 I hope you enjoyed the concept of event listeners. 9:27 They are very prominent in most UI code 9:30 as it lets you hook into different life cycles of objects. 9:33 So we pretty much got the visual stuff in place to let the user know that 9:36 things are changing. 9:40 But if focus time is working correctly, we should make sure that they really know. 9:41 We wanna snap them out of it. 9:46 Now JavaFX is super media friendly so 9:48 why don't play an appropriate sound to get their attention? 9:51
You need to sign up for Treehouse in order to download course files.Sign up