Android Open Source - android-passwordKeeper View File Fragment






From Project

Back to project page android-passwordKeeper.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions...

If you think the Android project android-passwordKeeper listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright 2014 Cody Munger// www .  java2s .  c  om
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.munger.passwordkeeper.view;


import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.munger.passwordkeeper.MainActivity;
import com.munger.passwordkeeper.R;
import com.munger.passwordkeeper.alert.ConfirmFragment;
import com.munger.passwordkeeper.struct.PasswordDetails;
import com.munger.passwordkeeper.struct.PasswordDocument;
import com.munger.passwordkeeper.view.widget.TextWidget;

/**
 * Fragment used to view all the defined entries in a passwordDocument.
 *
 */
public class ViewFileFragment extends Fragment 
{
  private MainActivity parent;
  private View root;
  
  /** the title of this password document */ private TextView title;
  /** a button used to add new entries to this document */ private Button addButton;
  /** a list displaying all the current entries in the document */ private ListView detailList;
  
  /** 
   * an adapter that converts the list of document entries to view widgets.
   * PassowrdDetails -> DetailView
  */
  private DetailListAdapter detailListAdapter;
  
  /** the currently opened password document */ private PasswordDocument document = null;
  /** the file where this document is stored */ private String file = "";
  
  private boolean editable = false;
  
  public static String getName()
  {
    return "File";
  }
  
  /**
   * Class the populates the specified ListView with a collections of DetailsViews.
   * Each DetailWidget should match an entry in the list of PasswordDetails belonging
   * to the currently opened document.
   */
  private static class DetailListAdapter extends ArrayAdapter<PasswordDetails>
  {
    private ViewFileFragment parent;
    
    /**
     * Constructor.
     * @param parent The fragment this object belongs to for passing events on to.
     * @param context The application context
     * @param objects the list of object to covert to the list
     */
    public DetailListAdapter(ViewFileFragment parent, Context context, List<PasswordDetails> objects) 
    {
      super(context, 0, objects);
      
      this.parent = parent;
    }
    
    /**
     * Render the list item to a widget
     */
    @Override
    public View getView(int position, View convertView, ViewGroup par) 
    {
      final DetailView ret;
      final DetailListAdapter that = this;
      PasswordDetails details = getItem(position);
      
      //if we're recycling the view
      if (convertView != null)
      {
        ret = (DetailView) convertView;
        ret.setDetails(details);
      }
      //if it's a new view
      //setup event listeners as well
      else
      {
        ret = new DetailView(details, getContext());
        ret.setListener(new TextWidget.Listener() 
        {
          public void labelClicked() 
          {
            //open a ViewDetailFragment
            that.parent.openDetail(ret.getDetails());
          }
          
          public void deleteClicked() 
          {
            //delete the selected detail
            that.parent.deleteClicked(ret.getDetails());
          }
        });
      }
      
      ret.setEditable(parent.editable);
      
      return ret;
    }
  }
  
  /**
   * Modifies the existing TextWidget class to render its assigned details
   */
  private static class DetailView extends TextWidget
  {
    private PasswordDetails details;
    
    public DetailView(PasswordDetails details, Context context) 
    {
      super(context, null);

      setDetails(details);
    }
    
    public void setDetails(PasswordDetails dets)
    {
      details = dets;
      
      if (details != null)
        setText(dets.name);
    }
    
    public PasswordDetails getDetails()
    {
      return details;
    }
  }
  
  @Override
  public void onSaveInstanceState(Bundle outState) 
  {
    outState.putString("file", parent.currentDoc);
    outState.putString("password", parent.password);
  };
  
  @Override
  public void onCreate(Bundle savedInstanceState) 
  {
    super.onCreate(savedInstanceState);
    
    parent = (MainActivity) getActivity();
    
    if (savedInstanceState != null)
    {
      String file = savedInstanceState.getString("file");
      String password = savedInstanceState.getString("password");
      
      parent.setFile(file, password);
      parent.fragmentExists(this);
    }
    
    setDocument(parent.document);
  };
  
  /**
   * Get references to relevant components and setup events for most components
   */
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
  {
    final ViewFileFragment that = this;
    this.parent = (MainActivity) getActivity();
    
    setHasOptionsMenu(true);
    
    root = inflater.inflate(R.layout.fragment_viewfile, container, false);
    
    //get component references
    title = (TextView) root.findViewById(R.id.viewfile_name);
    addButton = (Button) root.findViewById(R.id.viewfile_addbtn);
    detailList = (ListView) root.findViewById(R.id.viewfile_detaillist);
    
    //set up the detailList renderer
    if (document != null)
      setupDetailListAdapter();
    
    
    //setup the create new details button
    addButton.setOnClickListener(new View.OnClickListener() {public void onClick(View v) 
    {
      if (document != null)
      {
        PasswordDetails details = new PasswordDetails();
        details.name = "new details";
        that.detailListAdapter.add(details);
        
        try
        {
          document.save();
        }
        catch(Exception e){
          Log.e("passwordkeeper", "failed to save file " + file);
        }
        
        
        that.detailListAdapter.notifyDataSetChanged();
      }
    }});
    
    return root;
  }
  
  /**
   * Filter the list of detials down to matching details.
   * Detail names are the only thing search.  Matches detail names that contain the search string anywhere in the string.
   * @param details the list of details to filter
   * @param search the search string to filter on.
   * @return the filtered list of details
   */
  private ArrayList<PasswordDetails> searchDetails(ArrayList<PasswordDetails> details, String search)
  {
    search = search.toLowerCase();
    ArrayList<PasswordDetails> ret = new ArrayList<PasswordDetails>();
    
    for (PasswordDetails dets : document.details)
    {
      if (dets.name.toLowerCase().contains(search))
        ret.add(dets);
    }
    
    return ret;
  }
  
