Skip to content
This repository was archived by the owner on Mar 5, 2023. It is now read-only.

Commit c74fec8

Browse files
committed
Fix mods tab in Android launcher, add some progress reporter
1 parent 5e56ad0 commit c74fec8

File tree

15 files changed

+444
-52
lines changed

15 files changed

+444
-52
lines changed

ext/vcmi

Submodule vcmi updated 108 files

project/vcmi-app/src/main/java/eu/vcmi/vcmi/ActivityMods.java

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
import android.os.AsyncTask;
44
import android.os.Bundle;
5-
import android.os.Environment;
5+
66
import androidx.annotation.Nullable;
77
import com.google.android.material.snackbar.Snackbar;
88
import androidx.recyclerview.widget.DefaultItemAnimator;
99
import androidx.recyclerview.widget.DividerItemDecoration;
1010
import androidx.recyclerview.widget.LinearLayoutManager;
1111
import androidx.recyclerview.widget.RecyclerView;
12-
import androidx.appcompat.widget.Toolbar;
12+
1313
import android.view.Menu;
1414
import android.view.MenuInflater;
1515
import android.view.MenuItem;
@@ -24,24 +24,24 @@
2424
import java.util.ArrayList;
2525
import java.util.Collections;
2626
import java.util.List;
27-
import java.util.stream.Stream;
28-
import java.util.stream.Collectors;
2927

3028
import eu.vcmi.vcmi.content.ModBaseViewHolder;
3129
import eu.vcmi.vcmi.content.ModsAdapter;
32-
import eu.vcmi.vcmi.content.ModsViewHolder;
30+
import eu.vcmi.vcmi.mods.VCMIMod;
3331
import eu.vcmi.vcmi.mods.VCMIModContainer;
3432
import eu.vcmi.vcmi.mods.VCMIModsRepo;
33+
import eu.vcmi.vcmi.util.InstallModAsync;
3534
import eu.vcmi.vcmi.util.FileUtil;
3635
import eu.vcmi.vcmi.util.Log;
36+
import eu.vcmi.vcmi.util.ServerResponse;
3737

3838
/**
3939
* @author F
4040
*/
4141
public class ActivityMods extends ActivityWithToolbar
4242
{
43-
private static final boolean ENABLE_REPO_DOWNLOADING = false;
44-
private static final String REPO_URL = "http://download.vcmi.eu/mods/repository/repository.json";
43+
private static final boolean ENABLE_REPO_DOWNLOADING = true;
44+
private static final String REPO_URL = "https://raw.githubusercontent.com/vcmi/vcmi-mods-repository/develop/github.json";
4545
private VCMIModsRepo mRepo;
4646
private RecyclerView mRecycler;
4747

@@ -70,15 +70,18 @@ protected void onCreate(@Nullable final Bundle savedInstanceState)
7070
mRecycler.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
7171
mRecycler.setVisibility(View.GONE);
7272

73+
mModsAdapter = new ModsAdapter(new OnAdapterItemAction());
74+
mRecycler.setAdapter(mModsAdapter);
75+
7376
new AsyncLoadLocalMods().execute((Void) null);
7477
}
7578

