move new transaction UI into a fragment, have a clean saving progress
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 24 Nov 2019 20:43:43 +0000 (22:43 +0200)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 24 Nov 2019 20:43:43 +0000 (22:43 +0200)
13 files changed:
app/src/main/java/net/ktnx/mobileledger/ui/NewTransactionSavingFragment.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionFragment.java [new file with mode: 0644]
app/src/main/res/anim/slide_in_up.xml
app/src/main/res/anim/slide_out_down.xml [new file with mode: 0644]
app/src/main/res/anim/slide_out_up.xml
app/src/main/res/layout/activity_new_transaction.xml
app/src/main/res/layout/fragment_new_transaction.xml [new file with mode: 0644]
app/src/main/res/layout/fragment_new_transaction_saving.xml [new file with mode: 0644]
app/src/main/res/layout/new_transaction_accounts.xml [deleted file]
app/src/main/res/menu/new_transaction.xml
app/src/main/res/menu/new_transaction_fragment.xml [new file with mode: 0644]
app/src/main/res/navigation/new_transaction_navigation.xml [new file with mode: 0644]

diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/NewTransactionSavingFragment.java b/app/src/main/java/net/ktnx/mobileledger/ui/NewTransactionSavingFragment.java
new file mode 100644 (file)
index 0000000..022885f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2019 Damyan Ivanov.
+ * This file is part of MoLe.
+ * MoLe is free software: you can distribute it and/or modify it
+ * under the term of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your opinion), any later version.
+ *
+ * MoLe 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 terms for details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.ui;
+
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+
+import net.ktnx.mobileledger.R;
+
+
+/**
+ * A simple {@link Fragment} subclass.
+ */
+public class NewTransactionSavingFragment extends Fragment {
+
+
+    public NewTransactionSavingFragment() {
+        // Required empty public constructor
+    }
+
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        return inflater.inflate(R.layout.fragment_new_transaction_saving, container, false);
+    }
+
+}
index 90ce60b..6287ac8 100644 (file)
@@ -22,19 +22,10 @@ import android.os.Bundle;
 import android.util.TypedValue;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.View;
-import android.widget.ProgressBar;
 
-import androidx.annotation.NonNull;
 import androidx.appcompat.widget.Toolbar;
-import androidx.lifecycle.ViewModelProviders;
-import androidx.recyclerview.widget.ItemTouchHelper;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.snackbar.BaseTransientBottomBar;
-import com.google.android.material.snackbar.Snackbar;
+import androidx.navigation.NavController;
+import androidx.navigation.Navigation;
 
 import net.ktnx.mobileledger.BuildConfig;
 import net.ktnx.mobileledger.R;
@@ -42,9 +33,7 @@ import net.ktnx.mobileledger.async.SendTransactionTask;
 import net.ktnx.mobileledger.async.TaskCallback;
 import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.model.LedgerTransaction;
-import net.ktnx.mobileledger.model.LedgerTransactionAccount;
 
-import java.util.Date;
 import java.util.Objects;
 
 import static net.ktnx.mobileledger.utils.Logger.debug;
@@ -56,13 +45,9 @@ import static net.ktnx.mobileledger.utils.Logger.debug;
  *         (the last problem with the POST was the missing content-length header)
  *  */
 
