de.jan.ledgerjournal.JournalActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.jan.ledgerjournal.JournalActivity.java

Source

/*
 * Copyright (c) 2016-2017 Jan Felix Schmidt <janschmidt@mailbox.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.jan.ledgerjournal;

import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.ShareActionProvider;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.util.ArrayList;

public class JournalActivity extends AppCompatActivity {

    Journal journal;
    ListView journalListView;
    TransactionsAdapter journalAdapter;
    int topfId;

    JournalDataSource dataSource;
    SharedPreferences sharedPref;

    private static final int REQUEST_WRITE_STORAGE = 42;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_journal);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); // Up-Button

        dataSource = new JournalDataSource(this);
        sharedPref = PreferenceManager.getDefaultSharedPreferences(this);

        Bundle bundle = getIntent().getExtras();
        topfId = bundle.getInt("topfId");

        //attaching TransactionsAdapter to journal
        journal = new Journal();
        journalListView = (ListView) findViewById(R.id.journalListView);
        journalAdapter = new TransactionsAdapter(this, journal.list);
        journalListView.setAdapter(journalAdapter);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.journalFab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(JournalActivity.this, TransactionActivity.class);
                i.putExtra("topfId", topfId);
                startActivity(i);
            }
        });

        //context menu
        registerForContextMenu(journalListView);
    }

    protected void onResume() {
        super.onResume();
        dataSource.open();

        String name = dataSource.getTopfName(topfId);
        this.setTitle(name);
        journal.setName(name);

        showAllJournalTransactions();
    }

    protected void onStop() {
        super.onStop();
        dataSource.close();
    }

    // Share menu
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate menu resource file.
        getMenuInflater().inflate(R.menu.menu_journal, menu);

        // Locate MenuItem with ShareActionProvider
        MenuItem item = menu.findItem(R.id.menu_item_share);

        // Fetch and store ShareActionProvider
        ShareActionProvider mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
        mShareActionProvider
                .setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
                    @Override
                    public boolean onShareTargetSelected(ShareActionProvider actionProvider, Intent intent) {
                        saveToFile();
                        return false;
                    }
                });

        // Set share intent
        mShareActionProvider.setShareIntent(createShareIntent());

        // Return true to display menu
        return true;
    }

    private Intent createShareIntent() {
        Intent shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.setType("text/*");

        File journalFile = new File(
                journal.exportFilePath(sharedPref.getString("exportpath", SettingsActivity.defaultPath(this))));
        shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(journalFile));
        shareIntent.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.app_name) + " "
                + getResources().getString(R.string.share_subject));
        //startActivity(Intent.createChooser(shareIntent, "Share Ledger file using")); //ich mchte keinen "Chooser" sobald ich JournalActivity ffne!
        return shareIntent;
    }

    //Other menu icons (export)
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        // menu_item_share not called, because it is handled by ShareActionProvider
        case R.id.menu_item_export:
            saveToFile();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    // List item context menu
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        if (v.getId() == R.id.journalListView) {
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
            Transaction t = journal.get(info.position);
            menu.setHeaderTitle(t.date + "\t" + t.payee);

            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.context_journal, menu);
            if (topfId == JournalDbHelper.TEMPLATE_TOPFID)
                menu.removeItem(R.id.context_journal_template);
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();

        if (item.getItemId() == R.id.context_journal_edit) {
            Log.d("JournalActivity", "Context menu: edit selected");
            editJournalTransaction(info.position);
        } else if (item.getItemId() == R.id.context_journal_delete) {
            Log.d("JournalActivity", "Context menu: delete selected");
            deleteJournalTransaction(info.position);
        } else if (item.getItemId() == R.id.context_journal_template) {
            addToTemplates(journal.get(info.position));
        } else {
            return false;
        }
        return true;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
        case REQUEST_WRITE_STORAGE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, getResources().getString(R.string.toast_permission_granted),
                        Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, getResources().getString(R.string.toast_permission_denied), Toast.LENGTH_LONG)
                        .show();
            }
        }
        }

    }

    private void showAllJournalTransactions() {
        journal.set(dataSource.getAllTransactions(topfId));
        journalAdapter.notifyDataSetChanged();
        Log.d("JournalActivity", "called notifyDataSetChanged()");
    }

    private void deleteJournalTransaction(int position) {
        dataSource.deleteTransaction(journal.get(position));
        journal.remove(position);
        journalAdapter.notifyDataSetChanged();
    }

    private void clearJournal() {
        dataSource.clearTopf(topfId);
        journal.clear();
        journalAdapter.notifyDataSetChanged();
    }

    private void editJournalTransaction(int position) {
        Intent i = new Intent(JournalActivity.this, TransactionActivity.class);
        i.putExtra("topfId", topfId);
        i.putExtra("transaction", journal.get(position));
        startActivity(i);
    }

    private void addToTemplates(Transaction t) {
        if (dataSource.addTemplate(t)) {
            Toast toast = Toast.makeText(this, R.string.toast_addtemplate, Toast.LENGTH_SHORT);
            toast.show();
        } else {
            replaceTemplateDialog(t);
        }
    }

    private void saveToFile() {
        // check permission
        boolean hasPermission = (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
        if (!hasPermission) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
                    REQUEST_WRITE_STORAGE);
        }
        int ret = journal.export(sharedPref.getString("exportpath", SettingsActivity.defaultPath(this)),
                Integer.parseInt(sharedPref.getString("exportwidth", "35")));
        Toast toast;
        if (ret == 0) {
            toast = Toast.makeText(this,
                    getResources().getString(R.string.toast_exportfile) + " "
                            + journal.exportFilePath(
                                    sharedPref.getString("exportpath", SettingsActivity.defaultPath(this))),
                    Toast.LENGTH_LONG);
        } else {
            toast = Toast.makeText(this,
                    getResources().getString(R.string.toast_exportfile_error) + " "
                            + journal.exportFilePath(
                                    sharedPref.getString("exportpath", SettingsActivity.defaultPath(this))),
                    Toast.LENGTH_LONG);
        }
        toast.show();
        if (topfId != JournalDbHelper.TEMPLATE_TOPFID) // deleting templates after export makes no sense
            deleteExported();
    }

    protected void replaceTemplateDialog(final Transaction t) {
        AlertDialog.Builder alert = new AlertDialog.Builder(this);
        alert.setMessage(getString(R.string.dialog_replacetemplate) + " " + t.payee + "?");
        alert.setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                dataSource.replaceTemplate(t);
                Toast toast = Toast.makeText(getApplicationContext(),
                        getString(R.string.toast_replacetemplate) + " " + t.payee, Toast.LENGTH_SHORT);
                toast.show();
            }
        });
        alert.setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
            }
        });
        alert.show();
    }

    private void deleteExported() {
        String delete = sharedPref.getString("delete", "never");
        Log.d("JournalActivity", "deleteExported() called: Preference is " + delete);
        if (delete.equals("always")) {
            clearJournal();
        } else if (delete.equals("ask")) {
            deleteExportedDialog();
        }
        // else: nothing is deleted.
    }

    protected void deleteExportedDialog() {
        AlertDialog.Builder alert = new AlertDialog.Builder(this);
        alert.setMessage(getResources().getString(R.string.dialog_deleteexported_1) + " " + journal.size() + " "
                + getResources().getString(R.string.dialog_deleteexported_2) + " " + journal.name + " "
                + getResources().getString(R.string.dialog_deleteexported_3));
        alert.setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                clearJournal();
            }
        });
        alert.setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
            }
        });
        alert.show();
    }

}

class TransactionsAdapter extends ArrayAdapter<Transaction> {

    public TransactionsAdapter(Context context, ArrayList<Transaction> transactions) {
        super(context, 0, transactions);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        // Get the data item for this position
        Transaction t = getItem(position);

        // If no existing view is reused: inflate the view & create PostingLayouts
        // This is done for new Transactions OR if number of postings has changed
        if (view == null || ((ViewGroup) view).getChildCount() != (t.numPostings() + 1)) {
            view = LayoutInflater.from(getContext()).inflate(R.layout.transaction, parent, false);
            LinearLayout transactionLayout = (LinearLayout) view.findViewById(R.id.transactionLayout);
            //for each posting, PostingLayout is created
            for (Posting p : t.getPostings()) {
                PostingLayout pl = new PostingLayout(getContext());
                pl.set(p);
                transactionLayout.addView(pl);
            }
        }
        // If view is reused: update PostingLayouts
        else {
            int numViews = ((ViewGroup) view).getChildCount();
            //Log.d("TransactionAdapter", "update up to "+numViews+" Views for Payee "+t.payee);
            int i = 0;
            for (int n = 0; i < numViews; ++n) {
                if (i >= t.numPostings())
                    break;
                View nextChild = ((ViewGroup) view).getChildAt(n);
                if (nextChild instanceof PostingLayout) {
                    //Log.d("TransactionAdapter", "update PostingLayout (child "+n+")");
                    ((PostingLayout) nextChild).set(t.posting(i));
                    i++;
                }
            }
        }

        // always set date & payee
        TextView date = (TextView) view.findViewById(R.id.transactDate);
        TextView payee = (TextView) view.findViewById(R.id.transactPayee);
        date.setText(t.date);
        payee.setText(t.payee);

        return view;
    }
}