mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-20 18:48:16 -04:00
Merge remote-tracking branch 'origin/develop' into feature/macgills/#1258-leakcanary-ci
# Conflicts: # app/build.gradle
This commit is contained in:
commit
9f1149b507
@ -76,6 +76,7 @@ before_deploy:
|
||||
- export UNIVERSAL_RELEASE_APK=$OUTPUT_DIR/release/*universal*.apk
|
||||
- export UNIVERSAL_DEBUG_APK=$OUTPUT_DIR/debug/*universal*.apk
|
||||
- export SSH_KEY=travisci_builder_id_key
|
||||
- chmod 600 $SSH_KEY
|
||||
|
||||
deploy:
|
||||
|
||||
|
@ -56,9 +56,6 @@ dependencies {
|
||||
archs = file("../kiwixlib/src/main/jniLibs").list()
|
||||
}
|
||||
|
||||
// Storage Devices
|
||||
implementation "eu.mhutti1.utils.storage:android-storage-devices:0.6.2"
|
||||
|
||||
// Android Support
|
||||
implementation "androidx.appcompat:appcompat:$appCompatVersion"
|
||||
implementation "com.google.android.material:material:$materialVersion"
|
||||
@ -232,9 +229,11 @@ android {
|
||||
//TODO stop ignoring
|
||||
ignore 'MissingTranslation',
|
||||
'CheckResult',
|
||||
'LabelFor',
|
||||
'DuplicateStrings',
|
||||
'LogConditional'
|
||||
warning 'UnknownNullness'
|
||||
warning 'UnknownNullness',
|
||||
'SelectableText'
|
||||
baseline file("lint-baseline.xml")
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2016 Isaac Hutt <mhutti1@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package eu.mhutti1.utils.storage;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
class ExternalPaths {
|
||||
|
||||
@SuppressLint("SdCardPath") private static final String[] paths = {
|
||||
"/storage/sdcard0",
|
||||
"/storage/sdcard1",
|
||||
"/storage/extsdcard",
|
||||
"/storage/extSdCard",
|
||||
"/storage/sdcard0/external_sdcard",
|
||||
"/mnt/sdcard/external_sd",
|
||||
"/mnt/external_sd",
|
||||
"/mnt/media_rw/*",
|
||||
"/removable/microsd",
|
||||
"/mnt/emmc",
|
||||
"/storage/external_SD",
|
||||
"/storage/ext_sd",
|
||||
"/storage/removable/sdcard1",
|
||||
"/data/sdext",
|
||||
"/data/sdext2",
|
||||
"/data/sdext3",
|
||||
"/data/sdext2",
|
||||
"/data/sdext3",
|
||||
"/data/sdext4",
|
||||
"/sdcard",
|
||||
"/sdcard1",
|
||||
"/sdcard2",
|
||||
"/storage/microsd",
|
||||
"/mnt/extsd",
|
||||
"/extsd",
|
||||
"/mnt/sdcard",
|
||||
"/misc/android",
|
||||
};
|
||||
|
||||
public static String[] getPossiblePaths() {
|
||||
return paths;
|
||||
}
|
||||
}
|
164
app/src/main/java/eu/mhutti1/utils/storage/StorageDevice.java
Normal file
164
app/src/main/java/eu/mhutti1/utils/storage/StorageDevice.java
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2016 Isaac Hutt <mhutti1@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package eu.mhutti1.utils.storage;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.StatFs;
|
||||
import android.util.Log;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class StorageDevice {
|
||||
|
||||
// File object containing device path
|
||||
private final File mFile;
|
||||
|
||||
private final boolean mInternal;
|
||||
|
||||
private boolean mDuplicate = true;
|
||||
|
||||
public StorageDevice(String path, boolean internal) {
|
||||
mFile = new File(path);
|
||||
mInternal = internal;
|
||||
if (mFile.exists()) {
|
||||
createLocationCode();
|
||||
}
|
||||
}
|
||||
|
||||
public StorageDevice(File file, boolean internal) {
|
||||
mFile = file;
|
||||
mInternal = internal;
|
||||
if (mFile.exists()) {
|
||||
createLocationCode();
|
||||
}
|
||||
}
|
||||
|
||||
// Get device path
|
||||
public String getName() {
|
||||
return mFile.getPath();
|
||||
}
|
||||
|
||||
// Get available space on device
|
||||
public String getSize() {
|
||||
return bytesToHuman(getAvailableBytes());
|
||||
}
|
||||
|
||||
private Long getAvailableBytes() {
|
||||
StatFs statFs = new StatFs(mFile.getPath());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return statFs.getBlockSizeLong() * statFs.getAvailableBlocksLong();
|
||||
} else {
|
||||
return (long) statFs.getBlockSize() * (long) statFs.getAvailableBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
public String getTotalSize() {
|
||||
return bytesToHuman(getTotalBytes());
|
||||
}
|
||||
|
||||
// Get total space on device
|
||||
private Long getTotalBytes() {
|
||||
StatFs statFs = new StatFs((mFile.getPath()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return statFs.getBlockSizeLong() * statFs.getBlockCountLong();
|
||||
} else {
|
||||
return (long) statFs.getBlockSize() * (long) statFs.getBlockCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert bytes to human readable form
|
||||
private static String bytesToHuman(long size) {
|
||||
long Kb = 1 * 1024;
|
||||
long Mb = Kb * 1024;
|
||||
long Gb = Mb * 1024;
|
||||
long Tb = Gb * 1024;
|
||||
long Pb = Tb * 1024;
|
||||
long Eb = Pb * 1024;
|
||||
|
||||
if (size < Kb) return floatForm(size) + " byte";
|
||||
if (size >= Kb && size < Mb) return floatForm((double) size / Kb) + " KB";
|
||||
if (size >= Mb && size < Gb) return floatForm((double) size / Mb) + " MB";
|
||||
if (size >= Gb && size < Tb) return floatForm((double) size / Gb) + " GB";
|
||||
if (size >= Tb && size < Pb) return floatForm((double) size / Tb) + " TB";
|
||||
if (size >= Pb && size < Eb) return floatForm((double) size / Pb) + " PB";
|
||||
if (size >= Eb) return floatForm((double) size / Eb) + " EB";
|
||||
|
||||
return "???";
|
||||
}
|
||||
|
||||
public boolean isInternal() {
|
||||
return mInternal;
|
||||
}
|
||||
|
||||
public File getPath() {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
private static String floatForm(double d) {
|
||||
return new DecimalFormat("#.#").format(d);
|
||||
}
|
||||
|
||||
// Create unique file to identify duplicate devices.
|
||||
private void createLocationCode() {
|
||||
if (!getLocationCodeFromFolder(mFile)) {
|
||||
File locationCode = new File(mFile.getPath(), ".storageLocationMarker");
|
||||
try {
|
||||
locationCode.createNewFile();
|
||||
FileWriter fw = new FileWriter(locationCode);
|
||||
fw.write(mFile.getPath());
|
||||
fw.close();
|
||||
} catch (IOException e) {
|
||||
Log.d("android-storage-devices", "Unable to create marker file, duplicates may be listed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is already a device code in our path
|
||||
private boolean getLocationCodeFromFolder(File folder) {
|
||||
File locationCode = new File(folder.getPath(), ".storageLocationMarker");
|
||||
if (locationCode.exists()) {
|
||||
try ( BufferedReader br = new BufferedReader(new FileReader(locationCode))){
|
||||
if (br.readLine().equals(mFile.getPath())) {
|
||||
mDuplicate = false;
|
||||
} else {
|
||||
mDuplicate = true;
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
String path = folder.getPath();
|
||||
String parent = path.substring(0, path.lastIndexOf("/"));
|
||||
if (parent.equals("")) {
|
||||
mDuplicate = false;
|
||||
return false;
|
||||
}
|
||||
return getLocationCodeFromFolder(new File(parent));
|
||||
}
|
||||
|
||||
public boolean isDuplicate() {
|
||||
return mDuplicate;
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2016 Isaac Hutt <mhutti1@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package eu.mhutti1.utils.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class StorageDeviceUtils {
|
||||
|
||||
public static ArrayList<StorageDevice> getStorageDevices(Context context, boolean writable) {
|
||||
ArrayList<StorageDevice> storageDevices = new ArrayList<>();
|
||||
|
||||
// Add as many possible mount points as we know about
|
||||
|
||||
// Only add this device if its very likely that we have missed a users sd card
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
// This is our internal storage directory
|
||||
storageDevices.add(new StorageDevice(
|
||||
generalisePath(Environment.getExternalStorageDirectory().getPath(), writable), true));
|
||||
} else {
|
||||
// This is an external storage directory
|
||||
storageDevices.add(new StorageDevice(
|
||||
generalisePath(Environment.getExternalStorageDirectory().getPath(), writable), false));
|
||||
}
|
||||
|
||||
// These are possible manufacturer sdcard mount points
|
||||
|
||||
String[] paths = ExternalPaths.getPossiblePaths();
|
||||
|
||||
for (String path : paths) {
|
||||
if (path.endsWith("*")) {
|
||||
File root = new File(path.substring(0, path.length() - 1));
|
||||
File[] directories = root.listFiles(file -> file.isDirectory());
|
||||
if (directories != null) {
|
||||
for (File dir : directories) {
|
||||
storageDevices.add(new StorageDevice(dir, false));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
storageDevices.add(new StorageDevice(path, false));
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through any sdcards manufacturers may have specified
|
||||
for (File file : ContextCompat.getExternalFilesDirs(context, "")) {
|
||||
if (file != null) {
|
||||
storageDevices.add(new StorageDevice(generalisePath(file.getPath(), writable), false));
|
||||
}
|
||||
}
|
||||
|
||||
// Check all devices exist, we can write to them if required and they are not duplicates
|
||||
return checkStorageValid(writable, storageDevices);
|
||||
}
|
||||
|
||||
// Remove app specific path from directories so that we can search them from the top
|
||||
private static String generalisePath(String path, boolean writable) {
|
||||
if (writable) {
|
||||
return path;
|
||||
}
|
||||
int endIndex = path.lastIndexOf("/Android/data/");
|
||||
if (endIndex != -1) {
|
||||
return path.substring(0, endIndex);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static ArrayList<StorageDevice> checkStorageValid(boolean writable,
|
||||
ArrayList<StorageDevice> storageDevices) {
|
||||
ArrayList<StorageDevice> activeDevices = new ArrayList<>();
|
||||
ArrayList<StorageDevice> devicePaths = new ArrayList<>();
|
||||
for (StorageDevice device : storageDevices) {
|
||||
if (existsAndIsDirAndWritableIfRequiredAndNotDuplicate(writable, devicePaths, device)) {
|
||||
activeDevices.add(device);
|
||||
devicePaths.add(device);
|
||||
}
|
||||
}
|
||||
return activeDevices;
|
||||
}
|
||||
|
||||
private static boolean existsAndIsDirAndWritableIfRequiredAndNotDuplicate(boolean writable,
|
||||
ArrayList<StorageDevice> devicePaths, StorageDevice device) {
|
||||
final File devicePath = device.getPath();
|
||||
return devicePath.exists()
|
||||
&& devicePath.isDirectory()
|
||||
&& (canWrite(devicePath) || !writable)
|
||||
&& !device.isDuplicate()
|
||||
&& !devicePaths.contains(device);
|
||||
}
|
||||
|
||||
// Amazingly file.canWrite() does not always return the correct value
|
||||
private static boolean canWrite(File file) {
|
||||
final String filePath = file + "/test.txt";
|
||||
try {
|
||||
RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "rw");
|
||||
FileChannel fileChannel = randomAccessFile.getChannel();
|
||||
FileLock fileLock = fileChannel.lock();
|
||||
fileLock.release();
|
||||
fileChannel.close();
|
||||
randomAccessFile.close();
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
} finally {
|
||||
new File(filePath).delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2016 Isaac Hutt <mhutti1@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package eu.mhutti1.utils.storage;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
import java.util.ArrayList;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
|
||||
class StorageSelectArrayAdapter extends ArrayAdapter<StorageDevice> {
|
||||
|
||||
private final String mInternal;
|
||||
|
||||
private final String mExternal;
|
||||
|
||||
public StorageSelectArrayAdapter(Context context, int resource, ArrayList<StorageDevice> devices,
|
||||
String internal, String external) {
|
||||
super(context, resource, devices);
|
||||
mInternal = internal;
|
||||
mExternal = external;
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n") @Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
|
||||
ViewHolder holder;
|
||||
if (convertView == null) {
|
||||
convertView = View.inflate(getContext(), R.layout.device_item, null);
|
||||
holder = new ViewHolder();
|
||||
holder.fileName = convertView.findViewById(R.id.file_name);
|
||||
holder.fileSize = convertView.findViewById(R.id.file_size);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
StorageDevice device = getItem(position);
|
||||
if (device.isInternal()) {
|
||||
holder.fileName.setText(mInternal);
|
||||
} else {
|
||||
holder.fileName.setText(mExternal);
|
||||
}
|
||||
holder.fileSize.setText(device.getSize() + " / " + device.getTotalSize());
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
TextView fileName;
|
||||
TextView fileSize;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2016 Isaac Hutt <mhutti1@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package eu.mhutti1.utils.storage;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import java.io.File;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
|
||||
public class StorageSelectDialog extends DialogFragment implements ListView.OnItemClickListener {
|
||||
|
||||
// Activities/Fragments can create instances of a StorageSelectDialog and bind a listener to get its result
|
||||
|
||||
public static final String STORAGE_DIALOG_THEME = "THEME";
|
||||
|
||||
public static final String STORAGE_DIALOG_INTERNAL = "INTERNAL";
|
||||
|
||||
public static final String STORAGE_DIALOG_EXTERNAL = "EXTERNAL";
|
||||
|
||||
private StorageSelectArrayAdapter mAdapter;
|
||||
|
||||
private OnSelectListener mOnSelectListener;
|
||||
private String mTitle;
|
||||
|
||||
private String mInternal = "Internal";
|
||||
|
||||
private String mExternal = "External";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (getArguments() != null) {
|
||||
// Set string values
|
||||
mInternal = getArguments().getString(STORAGE_DIALOG_INTERNAL, mInternal);
|
||||
mExternal = getArguments().getString(STORAGE_DIALOG_EXTERNAL, mExternal);
|
||||
// Set the theme to a supplied value
|
||||
if (getArguments().containsKey(STORAGE_DIALOG_THEME)) {
|
||||
setStyle(DialogFragment.STYLE_NORMAL, getArguments().getInt(STORAGE_DIALOG_THEME));
|
||||
}
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.storage_select_dialog, container, false);
|
||||
TextView title = rootView.findViewById(R.id.title);
|
||||
title.setText(mTitle);
|
||||
ListView listView = rootView.findViewById(R.id.device_list);
|
||||
mAdapter = new StorageSelectArrayAdapter(getActivity(), 0,
|
||||
StorageDeviceUtils.getStorageDevices(getActivity(), true), mInternal, mExternal);
|
||||
listView.setAdapter(mAdapter);
|
||||
listView.setOnItemClickListener(this);
|
||||
Button button = rootView.findViewById(R.id.button);
|
||||
final EditText editText = rootView.findViewById(R.id.editText);
|
||||
button.setOnClickListener(view -> {
|
||||
if (editText.getText().length() != 0) {
|
||||
String path = editText.getText().toString();
|
||||
if (new File(path).exists()) {
|
||||
mAdapter.add(new StorageDevice(path, false));
|
||||
}
|
||||
}
|
||||
});
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (mOnSelectListener != null) {
|
||||
mOnSelectListener.selectionCallback(mAdapter.getItem(position));
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
public void setOnSelectListener(OnSelectListener selectListener) {
|
||||
mOnSelectListener = selectListener;
|
||||
}
|
||||
|
||||
public interface OnSelectListener {
|
||||
void selectionCallback(StorageDevice s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(FragmentManager fm, String text) {
|
||||
mTitle = text;
|
||||
super.show(fm, text);
|
||||
}
|
||||
}
|
@ -19,7 +19,6 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.settings;
|
||||
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
@ -35,6 +34,7 @@ import android.webkit.WebView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import eu.mhutti1.utils.storage.StorageDevice;
|
||||
import eu.mhutti1.utils.storage.StorageSelectDialog;
|
||||
@ -200,7 +200,7 @@ public class KiwixSettingsActivity extends BaseActivity {
|
||||
String selectedLang = sharedPreferenceUtil.getPrefLanguage(Locale.getDefault().toString());
|
||||
List<String> languageCodeList = new LanguageUtils(getActivity()).getKeys();
|
||||
selectedLang = languageCodeList.contains(selectedLang) ? selectedLang : "en";
|
||||
String code[] = languageCodeList.toArray(new String[languageCodeList.size()]);
|
||||
String code[] = languageCodeList.toArray(new String[0]);
|
||||
String[] entries = new String[code.length];
|
||||
for (int index = 0; index < code.length; index++) {
|
||||
Locale locale = new Locale(code[index]);
|
||||
@ -322,7 +322,6 @@ public class KiwixSettingsActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
public void openFolderSelect() {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
StorageSelectDialog dialogFragment = new StorageSelectDialog();
|
||||
Bundle b = new Bundle();
|
||||
b.putString(StorageSelectDialog.STORAGE_DIALOG_INTERNAL,
|
||||
@ -332,7 +331,7 @@ public class KiwixSettingsActivity extends BaseActivity {
|
||||
b.putInt(StorageSelectDialog.STORAGE_DIALOG_THEME, StyleUtils.dialogStyle());
|
||||
dialogFragment.setArguments(b);
|
||||
dialogFragment.setOnSelectListener(this);
|
||||
dialogFragment.show(fm, getResources().getString(R.string.pref_storage));
|
||||
dialogFragment.show(((AppCompatActivity) getActivity()).getSupportFragmentManager(), getResources().getString(R.string.pref_storage));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.zim_manager.library_view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@ -30,7 +31,7 @@ import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.mhutti1.utils.storage.StorageDevice
|
||||
import eu.mhutti1.utils.storage.support.StorageSelectDialog
|
||||
import eu.mhutti1.utils.storage.StorageSelectDialog
|
||||
import kotlinx.android.synthetic.main.activity_library.libraryErrorText
|
||||
import kotlinx.android.synthetic.main.activity_library.libraryList
|
||||
import kotlinx.android.synthetic.main.activity_library.librarySwipeRefresh
|
||||
@ -209,8 +210,10 @@ class LibraryFragment : BaseFragment() {
|
||||
private fun notEnoughSpaceAvailable(item: BookItem) =
|
||||
spaceAvailable < item.book.size.toLong() * 1024f
|
||||
|
||||
@SuppressLint("ImplicitSamInstance")
|
||||
private fun showStorageSelectDialog() {
|
||||
StorageSelectDialog().apply {
|
||||
StorageSelectDialog()
|
||||
.apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(
|
||||
StorageSelectDialog.STORAGE_DIALOG_INTERNAL,
|
||||
|
29
app/src/main/res/layout/device_item.xml
Normal file
29
app/src/main/res/layout/device_item.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:textSize="18sp"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_toEndOf="@id/file_name"
|
||||
android:gravity="end"
|
||||
android:padding="10dp"
|
||||
android:textSize="18sp"
|
||||
android:layout_toRightOf="@id/file_name"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
53
app/src/main/res/layout/storage_select_dialog.xml
Normal file
53
app/src/main/res/layout/storage_select_dialog.xml
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:textAlignment="center"
|
||||
android:textSize="22sp"
|
||||
/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/device_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
|
||||
</ListView>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<EditText
|
||||
android:id="@+id/editText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:ems="10"
|
||||
android:inputType="textPersonName"
|
||||
android:text="@string/slash"
|
||||
android:importantForAutofill="no"
|
||||
tools:targetApi="o"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/plus"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -6,4 +6,6 @@
|
||||
<item>large</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
<string name="slash">/</string>
|
||||
<string name="plus">+</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user