-public class NewTransactionActivity extends ProfileThemedActivity implements TaskCallback {
-    private static SendTransactionTask saver;
-    private ProgressBar progress;
-    private FloatingActionButton fab;
-    private NewTransactionItemsAdapter listAdapter;
-    private NewTransactionModel viewModel;
-    private RecyclerView list;
+public class NewTransactionActivity extends ProfileThemedActivity implements TaskCallback,
+        NewTransactionFragment.OnNewTransactionFragmentInteractionListener {
+    private NavController navController;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -73,73 +58,10 @@ public class NewTransactionActivity extends ProfileThemedActivity implements Tas
         Data.profile.observe(this,
                 mobileLedgerProfile -> toolbar.setSubtitle(mobileLedgerProfile.getName()));
 
-        progress = findViewById(R.id.save_transaction_progress);
-        fab = findViewById(R.id.fab);
-        fab.setOnClickListener(v -> saveTransaction());
+        navController = Navigation.findNavController(this, R.id.new_transaction_nav);
 
         Objects.requireNonNull(getSupportActionBar())
                .setDisplayHomeAsUpEnabled(true);
-        list = findViewById(R.id.new_transaction_accounts);
-        viewModel = ViewModelProviders.of(this)
-                                      .get(NewTransactionModel.class);
-        listAdapter = new NewTransactionItemsAdapter(viewModel, mProfile);
-        list.setAdapter(listAdapter);
-        list.setLayoutManager(new LinearLayoutManager(this));
-        Data.profile.observe(this, profile -> listAdapter.setProfile(profile));
-        listAdapter.notifyDataSetChanged();
-        new ItemTouchHelper(new ItemTouchHelper.Callback() {
-            @Override
-            public int getMovementFlags(@NonNull RecyclerView recyclerView,
-                                        @NonNull RecyclerView.ViewHolder viewHolder) {
-                int flags = makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END);
-                // the top item is always there (date and description)
-                if (viewHolder.getAdapterPosition() > 0) {
-                    if (viewModel.getAccountCount() > 2) {
-                        flags |= makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE,
-                                ItemTouchHelper.START | ItemTouchHelper.END);
-                    }
-                }
-
-                return flags;
-            }
-            @Override
-            public boolean onMove(@NonNull RecyclerView recyclerView,
-                                  @NonNull RecyclerView.ViewHolder viewHolder,
-                                  @NonNull RecyclerView.ViewHolder target) {
-                return false;
-            }
-            @Override
-            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
-                if (viewModel.getAccountCount() == 2)
-                    Snackbar.make(list, R.string.msg_at_least_two_accounts_are_required,
-                            Snackbar.LENGTH_LONG)
-                            .setAction("Action", null)
-                            .show();
-                else {
-                    int pos = viewHolder.getAdapterPosition();
-                    viewModel.removeItem(pos - 1);
-                    listAdapter.notifyItemRemoved(pos);
-                    viewModel.sendCountNotifications(); // needed after items re-arrangement
-                    viewModel.checkTransactionSubmittable(listAdapter);
-                }
-            }
-        }).attachToRecyclerView(list);
-
-        viewModel.isSubmittable()
-                 .observe(this, isSubmittable -> {
-                     if (isSubmittable) {
-                         if (fab != null) {
-                             fab.show();
-                             fab.setEnabled(true);
-                         }
-                     }
-                     else {
-                         if (fab != null) {
-                             fab.hide();
-                         }
-                     }
-                 });
-        viewModel.checkTransactionSubmittable(listAdapter);
     }
     @Override
     protected void initProfile() {
@@ -157,7 +79,7 @@ public class NewTransactionActivity extends ProfileThemedActivity implements Tas
     @Override
     public void finish() {
         super.finish();
-        overridePendingTransition(R.anim.dummy, R.anim.slide_out_right);
+        overridePendingTransition(R.anim.dummy, R.anim.slide_out_down);
     }
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
@@ -173,49 +95,19 @@ public class NewTransactionActivity extends ProfileThemedActivity implements Tas
         super.onStart();
         // FIXME if (tvDescription.getText().toString().isEmpty()) tvDescription.requestFocus();
     }
-    public void saveTransaction() {
-        if (fab != null)
-            fab.setEnabled(false);
-        listAdapter.toggleAllEditing(false);
-        progress.setVisibility(View.VISIBLE);
+    public void onTransactionSave(LedgerTransaction tr) {
+        navController.navigate(R.id.action_newTransactionFragment_to_newTransactionSavingFragment);
         try {
 
-            saver = new SendTransactionTask(this, mProfile);
-
-            Date date = viewModel.getDate();
-            LedgerTransaction tr =
-                    new LedgerTransaction(null, date, viewModel.getDescription(), mProfile);
-
-            LedgerTransactionAccount emptyAmountAccount = null;
-            float emptyAmountAccountBalance = 0;
-            for (int i = 0; i < viewModel.getAccountCount(); i++) {
-                LedgerTransactionAccount acc = viewModel.getAccount(i);
-                if (acc.getAccountName()
-                       .trim()
-                       .isEmpty())
-                    continue;
-
-                if (acc.isAmountSet()) {
-                    emptyAmountAccountBalance += acc.getAmount();
-                }
-                else {
-                    emptyAmountAccount = acc;
-                }
-
-                tr.addAccount(acc);
-            }
-
-            if (emptyAmountAccount != null)
-                emptyAmountAccount.setAmount(-emptyAmountAccountBalance);
+            SendTransactionTask saver = new SendTransactionTask(this, mProfile);
             saver.execute(tr);
         }
         catch (Exception e) {
             debug("new-transaction", "Unknown error", e);
 
-            progress.setVisibility(View.GONE);
-            listAdapter.toggleAllEditing(true);
-            if (fab != null)
-                fab.setEnabled(true);
+            Bundle b = new Bundle();
+            b.putString("error", "unknown error");
+            navController.navigate(R.id.newTransactionFragment, b);
         }
     }
     public void simulateCrash(MenuItem item) {
@@ -239,23 +131,15 @@ public class NewTransactionActivity extends ProfileThemedActivity implements Tas
         return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                 getResources().getDisplayMetrics()));
     }
