void Start()
    {
        listView   = new MJAListView("Concert Group ListView");
        detailView = new MJADetailViewConcertGroup("Concert Group DetailView");

        listView.transform.position   = leftPosition;
        detailView.transform.position = spawnPosition;

        OnValidate();

        if (Application.sandboxType != ApplicationSandboxType.NotSandboxed)
        {
            archive.jsonPath = Application.streamingAssetsPath;
        }
        MJAData.archive = archive;
        MJAData.archive.Load();

        if (defaultImagePath.Length > 0 && File.Exists(defaultImagePath))
        {
            MJAData.defaultImageData = File.ReadAllBytes(defaultImagePath);
        }
        else
        {
            Debug.Log("no default image or file not found");
        }

        listView.SetData(MJAData.Field.ConcertGroup, MJAData.archive.concertGroups.GetAllIds(), "All Concert Groups");
        listView.Move(0); // set first entry active
        listView.Update();

        detailView.SetId(listView.CurrentId);
    }
    public override MJAListView CreateListView()
    {
        Debug.Log("MJADetailViewImage CreateListView ID:" + currentId);
        var         data = MJAData.archive.images[currentId];
        MJAListView list = null;

        switch (currentIndex)
        {
        case 0:         // concerts
            list = new MJAListView("concert list (image)");
            list.SetData(MJAData.Field.Concert, data.concerts, "Concerts: Image ID=" + data.id);
            break;

        case 1:         // tags
            list = new MJAListView("tag list (image)");
            list.SetData(MJAData.Field.ImageTag, data.tags, "Tags: Image ID=" + data.id);
            break;

        case 2:         // artists
            list = new MJAListView("artist list (image)");
            list.SetData(MJAData.Field.Person, data.artists, "Artists: Image ID=" + data.id);
            break;
        }
        return(list);
    }
    public override MJAListView CreateListView()
    {
        Debug.Log("MJADetailViewImage CreateListView ID:" + currentId);
        var         data = MJAData.archive.imageTags[currentId];
        MJAListView list = null;

        switch (currentIndex)
        {
        case 0:         // images
            list = new MJAListView("image list (imageTag)");
            list.SetData(MJAData.Field.Image, data.images, "Images with tag " + data.name);
            break;
        }
        return(list);
    }
    public override MJAListView CreateListView()
    {
        var         data = MJAData.archive.concertGroups[currentId];
        MJAListView list = null;

        switch (currentIndex)
        {
        case 0:     // concerts
            list = new MJAListView("concert list (concertGroup)");
            list.SetData(MJAData.Field.Concert, data.concerts, "Concerts: " + data.nameEn);
            break;

        case 1:     // images
            list = new MJAListView("image list (concertGroup)");
            list.SetData(MJAData.Field.Image, data.mainImages, "Images: " + data.nameEn);
            break;
        }
        return(list);
    }
    public override MJAListView CreateListView()
    {
        Debug.Log("MJADetailViewPerson CreateListView ID:" + currentId);
        var         data = MJAData.archive.persons[currentId];
        MJAListView list = null;

        switch (currentIndex)
        {
        case 0:     // concerts
            list = new MJAListView("concert list (person)");
            list.SetData(MJAData.Field.Concert, data.concerts, "Concerts: " + data.fullName);
            break;

        case 1:     // images
            list = new MJAListView("image list (person)");
            list.SetData(MJAData.Field.Person, data.images, "Images: " + data.fullName);
            break;
        }
        return(list);
    }
    public override MJAListView CreateListView()
    {
        Debug.Log("MJADetailViewConcert CreateListView ID:" + currentId);
        var         data = MJAData.archive.concerts[currentId];
        MJAListView list = null;

        switch (currentIndex)
        {
        case 0:     // concertGroups
            list = new MJAListView("concert group list (concert)");
            list.SetData(MJAData.Field.ConcertGroup, data.concertGroupIds, "Concert Groups: " + data.name);
            break;

        case 1:     // images
            list = new MJAListView("image list (concert)");
            list.SetData(MJAData.Field.Image, data.images, "Images: " + data.name);
            break;
        }
        return(list);
    }
    void Update()
    {
        bool moved = false;

        if (inList)
        {
            if (UnityEngine.Input.GetKeyDown(KeyCode.DownArrow))
            {
                moved = listView.Move(1);
                listView.Update();
            }
            else if (UnityEngine.Input.GetKeyDown(KeyCode.UpArrow))
            {
                moved = listView.Move(-1);
                listView.Update();
            }
            else if (UnityEngine.Input.GetKeyDown(KeyCode.Return))
            {
                inList = false;
                detailView.Move(0);
                listView.Cleanup();
                listView = detailView.CreateListView();
                listView.transform.position = spawnPosition;
                listView.Update();
            }
            if (moved)
            {
                detailView.SetId(listView.CurrentId);
            }
        }
        else
        {
            if (UnityEngine.Input.GetKeyDown(KeyCode.DownArrow))
            {
                moved = detailView.Move(1);
                detailView.Update();
            }
            else if (UnityEngine.Input.GetKeyDown(KeyCode.UpArrow))
            {
                moved = detailView.Move(-1);
                detailView.Update();
            }
            else if (UnityEngine.Input.GetKeyDown(KeyCode.Return))
            {
                inList = true;
                listView.Move(0);
                detailView.Cleanup();
                detailView = listView.CreateDetailView();
                detailView.transform.position = spawnPosition;
                detailView.Reshape();
            }
            if (moved)
            {
                listView.Cleanup();
                listView = detailView.CreateListView();
                listView.transform.position = spawnPosition;
                listView.Update();
            }
        }

        // move the two panels into place
        if (inList)
        {
            listView.transform.position   = Vector3.Lerp(listView.transform.position, leftPosition, 0.2f);
            detailView.transform.position = Vector3.Lerp(detailView.transform.position, rightPosition, 0.2f);
        }
        else
        {
            listView.transform.position   = Vector3.Lerp(listView.transform.position, rightPosition, 0.2f);
            detailView.transform.position = Vector3.Lerp(detailView.transform.position, leftPosition, 0.2f);
        }
    }