  /** the filtered list of details */ private ArrayList<PasswordDetails> filtered = new ArrayList<PasswordDetails>();
  /** render with the filtered list or full list? */ private boolean useFiltered = false;
  /** The filter list widget generator */ private DetailListAdapter filterAdapter;
  
  /**
   * setup the options menu.
   * Add events to each option
   */
  @Override
  public void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) 
  {
    inflater.inflate(R.menu.main, menu);
    
    MenuItem searchItem = menu.findItem(R.id.action_search);
      SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
      
      
      searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
      {
        public boolean onQueryTextSubmit(String arg0) 
        {
        return false;
      }
      
        /**
         * filter a new list for the filter view on each keypress.
         * return to the default list if the search input is empty.
         */
      public boolean onQueryTextChange(String arg0) 
      {
        if (arg0.isEmpty())
        {
          if (useFiltered == true)
          {
            useFiltered = false;
            detailList.setAdapter(detailListAdapter);
          }
        }
        else
        {
          if (document != null)
          {
            filtered = searchDetails(document.details, arg0);

            filterAdapter.clear();
            filterAdapter.addAll(filtered);
            
            if (useFiltered == false)
            {
              useFiltered = true;
              detailList.setAdapter(filterAdapter);
            }

            filterAdapter.notifyDataSetChanged();
          }
        }
        
        return false;
      }
    });
  };
  
  /**
   * events for the rest of the options menu items.
   * setup editable mode.
   */
  @Override
  public boolean onOptionsItemSelected(MenuItem item) 
  {
    int id = item.getItemId();
    
    if (id == R.id.action_edit)
    {
      setEditable(!editable);
    }
    
    return true;
  };
  
  public void setEditable(boolean editable)
  {
    this.editable = editable;
    
    if (root == null)
      return;
    
    setupEditable();
  }
  
  /**
   * Set the default document this fragment is rendering
   * @param file
   * @param document
   */
  public void setDocument(PasswordDocument document)
  {
    this.document = document;
    this.file = document.name;
    
    if (root != null)
    {
      setupDetailListAdapter();
    }
  }
  
  /**
   * setup of the list to widget generators
   */
  private void setupDetailListAdapter()
  {
    detailListAdapter = new DetailListAdapter(this, getActivity(), this.document.details);
    filterAdapter = new DetailListAdapter(this, getActivity(), this.filtered);
    
    detailList.setAdapter(detailListAdapter);
    
    title.setText(file);
  }
  
  /**
   * make sure the view is updated
   */
  @Override
  public void onResume() 
  {
    super.onResume();
    
    if (document == null)
      return;
    
    title.setText(file);
    
    setupEditable();
    root.invalidate();
  }

  /**
   * set each component to its editable mode.
   */
  private void setupEditable()
  {
    int sz = detailList.getChildCount();
    
    for (int i = 0; i < sz; i++)
    {
      TextWidget w = (TextWidget) detailList.getChildAt(i);
      w.setEditable(editable);
    }
    
    addButton.setVisibility((editable) ? View.VISIBLE : View.GONE);
  }
  
  /**
   * Open the specified details in a new ViewDetailFragment.
   * @param dets
   */
  private void openDetail(final PasswordDetails dets)
  {
    parent.openDetail(dets);
  }
  
  /**
   * Delete the specified details from the passwordDocument.
   * A confirmation dialog is brought up because this action is permanent.
   * @param dets
   */
  private void deleteClicked(final PasswordDetails dets)
  {
    final ViewFileFragment that = this;
    ConfirmFragment frag = new ConfirmFragment("Delete \"" + dets.name + "\"?", new ConfirmFragment.Listener() 
    {
      public void okay() 
      {
        //update all of the widget generator's backing lists
        document.details.remove(dets);
        detailListAdapter.remove(dets);
        detailListAdapter.notifyDataSetChanged();
        
        //save the changes permanently
        try
        {
          document.save();
        }
        catch(Exception e){
          Log.e("passwordkeeper", "failed to save file " + file);
        }
        
        if (useFiltered)
        {
          filterAdapter.remove(dets);
          filterAdapter.notifyDataSetChanged();
        }
        
        that.onResume();
      }
      
      public void cancel() 
      {  
      }
    });
    frag.show(parent.getSupportFragmentManager(), "confirm_fragment");
  }
}




Java Source Code List

com.munger.passwordkeeper.MainActivity.java
com.munger.passwordkeeper.SplashScreen.java
com.munger.passwordkeeper.alert.AlertFragment.java
com.munger.passwordkeeper.alert.ConfirmFragment.java
com.munger.passwordkeeper.alert.InputFragment.java
com.munger.passwordkeeper.alert.PasswordFragment.java
com.munger.passwordkeeper.struct.AES256.java
com.munger.passwordkeeper.struct.PasswordDetails.java
com.munger.passwordkeeper.struct.PasswordDocumentDropbox.java
com.munger.passwordkeeper.struct.PasswordDocumentFile.java
com.munger.passwordkeeper.struct.PasswordDocument.java
com.munger.passwordkeeper.view.AboutFragment.java
com.munger.passwordkeeper.view.CreateFileFragment.java
com.munger.passwordkeeper.view.ImportFileFragment.java
com.munger.passwordkeeper.view.SelectFileFragment.java
com.munger.passwordkeeper.view.ViewDetailFragment.java
com.munger.passwordkeeper.view.ViewFileFragment.java
com.munger.passwordkeeper.view.widget.DetailItemWidget.java
com.munger.passwordkeeper.view.widget.FileItemWidget.java
com.munger.passwordkeeper.view.widget.TextInputWidget.java
com.munger.passwordkeeper.view.widget.TextWidget.java