7679
private void loadLocalModData() throws IOException, JSONException
7780
{
78-
final String dataRoot = getDataDir() + "/" + Const.VCMI_DATA_ROOT_FOLDER_NAME;
81+
final File dataRoot = Storage.getVcmiDataDir(this);
7982
final String internalDataRoot = getFilesDir() + "/" + Const.VCMI_DATA_ROOT_FOLDER_NAME;
8083

81-
final File modsRoot = new File(dataRoot + "/Mods");
84+
final File modsRoot = new File(dataRoot,"/Mods");
8285
final File internalModsRoot = new File(internalDataRoot + "/Mods");
8386
if (!modsRoot.exists() && !internalModsRoot.exists())
8487
{
@@ -98,8 +101,7 @@ private void loadLocalModData() throws IOException, JSONException
98101
}
99102
mModContainer = VCMIModContainer.createContainer(topLevelModsFolders);
100103

101-
final String configPath = dataRoot + "/config/modSettings.json";
102-
final File modConfigFile = new File(configPath);
104+
final File modConfigFile = new File(dataRoot, "config/modSettings.json");
103105
if (!modConfigFile.exists())
104106
{
105107
Log.w(this, "We don't have mods config");
@@ -129,6 +131,7 @@ public boolean onOptionsItemSelected(final MenuItem item)
129131
Log.i(this, "Should download repo now...");
130132
if (ENABLE_REPO_DOWNLOADING)
131133
{
134+
mProgress.setVisibility(View.VISIBLE);
132135
mRepo.init(REPO_URL, new OnModsRepoInitialized()); // disabled because the json is broken anyway
133136
}
134137
else
@@ -150,16 +153,21 @@ private void handleNoData()
150153

151154
private void saveModSettingsToFile()
152155
{
153-
mModContainer.saveToFile(new File(getDataDir(), Const.VCMI_DATA_ROOT_FOLDER_NAME + "/config/modSettings.json"));
156+
mModContainer.saveToFile(
157+
new File(
158+
Storage.getVcmiDataDir(this),
159+
"config/modSettings.json"));
154160
}
155161

156162
private class OnModsRepoInitialized implements VCMIModsRepo.IOnModsRepoDownloaded
157163
{
158164
@Override
159-
public void onSuccess()
165+
public void onSuccess(ServerResponse<List<VCMIMod>> response)
160166
{
161167
Log.i(this, "Initialized mods repo");
162-
// TODO update dataset
168+
mModContainer.updateFromRepo(response.mContent);
169+
mModsAdapter.updateModsList(mModContainer.submods());
170+
mProgress.setVisibility(View.GONE);
163171
}
164172

165173
@Override
@@ -206,13 +214,7 @@ protected void onPostExecute(final Void aVoid)
206214
{
207215
mProgress.setVisibility(View.GONE);
208216
mRecycler.setVisibility(View.VISIBLE);
209-
mModsAdapter = new ModsAdapter(
210-
mModContainer.submods()
211-
.stream()
212-
.map(ModsAdapter.ModItem::new)
213-
.collect(Collectors.toList()),
214-
new OnAdapterItemAction());
215-
mRecycler.setAdapter(mModsAdapter);
217+
mModsAdapter.updateModsList(mModContainer.submods());
216218
}
217219
}
218220
}
@@ -242,14 +244,58 @@ public void onItemPressed(final ModsAdapter.ModItem mod, final RecyclerView.View
242244
public void onDownloadPressed(final ModsAdapter.ModItem mod, final RecyclerView.ViewHolder vh)
243245
{
244246
Log.i(this, "Mod download pressed: " + mod);
247+
mModsAdapter.downloadProgress(mod, "0%");
248+
installModAsync(mod);
245249
}
246250

247251
@Override
248252
public void onTogglePressed(final ModsAdapter.ModItem item, final ModBaseViewHolder holder)
249253
{
250-
item.mMod.mActive = !item.mMod.mActive;
251-
mModsAdapter.notifyItemChanged(holder.getAdapterPosition());
252-
saveModSettingsToFile();
254+
if(item.mMod.mInstalled)
255+
{
256+
item.mMod.mActive = !item.mMod.mActive;
257+
mModsAdapter.notifyItemChanged(holder.getAdapterPosition());
258+
saveModSettingsToFile();
259+
}
260+
}
261+
}
262+
263+
private void installModAsync(ModsAdapter.ModItem mod){
264+
File dataDir = Storage.getVcmiDataDir(this);
265+
266+
InstallModAsync modInstaller = new InstallModAsync(
267+
new File(dataDir, "Mods"),
268+
this,
269+
new InstallModCallback(mod)
270+
);
271+
272+
modInstaller.execute(mod.mMod.mArchiveUrl);
273+
}
274+
275+
public class InstallModCallback implements InstallModAsync.PostDownload
276+
{
277+
private ModsAdapter.ModItem mod;
278+
279+
public InstallModCallback(ModsAdapter.ModItem mod)
280+
{
281+
this.mod = mod;
282+
}
283+
284+
@Override
285+
public void downloadDone(Boolean succeed, File modFolder)
286+
{
287+
if(succeed){
288+
mModsAdapter.modInstalled(mod, modFolder);
289+
}
290+
}
291+
292+
@Override
293+
public void downloadProgress(String... progress)
294+
{
295+
if(progress.length > 0)
296+
{
297+
mModsAdapter.downloadProgress(mod, progress[0]);
298+
}
253299
}
254300
}
255301
}

