I don't see anywhere in your code where "landed" is being set to True. It looks like you are calculating "isGrounded" to see if your character is touching the ground. So if your character is currently in the Jumping state, you can check to see if isGrounded is set to True. If it is, then you can set your state to Landing.
Also, it may not be the best idea to use the "animation.complete" callback to make changes to your character's state. This is how I would set up jumping:
1) Check if the Player presses the jump button, and your character isGrounded == true, and you're in a State where jumping is allowed
2) Switch your state to Jumping. Set your animation to TakeOff, and then queue up the JumpLoop (using AddAnimation() instead of SetAnimation(), and setting it to loop). Only apply these animations once, right when you switch to the Jumping state. Not every frame.
3) While your character is in the Jumping state, check if isGrounded == true. If it is, then switch to the Landing state.
4) While in the Landing state, check if your Landing animation has completed: "skeletonAnimation.AnimationState.Tracks.Items[trackIndex].IsComplete". If it has, then you can switch states back to Idle. This is sort of the same as using the animation.complete callback, but it keeps your code better compartmentalized.
I also suggest looking up State Machines and implementing a basic version of one - its kind of like what you have going on, but doing a bit of research on it will definitely make it less of a headache to implement 🙂