-    public void resetTransactionFromMenu(MenuItem item) {
-        listAdapter.reset();
-    }
     @Override
     public void done(String error) {
-        progress.setVisibility(View.INVISIBLE);
-        debug("visuals", "hiding progress");
-
-        if (error == null)
-            listAdapter.reset();
+        Bundle b = new Bundle();
+        if (error != null) {
+            b.putString("error", error);
+            navController.navigate(R.id.action_newTransactionSavingFragment_Failure);
+        }
         else
-            Snackbar.make(list, error, BaseTransientBottomBar.LENGTH_LONG)
-                    .show();
-
-        listAdapter.toggleAllEditing(true);
-
-        viewModel.checkTransactionSubmittable(listAdapter);
+            navController.navigate(R.id.action_newTransactionSavingFragment_Success, b);
     }
 
     private class AsyncCrasher extends AsyncTask<Void, Void, Void> {
diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionFragment.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/NewTransactionFragment.java
new file mode 100644 (file)
index 0000000..2775716
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2019 Damyan Ivanov.
+ * This file is part of MoLe.
+ * MoLe is free software: you can distribute it and/or modify it
+ * under the term of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your opinion), any later version.
+ *
+ * MoLe 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 terms for details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.ui.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.renderscript.RSInvalidStateException;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+
+import net.ktnx.mobileledger.R;
+import net.ktnx.mobileledger.model.Data;
+import net.ktnx.mobileledger.model.LedgerTransaction;
+import net.ktnx.mobileledger.model.LedgerTransactionAccount;
+import net.ktnx.mobileledger.model.MobileLedgerProfile;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Date;
+
+/**
+ * A simple {@link Fragment} subclass.
+ * Activities that contain this fragment must implement the
+ * {@link OnNewTransactionFragmentInteractionListener} interface
+ * to handle interaction events.
+ */
+public class NewTransactionFragment extends Fragment {
+    private NewTransactionItemsAdapter listAdapter;
+    private NewTransactionModel viewModel;
+    private RecyclerView list;
+    private FloatingActionButton fab;
+    private OnNewTransactionFragmentInteractionListener mListener;
+    private MobileLedgerProfile mProfile;
+    public NewTransactionFragment() {
+        // Required empty public constructor
+        setHasOptionsMenu(true);
+    }
+    @Override
+    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.new_transaction_fragment, menu);
+        menu.findItem(R.id.action_reset_new_transaction_activity)
+            .setOnMenuItemClickListener(item -> {
+                listAdapter.reset();
+                return true;
+            });
+    }
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        return inflater.inflate(R.layout.fragment_new_transaction, container, false);
+    }
+
+    @Override
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        Activity activity = getActivity();
+        if (activity == null)
+            throw new RSInvalidStateException(
+                    "getActivity() returned null within onActivityCreated()");
+
+        list = activity.findViewById(R.id.new_transaction_accounts);
+        viewModel = ViewModelProviders.of(this)
+                                      .get(NewTransactionModel.class);
+        mProfile = Data.profile.getValue();
+        listAdapter = new NewTransactionItemsAdapter(viewModel, mProfile);
+        list.setAdapter(listAdapter);
+        list.setLayoutManager(new LinearLayoutManager(activity));
+        Data.profile.observe(this, profile -> {
+            mProfile = profile;
+            listAdapter.setProfile(profile);
+        });
+        listAdapter.notifyDataSetChanged();
+        new ItemTouchHelper(new ItemTouchHelper.Callback() {
+            @Override
+            public int getMovementFlags(@NonNull RecyclerView recyclerView,
+                                        @NonNull RecyclerView.ViewHolder viewHolder) {
+                int flags = makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END);
+                // the top item is always there (date and description)
+                if (viewHolder.getAdapterPosition() > 0) {
+                    if (viewModel.getAccountCount() > 2) {
+                        flags |= makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE,
+                                ItemTouchHelper.START | ItemTouchHelper.END);
+                    }
+                }
+
+                return flags;
+            }
+            @Override
+            public boolean onMove(@NonNull RecyclerView recyclerView,
+                                  @NonNull RecyclerView.ViewHolder viewHolder,
+                                  @NonNull RecyclerView.ViewHolder target) {
+                return false;
+            }
+            @Override
+            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
+                if (viewModel.getAccountCount() == 2)
+                    Snackbar.make(list, R.string.msg_at_least_two_accounts_are_required,
+                            Snackbar.LENGTH_LONG)
+                            .setAction("Action", null)
+                            .show();
+                else {
+                    int pos = viewHolder.getAdapterPosition();
+                    viewModel.removeItem(pos - 1);
+                    listAdapter.notifyItemRemoved(pos);
+                    viewModel.sendCountNotifications(); // needed after items re-arrangement
+                    viewModel.checkTransactionSubmittable(listAdapter);
+                }
+            }
+        }).attachToRecyclerView(list);
+
+        viewModel.isSubmittable()
+                 .observe(this, isSubmittable -> {
+                     if (isSubmittable) {
+                         if (fab != null) {
+                             fab.show();
+                             fab.setEnabled(true);
+                         }
+                     }
+                     else {
+                         if (fab != null) {
+                             fab.hide();
+                         }
+                     }
+                 });
+        viewModel.checkTransactionSubmittable(listAdapter);
+
+        fab = activity.findViewById(R.id.fab);
+        fab.setOnClickListener(v -> onFabPressed());
+
+        Bundle args = getArguments();
+        if (args != null) {
+            String error = args.getString("error");
+            if (error != null) {
+                // TODO display error
+            }
+            else {
+                viewModel.reset();
+            }
+        }
+    }
+    private void onFabPressed() {
+        fab.setEnabled(false);
+        if (mListener != null) {
+            Date date = viewModel.getDate();
+            LedgerTransaction tr =
+                    new LedgerTransaction(null, date, viewModel.getDescription(), mProfile);
+
+            LedgerTransactionAccount emptyAmountAccount = null;
+            float emptyAmountAccountBalance = 0;
+            for (int i = 0; i < viewModel.getAccountCount(); i++) {
+                LedgerTransactionAccount acc = viewModel.getAccount(i);
+                if (acc.getAccountName()
+                       .trim()
+                       .isEmpty())
+                    continue;
+
+                if (acc.isAmountSet()) {
+                    emptyAmountAccountBalance += acc.getAmount();
+                }
+                else {
+                    emptyAmountAccount = acc;
+                }
+
+                tr.addAccount(acc);
+            }
+
+            if (emptyAmountAccount != null)
+                emptyAmountAccount.setAmount(-emptyAmountAccountBalance);
+
+            mListener.onTransactionSave(tr);
+        }
+    }
+
+    @Override
+    public void onAttach(@NotNull Context context) {
+        super.onAttach(context);
+        if (context instanceof OnNewTransactionFragmentInteractionListener) {
+            mListener = (OnNewTransactionFragmentInteractionListener) context;
+        }
+        else {
+            throw new RuntimeException(
+                    context.toString() + " must implement OnFragmentInteractionListener");
+        }
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        mListener = null;
+    }
+
+    /**
+     * This interface must be implemented by activities that contain this
+     * fragment to allow an interaction in this fragment to be communicated
+     * to the activity and potentially other fragments contained in that
+     * activity.
+     * <p>
+     * See the Android Training lesson <a href=
+     * "http://developer.android.com/training/basics/fragments/communicating.html"
+     * >Communicating with Other Fragments</a> for more information.
+     */
+    public interface OnNewTransactionFragmentInteractionListener {
+        void onTransactionSave(LedgerTransaction tr);
+    }
+}
index 36c411a..2513fac 100644 (file)
@@ -16,7 +16,7 @@
   -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@android:integer/config_shortAnimTime">