project/vcmi-app/src/main/java/eu/vcmi/vcmi/Const.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,4 @@ public class Const
2121
public static final int SUPPRESS_TRY_WITH_RESOURCES_WARNING = Build.VERSION_CODES.KITKAT;
2222

2323
public static final String VCMI_DATA_ROOT_FOLDER_NAME = "vcmi-data";
24-
25-
public static final String VCMI_DATA_ZIP_FILE_NAME = "vcmi-data.zip";
26-
public static final String STORAGE_CONFIG_FILE_NAME = "storage.config";
27-
public static final boolean INTERNAL_STORAGE_AVAILABLE = Build.VERSION.SDK_INT >= 24;
2824
}

project/vcmi-app/src/main/java/eu/vcmi/vcmi/Storage.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,4 @@ public static boolean testH3DataFolder(final File baseDir)
2828
public static String getH3DataFolder(Context context){
2929
return getVcmiDataDir(context).getAbsolutePath();
3030
}
31-
32-
private static File getStorageSettingsFile(Context context)
33-
{
34-
return new File(context.getFilesDir(),"storage.config");
35-
}
3631
}

project/vcmi-app/src/main/java/eu/vcmi/vcmi/content/AsyncLauncherInitialization.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ private InitResult handleDataFoldersInitialization()
6666
Log.i(this, "Using " + vcmiDir.getAbsolutePath() + " as root vcmi dir");
6767

6868
if(!vcmiInternalDir.exists()) vcmiInternalDir.mkdir();
69+
if(!vcmiDir.exists()) vcmiDir.mkdir();
6970

7071
if (!Storage.testH3DataFolder(ctx))
7172
{

project/vcmi-app/src/main/java/eu/vcmi/vcmi/content/ModsAdapter.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.view.View;
66
import android.view.ViewGroup;
77

8+
import java.io.File;
89
import java.util.stream.Collectors;
910
import java.util.stream.Stream;
1011

@@ -27,10 +28,9 @@ public class ModsAdapter extends RecyclerView.Adapter<ModBaseViewHolder>
2728
private final List<ModItem> mDataset = new ArrayList<>();
2829
private final IOnItemAction mItemListener;
2930

30-
public ModsAdapter(final List<ModItem> mods, final IOnItemAction itemListener)
31+
public ModsAdapter(final IOnItemAction itemListener)
3132
{
3233
mItemListener = itemListener;
33-
mDataset.addAll(mods);
3434
}
3535

3636
@Override
@@ -75,8 +75,17 @@ public void onBindViewHolder(final ModBaseViewHolder holder, final int position)
7575
modHolder.mModAuthor.setText(ctx.getString(R.string.mods_item_author_template, item.mMod.mAuthor));
7676
modHolder.mStatusIcon.setImageResource(selectModStatusIcon(item.mMod.mActive));
7777

78+
modHolder.mDownloadBtn.setVisibility(View.GONE);
79+
modHolder.mDownloadProgress.setVisibility(View.GONE);
7880

79-
modHolder.mDownloadBtn.setVisibility(View.GONE); // TODO visible for mods that aren't downloaded
81+
if(item.mDownloadProgress != null)
82+
{
83+
modHolder.mDownloadProgress.setText(item.mDownloadProgress);
84+
modHolder.mDownloadProgress.setVisibility(View.VISIBLE);
85+
}
86+
else if(!item.mMod.mInstalled){
87+
modHolder.mDownloadBtn.setVisibility(View.VISIBLE);
88+
}
8089

8190
modHolder.itemView.setOnClickListener(v -> mItemListener.onItemPressed(item, holder));
8291
modHolder.mStatusIcon.setOnClickListener(v -> mItemListener.onTogglePressed(item, holder));
@@ -138,6 +147,39 @@ public void detachSubmods(final ModItem mod, final RecyclerView.ViewHolder vh)
138147
notifyItemRangeRemoved(checkedPosition, detachedElements);
139148
}
140149

