(bright piano key notes)
Alright so we've changed our layout to allow
the edited fragment to be displayed where we need it.
But there's still some work to do before it's fully working.
You can run the app to make sure we haven't made
any mistakes in the layout.
Firstly though, we need to fix the error in main activity.
Now the error is actually in the task edit request function
and you may need to rebuild the project
to get Android Studio to highlight that for you.
And you can see that I'm not showing an error currently.
So if I do that, I can rebuild the project.
Just fast forward this bit.
Okay so you can see that there's no more error there,
now that we have rebuilt the project.
And the problem there is that we've
called our frame layer task_details_container,
so that's the ID we should be using here.
So I'm just going to delete that, that should be
task_details_container.
Before I continue, there seems to be a slight problem
at the moment, and you may get an error with the
tool power reference in onCreate,
that's the code on line 17.
If you haven't got an error, which I haven't,
comment out the synthetic import on line eight,
to see what I'm talking about.
So I'm just going to comment that out.
Sometimes Android Studio doesn't recognise the static import
and will add another import, and I'm just gonna bring that
up on the screen and show you the potential two imports.
So sometimes you might see that this other one
will be imported automatically.
If I click on that to add it,
you'll then get this weird error there.
So the error is now showing Type mismatch Required: Toolbar?
Safe operator found int.
So if you get strange errors like that when your code
was working fine, rebuild the project.
That will often fix it, although you might have to use the
File, Invalidate caches/Restart option first.
This one up here.
But also check your imports as well.
That's annoying that it does happen,
but bugs like this do tend to be fixed quite quickly.
But I'm going to undo those two changes since
I didn't really originally have that error.
So you go back to the original import
and the error disappears.
Right, so moving on now let's actually run
our application in portrait mode.
Alright, so at this point with our app running
you can see that we've got no task selected at the moment.
So if you come over here
and click on the plus in the toolbar,
and you can see now a task and a request function
adds the Add Edit fragment to the frame layout.
This isn't quite what we want,
but we've still got some code to write.
At the moment, we can see that the layout seems to be okay.
If you rotate the emulator now into our landscape mode,
and you can see that's the correct effect that we wanted.
So we've got the task on the left,
which will ultimately be the task list,
and the details for a new task on the right hand side.
Now switching back to portrait mode again now.
That'll look fine if we can hide the left hand fragment.
We also need to show it again,
after we've finished adding the task.
When we do finish the editing,
we also need to remove the Add Edit fragment
from the right hand pane.
We need to do that in portrait to make room for
the task list again and also in landscape.
And I'll rotate the device again.
We need to then remove the right hand fragment
in landscape as well.
We won't hide the frame layout in landscape,
we'll just remove the fragment from it.
That way, the task list will only occupy half the screen.
The right hand side is reserved for the task details.
So, there's at least three places where we need to remove
the Add Edit fragment.
Obviously when the user taps the save button,
and they won't want the details to remain.
But they may also cancel editing by tapping either the
back or up buttons.
Rather than duplicating code each time,
I'm going to create a function to remove the fragment
and deal with hiding and showing the frame.
Let's go ahead and do that.
I'm going to put that just after the onCreate method
here in our main activity class.
So, private fun removeEditPane, parenthesis fragment, colon
fragment with a capital F, and in the save call operator
question mark equals null.
If you're asked to confirm the import,
which I am here because there's two of them,
make sure you select the support version,
in this case android.support.v4.app.Fragment.
So you wouldn't want to select the frame cast version there.
Alright so let's start with a log.
So Log.d, parenthesis TAG comma removeEditPane called.
Then we are gonna start with if parenthesis
fragment is not equal to null, and the code blocker
is going to be supportFragmentManager.beginTransaction.
On the next line, .remove parenthesis fragment,
and on the next line, .commit.
Next, start another code block.
First thing you want to set the visibility
of the right hand pane.
So I'm going to add a current to that effect.
I set the visibility of the right hand pane,
and we'll do that by typing
task_details_container.visibility, set that equal to
if parenthesis mTwoPane, then it's going to be
View.INVISIBLE else View.GONE.
So I'm going to import the android.view.view first,
that's at the top one there.
Now in terms of this mTwoPane, we also need to set up
a variable for that too, so this is gonna actually track
whether our app's running in portrait or landscape mode.
So let's go ahead and add that up here
to our main activity class.
We'll just put a note here to the effect of
whether or not the activity is in two pane mode,
i.e, running in landscape or on a tablet.
And the definition will be private var mTwoPane,
it will set that initially to false.
That obviously fixes up the error now in remove edit pane.
So continuing with that, so first thing, we've set
the visibility of the right hand pane there.
And then the line after that they want to
show the left hand pane.
Okay, add a comment here and show the left hand pane.
And it's gonna be mainFragment.view
safe call operator, which is a question mark,
.visibility is equal to View.VISIBLE.
task_details_container may also need its import
to be specified. We want the synthetic import
and definitely not the entry source.
Alright, so back to our removeEditPane function.
If you ever pass, then you can see a fragment reference,
or the fragment reference,
rather than finding it in this function,
that probably isn't an obvious thing to do at this stage.
I don't want to give the impression that code
is written perfectly the first time.
While developing this app, the natural thing to do here
was to find the fragment inside the removeEditPane function.
So the earlier version of this function
did something along these lines.
On this line, before the quote test for null,
we did something like var fragment is equal to
supportFragmentManager.findFragmentByID
and then parenthesis R.ID.task_details_container.
Now that's fine and it works.
As we develop the app, you'll notice that, most of the time,
we get a reference to the fragment before removing it.
The only time we don't is when the save button's tapped.
So it makes sense to pass in the fragment reference
that we've already got, rather than finding it again.
Calls like findVYID, and this one,
findFragmentByID are quite expensive.
They use a lot of processing time.
If we can reduce the number of times we do that,
we save the users battery on their Android device,
and that's always a good thing.
So we're gonna cut that line out,
and we're gonna paste it into the
onSaveClicked function instead.
One that we haven't yet implemented.
Paste it in there.
Alright, so back to removeEditPane.
It checks to see if the frame isn't null,
and then it removes it, if it isn't.
Next we have to decide whether to show
or hide the task details frame.
Now if we're in landscape, mTwoPane will be true.
In that case, we set the frame to invisible.
This is the code on line 37.
Otherwise, in portrait, we set the frame to gone.
These two settings are very similar.
Invisible makes the widget, the frame layout in this case,
invisible. Gone does the same thing.
The difference is that invisible still reserves space
in the display, whereas gone doesn't.
If you use gone, the frame won't take up any space.
That's what we want in portrait, because it allows the
main fragment to fill the screen.
In landscape, the frame won't be visible,
but it still takes up space on the screen.
Alright, and then that last line, line 39,
makes sure that the main fragment,
the task list in this case, is visible again.
Now we have to use the save call operator there,
which may seem a bit strange.
The task_details_container on the line above, line 37,
is part of our layout and can't be null.
Main fragment also can't be null.
That's the fragment widget in the layout.
Fragments don't have to have layouts, though.
You can create a fragment that just does things,
rather than displaying things.
So, in that case, the fragment doesn't have a view,
which is why we have to use the save call operator
when making it visible.
We haven't edited the code to make it invisible yet,
but let's actually see if our function works first.
And we can call that in the onSaveClicked method.
So let's add some logging to that.
I set method.function, so Log.d parenthesis TAG
comma double quote onSavedClicked colon called.
We go to our R fragment line to find our fragment.
And let's try calling our method removeEditPane
parsing in fragment.
So obviously that's gonna occur
when the save button's clicked.
So basically the activity removes the fragment
when the user taps the save button.
So the last thing we now need to do to test this, is to
call this onSaveClicked function from the fragment.
So in Add Edit Fragment, we're going to
add a listener to the save button.
So you may try to add that to the onCreate function,
and as we haven't discussed the fragment life cycle yet,
that may well be where you'd expect it to go.
But I'm going to override the
onActivityCreated function instead.
Now that function is called after onCreate and we'll see
how this fits into the activity lifecycle soon.
Very briefly though, let's have a look at that
fragment life cycle diagram and let's go quickly
bring up our guide there.
If we move down a little bit to the creating a fragment
section, you can see over here to the right hand side,
there's a diagram there outlining what happens.
That's very similar to the activity life cycle,
but it has got a few extra functions.
The ones we're interested in at the moment are
onCreate(), onCreateView(), and onActivtityCreated().
Now, we'll look at these in more detail soon.
What's important now, is that onCreate is called
before the onCreateView function.
So why is that important?
Well, go back to our Add Edit Fragment code.
We can see here that the layout for the fragment
is inflated in onCreateView. That's the code on line 41.
Until then, we can't access any of the widgets
in our fragments layout.
Attempting to attach a listener to any button
in onCreate just won't work,
and that's because we don't yet have a button.
Now, when you first start dealing with fragment layouts,
rather than activity layouts,
things like that aren't obvious.
It makes perfect sense that you can't access the widgets
until the layout's been inflated from the XML,
but it's an easy thing to overlook first.
Alright, so I'm going to override the onActivityCreated
function and I'm gonna get Android Studio
to do that just after the onCreateView function.
So onActivityCreated is the one we want.
Override that.
We're going to add some logging.
Log.D parenthesis TAG comma double quotes
onActivityCreated starts.
I've got a super call which I'm going to leave in.
And we're going to do addedit_save.setOnClickListener.
And within there we're gonna add a
left to right curly brace.
And the actual code is gonna be listener,
safe call operator.onSaveClicked.
And you can see we've got a closing right curly brace
and a closing right parenthesis.
And, again, you want to make sure that you choose
the synthetic import, if Android Studio offers a choice
for the AddEdit_save button.
We have to look at our imports.
You can see it's added that for me automatically,
but make sure you do choose the right one,
if you are prompted to import.
All the onClickListed does at the moment, as you can see,
is call the activities onSaveClicked function
that we've added. That code on line 50.
We'll be adding more code in here later.
We need to save the cast details, but for now we're
just getting the fragments working.
Android Studio's offering a suggestion to tidy the code up.
The parenthesis around the listener block are redundant,
so I come over here and click on that.
We can use the option here to
move lambda argument out of parenthesis.
If I do that, you can see that it's
removed the parenthesis for us.
Notice also that we have to use the save call operator
after listener on line 50.
The activity can be destroyed, and attempting to
call its functions after it's destroyed won't go well.
Alright, the app should now run.
So let's run this now.
I'm just gonna open Logcat as well,
so I can see what's going on.
Have a look at that app.
Now we're still in landscape mode, as you can see there.
Tapping on the plus button displays the
details fragment to add a new task.
Now if I come down here and click on the save button,
and again the fragment was removed from the display.
In the Logcat down here, we can see that
onSaveClicked was called.
That call was removeEditPane and the fragments
onDetach function got called there, as you can see,
when the fragments removed from the activity.
Should work the same in portrait,
so I'll go back to portrait mode here now.
Tap the plus button to display the fragment,
then tap save again, and it's actually removed.
Incidentally, this doesn't work for a second time,
because we've now hidden the frame layer.
So if I tap on the plus again, you can see that
nothing seems to happen on the screen.
It has actually worked, and you'll see the fragment
when you rotate the device back into landscape,
which I'll do now.
There's the fragment showing up.
So we've still got a bit of work to do,
but the basic functionality is now working.
In the next video, we'll finish up this display,
so that it works properly
in both portrait and landscape mode.
See you in the next video.