Skip to content

Commit 9fa8d77

Browse files
committed
feat: added swipe refresh layout for ease of use, refactoring, improved password strength indicator, version bump
1 parent c348d56 commit 9fa8d77

File tree

7 files changed

+102
-67
lines changed

7 files changed

+102
-67
lines changed

app/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "com.codedead.advancedpassgen"
1111
minSdk 29
1212
targetSdk 35
13-
versionCode 2
14-
versionName "1.0.1"
13+
versionCode 3
14+
versionName "1.0.2"
1515

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}
@@ -46,6 +46,7 @@ dependencies {
4646
implementation libs.navigation.ui
4747
implementation libs.preference
4848
implementation libs.recyclerview
49+
implementation libs.swiperefreshlayout
4950
testImplementation libs.junit
5051
androidTestImplementation libs.ext.junit
5152
androidTestImplementation libs.espresso.core

app/src/main/java/com/codedead/advancedpassgen/domain/PasswordAdapter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.content.ClipDescription;
66
import android.content.ClipboardManager;
77
import android.content.Context;
8+
import android.graphics.Color;
89
import android.os.Build;
910
import android.os.PersistableBundle;
1011
import android.view.LayoutInflater;
@@ -13,6 +14,7 @@
1314

1415
import androidx.annotation.NonNull;
1516
import androidx.core.content.ContextCompat;
17+
import androidx.core.graphics.drawable.DrawableCompat;
1618
import androidx.recyclerview.widget.RecyclerView;
1719

1820
import com.codedead.advancedpassgen.R;
@@ -92,6 +94,14 @@ public void onBindViewHolder(@NonNull final PasswordViewHolder holder, final int
9294
holder.getPasswordTextView().setText(item.password());
9395
holder.getStrengthProgressBar().setProgress(item.strength());
9496

97+
if (item.strength() == 100) {
98+
DrawableCompat.setTint(holder.getStrengthProgressBar().getProgressDrawable(), Color.GREEN);
99+
} else if (item.strength() < 35) {
100+
DrawableCompat.setTint(holder.getStrengthProgressBar().getProgressDrawable(), Color.RED);
101+
} else if (item.strength() < 75) {
102+
DrawableCompat.setTint(holder.getStrengthProgressBar().getProgressDrawable(), Color.parseColor("#FFA500"));
103+
}
104+
95105
holder.getCopyButton().setOnClickListener(e -> {
96106
// Copy the password to the clipboard
97107
final ClipboardManager clipboard = ContextCompat.getSystemService(context, ClipboardManager.class);
Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
package com.codedead.advancedpassgen.ui.home;
22

33
import android.content.SharedPreferences;
4-
import android.content.res.Configuration;
54
import android.os.Bundle;
65
import android.view.LayoutInflater;
76
import android.view.View;
87
import android.view.ViewGroup;
98

109
import androidx.annotation.NonNull;
1110
import androidx.fragment.app.Fragment;
11+
import androidx.fragment.app.FragmentActivity;
1212
import androidx.preference.PreferenceManager;
1313
import androidx.recyclerview.widget.LinearLayoutManager;
1414
import androidx.recyclerview.widget.RecyclerView;
15+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
1516

1617
import com.codedead.advancedpassgen.databinding.FragmentHomeBinding;
17-
import com.codedead.advancedpassgen.domain.LocaleHelper;
1818
import com.codedead.advancedpassgen.domain.PasswordAdapter;
1919
import com.codedead.advancedpassgen.domain.PasswordGenerator;
2020
import com.codedead.advancedpassgen.domain.PasswordItem;
@@ -23,11 +23,11 @@
2323
import java.util.List;
2424
import java.util.concurrent.Executors;
2525

26-
public class HomeFragment extends Fragment {
26+
public class HomeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
2727

2828
private FragmentHomeBinding binding;
2929
private SharedPreferences sharedPreferences;
30-
private String lastLanguage;
30+
private PasswordAdapter adapter;
3131
private String customCharacterSet;
3232
private int minimumLength;
3333
private int maximumLength;
@@ -45,15 +45,18 @@ public View onCreateView(@NonNull final LayoutInflater inflater,
4545
binding = FragmentHomeBinding.inflate(inflater, container, false);
4646
View root = binding.getRoot();
4747

48+
binding.swipeRefresh.setOnRefreshListener(this);
49+
binding.textHome.setOnRefreshListener(this);
50+
4851
final RecyclerView recyclerView = binding.recyclerView;
49-
final PasswordAdapter adapter = new PasswordAdapter(requireContext());
52+
adapter = new PasswordAdapter(requireContext());
5053

5154
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false));
5255
recyclerView.setAdapter(adapter);
5356

5457
binding.fabAdd.setOnClickListener(view -> {
5558
binding.textHome.setVisibility(View.GONE);
56-
binding.recyclerView.setVisibility(View.VISIBLE);
59+
binding.swipeRefresh.setVisibility(View.VISIBLE);
5760

5861
binding.fabClear.setEnabled(false);
5962
binding.fabRefresh.setEnabled(false);
@@ -73,36 +76,12 @@ public View onCreateView(@NonNull final LayoutInflater inflater,
7376
adapter.clear();
7477

7578
binding.textHome.setVisibility(View.VISIBLE);
76-
binding.recyclerView.setVisibility(View.GONE);
79+
binding.swipeRefresh.setVisibility(View.GONE);
7780
});
7881

79-
binding.fabRefresh.setOnClickListener(view -> {
80-
binding.textHome.setVisibility(View.GONE);
81-
binding.loadingLayout.setVisibility(View.VISIBLE);
82-
83-
binding.fabClear.setEnabled(false);
84-
binding.fabRefresh.setEnabled(false);
85-
binding.fabAdd.setEnabled(false);
86-
87-
Executors.newSingleThreadExecutor().execute(() -> {
88-
final List<PasswordItem> items = PasswordGenerator.generatePasswords(minimumLength, maximumLength, passwordAmount, smallLetters, capitalLetters, numbers, specialCharacters, brackets, spaces, customCharacterSet);
89-
requireActivity().runOnUiThread(() -> {
90-
if (binding == null)
91-
return;
92-
93-
binding.loadingLayout.setVisibility(View.GONE);
94-
binding.recyclerView.setVisibility(View.VISIBLE);
95-
adapter.insert(items);
96-
97-
binding.fabClear.setEnabled(true);
98-
binding.fabRefresh.setEnabled(true);
99-
binding.fabAdd.setEnabled(true);
100-
});
101-
});
102-
});
82+
binding.fabRefresh.setOnClickListener(view -> refreshPasswords());
10383

10484
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
105-
lastLanguage = sharedPreferences.getString("appLanguage", "en");
10685
customCharacterSet = sharedPreferences.getString("customCharacterSet", "");
10786
minimumLength = Integer.parseInt(sharedPreferences.getString("minimumLength", "8"));
10887
maximumLength = Integer.parseInt(sharedPreferences.getString("maximumLength", "30"));
@@ -121,16 +100,45 @@ public View onCreateView(@NonNull final LayoutInflater inflater,
121100
return root;
122101
}
123102

124-
@Override
125-
public void onResume() {
126-
final String selectedLanguage = sharedPreferences.getString("appLanguage", "en");
103+
/**
104+
* Refresh the passwords
105+
*/
106+
private void refreshPasswords() {
107+
binding.textHome.setVisibility(View.GONE);
108+
binding.loadingLayout.setVisibility(View.VISIBLE);
109+
binding.swipeRefresh.setVisibility(View.GONE);
110+
111+
binding.fabClear.setEnabled(false);
112+
binding.fabRefresh.setEnabled(false);
113+
binding.fabAdd.setEnabled(false);
114+
115+
Executors.newSingleThreadExecutor().execute(() -> {
116+
final List<PasswordItem> items = PasswordGenerator.generatePasswords(minimumLength, maximumLength, passwordAmount, smallLetters, capitalLetters, numbers, specialCharacters, brackets, spaces, customCharacterSet);
127117

128-
if (!lastLanguage.equals(selectedLanguage)) {
129-
LocaleHelper.setLocale(getContext(), selectedLanguage);
130-
// recreate();
131-
}
118+
final FragmentActivity activity = getActivity();
119+
if (activity == null)
120+
return;
132121

133-
lastLanguage = sharedPreferences.getString("appLanguage", "en");
122+
activity.runOnUiThread(() -> {
123+
if (binding == null || adapter == null)
124+
return;
125+
126+
binding.loadingLayout.setVisibility(View.GONE);
127+
binding.swipeRefresh.setVisibility(View.VISIBLE);
128+
adapter.insert(items);
129+
130+
binding.fabClear.setEnabled(true);
131+
binding.fabRefresh.setEnabled(true);
132+
binding.fabAdd.setEnabled(true);
133+
134+
binding.swipeRefresh.setRefreshing(false);
135+
binding.textHome.setRefreshing(false);
136+
});
137+
});
138+
}
139+
140+
@Override
141+
public void onResume() {
134142
customCharacterSet = sharedPreferences.getString("customCharacterSet", "");
135143
minimumLength = Integer.parseInt(sharedPreferences.getString("minimumLength", "8"));
136144
maximumLength = Integer.parseInt(sharedPreferences.getString("maximumLength", "30"));
@@ -149,15 +157,14 @@ public void onResume() {
149157
UtilController.applyFlagSecure(getActivity(), preventScreenshot);
150158
}
151159

152-
@Override
153-
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
154-
super.onConfigurationChanged(newConfig);
155-
LocaleHelper.onAttach(getContext());
156-
}
157-
158160
@Override
159161
public void onDestroyView() {
160162
super.onDestroyView();
161163
binding = null;
162164
}
165+
166+
@Override
167+
public void onRefresh() {
168+
refreshPasswords();
169+
}
163170
}

app/src/main/res/layout/fragment_home.xml

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,61 @@
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
xmlns:tools="http://schemas.android.com/tools"
5+
android:id="@+id/nav_home"
56
android:layout_width="match_parent"
67
android:layout_height="match_parent"
78
android:layout_gravity="center"
89
android:gravity="center"
910
android:orientation="vertical"
10-
android:id="@+id/nav_home"
1111
tools:context=".ui.home.HomeFragment">
1212

13-
<TextView
13+
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
1414
android:id="@+id/text_home"
1515
android:layout_width="match_parent"
16-
android:layout_height="wrap_content"
17-
android:layout_marginStart="8dp"
18-
android:layout_marginTop="8dp"
19-
android:layout_marginEnd="8dp"
16+
android:layout_height="match_parent"
17+
android:layout_gravity="center"
2018
android:layout_weight="1"
21-
android:gravity="center"
22-
android:text="@string/refresh_to_start"
23-
android:textAlignment="center"
24-
android:textSize="20sp" />
19+
android:gravity="center">
20+
21+
<TextView
22+
android:layout_width="match_parent"
23+
android:layout_height="wrap_content"
24+
android:layout_marginLeft="8dp"
25+
android:layout_marginRight="8dp"
26+
android:layout_weight="1"
27+
android:gravity="center"
28+
android:text="@string/refresh_to_start"
29+
android:textAlignment="center"
30+
android:textSize="20sp" />
31+
32+
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
2533

2634
<LinearLayout
2735
android:id="@+id/loadingLayout"
2836
android:layout_width="match_parent"
2937
android:layout_height="match_parent"
3038
android:layout_weight="1"
31-
android:visibility="gone"
32-
android:gravity="center">
39+
android:gravity="center"
40+
android:visibility="gone">
3341

3442
<ProgressBar
3543
android:layout_width="match_parent"
3644
android:layout_height="wrap_content"
3745
android:indeterminate="true" />
3846
</LinearLayout>
3947

40-
<androidx.recyclerview.widget.RecyclerView
41-
android:id="@+id/recycler_view"
48+
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
49+
android:id="@+id/swipe_refresh"
4250
android:layout_width="match_parent"
43-
android:layout_height="0dp"
44-
android:layout_marginBottom="5dp"
51+
android:layout_height="match_parent"
4552
android:layout_weight="1"
46-
android:visibility="gone" />
53+
android:visibility="gone">
54+
55+
<androidx.recyclerview.widget.RecyclerView
56+
android:id="@+id/recycler_view"
57+
android:layout_width="match_parent"
58+
android:layout_height="match_parent" />
59+
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
4760

4861
<LinearLayout
4962
android:layout_width="match_parent"

app/src/main/res/layout/password_item_view.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
android:id="@+id/password_strength"
2727
style="?android:attr/progressBarStyleHorizontal"
2828
android:layout_width="match_parent"
29-
android:layout_height="match_parent" />
29+
android:layout_height="match_parent"
30+
android:max="100"
31+
android:min="0" />
3032

3133
</LinearLayout>
3234

app/src/main/res/values-nl/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<string name="small_letters_summary">Gebruik kleine letters in het gegenereerde wachtwoord</string>
4444
<string name="capital_letters">Hoofdletters</string>
4545
<string name="capital_letters_summary">Gebruik hoofdletters in het gegenereerde wachtwoord</string>
46-
<string name="spaces">Ruimtes</string>
46+
<string name="spaces">Spaties</string>
4747
<string name="spaces_summary">Spaties toevoegen aan het gegenereerde wachtwoord</string>
4848
<string name="special_characters">Speciale tekens</string>
4949
<string name="special_characters_summary">Speciale tekens toevoegen aan het gegenereerde wachtwoord</string>

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ navigationFragment = "2.8.9"
1212
navigationUi = "2.8.9"
1313
preference = "1.2.1"
1414
recyclerview = "1.4.0"
15+
swiperefreshlayout = "1.2.0-beta01"
1516

1617
[libraries]
1718
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -26,6 +27,7 @@ navigation-fragment = { group = "androidx.navigation", name = "navigation-fragme
2627
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
2728
preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
2829
recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
30+
swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" }
2931

3032
[plugins]
3133
android-application = { id = "com.android.application", version.ref = "agp" }

0 commit comments

Comments
 (0)