150+
public void updateModsList(List<VCMIMod> mods)
151+
{
152+
mDataset.clear();
153+
mDataset.addAll(
154+
mods.stream()
155+
.map(ModItem::new)
156+
.collect(Collectors.toList()));
157+
158+
notifyDataSetChanged();
159+
}
160+
161+
public void modInstalled(ModItem mod, File modFolder)
162+
{
163+
try
164+
{
165+
mod.mMod.updateFromModInfo(modFolder);
166+
mod.mMod.mLoadedCorrectly = true;
167+
mod.mMod.mActive = true; // active by default
168+
mod.mMod.mInstalled = true;
169+
mod.mDownloadProgress = null;
170+
notifyItemChanged(mDataset.indexOf(mod));
171+
} catch (Exception ex)
172+
{
173+
Log.e("Failed to install mod", ex);
174+
}
175+
}
176+
177+
public void downloadProgress(ModItem mod, String progress)
178+
{
179+
mod.mDownloadProgress = progress;
180+
notifyItemChanged(mDataset.indexOf(mod));
181+
}
182+
141183
public interface IOnItemAction
142184
{
143185
void onItemPressed(final ModItem mod, final RecyclerView.ViewHolder vh);
@@ -152,6 +194,7 @@ public static class ModItem
152194
public final VCMIMod mMod;
153195
public int mNestingLevel;
154196
public boolean mExpanded;
197+
public String mDownloadProgress;
155198

156199
public ModItem(final VCMIMod mod)
157200
{

project/vcmi-app/src/main/java/eu/vcmi/vcmi/content/ModsViewHolder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class ModsViewHolder extends ModBaseViewHolder
1818
final TextView mModSize;
1919
final ImageView mStatusIcon;
2020
final View mDownloadBtn;
21+
final TextView mDownloadProgress;
2122

2223
ModsViewHolder(final View parentView)
2324
{
@@ -27,5 +28,6 @@ public class ModsViewHolder extends ModBaseViewHolder
2728
mModSize = (TextView) itemView.findViewById(R.id.mods_adapter_item_size);
2829
mDownloadBtn = itemView.findViewById(R.id.mods_adapter_item_btn_download);
2930
mStatusIcon = (ImageView) itemView.findViewById(R.id.mods_adapter_item_status);
31+
mDownloadProgress = (TextView) itemView.findViewById(R.id.mods_adapter_item_install_progress);
3032
}
3133
}

project/vcmi-app/src/main/java/eu/vcmi/vcmi/mods/VCMIMod.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class VCMIMod
3737

3838
// config values
3939
public boolean mActive;
40+
public boolean mInstalled;
4041
public boolean mValidated;
4142
public String mChecksum;
4243

@@ -48,7 +49,9 @@ protected VCMIMod()
4849
mSubmods = new HashMap<>();
4950
}
5051

51-
public static VCMIMod buildFromRepoJson(final String id, final JSONObject obj)
52+
public static VCMIMod buildFromRepoJson(final String id,
53+
final JSONObject obj,
54+
JSONObject modDownloadData)
5255
{
5356
final VCMIMod mod = new VCMIMod();
5457
mod.mId = id.toLowerCase(Locale.US);
@@ -58,7 +61,7 @@ public static VCMIMod buildFromRepoJson(final String id, final JSONObject obj)
5861
mod.mAuthor = obj.optString("author");
5962
mod.mContact = obj.optString("contact");
6063
mod.mModType = obj.optString("modType");
61-
mod.mArchiveUrl = obj.optString("download");
64+
mod.mArchiveUrl = modDownloadData.optString("download");
6265
mod.mSize = obj.optLong("size");
6366
mod.mLoadedCorrectly = true;
6467
return mod;
@@ -68,6 +71,7 @@ public static VCMIMod buildFromConfigJson(final String id, final JSONObject obj)
6871
{
6972
final VCMIMod mod = new VCMIMod();
7073
mod.updateFromConfigJson(id, obj);
74+
mod.mInstalled = true;
7175
return mod;
7276
}
7377

@@ -80,6 +84,7 @@ public static VCMIMod buildFromModInfo(final File modPath) throws IOException, J
8084
}
8185
mod.mLoadedCorrectly = true;
8286
mod.mActive = true; // active by default
87+
mod.mInstalled = true;
8388
return mod;
8489
}
8590

@@ -220,4 +225,12 @@ public List<VCMIMod> submods()
220225
ret.addAll(mSubmods.values());
221226
return ret;
222227
}
228+
229+
protected void updateFrom(VCMIMod other)
230+
{
231+
this.mModType = other.mModType;
232+
this.mAuthor = other.mAuthor;
233+
this.mDesc = other.mDesc;
234+
this.mArchiveUrl = other.mArchiveUrl;
235+
}
223236
}

0 commit comments

Comments
 (0)