try {
for (LedgerAccount acc : params[0].accountList) {
Log.d("CAT", String.format("Setting %s to %s", acc.getName(),
- acc.isHiddenToBe() ? "hidden" : "starred"));
+ acc.isHiddenByStarToBe() ? "hidden" : "starred"));
db.execSQL("UPDATE accounts SET hidden=? WHERE profile=? AND name=?",
- new Object[]{acc.isHiddenToBe() ? 1 : 0, profile, acc.getName()});
+ new Object[]{acc.isHiddenByStarToBe() ? 1 : 0, profile, acc.getName()});
- acc.setHidden(acc.isHiddenToBe());
- if (!params[0].showOnlyStarred || !acc.isHidden()) newList.add(acc);
+ acc.setHiddenByStar(acc.isHiddenByStarToBe());
+ if (!params[0].showOnlyStarred || !acc.isHiddenByStar()) newList.add(acc);
}
db.setTransactionSuccessful();
}
acct_name = acct_name.replace("\"", "");
L(String.format("found account: %s", acct_name));
- lastAccount = profile.loadAccount(acct_name);
+ lastAccount = profile.tryLoadAccount(db, acct_name);
if (lastAccount == null) {
lastAccount = new LedgerAccount(acct_name);
- profile.storeAccount(db, lastAccount);
}
+ profile.storeAccount(db, lastAccount);
// make sure the parent account(s) are present,
// synthesising them if necessary
while (!toAppend.isEmpty()) {
String aName = toAppend.pop();
LedgerAccount acc = new LedgerAccount(aName);
- acc.setHidden(lastAccount.isHidden());
- if (!onlyStarred || !acc.isHidden())
+ acc.setHiddenByStar(lastAccount.isHiddenByStar());
+ if (!onlyStarred || !acc.isHiddenByStar())
accountList.add(acc);
L(String.format("gap-filling with %s", aName));
accountNames.put(aName, null);
}
}
- if (!onlyStarred || !lastAccount.isHidden())
+ if (!onlyStarred || !lastAccount.isHiddenByStar())
accountList.add(lastAccount);
accountNames.put(acct_name, null);
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.model.LedgerAccount;
+import net.ktnx.mobileledger.model.MobileLedgerProfile;
import net.ktnx.mobileledger.utils.MLDB;
import java.util.ArrayList;
protected ArrayList<LedgerAccount> doInBackground(Void... params) {
Data.backgroundTaskCount.incrementAndGet();
try {
- String profileUUID = Data.profile.get().getUuid();
+ MobileLedgerProfile profile = Data.profile.get();
+ String profileUUID = profile.getUuid();
boolean onlyStarred = Data.optShowOnlyStarred.get();
ArrayList<LedgerAccount> newList = new ArrayList<>();
- String sql = "SELECT name, hidden FROM accounts WHERE profile = ?";
- if (onlyStarred) sql += " AND hidden = 0";
- sql += " ORDER BY name";
+ String sql = "SELECT a.name from accounts a WHERE a.profile = ?";
+ if (onlyStarred) sql += " AND a.hidden = 0";
+ sql += " ORDER BY a.name";
SQLiteDatabase db = MLDB.getReadableDatabase();
try (Cursor cursor = db.rawQuery(sql, new String[]{profileUUID})) {
final String accName = cursor.getString(0);
// Log.d("accounts",
// String.format("Read account '%s' from DB [%s]", accName, profileUUID));
- LedgerAccount acc = new LedgerAccount(accName);
- acc.setHidden(cursor.getInt(1) == 1);
- try (Cursor c2 = db.rawQuery(
- "SELECT value, currency FROM account_values WHERE profile = ? " +
- "AND account = ?", new String[]{profileUUID, acc.getName()}))
- {
- while (c2.moveToNext()) {
- acc.addAmount(c2.getFloat(0), c2.getString(1));
- }
- }
- newList.add(acc);
+ LedgerAccount acc = profile.loadAccount(db, accName);
+ if (acc.isVisible(newList)) newList.add(acc);
}
}
import androidx.annotation.NonNull;
public class LedgerAccount {
+ static Pattern reHigherAccount = Pattern.compile("^[^:]+:");
private String name;
private String shortName;
private int level;
private String parentName;
- private boolean hidden;
- private boolean hiddenToBe;
+ private boolean hiddenByStar;
+ private boolean hiddenByStarToBe;
+ private boolean expanded;
private List<LedgerAmount> amounts;
- static Pattern reHigherAccount = Pattern.compile("^[^:]+:");
+ private boolean hasSubAccounts;
public LedgerAccount(String name) {
this.setName(name);
- hidden = false;
- }
-
- public boolean isHidden() {
- return hidden;
- }
-
- public void setHidden(boolean hidden) {
- this.hidden = hidden;
+ hiddenByStar = false;
}
public LedgerAccount(String name, float amount) {
this.setName(name);
- this.hidden = false;
+ this.hiddenByStar = false;
+ this.expanded = true;
this.amounts = new ArrayList<LedgerAmount>();
this.addAmount(amount);
}
+ // an account is visible if:
+ // - it is starred (not hidden by a star)
+ // - and it has an expanded parent or is a top account
+ public boolean isVisible() {
+ if (hiddenByStar) return false;
- public void setName(String name) {
- this.name = name;
- stripName();
- }
+ if (level == 0) return true;
+ return isVisible(Data.accounts.get());
+ }
+ public boolean isVisible(ArrayList<LedgerAccount> list) {
+ for (LedgerAccount acc : list) {
+ if (acc.isParentOf(this)) {
+ if (!acc.isExpanded()) return false;
+ }
+ }
+ return true;
+ }
+ public boolean isParentOf(LedgerAccount potentialChild) {
+ return potentialChild.getName().startsWith(name + ":");
+ }
+ public boolean isHiddenByStar() {
+ return hiddenByStar;
+ }
+ public void setHiddenByStar(boolean hiddenByStar) {
+ this.hiddenByStar = hiddenByStar;
+ }
private void stripName() {
level = 0;
shortName = name;
parentName = parentBuilder.substring(0, parentBuilder.length() - 1);
else parentName = null;
}
-
public String getName() {
return name;
}
-
+ public void setName(String name) {
+ this.name = name;
+ stripName();
+ }
public void addAmount(float amount, String currency) {
- if (amounts == null ) amounts = new ArrayList<>();
+ if (amounts == null) amounts = new ArrayList<>();
amounts.add(new LedgerAmount(amount, currency));
}
public void addAmount(float amount) {
if ((amounts == null) || amounts.isEmpty()) return "";
StringBuilder builder = new StringBuilder();
- for( LedgerAmount amount : amounts ) {
+ for (LedgerAmount amount : amounts) {
String amt = amount.toString();
if (builder.length() > 0) builder.append('\n');
builder.append(amt);
return parentName;
}
public void togglehidden() {
- hidden = !hidden;
+ hiddenByStar = !hiddenByStar;
}
- public boolean isHiddenToBe() {
- return hiddenToBe;
+ public boolean isHiddenByStarToBe() {
+ return hiddenByStarToBe;
}
- public void setHiddenToBe(boolean hiddenToBe) {
- this.hiddenToBe = hiddenToBe;
+ public void setHiddenByStarToBe(boolean hiddenByStarToBe) {
+ this.hiddenByStarToBe = hiddenByStarToBe;
}
public void toggleHiddenToBe() {
- setHiddenToBe(!hiddenToBe);
+ setHiddenByStarToBe(!hiddenByStarToBe);
+ }
+ public boolean hasSubAccounts() {
+ return hasSubAccounts;
+ }
+ public void setHasSubAccounts(boolean hasSubAccounts) {
+ this.hasSubAccounts = hasSubAccounts;
+ }
+ public boolean isExpanded() {
+ return expanded;
+ }
+ public void setExpanded(boolean expanded) {
+ this.expanded = expanded;
+ }
+ public void toggleExpanded() {
+ expanded = !expanded;
}
}
import java.util.List;
import java.util.UUID;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
public final class MobileLedgerProfile {
private String uuid;
private String name;
public void storeAccount(SQLiteDatabase db, LedgerAccount acc) {
// replace into is a bad idea because it would reset hidden to its default value
// we like the default, but for new accounts only
- db.execSQL("update accounts set level = ?, keep = 1 where profile=? and name = ?",
- new Object[]{acc.getLevel(), uuid, acc.getName()});
- db.execSQL("insert into accounts(profile, name, name_upper, parent_name, level, keep) " +
- "select ?,?,?,?,?,1 where (select changes() = 0)",
+ db.execSQL("update accounts set level = ?, keep = 1, hidden=?, expanded=? " +
+ "where profile=? and name = ?",
+ new Object[]{acc.getLevel(), acc.isHiddenByStar(), acc.isExpanded(), uuid,
+ acc.getName()
+ });
+ db.execSQL(
+ "insert into accounts(profile, name, name_upper, parent_name, level, hidden, expanded, keep) " +
+ "select ?,?,?,?,?,?,?,1 where (select changes() = 0)",
new Object[]{uuid, acc.getName(), acc.getName().toUpperCase(), acc.getParentName(),
- acc.getLevel()
+ acc.getLevel(), acc.isHiddenByStar(), acc.isExpanded()
});
// Log.d("accounts", String.format("Stored account '%s' in DB [%s]", acc.getName(), uuid));
}
Log.d("db", String.format("removing progile %s from DB", uuid));
db.execSQL("delete from profiles where uuid=?", new Object[]{uuid});
}
+ @NonNull
public LedgerAccount loadAccount(String name) {
SQLiteDatabase db = MLDB.getReadableDatabase();
- try (Cursor cursor = db.rawQuery("SELECT hidden from accounts where profile=? and name=?",
- new String[]{uuid, name}))
+ return loadAccount(db, name);
+ }
+ @Nullable
+ public LedgerAccount tryLoadAccount(String acct_name) {
+ SQLiteDatabase db = MLDB.getReadableDatabase();
+ return loadAccount(acct_name);
+ }
+ @NonNull
+ public LedgerAccount loadAccount(SQLiteDatabase db, String accName) {
+ LedgerAccount acc = tryLoadAccount(db, accName);
+
+ if (acc == null) throw new RuntimeException("Unable to load account with name "+accName);
+
+ return acc;
+ }
+ @Nullable
+ public LedgerAccount tryLoadAccount(SQLiteDatabase db, String accName) {
+ try (Cursor cursor = db.rawQuery(
+ "SELECT a.hidden, a.expanded, (select 1 from accounts a2 " +
+ "where a2.profile = a.profile and a2.name like a.name||':%' limit 1) " +
+ "FROM accounts a WHERE a.profile = ? and a.name=?", new String[]{uuid, accName}))
{
if (cursor.moveToFirst()) {
- LedgerAccount acc = new LedgerAccount(name);
- acc.setHidden(cursor.getInt(0) == 1);
+ LedgerAccount acc = new LedgerAccount(accName);
+ acc.setHiddenByStar(cursor.getInt(0) == 1);
+ acc.setExpanded(cursor.getInt(1) == 1);
+ acc.setHasSubAccounts(cursor.getInt(2) == 1);
+
+ try (Cursor c2 = db.rawQuery(
+ "SELECT value, currency FROM account_values WHERE profile = ? " +
+ "AND account = ?", new String[]{uuid, accName}))
+ {
+ while (c2.moveToNext()) {
+ acc.addAmount(c2.getFloat(0), c2.getString(1));
+ }
+ }
return acc;
}
+ return null;
}
-
- return null;
}
public LedgerTransaction loadTransaction(int transactionId) {
LedgerTransaction tr = new LedgerTransaction(transactionId, this.uuid);
setLongOption(MLDB.OPT_LAST_SCRAPE, now.getTime());
Data.lastUpdateDate.set(now);
}
+ public List<LedgerAccount> loadChildAccountsOf(LedgerAccount acc) {
+ List<LedgerAccount> result = new ArrayList<>();
+ SQLiteDatabase db = MLDB.getReadableDatabase();
+ try (Cursor c = db.rawQuery(
+ "SELECT a.name FROM accounts a WHERE a.profile = ? and a.name like ?||':%'",
+ new String[]{uuid, acc.getName()}))
+ {
+ while (c.moveToNext()) {
+ LedgerAccount a = loadAccount(db, c.getString(0));
+ result.add(a);
+ }
+ }
+
+ return result;
+ }
+ public List<LedgerAccount> loadVisibleChildAccountsOf(LedgerAccount acc) {
+ List<LedgerAccount> result = new ArrayList<>();
+ ArrayList<LedgerAccount> visibleList = new ArrayList<>();
+ visibleList.add(acc);
+
+ SQLiteDatabase db = MLDB.getReadableDatabase();
+ try (Cursor c = db.rawQuery(
+ "SELECT a.name FROM accounts a WHERE a.profile = ? and a.name like ?||':%'",
+ new String[]{uuid, acc.getName()}))
+ {
+ while (c.moveToNext()) {
+ LedgerAccount a = loadAccount(db, c.getString(0));
+ if (a.isVisible(visibleList)) {
+ result.add(a);
+ visibleList.add(a);
+ }
+ }
+ }
+
+ return result;
+ }
}
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.TextView;
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.model.Data;
import net.ktnx.mobileledger.model.LedgerAccount;
-import net.ktnx.mobileledger.utils.Colors;
import java.util.List;
import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
-class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAdapter.LedgerRowHolder> {
+public class AccountSummaryAdapter
+ extends RecyclerView.Adapter<AccountSummaryAdapter.LedgerRowHolder> {
private boolean selectionActive;
AccountSummaryAdapter() {
Context ctx = holder.row.getContext();
Resources rm = ctx.getResources();
+ holder.row.setTag(acc);
holder.row.setVisibility(View.VISIBLE);
holder.vTrailer.setVisibility(View.GONE);
holder.tvAccountName.setText(acc.getShortName());
- holder.tvAccountName.setPadding(
- acc.getLevel() * rm.getDimensionPixelSize(R.dimen.activity_horizontal_margin) /
- 2, 0, 0, 0);
+ ConstraintLayout.LayoutParams lp =
+ (ConstraintLayout.LayoutParams) holder.tvAccountName.getLayoutParams();
+ lp.setMarginStart(
+ acc.getLevel() * rm.getDimensionPixelSize(R.dimen.thumb_row_height) / 2);
+ holder.expanderContainer
+ .setVisibility(acc.hasSubAccounts() ? View.VISIBLE : View.INVISIBLE);
+ holder.expanderContainer.setRotation(acc.isExpanded() ? 0 : 180);
holder.tvAccountAmounts.setText(acc.getAmountsString());
- if (acc.isHidden()) {
+ if (acc.isHiddenByStar()) {
holder.tvAccountName.setTypeface(null, Typeface.ITALIC);
holder.tvAccountAmounts.setTypeface(null, Typeface.ITALIC);
}
holder.tvAccountAmounts.setTypeface(null, Typeface.NORMAL);
}
- if (position % 2 == 0) {
- holder.row.setBackgroundColor(Colors.tableRowDarkBG);
- }
- else {
- holder.row.setBackgroundColor(Colors.tableRowLightBG);
- }
-
holder.selectionCb.setVisibility(selectionActive ? View.VISIBLE : View.GONE);
- holder.selectionCb.setChecked(!acc.isHiddenToBe());
+ holder.selectionCb.setChecked(!acc.isHiddenByStarToBe());
holder.row.setTag(R.id.POS, position);
}
return Data.accounts.get().size() + 1;
}
public void startSelection() {
- for (LedgerAccount acc : Data.accounts.get()) acc.setHiddenToBe(acc.isHidden());
+ for (LedgerAccount acc : Data.accounts.get()) acc.setHiddenByStarToBe(acc.isHiddenByStar());
this.selectionActive = true;
notifyDataSetChanged();
}
public void selectItem(int position) {
LedgerAccount acc = Data.accounts.get().get(position);
acc.toggleHiddenToBe();
- toggleChildrenOf(acc, acc.isHiddenToBe(), position);
+ toggleChildrenOf(acc, acc.isHiddenByStarToBe(), position);
notifyItemChanged(position);
}
void toggleChildrenOf(LedgerAccount parent, boolean hiddenToBe, int parentPosition) {
int i = parentPosition + 1;
for (LedgerAccount acc : Data.accounts.get()) {
if (acc.getName().startsWith(parent.getName() + ":")) {
- acc.setHiddenToBe(hiddenToBe);
+ acc.setHiddenByStarToBe(hiddenToBe);
notifyItemChanged(i);
toggleChildrenOf(acc, hiddenToBe, i);
i++;
class LedgerRowHolder extends RecyclerView.ViewHolder {
CheckBox selectionCb;
TextView tvAccountName, tvAccountAmounts;
- LinearLayout row;
+ ConstraintLayout row;
View vTrailer;
+ FrameLayout expanderContainer;
+ ImageView expander;
public LedgerRowHolder(@NonNull View itemView) {
super(itemView);
this.row = itemView.findViewById(R.id.account_summary_row);
this.tvAccountAmounts = itemView.findViewById(R.id.account_row_acc_amounts);
this.selectionCb = itemView.findViewById(R.id.account_row_check);
this.vTrailer = itemView.findViewById(R.id.account_summary_trailer);
+ this.expanderContainer = itemView.findViewById(R.id.account_expander_container);
+ this.expander = itemView.findViewById(R.id.account_expander);
+
+ expanderContainer.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ int w = right - left;
+ int h = bottom - top;
+ if (h > w) {
+ int p = (h - w) / 2;
+ v.setPadding(0, p, 0, p);
+ }
+ else v.setPadding(0, 0, 0, 0);
+ });
}
}
}
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.model.Data;
-import net.ktnx.mobileledger.model.LedgerAccount;
import net.ktnx.mobileledger.ui.MobileLedgerListFragment;
-import net.ktnx.mobileledger.ui.RecyclerItemListener;
import net.ktnx.mobileledger.ui.activity.MainActivity;
import net.ktnx.mobileledger.utils.Colors;
-import java.util.List;
import java.util.Observer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class AccountSummaryFragment extends MobileLedgerListFragment {
MenuItem mShowOnlyStarred;
- private AccountSummaryAdapter modelAdapter;
+ public AccountSummaryAdapter modelAdapter;
private Menu optMenu;
private FloatingActionButton fab;
private Observer backgroundTaskCountObserver;
modelAdapter = new AccountSummaryAdapter();
+ mActivity.mAccountSummaryFragment = this;
root = mActivity.findViewById(R.id.account_root);
LinearLayoutManager llm = new LinearLayoutManager(mActivity);
llm.setOrientation(RecyclerView.VERTICAL);
root.setLayoutManager(llm);
root.setAdapter(modelAdapter);
+ DividerItemDecoration did = new DividerItemDecoration(mActivity, DividerItemDecoration.VERTICAL);
+ root.addItemDecoration(did);
fab = mActivity.findViewById(R.id.btn_add_transaction);
- root.addOnItemTouchListener(new RecyclerItemListener(mActivity, root,
- new RecyclerItemListener.RecyclerTouchListener() {
- @Override
- public void onClickItem(View v, int position) {
- Log.d("value", String.format("item %d clicked", position));
- if (modelAdapter.isSelectionActive()) {
- modelAdapter.selectItem(position);
- }
- else {
- List<LedgerAccount> accounts = Data.accounts.get();
- if (accounts != null) {
- LedgerAccount account = accounts.get(position);
-
- mActivity.showAccountTransactions(account);
- }
- }
- }
-
- @Override
- public void onLongClickItem(View v, int position) {
- Log.d("value", String.format("item %d long-clicked", position));
- modelAdapter.startSelection();
- if (optMenu != null) {
- optMenu.findItem(R.id.menu_acc_summary_cancel_selection)
- .setVisible(true);
- optMenu.findItem(R.id.menu_acc_summary_confirm_selection)
- .setVisible(true);
- optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(false);
- }
- {
- if (fab != null) fab.hide();
- }
- }
- }));
+// root.addOnItemTouchListener(new RecyclerItemListener(mActivity, root,
+// new RecyclerItemListener.RecyclerTouchListener() {
+// @Override
+// public void onClickItem(View v, int position) {
+// Log.d("value", String.format("item %d clicked", position));
+// if (modelAdapter.isSelectionActive()) {
+// modelAdapter.selectItem(position);
+// }
+// else {
+// List<LedgerAccount> accounts = Data.accounts.get();
+// if (accounts != null) {
+// LedgerAccount account = accounts.get(position);
+//
+// mActivity.showAccountTransactions(account);
+// }
+// }
+// }
+//
+// @Override
+// public void onLongClickItem(View v, int position) {
+// Log.d("value", String.format("item %d long-clicked", position));
+// modelAdapter.startSelection();
+// if (optMenu != null) {
+// optMenu.findItem(R.id.menu_acc_summary_cancel_selection)
+// .setVisible(true);
+// optMenu.findItem(R.id.menu_acc_summary_confirm_selection)
+// .setVisible(true);
+// optMenu.findItem(R.id.menu_acc_summary_only_starred).setVisible(false);
+// }
+// {
+// if (fab != null) fab.hide();
+// }
+// }
+// }));
mActivity.fabShouldShow();
root.addOnScrollListener(new RecyclerView.OnScrollListener() {
}
});
swiper = mActivity.findViewById(R.id.account_swiper);
- Colors.themeWatch.addObserver(
- (o, arg) -> swiper.setColorSchemeColors(Colors.primary));
+ Colors.themeWatch.addObserver((o, arg) -> swiper.setColorSchemeColors(Colors.primary));
swiper.setColorSchemeColors(Colors.primary);
swiper.setOnRefreshListener(() -> {
Log.d("ui", "refreshing accounts via swipe");
import androidx.lifecycle.ViewModel;
-class AccountSummaryViewModel extends ViewModel {
+public class AccountSummaryViewModel extends ViewModel {
static void commitSelections(Context context) {
CAT task = new CAT();
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
new CommitAccountsTaskParams(Data.accounts.get(), Data.optShowOnlyStarred.get()));
}
- static void scheduleAccountListReload() {
+ static public void scheduleAccountListReload() {
if (Data.profile.get() == null) return;
UAT task = new UAT();
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class MainActivity extends ProfileThemedActivity {
private static final String STATE_CURRENT_PAGE = "current_page";
private static final String BUNDLE_SAVED_STATE = "bundle_savedState";
+ public AccountSummaryFragment mAccountSummaryFragment;
DrawerLayout drawer;
private LinearLayout profileListContainer;
private View profileListHeadArrow, profileListHeadMore, profileListHeadCancel;
private boolean profileModificationEnabled = false;
private boolean profileListExpanded = false;
private ProfilesRecyclerViewAdapter mProfileListAdapter;
-
@Override
protected void onStart() {
super.onStart();
// FIXME disable rearranging
}
+ public void onAccountSummaryRowViewClicked(View view) {
+ ViewGroup row = (ViewGroup) view.getParent();
+ if (view.getId() == R.id.account_expander_container) {
+ Log.d("accounts", "Account expander clicked");
+ LedgerAccount acc = (LedgerAccount) row.getTag();
+ if (!acc.hasSubAccounts()) return;
+
+ boolean wasExpanded = acc.isExpanded();
+
+ view.clearAnimation();
+ ViewPropertyAnimator animator = view.animate();
+
+ acc.toggleExpanded();
+ Data.profile.get().storeAccount(MLDB.getWritableDatabase(), acc);
+
+ if (wasExpanded) {
+ Log.d("accounts", String.format("Collapsing account '%s'", acc.getName()));
+ animator.rotationBy(180);
+
+ // removing all child accounts from the view
+ int start = -1, count = 0;
+ int i = 0;
+ final ArrayList<LedgerAccount> accountList = Data.accounts.get();
+ for (LedgerAccount a : accountList) {
+ if (acc.isParentOf(a)) {
+ if (start == -1) {
+ start = i;
+ }
+ count++;
+ }
+ else {
+ if (start != -1) {
+ break;
+ }
+ }
+ i++;
+ }
+
+ if (start != -1) {
+ for (int j = 0; j < count; j++) {
+ Log.d("accounts", String.format("Removing item %d: %s", start + j,
+ accountList.get(start).getName()));
+ accountList.remove(start);
+ }
+
+ mAccountSummaryFragment.modelAdapter.notifyItemRangeRemoved(start, count);
+ }
+ }
+ else {
+ Log.d("accounts", String.format("Expanding account '%s'", acc.getName()));
+ animator.rotationBy(-180);
+ ArrayList<LedgerAccount> accounts = Data.accounts.get();
+ List<LedgerAccount> children = Data.profile.get().loadVisibleChildAccountsOf(acc);
+ int parentPos = accounts.indexOf(acc);
+ if (parentPos == -1) throw new RuntimeException(
+ "Can't find index of clicked account " + acc.getName());
+ accounts.addAll(parentPos + 1, children);
+ mAccountSummaryFragment.modelAdapter
+ .notifyItemRangeInserted(parentPos + 1, children.size());
+ }
+ }
+ }
public class SectionsPagerAdapter extends FragmentPagerAdapter {
Log.d("main", String.format("Switching to fragment %d", position));
switch (position) {
case 0:
- return new AccountSummaryFragment();
+// Log.d("flow", "Creating account summary fragment");
+ return mAccountSummaryFragment = new AccountSummaryFragment();
case 1:
return new TransactionListFragment();
default:
return 2;
}
}
-
}
class MobileLedgerDatabase extends SQLiteOpenHelper implements AutoCloseable {
public static final String DB_NAME = "MoLe.db";
- public static final int LATEST_REVISION = 18;
+ public static final int LATEST_REVISION = 19;
private final Application mContext;
--- /dev/null
+<!--
+ ~ Copyright Google Inc.
+ ~
+ ~ 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:
+ ~
+ ~ https://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distribution 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.
+ ~
+ ~ Modified/adapted by Damyan Ivanov for MoLe
+ -->
+
+<vector android:height="24dp" android:tint="?colorAccent"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
+</vector>
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2019 Damyan Ivanov.
~ This file is part of MoLe.
~ MoLe is free software: you can distribute it and/or modify it
android:id="@+id/account_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:scrollbars="vertical"
android:choiceMode="multipleChoice"
android:drawSelectorOnTop="true"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:scrollbars="vertical">
</androidx.recyclerview.widget.RecyclerView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/account_summary_row"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- tools:showIn="@id/account_root">
+ android:layout_height="wrap_content">
- <LinearLayout
- android:id="@+id/account_summary_row"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ <CheckBox
+ android:id="@+id/account_row_check"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:button="@drawable/checkbox_star_black"
+ android:onClick="onAccountSummaryRowViewClicked"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/account_row_acc_name"
+ style="@style/account_summary_account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
android:gravity="center_vertical"
- android:minHeight="?attr/android:actionBarSize"
- android:orientation="horizontal"
+ android:onClick="onAccountSummaryRowViewClicked"
android:paddingStart="8dp"
- android:paddingEnd="8dp"
+ android:text="Account name, a really long one. A very very very long one. It may even spawn on more than two lines -- three, four or more."
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintStart_toEndOf="@id/account_row_check"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:ignore="HardcodedText" />
+
+ <FrameLayout
+ android:id="@+id/account_expander_container"
+ android:layout_width="@dimen/thumb_row_height"
+ android:layout_height="@dimen/thumb_row_height"
+ android:foregroundGravity="center_vertical"
+ android:minHeight="@dimen/thumb_row_height"
+ android:onClick="onAccountSummaryRowViewClicked"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/account_row_acc_name"
app:layout_constraintTop_toTopOf="parent">
- <CheckBox
- android:id="@+id/account_row_check"
- android:layout_width="wrap_content"
+ <ImageView
+ android:id="@+id/account_expander"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:button="@drawable/checkbox_star_black" />
+ android:layout_margin="8dp"
+ android:background="@drawable/ic_expand_less_black_24dp" />
+ </FrameLayout>
- <TextView
- android:id="@+id/account_row_acc_name"
- style="@style/account_summary_account_name"
- android:text="Account name, a really long one. A very very very long one. It may even spawn on more than two lines -- three, four or more."
- tools:ignore="HardcodedText" />
+ <TextView
+ android:id="@+id/account_row_filler1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/account_row_acc_amounts"
+ app:layout_constraintStart_toEndOf="@id/account_expander_container"
+ app:layout_constraintTop_toTopOf="parent" />
- <TextView
- android:id="@+id/account_row_acc_amounts"
- style="@style/account_summary_amounts"
- android:text="123,45\n678,90"
- tools:ignore="HardcodedText" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/account_row_acc_amounts"
+ style="@style/account_summary_amounts"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:layout_weight="0"
+ android:gravity="center_vertical"
+ android:onClick="onAccountSummaryRowViewClicked"
+ android:text="123,45\n678,90"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:ignore="HardcodedText" />
<View
android:id="@+id/account_summary_trailer"
--- /dev/null
+alter table accounts add expanded default 1;
+update accounts set expanded = 1;
\ No newline at end of file