+    android:duration="@android:integer/config_mediumAnimTime">
     <translate
         android:fromYDelta="+100%"
         android:toYDelta="0%" />
diff --git a/app/src/main/res/anim/slide_out_down.xml b/app/src/main/res/anim/slide_out_down.xml
new file mode 100644 (file)
index 0000000..963c4d9
--- /dev/null
@@ -0,0 +1,23 @@
+<?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
+  ~ under the term of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ (at your opinion), any later version.
+  ~
+  ~ MoLe 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 terms for details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:duration="@android:integer/config_shortAnimTime">
+    <translate
+        android:fromYDelta="0%"
+        android:toYDelta="100%" />
+</set>
\ No newline at end of file
index 0437ef5..6978439 100644 (file)
@@ -16,7 +16,7 @@
   -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:duration="@android:integer/config_shortAnimTime">
+    android:duration="@android:integer/config_longAnimTime">
     <translate
         android:fromYDelta="0%"
         android:toYDelta="-100%" />
index c865fdc..6913a77 100644 (file)
         android:layout_height="match_parent">
 
         <com.google.android.material.appbar.AppBarLayout
+            android:id="@+id/toolbar_layout"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:id="@+id/toolbar_layout"
             android:theme="@style/AppTheme.AppBarOverlay"
-            app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
-            >
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
 
             <androidx.appcompat.widget.Toolbar
                 android:id="@+id/toolbar"
 
         </com.google.android.material.appbar.AppBarLayout>
 
