Skip to content

Commit abbe0f4

Browse files
committed
feat(mods): auto-check for updates on open, spinner while checking, icon-only update button
- ManageModsFragment: run update check automatically when the screen opens (silent, no toasts) in addition to the manual refresh button tap. While a check is in flight, hide the refresh icon and show a ProgressBar in its place instead. - fragment_manage_mods.xml: add manage_mods_update_progress ProgressBar next to the refresh button, gone by default. - item_installed_mod.xml: replace the text Update MineButton with a plain ImageButton using ic_export_mrpack, styled like the other row icon buttons. Still hidden until an update is available. - InstalledModAdapter: ModViewHolder.update field type changed from Button to ImageButton to match the new layout; bind logic unchanged.
1 parent a08667d commit abbe0f4

4 files changed

Lines changed: 55 additions & 22 deletions

File tree

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ManageModsFragment.java

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import android.widget.ArrayAdapter;
77
import android.widget.Button;
88
import android.widget.ImageButton;
9+
import android.widget.ProgressBar;
910
import android.widget.Spinner;
1011
import android.widget.TextView;
1112
import android.widget.Toast;
@@ -37,6 +38,7 @@ public class ManageModsFragment extends Fragment {
3738

3839
private ImageButton mFilterButton;
3940
private ImageButton mRefreshButton;
41+
private ProgressBar mUpdateProgress;
4042
private InstalledModAdapter mAdapter;
4143

4244
public ManageModsFragment() {
@@ -48,14 +50,15 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
4850
ImageButton backButton = view.findViewById(R.id.manage_mods_back);
4951
mFilterButton = view.findViewById(R.id.manage_mods_filter);
5052
mRefreshButton = view.findViewById(R.id.manage_mods_refresh);
53+
mUpdateProgress = view.findViewById(R.id.manage_mods_update_progress);
5154
ImageButton addButton = view.findViewById(R.id.manage_mods_add);
5255
TextView title = view.findViewById(R.id.manage_mods_title);
5356
RecyclerView recycler = view.findViewById(R.id.manage_mods_recycler);
5457
View emptyState = view.findViewById(R.id.manage_mods_empty);
5558

5659
backButton.setOnClickListener(v -> requireActivity().onBackPressed());
5760
mFilterButton.setOnClickListener(v -> showFilterDialog());
58-
mRefreshButton.setOnClickListener(v -> runUpdateCheck());
61+
mRefreshButton.setOnClickListener(v -> runUpdateCheck(false));
5962
addButton.setOnClickListener(v -> openModSearch());
6063

6164
String profileName = getCurrentProfileName();
@@ -81,19 +84,24 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
8184
recycler.setLayoutManager(new LinearLayoutManager(requireContext()));
8285
recycler.setAdapter(mAdapter);
8386

84-
// Update checking is opt-in: only runs when the user taps the refresh
85-
// button (see mRefreshButton's listener above). Auto-checking here used
86-
// to fire a network call per mod the instant this screen opened, which
87-
// also fought with the initial icon-resolution pass and made icons
88-
// flash to the placeholder glyph.
87+
// Auto-check for updates as soon as the screen opens, in addition to
88+
// the manual refresh button. Silent (no "checking…" toast, and no
89+
// "set a filter first" toast) since this fires automatically — if
90+
// there's no filter set yet, it just quietly does nothing until the
91+
// user configures one and hits refresh manually.
92+
runUpdateCheck(true);
8993
}
9094

9195
/**
9296
* Runs the Modrinth update check across all installed mods for this instance.
93-
* Only ever triggered by the user tapping the refresh button — update
94-
* checking is fully opt-in, never automatic.
97+
* Triggered automatically when the screen opens (silent = true) and manually
98+
* via the refresh button (silent = false).
99+
*
100+
* @param silent when true, skips the "checking…"/"set a filter first" toasts —
101+
* used for the automatic on-open check so it doesn't nag the
102+
* user if they haven't configured a version/loader filter yet.
95103
*/
96-
private void runUpdateCheck() {
104+
private void runUpdateCheck(boolean silent) {
97105
if (mAdapter == null) return;
98106

99107
String profileKey = getCurrentProfileKey();
@@ -103,17 +111,31 @@ private void runUpdateCheck() {
103111
String loader = prefs.getString(KEY_LOADER + profileKey, "");
104112

105113
if (version.isEmpty() && loader.isEmpty()) {
106-
Toast.makeText(requireContext(),
107-
R.string.mod_update_no_filter, Toast.LENGTH_SHORT).show();
114+
if (!silent) {
115+
Toast.makeText(requireContext(),
116+
R.string.mod_update_no_filter, Toast.LENGTH_SHORT).show();
117+
}
108118
return;
109119
}
110120

111121
mAdapter.setFilter(version, loader);
112122

123+
// While checking: hide the refresh button and show just a spinner in
124+
// its place. No per-mod update button appears until its own check
125+
// resolves, so this spinner is the only thing indicating progress.
113126
mRefreshButton.setEnabled(false);
114-
Toast.makeText(requireContext(), R.string.mod_update_checking, Toast.LENGTH_SHORT).show();
127+
mRefreshButton.setVisibility(View.GONE);
128+
if (mUpdateProgress != null) mUpdateProgress.setVisibility(View.VISIBLE);
129+
130+
if (!silent) {
131+
Toast.makeText(requireContext(), R.string.mod_update_checking, Toast.LENGTH_SHORT).show();
132+
}
115133

116-
mAdapter.checkForUpdates(() -> mRefreshButton.setEnabled(true));
134+
mAdapter.checkForUpdates(() -> {
135+
mRefreshButton.setEnabled(true);
136+
mRefreshButton.setVisibility(View.VISIBLE);
137+
if (mUpdateProgress != null) mUpdateProgress.setVisibility(View.GONE);
138+
});
117139
}
118140

119141
// ── Filter dialog ────────────────────────────────────────────────────────

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/InstalledModAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ class ModViewHolder extends RecyclerView.ViewHolder {
740740
final ImageView icon;
741741
final TextView name, version;
742742
final SwitchCompat toggle;
743-
final android.widget.Button update;
743+
final ImageButton update;
744744
final ImageButton delete;
745745
final ImageButton switchVersion;
746746

app_pojavlauncher/src/main/res/layout/fragment_manage_mods.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@
3636
android:ellipsize="end"
3737
android:text="@string/mcl_button_manage_mods" />
3838

39+
<!-- Shown in place of the refresh button while an update check is running -->
40+
<ProgressBar
41+
android:id="@+id/manage_mods_update_progress"
42+
style="?android:attr/progressBarStyleSmall"
43+
android:layout_width="@dimen/_38sdp"
44+
android:layout_height="@dimen/_38sdp"
45+
android:layout_marginEnd="@dimen/padding_small"
46+
android:padding="@dimen/padding_moderate"
47+
android:visibility="gone" />
48+
3949
<ImageButton
4050
android:id="@+id/manage_mods_refresh"
4151
android:layout_width="@dimen/_38sdp"

app_pojavlauncher/src/main/res/layout/item_installed_mod.xml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,18 @@
7474
app:layout_constraintVertical_bias="0.0"
7575
tools:text="This mod uses async path-tracing to hide Tiles/Entities that are not vi…" />
7676

77-
<!-- Update button — hidden until an update is available, uses MineButton style -->
78-
<com.kdt.mcgui.MineButton
77+
<!-- Update button — hidden until an update is available. Icon-only button
78+
using ic_export_mrpack, matching the switch-version/delete ImageButton style. -->
79+
<ImageButton
7980
android:id="@+id/installed_mod_update"
80-
android:layout_width="wrap_content"
81-
android:layout_height="wrap_content"
81+
android:layout_width="@dimen/_38sdp"
82+
android:layout_height="@dimen/_38sdp"
8283
android:layout_marginEnd="@dimen/padding_small"
83-
android:text="@string/mod_update"
84-
android:textSize="@dimen/_10ssp"
85-
android:paddingHorizontal="@dimen/padding_moderate"
86-
android:paddingVertical="@dimen/padding_small"
84+
android:background="?android:attr/selectableItemBackgroundBorderless"
85+
android:src="@drawable/ic_export_mrpack"
86+
android:padding="@dimen/padding_moderate"
8787
android:visibility="gone"
88+
android:contentDescription="@string/mod_update"
8889
app:layout_constraintEnd_toStartOf="@+id/installed_mod_switch_version"
8990
app:layout_constraintTop_toTopOf="parent"
9091
app:layout_constraintBottom_toBottomOf="parent" />

0 commit comments

Comments
 (0)