mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2026-04-05 08:03:47 -04:00
Merge #557
557: Group management POC for #129 r=TheLastProject a=Kethen Proof of concept for #129, please review and comment on desired changes A few new strings are added so translations will be needed meanwhile I think all added group has to be trimmed to avoid having identical groups like in the example https://user-images.githubusercontent.com/22017945/139289359-32f42b48-a40e-4039-8f0b-72bbe43cd0de.mp4 https://user-images.githubusercontent.com/22017945/139294845-28c88e03-871f-49d1-9b45-f0648f2f7b50.mp4 Co-authored-by: Katharine <kwchuiaa@connect.ust.hk> Co-authored-by: Katharine Chui <kwchuiaa@connect.ust.hk>
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="protect.card_locker"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="protect.card_locker">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.CAMERA"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
@@ -17,8 +16,6 @@
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android"/>
|
||||
|
||||
<application
|
||||
android:name=".LoyaltyCardLockerApplication"
|
||||
android:allowBackup="true"
|
||||
@@ -27,98 +24,106 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name="protect.card_locker.MainActivity"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.App.Starting"
|
||||
android:exported="true">
|
||||
android:theme="@style/Theme.App.Starting">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AboutActivity"
|
||||
android:label="@string/about"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar"></activity>
|
||||
<activity
|
||||
android:name=".ManageGroupsActivity"
|
||||
android:label="@string/groups"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
</activity>
|
||||
android:theme="@style/AppTheme.NoActionBar"></activity>
|
||||
<activity
|
||||
android:name=".ManageGroupActivity"
|
||||
android:label="@string/group_edit"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".LoyaltyCardViewActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:exported="true"/>
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".LoyaltyCardEditActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:exported="true">
|
||||
<intent-filter android:autoVerify="true" android:label="@string/app_name">
|
||||
android:windowSoftInputMode="stateHidden">
|
||||
<intent-filter
|
||||
android:autoVerify="true"
|
||||
android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Main card sharing URIs -->
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data android:host="@string/intent_import_card_from_url_host_catima_app"
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_catima_app"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_catima_app" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Old card sharing URIs -->
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data android:host="@string/intent_import_card_from_url_host_thelastproject"
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_thelastproject"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_thelastproject" />
|
||||
<data android:host="@string/intent_import_card_from_url_host_brarcher"
|
||||
<data
|
||||
android:host="@string/intent_import_card_from_url_host_brarcher"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_brarcher" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ScanActivity"
|
||||
android:label="@string/scanCardBarcode"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".BarcodeSelectorActivity"
|
||||
android:label="@string/selectBarcodeTitle"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden"/>
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".preferences.SettingsActivity"
|
||||
android:label="@string/settings"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".ImportExportActivity"
|
||||
android:label="@string/importExport"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
android:theme="@style/AppTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".CardShortcutConfigure"
|
||||
android:exported="true"
|
||||
android:label="@string/cardShortcut"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:exported="true">
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:authorities="${applicationId}"
|
||||
android:exported="false"
|
||||
android:authorities="${applicationId}">
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_provider_paths"/>
|
||||
android:resource="@xml/file_provider_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
@@ -2,6 +2,8 @@ package protect.card_locker;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class Group
|
||||
{
|
||||
public final String _id;
|
||||
@@ -19,4 +21,22 @@ public class Group
|
||||
|
||||
return new Group(_id, order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null){
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Group)){
|
||||
return false;
|
||||
}
|
||||
Group anotherGroup = (Group)obj;
|
||||
return _id.equals(anotherGroup._id) && order == anotherGroup.order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(){
|
||||
String combined = _id + "_" + order;
|
||||
return combined.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ public class LoyaltyCardCursorAdapter extends BaseCursorAdapter<LoyaltyCardCurso
|
||||
boolean mDarkModeEnabled;
|
||||
private Context mContext;
|
||||
private CardAdapterListener mListener;
|
||||
private SparseBooleanArray mSelectedItems;
|
||||
private SparseBooleanArray mAnimationItemsIndex;
|
||||
protected SparseBooleanArray mSelectedItems;
|
||||
protected SparseBooleanArray mAnimationItemsIndex;
|
||||
private boolean mReverseAllAnimations = false;
|
||||
|
||||
public LoyaltyCardCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener) {
|
||||
|
||||
223
app/src/main/java/protect/card_locker/ManageGroupActivity.java
Normal file
223
app/src/main/java/protect/card_locker/ManageGroupActivity.java
Normal file
@@ -0,0 +1,223 @@
|
||||
package protect.card_locker;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class ManageGroupActivity extends CatimaAppCompatActivity implements ManageGroupCursorAdapter.CardAdapterListener
|
||||
{
|
||||
|
||||
private final DBHelper mDB = new DBHelper(this);
|
||||
private ManageGroupCursorAdapter mAdapter;
|
||||
|
||||
private final String SAVE_INSTANCE_ADAPTER_STATE = "adapterState";
|
||||
private final String SAVE_INSTANCE_CURRENT_GROUP_NAME = "currentGroupName";
|
||||
|
||||
protected Group mGroup = null;
|
||||
private RecyclerView mCardList;
|
||||
private TextView mHelpText;
|
||||
private EditText mGroupNameText;
|
||||
|
||||
private boolean mGroupNameNotInUse;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle inputSavedInstanceState)
|
||||
{
|
||||
super.onCreate(inputSavedInstanceState);
|
||||
setContentView(R.layout.activity_manage_group);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
mHelpText = findViewById(R.id.helpText);
|
||||
mCardList = findViewById(R.id.list);
|
||||
FloatingActionButton saveButton = findViewById(R.id.fabSave);
|
||||
|
||||
mGroupNameText = findViewById(R.id.editTextGroupName);
|
||||
|
||||
mGroupNameText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mGroupNameNotInUse = true;
|
||||
mGroupNameText.setError(null);
|
||||
String currentGroupName = mGroupNameText.getText().toString().trim();
|
||||
if(currentGroupName.length() == 0){
|
||||
mGroupNameText.setError(getResources().getText(R.string.group_name_is_empty));
|
||||
return;
|
||||
}
|
||||
if (!mGroup._id.equals(currentGroupName)) {
|
||||
if (mDB.getGroup(currentGroupName) != null) {
|
||||
mGroupNameNotInUse = false;
|
||||
mGroupNameText.setError(getResources().getText(R.string.group_name_already_in_use));
|
||||
} else {
|
||||
mGroupNameNotInUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Intent intent = getIntent();
|
||||
String groupId = intent.getStringExtra("group");
|
||||
if (groupId == null){
|
||||
throw(new IllegalArgumentException("this activity expects a group loaded into it's intent"));
|
||||
}
|
||||
Log.d("groupId", "groupId: " + groupId);
|
||||
mGroup = mDB.getGroup(groupId);
|
||||
if (mGroup == null){
|
||||
throw(new IllegalArgumentException("cannot load group " + groupId + " from database"));
|
||||
}
|
||||
mGroupNameText.setText(mGroup._id);
|
||||
setTitle(getString(R.string.editGroup, mGroup._id));
|
||||
mAdapter = new ManageGroupCursorAdapter(this, null, this, mGroup);
|
||||
mCardList.setAdapter(mAdapter);
|
||||
registerForContextMenu(mCardList);
|
||||
|
||||
if (inputSavedInstanceState != null) {
|
||||
mAdapter.importInGroupState(integerArrayToAdapterState(inputSavedInstanceState.getIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE)));
|
||||
mGroupNameText.setText(inputSavedInstanceState.getString(SAVE_INSTANCE_CURRENT_GROUP_NAME));
|
||||
}
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar == null){
|
||||
throw(new RuntimeException("mActionBar is not expected to be null here"));
|
||||
}
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
|
||||
saveButton.setOnClickListener(v -> {
|
||||
String currentGroupName = mGroupNameText.getText().toString().trim();
|
||||
if(!currentGroupName.equals(mGroup._id)){
|
||||
if(currentGroupName.length() == 0){
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if(!mGroupNameNotInUse) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mAdapter.commitToDatabase();
|
||||
if(!currentGroupName.equals(mGroup._id)){
|
||||
mDB.updateGroup(mGroup._id, currentGroupName);
|
||||
}
|
||||
Toast.makeText(getApplicationContext(), R.string.group_updated, Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
});
|
||||
// this setText is here because content_main.xml is reused from main activity
|
||||
mHelpText.setText(getResources().getText(R.string.noGiftCardsGroup));
|
||||
updateLoyaltyCardList();
|
||||
}
|
||||
|
||||
private ArrayList<Integer> adapterStateToIntegerArray(HashMap<Integer, Boolean> adapterState){
|
||||
ArrayList<Integer> ret = new ArrayList<>(adapterState.size() * 2);
|
||||
for (Map.Entry<Integer, Boolean> entry : adapterState.entrySet()) {
|
||||
ret.add(entry.getKey());
|
||||
ret.add(entry.getValue()?1:0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private HashMap<Integer, Boolean> integerArrayToAdapterState(ArrayList<Integer> in) {
|
||||
HashMap<Integer, Boolean> ret = new HashMap<>();
|
||||
if (in.size() % 2 != 0){
|
||||
throw(new RuntimeException("failed restoring adapterState from integer array list"));
|
||||
}
|
||||
for(int i = 0;i < in.size(); i += 2){
|
||||
ret.put(in.get(i), in.get(i+1) == 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState (@NonNull Bundle outState){
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putIntegerArrayList(SAVE_INSTANCE_ADAPTER_STATE, adapterStateToIntegerArray(mAdapter.exportInGroupState()));
|
||||
outState.putString(SAVE_INSTANCE_CURRENT_GROUP_NAME, mGroupNameText.getText().toString());
|
||||
}
|
||||
|
||||
private void updateLoyaltyCardList() {
|
||||
mAdapter.swapCursor(mDB.getLoyaltyCardCursor());
|
||||
|
||||
if(mAdapter.getCountFromCursor() == 0)
|
||||
{
|
||||
mCardList.setVisibility(View.GONE);
|
||||
mHelpText.setVisibility(View.VISIBLE);
|
||||
}else {
|
||||
mCardList.setVisibility(View.VISIBLE);
|
||||
mHelpText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void leaveWithoutSaving(){
|
||||
if (hasChanged()){
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(ManageGroupActivity.this);
|
||||
builder.setTitle(R.string.leaveWithoutSaveTitle);
|
||||
builder.setMessage(R.string.leaveWithoutSaveConfirmation);
|
||||
builder.setPositiveButton(R.string.confirm, (dialog, which) -> finish());
|
||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}else{
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
leaveWithoutSaving();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasChanged(){
|
||||
return mAdapter.hasChanged() || !mGroup._id.equals(mGroupNameText.getText().toString().trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowLongClicked(int inputPosition)
|
||||
{
|
||||
// do nothing for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRowClicked(int inputPosition)
|
||||
{
|
||||
mAdapter.toggleSelection(inputPosition);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ManageGroupCursorAdapter extends LoyaltyCardCursorAdapter {
|
||||
private HashMap<Integer, Integer> mIndexCardMap;
|
||||
private HashMap<Integer, Boolean> mInGroupOverlay;
|
||||
private HashMap<Integer, Boolean> mIsLoyaltyCardInGroupCache;
|
||||
private HashMap<Integer, List<Group>> mGetGroupCache;
|
||||
final private Group mGroup;
|
||||
final private DBHelper mDb;
|
||||
public ManageGroupCursorAdapter(Context inputContext, Cursor inputCursor, CardAdapterListener inputListener, Group group){
|
||||
super(inputContext, inputCursor, inputListener);
|
||||
mGroup = new Group(group._id, group.order);
|
||||
mInGroupOverlay = new HashMap<>();
|
||||
mDb = new DBHelper(inputContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swapCursor(Cursor inputCursor) {
|
||||
super.swapCursor(inputCursor);
|
||||
mIndexCardMap = new HashMap<>();
|
||||
mIsLoyaltyCardInGroupCache = new HashMap<>();
|
||||
mGetGroupCache = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(LoyaltyCardListItemViewHolder inputHolder, Cursor inputCursor){
|
||||
LoyaltyCard loyaltyCard = LoyaltyCard.toLoyaltyCard(inputCursor);
|
||||
Boolean overlayValue = mInGroupOverlay.get(loyaltyCard.id);
|
||||
if((overlayValue != null? overlayValue: isLoyaltyCardInGroup(loyaltyCard.id))) {
|
||||
mAnimationItemsIndex.put(inputCursor.getPosition(), true);
|
||||
mSelectedItems.put(inputCursor.getPosition(), true);
|
||||
}
|
||||
mIndexCardMap.put(inputCursor.getPosition(), loyaltyCard.id);
|
||||
super.onBindViewHolder(inputHolder, inputCursor);
|
||||
}
|
||||
|
||||
private List<Group> getGroups(int cardId){
|
||||
List<Group> cache = mGetGroupCache.get(cardId);
|
||||
if(cache != null){
|
||||
return cache;
|
||||
}
|
||||
List<Group> groups = mDb.getLoyaltyCardGroups(cardId);
|
||||
mGetGroupCache.put(cardId, groups);
|
||||
return groups;
|
||||
}
|
||||
|
||||
private boolean isLoyaltyCardInGroup(int cardId){
|
||||
Boolean cache = mIsLoyaltyCardInGroupCache.get(cardId);
|
||||
if(cache != null){
|
||||
return cache;
|
||||
}
|
||||
List<Group> groups = getGroups(cardId);
|
||||
if (groups.contains(mGroup)){
|
||||
mIsLoyaltyCardInGroupCache.put(cardId, true);
|
||||
return true;
|
||||
}
|
||||
mIsLoyaltyCardInGroupCache.put(cardId, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleSelection(int inputPosition){
|
||||
super.toggleSelection(inputPosition);
|
||||
Integer cardId = mIndexCardMap.get(inputPosition);
|
||||
if (cardId == null){
|
||||
throw(new RuntimeException("cardId should not be null here"));
|
||||
}
|
||||
Boolean overlayValue = mInGroupOverlay.get(cardId);
|
||||
if (overlayValue == null){
|
||||
mInGroupOverlay.put(cardId, !isLoyaltyCardInGroup(cardId));
|
||||
}else{
|
||||
mInGroupOverlay.remove(cardId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasChanged() {
|
||||
return mInGroupOverlay.size() > 0;
|
||||
}
|
||||
|
||||
public void commitToDatabase(){
|
||||
for(Map.Entry<Integer, Boolean> entry: mInGroupOverlay.entrySet()){
|
||||
int cardId = entry.getKey();
|
||||
List<Group> groups = getGroups(cardId);
|
||||
if(entry.getValue()){
|
||||
groups.add(mGroup);
|
||||
}else{
|
||||
groups.remove(mGroup);
|
||||
}
|
||||
mDb.setLoyaltyCardGroups(cardId, groups);
|
||||
}
|
||||
}
|
||||
|
||||
public void importInGroupState(HashMap<Integer, Boolean> cardIdInGroupMap) {
|
||||
mInGroupOverlay = new HashMap<>(cardIdInGroupMap);
|
||||
}
|
||||
|
||||
public HashMap<Integer, Boolean> exportInGroupState(){
|
||||
return new HashMap<>(mInGroupOverlay);
|
||||
}
|
||||
|
||||
public int getCountFromCursor() {
|
||||
return super.getCursor().getCount();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
@@ -9,6 +10,7 @@ import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
@@ -117,7 +119,16 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
builder.setView(input);
|
||||
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
mDb.insertGroup(input.getText().toString());
|
||||
String inputString = input.getText().toString().trim();
|
||||
if(inputString.length() == 0){
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_is_empty, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (mDb.getGroup(inputString) != null) {
|
||||
Toast.makeText(getApplicationContext(), R.string.group_name_already_in_use, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
mDb.insertGroup(inputString);
|
||||
updateGroupList();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
@@ -176,25 +187,9 @@ public class ManageGroupsActivity extends CatimaAppCompatActivity implements Gro
|
||||
|
||||
@Override
|
||||
public void onEditButtonClicked(View view) {
|
||||
final String groupName = getGroupName(view);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.enter_group_name);
|
||||
final EditText input = new EditText(this);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
input.setText(groupName);
|
||||
builder.setView(input);
|
||||
|
||||
builder.setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
String newGroupName = input.getText().toString();
|
||||
mDb.updateGroup(groupName, newGroupName);
|
||||
updateGroupList();
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.cancel());
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
input.requestFocus();
|
||||
Intent intent = new Intent(this, ManageGroupActivity.class);
|
||||
intent.putExtra("group", getGroupName(view));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
65
app/src/main/res/layout/activity_manage_group.xml
Normal file
65
app/src/main/res/layout/activity_manage_group.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
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"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="protect.card_locker.ManageGroupActivity">
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabSave"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
app:srcCompat="@drawable/save_24dp"
|
||||
android:contentDescription="@string/save"
|
||||
android:layout_margin="16dp" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/groups"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/storeNameField"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/storeName">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/editTextGroupName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<include
|
||||
android:id="@+id/include"
|
||||
layout="@layout/content_main" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2" xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="action_search">Search</string>
|
||||
<string name="action_add">Add</string>
|
||||
<plurals name="selectedCardCount">
|
||||
@@ -7,6 +7,7 @@
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> cards selected</item>
|
||||
</plurals>
|
||||
<string name="noGiftCards">Click the + plus button to add a card, or import some from the ⋮ menu first.</string>
|
||||
<string name="noGiftCardsGroup">You don\'t have any loyalty cards yet. Once you\'ve added some you can add them to the group here.</string>
|
||||
<string name="noMatchingGiftCards">Didn\'t find anything. Try changing your search.</string>
|
||||
<string name="storeName">Name</string>
|
||||
<string name="note">Note</string>
|
||||
@@ -123,12 +124,16 @@
|
||||
<string name="exportSuccessful">Card data exported</string>
|
||||
<string name="enter_group_name">Enter group name</string>
|
||||
<string name="groups">Groups</string>
|
||||
<string name="group_edit">Edit Group</string>
|
||||
<string name="noGroups">Click the + plus button to add groups for categorization first.</string>
|
||||
<string name="noGroupCards">This group does not contain any cards</string>
|
||||
<plurals name="groupCardCount">
|
||||
<item quantity="one"><xliff:g>%d</xliff:g> card</item>
|
||||
<item quantity="other"><xliff:g>%d</xliff:g> cards</item>
|
||||
</plurals>
|
||||
<string name="group_name_already_in_use">Group name already in use</string>
|
||||
<string name="group_name_is_empty">Group name cannot be empty</string>
|
||||
<string name="group_updated">Group updated</string>
|
||||
<string name="all">All</string>
|
||||
<string name="deleteConfirmationGroup">Delete group?</string>
|
||||
<string name="failedOpeningFileManager">Install a file manager first.</string>
|
||||
@@ -139,6 +144,7 @@
|
||||
<string name="addManually">Manually enter card ID</string>
|
||||
<string name="addFromImage">Select image from gallery</string>
|
||||
<string name="groupsList">Groups: <xliff:g>%s</xliff:g></string>
|
||||
<string name="editGroup">Editing Group: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentence">Expires: <xliff:g>%s</xliff:g></string>
|
||||
<string name="expiryStateSentenceExpired">Expired: <xliff:g>%s</xliff:g></string>
|
||||
<string name="balanceSentence">Balance: <xliff:g>%s</xliff:g></string>
|
||||
|
||||
Reference in New Issue
Block a user