-        <include layout="@layout/new_transaction_accounts" />
-
-        <ProgressBar
-            android:id="@+id/save_transaction_progress"
-            android:layout_width="80dp"
-            android:layout_height="80dp"
-            android:layout_margin="4dp"
-            android:indeterminate="true"
-            android:indeterminateTint="@color/colorPrimary"
-            android:visibility="invisible"
+        <fragment
+            android:id="@+id/new_transaction_nav"
+            android:name="androidx.navigation.fragment.NavHostFragment"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent" />
-
-        <com.google.android.material.floatingactionbutton.FloatingActionButton
-            android:id="@+id/fab"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:padding="@dimen/fab_margin"
-            android:tint="@android:color/white"
-            android:visibility="gone"
-            app:backgroundTint="?colorAccent"
-            app:layout_constraintBottom_toBottomOf="@id/save_transaction_progress"
-            app:layout_constraintEnd_toEndOf="@id/save_transaction_progress"
-            app:layout_constraintStart_toStartOf="@id/save_transaction_progress"
-            app:layout_constraintTop_toTopOf="@id/save_transaction_progress"
-            app:srcCompat="@drawable/ic_save_white_24dp" />
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/toolbar_layout"
+            app:navGraph="@navigation/new_transaction_navigation" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/app/src/main/res/layout/fragment_new_transaction.xml b/app/src/main/res/layout/fragment_new_transaction.xml
new file mode 100644 (file)
index 0000000..8a35cf6
--- /dev/null
@@ -0,0 +1,54 @@
+<!--
+  ~ Copyright © 2019 Damyan Ivanov.
+  ~ This file is part of MoLe.
+  ~ MoLe is free software: you can distribute it and/or modify it
+  ~ under the term of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ (at your opinion), any later version.
+  ~
+  ~ MoLe 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 terms for details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="net.ktnx.mobileledger.ui.activity.NewTransactionActivity">
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/new_transaction_accounts"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:paddingStart="@dimen/activity_horizontal_margin"
+        android:paddingEnd="@dimen/activity_horizontal_margin"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:showIn="@layout/activity_new_transaction">
+    </androidx.recyclerview.widget.RecyclerView>
+
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginEnd="@dimen/fab_margin"
+        android:layout_marginBottom="@dimen/fab_margin"
+        android:padding="@dimen/fab_margin"
+        android:tint="@android:color/white"
+        android:visibility="visible"
+        app:backgroundTint="?colorAccent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:srcCompat="@drawable/ic_save_white_24dp" />
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_new_transaction_saving.xml b/app/src/main/res/layout/fragment_new_transaction_saving.xml
new file mode 100644 (file)
index 0000000..eab55f0
--- /dev/null
@@ -0,0 +1,46 @@
+<?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
+  ~ under the term of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ (at your opinion), any later version.
+  ~
+  ~ MoLe 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 terms for details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/new_transaction_saving"
+            android:textAlignment="center"
+            android:textSize="18sp" />
+
+        <ProgressBar
+            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            android:progressTint="@color/colorAccent" />
+
+    </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/new_transaction_accounts.xml b/app/src/main/res/layout/new_transaction_accounts.xml
deleted file mode 100644 (file)
index 0a40f78..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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
-  ~ under the term of the GNU General Public License as published by
-  ~ the Free Software Foundation, either version 3 of the License, or
-  ~ (at your opinion), any later version.
-  ~
-  ~ MoLe 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 terms for details.
-  ~
-  ~ You should have received a copy of the GNU General Public License
-  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
-  -->
-
-<androidx.recyclerview.widget.RecyclerView 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/new_transaction_accounts"
-    android:layout_width="0dp"
-    android:layout_height="0dp"
-    android:paddingStart="@dimen/activity_horizontal_margin"
-    android:paddingEnd="@dimen/activity_horizontal_margin"
-    app:layout_constraintBottom_toBottomOf="parent"
-    app:layout_constraintEnd_toEndOf="parent"
-    app:layout_constraintStart_toStartOf="parent"
-    app:layout_constraintTop_toBottomOf="@id/toolbar_layout"
-    tools:showIn="@layout/activity_new_transaction">
-
-</androidx.recyclerview.widget.RecyclerView>
\ No newline at end of file
index 51fd885..45f11d7 100644 (file)
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item
-        android:id="@+id/action_reset_new_transaction_activity"
-        android:icon="@drawable/ic_refresh_white_24dp"
-        android:onClick="resetTransactionFromMenu"
-        android:title="@string/action_reset_new_transaction_activity_title"
-        app:showAsAction="never" />
     <item
         android:id="@+id/action_simulate_crash"
         android:title="@string/crash_app_label"
diff --git a/app/src/main/res/menu/new_transaction_fragment.xml b/app/src/main/res/menu/new_transaction_fragment.xml
new file mode 100644 (file)
index 0000000..dc9b08d
--- /dev/null
@@ -0,0 +1,27 @@
+<?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
+  ~ under the term of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ (at your opinion), any later version.
+  ~
+  ~ MoLe 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 terms for details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item
+        android:id="@+id/action_reset_new_transaction_activity"
+        android:icon="@drawable/ic_refresh_white_24dp"
+        android:title="@string/action_reset_new_transaction_activity_title"
+        app:showAsAction="never" />
+
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/navigation/new_transaction_navigation.xml b/app/src/main/res/navigation/new_transaction_navigation.xml
new file mode 100644 (file)
index 0000000..b68760c
--- /dev/null
@@ -0,0 +1,59 @@
+<?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
+  ~ under the term of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ (at your opinion), any later version.
+  ~
+  ~ MoLe 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 terms for details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<navigation 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/new_transaction_navigation"
+    app:startDestination="@id/newTransactionFragment">
+
+    <fragment
+        android:id="@+id/newTransactionFragment"
+        android:name="net.ktnx.mobileledger.ui.activity.NewTransactionFragment"
+        android:label="NewTransactionFragment" >
+        <action
+            android:id="@+id/action_newTransactionFragment_to_newTransactionSavingFragment"
+            app:destination="@id/newTransactionSavingFragment"
+            app:enterAnim="@anim/slide_in_up"
+            app:exitAnim="@anim/slide_out_up" />
+        <argument
+            android:name="error"
+            app:argType="string"
+            app:nullable="true"
+            android:defaultValue="@null"/>
+    </fragment>
+    <fragment
+        android:id="@+id/newTransactionSavingFragment"
+        android:name="net.ktnx.mobileledger.ui.NewTransactionSavingFragment"
+        android:label="fragment_new_transaction_saving" >
+        <action
+            android:id="@+id/action_newTransactionSavingFragment_Success"
+            app:destination="@id/newTransactionFragment"
+            app:enterAnim="@anim/slide_in_up"
+            app:exitAnim="@anim/slide_out_up"
+            app:popExitAnim="@anim/slide_out_down"
+            />
+        <action
+            android:id="@+id/action_newTransactionSavingFragment_Failure"
+            app:destination="@id/newTransactionFragment"
+            app:enterAnim="@anim/slide_in_down"
+            app:exitAnim="@anim/slide_out_down"
+            app:popExitAnim="@anim/slide_out_up"
+            />
+    </fragment>
+</navigation>
\ No newline at end of file