package com.dar.nclientv2.settings; import android.Manifest; import android.app.Activity; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.util.DisplayMetrics; import android.webkit.CookieSyncManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; import androidx.core.graphics.drawable.DrawableCompat; import com.dar.nclientv2.CopyToClipboardActivity; import com.dar.nclientv2.MainActivity; import com.dar.nclientv2.R; import com.dar.nclientv2.api.components.GenericGallery; import com.dar.nclientv2.api.enums.Language; import com.dar.nclientv2.api.enums.SortType; import com.dar.nclientv2.api.enums.TitleType; import com.dar.nclientv2.components.classes.CustomSSLSocketFactory; import com.dar.nclientv2.loginapi.LoadTags; import com.dar.nclientv2.loginapi.User; import com.dar.nclientv2.utility.LogUtility; import com.dar.nclientv2.utility.Utility; import com.dar.nclientv2.utility.network.NetworkUtil; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; import org.acra.ACRA; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import okhttp3.Cookie; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; public class Global { public static OkHttpClient client=null; public static File OLD_GALLERYFOLDER; public static File MAINFOLDER; public static File DOWNLOADFOLDER; public static File SCREENFOLDER; public static File PDFFOLDER; public static File UPDATEFOLDER; public static File ZIPFOLDER; public static final String CHANNEL_ID1="download_gallery",CHANNEL_ID2="create_pdf",CHANNEL_ID3="create_zip"; private static Language onlyLanguage; private static TitleType titleType; private static SortType sortType; private static boolean localSortByName,alternativeSite,volumeOverride,zoomOneColumn,keepHistory,lockScreen,onlyTag,showTitles,infiniteScroll, removeAvoidedGalleries,useRtl; private static ThemeScheme theme; private static DataUsageType usageMobile, usageWifi; private static String lastVersion; private static int maxHistory,columnCount,maxId,galleryWidth=-1, galleryHeight =-1; private static int colPortHist,colLandHist,colPortMain,colLandMain,colPortDownload,colLandDownload,colLandFavorite,colPortFavorite; private static int defaultZoom; private static Point screenSize; private static final DisplayMetrics lastDisplay=new DisplayMetrics(); public static long recursiveSize(File path) { if(path.isFile())return path.length(); long size=0; File[]files=path.listFiles(); if(files==null)return size; for(File f:files) size+=f.isFile()?f.length():recursiveSize(f); return size; } public static int getFavoriteLimit(Context context) { return context.getSharedPreferences("Settings", 0).getInt(context.getString(R.string.key_favorite_limit),10); } public static String getLastVersion(Context context) { if(context!=null)lastVersion=context.getSharedPreferences("Settings", 0).getString("last_version","0.0.0"); return lastVersion; } public static void setLastVersion(Context context) { lastVersion=getVersionName(context); context.getSharedPreferences("Settings", 0).edit().putString("last_version",lastVersion).apply(); } public static int getColLandHistory() { return colLandHist; } public static int getColPortHistory() { return colPortHist; } public static void updateACRAReportStatus(Context context) { ACRA.getErrorReporter().setEnabled(context.getSharedPreferences("Settings",0).getBoolean(context.getString(R.string.key_send_report),true)); } public static boolean isDestroyed(Activity activity) { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed(); } public static String getUserAgent() { return "NClientV2 "+Global.getLastVersion(null); } public enum ThemeScheme{LIGHT,DARK} public enum DataUsageType{NONE,THUMBNAIL,FULL} public static boolean isLocalSortByName() { return localSortByName; } public static void toggleLocalSort(Context context) { Global.localSortByName = !Global.localSortByName; context.getSharedPreferences("Settings", 0) .edit().putBoolean(context.getString(R.string.key_local_sort),Global.localSortByName) .apply(); } public static String getDefaultFileParent(Context context){ File f; if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){ f= context.getExternalFilesDir(null); }else{ f= Environment.getExternalStorageDirectory(); } return f.getAbsolutePath(); } private static void initFilesTree(Context context){ String path=context.getSharedPreferences("Settings",Context.MODE_PRIVATE).getString(context.getString(R.string.key_save_path),getDefaultFileParent(context)); assert path != null; MAINFOLDER=new File(path,"NClientV2"); OLD_GALLERYFOLDER=new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),"NClientV2"); DOWNLOADFOLDER=new File(MAINFOLDER,"Download"); SCREENFOLDER =new File(MAINFOLDER,"Screen"); PDFFOLDER =new File(MAINFOLDER,"PDF"); UPDATEFOLDER =new File(MAINFOLDER,"Update"); ZIPFOLDER =new File(MAINFOLDER,"ZIP"); } @Nullable public static OkHttpClient getClient(){ return client; } @NonNull public static OkHttpClient getClient(Context context){ if(client==null)initHttpClient(context); return client; } public static int getGalleryWidth(){ return galleryWidth; } public static void initScreenSize(AppCompatActivity activity){ if(screenSize==null) { screenSize = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(screenSize); } } private static void initGallerySize() { galleryHeight=screenSize.y/2; galleryWidth=(galleryHeight*3)/4;//the ratio is 3:4 } public static int getScreenHeight(){ return screenSize.y; } public static int getScreenWidth(){ return screenSize.x; } public static int getGalleryHeight(){ return galleryHeight; } public static int getMaxHistory() { return maxHistory; } public static boolean useAlternativeSite() { return alternativeSite; } private static void initTitleType(@NonNull Context context){ String s=context.getSharedPreferences("Settings", 0).getString(context.getString(R.string.key_title_type),"pretty"); switch (s){ case "pretty":titleType= TitleType.PRETTY;break; case "english":titleType= TitleType.ENGLISH;break; case "japanese":titleType= TitleType.JAPANESE;break; } } public static int getDeviceWidth(@Nullable Activity activity){ getDeviceMetrics(activity); return lastDisplay.widthPixels; } public static int getDeviceHeight(@Nullable Activity activity){ getDeviceMetrics(activity); return lastDisplay.heightPixels; } private static void getDeviceMetrics(Activity activity){ if (activity != null) activity.getWindowManager().getDefaultDisplay().getMetrics(lastDisplay); } public static void initFromShared(@NonNull Context context){ SharedPreferences shared=context.getSharedPreferences("Settings", 0); CookieSyncManager.createInstance(context); initHttpClient(context); initTitleType(context); initTheme(context); loadNotificationChannel(context); NotificationSettings.initializeNotificationManager(context); Login.initUseAccountTag(context); Global.initStorage(context); localSortByName=shared.getBoolean(context.getString(R.string.key_local_sort),true); useRtl=shared.getBoolean(context.getString(R.string.key_use_rtl),false); keepHistory=shared.getBoolean(context.getString(R.string.key_keep_history),true); infiniteScroll=shared.getBoolean(context.getString(R.string.key_infinite_scroll),false); removeAvoidedGalleries =shared.getBoolean(context.getString(R.string.key_remove_ignored),true); onlyTag=shared.getBoolean(context.getString(R.string.key_ignore_tags),true); volumeOverride=shared.getBoolean(context.getString(R.string.key_override_volume),true); columnCount=shared.getInt(context.getString(R.string.key_column_count),2); showTitles=shared.getBoolean(context.getString(R.string.key_show_titles),true); lockScreen=shared.getBoolean(context.getString(R.string.key_disable_lock),false); maxId=shared.getInt(context.getString(R.string.key_max_id),300000); maxHistory=shared.getInt(context.getString(R.string.key_max_history_size),2); defaultZoom=shared.getInt(context.getString(R.string.key_default_zoom),100); colPortMain=shared.getInt(context.getString(R.string.key_column_port_main),2); colLandMain=shared.getInt(context.getString(R.string.key_column_land_main),4); colPortDownload=shared.getInt(context.getString(R.string.key_column_port_down),2); colLandDownload=shared.getInt(context.getString(R.string.key_column_land_down),4); colPortFavorite=shared.getInt(context.getString(R.string.key_column_port_favo),2); colLandFavorite=shared.getInt(context.getString(R.string.key_column_land_favo),4); colPortHist=shared.getInt(context.getString(R.string.key_column_port_hist),2); colLandHist=shared.getInt(context.getString(R.string.key_column_land_hist),4); zoomOneColumn=shared.getBoolean(context.getString(R.string.key_zoom_one_column),false); alternativeSite=shared.getBoolean(context.getString(R.string.key_alternative_site),false); int x=Math.max(0,shared.getInt(context.getString(R.string.key_only_language),Language.ALL.ordinal())); sortType = SortType.values()[shared.getInt(context.getString(R.string.key_by_popular),SortType.RECENT_ALL_TIME.ordinal())]; usageMobile =DataUsageType.values()[shared.getInt(context.getString(R.string.key_mobile_usage),DataUsageType.FULL.ordinal())]; usageWifi =DataUsageType.values()[shared.getInt(context.getString(R.string.key_wifi_usage),DataUsageType.FULL.ordinal())]; if(Language.values()[x]==Language.UNKNOWN){ updateOnlyLanguage(context,Language.ALL); x=Language.ALL.ordinal(); } onlyLanguage=Language.values()[x]; } public static DataUsageType getDownloadPolicy(){ switch (NetworkUtil.getType()){ case WIFI:return usageWifi; case CELLULAR:return usageMobile; } return usageWifi; } public static boolean volumeOverride() { return volumeOverride; } public static boolean isZoomOneColumn() { return zoomOneColumn; } public static void reloadHttpClient(@NonNull Context context){ OkHttpClient.Builder builder=new OkHttpClient.Builder() .cookieJar( new PersistentCookieJar( new SetCookieCache(), new SharedPrefsCookiePersistor(context.getSharedPreferences("Login",0)) ) ); CustomSSLSocketFactory.enableTls12OnPreLollipop(builder); builder.addInterceptor(new CustomInterceptor()); client=builder.build(); client.dispatcher().setMaxRequests(25); client.dispatcher().setMaxRequestsPerHost(25); for(Cookie cookie:client.cookieJar().loadForRequest(HttpUrl.get(Utility.getBaseUrl()))){ LogUtility.d("Cookie: "+cookie); } if(Login.isLogged()&&Login.getUser()==null){ User.createUser(user -> { if(user!=null){ new LoadTags(null).start(); if(context instanceof MainActivity){ ((MainActivity) context).runOnUiThread(() -> ((MainActivity)context).loginItem.setTitle(context.getString(R.string.login_formatted,user.getUsername()))); } } }); } } private static void initHttpClient(@NonNull Context context){ if(client!=null)return; reloadHttpClient(context); } public static Locale initLanguage(Context context){ String x=context.getSharedPreferences("Settings",0).getString(context.getString(R.string.key_language),"en"); assert x != null; return new Locale(x); } private static ThemeScheme initTheme(Context context){ String h=context.getSharedPreferences("Settings",0).getString(context.getString(R.string.key_theme_select),"dark"); assert h != null; return theme=h.equals("light")?ThemeScheme.LIGHT:ThemeScheme.DARK; } public static boolean shouldCheckForUpdates(Context context){ return context.getSharedPreferences("Settings", 0).getBoolean(context.getString(R.string.key_check_update),true); } public static int getLogo(){ return theme==ThemeScheme.LIGHT?R.drawable.ic_logo_dark:R.drawable.ic_logo; } public static Drawable getLogo(Resources resources){ return ResourcesCompat.getDrawable(resources,getLogo(),null); } public static float getDefaultZoom() { return ((float)defaultZoom)/100f; } public static TitleType getTitleType() { return titleType; } public static ThemeScheme getTheme() { return theme; } public static boolean removeAvoidedGalleries(){return removeAvoidedGalleries;} @NonNull public static Language getOnlyLanguage() { return onlyLanguage; } public static boolean isOnlyTag() { return onlyTag; } public static boolean isLockScreen() { return lockScreen; } public static int getColLandDownload() { return colLandDownload; } public static int getColPortMain() { return colPortMain; } public static int getColLandMain() { return colLandMain; } public static int getColPortDownload() { return colPortDownload; } public static int getColLandFavorite() { return colLandFavorite; } public static int getColPortFavorite() { return colPortFavorite; } public static boolean isKeepHistory() { return keepHistory; } public static boolean useRtl() { return useRtl; } public static boolean showTitles() { return showTitles; } public static SortType getSortType() { return sortType; } public static boolean isInfiniteScroll(){ return infiniteScroll; } public static int getColumnCount() { return columnCount; } public static int getMaxId() { return maxId; } public static void initStorage(Context context){ if(!Global.hasStoragePermission(context))return; Global.initFilesTree(context); boolean[] bools=new boolean[]{ Global.MAINFOLDER.mkdirs(), Global.DOWNLOADFOLDER.mkdir(), Global.PDFFOLDER.mkdir(), Global.UPDATEFOLDER.mkdir(), Global.SCREENFOLDER.mkdir(), Global.ZIPFOLDER.mkdir(), }; LogUtility.d( "0:"+context.getFilesDir()+'\n'+ "1:"+Global.MAINFOLDER+bools[0]+'\n'+ "2:"+Global.DOWNLOADFOLDER+bools[1]+'\n'+ "3:"+Global.PDFFOLDER+bools[2]+'\n'+ "4:"+Global.UPDATEFOLDER+bools[3]+'\n'+ "5:"+Global.SCREENFOLDER+bools[4]+'\n'+ "5:"+Global.ZIPFOLDER+bools[5]+'\n' ); try { new File(Global.MAINFOLDER,".nomedia").createNewFile(); } catch (IOException e) {e.printStackTrace();} } public static void updateOnlyLanguage(@NonNull Context context, @Nullable Language type){ context.getSharedPreferences("Settings", 0).edit().putInt(context.getString((R.string.key_only_language)),type.ordinal()).apply();onlyLanguage=type; } public static void updateSortType(@NonNull Context context, @NonNull SortType sortType){ context.getSharedPreferences("Settings", 0).edit().putInt(context.getString((R.string.key_by_popular)),sortType.ordinal()).apply(); Global.sortType =sortType; } public static void updateColumnCount(@NonNull Context context, int count){context.getSharedPreferences("Settings", 0).edit().putInt(context.getString((R.string.key_column_count)),count).apply();columnCount=count; } public static void updateMaxId(@NonNull Context context, int id){context.getSharedPreferences("Settings", 0).edit().putInt(context.getString((R.string.key_max_id)),id).apply();maxId=id; } public static int getStatusBarHeight(Context context) { Resources resources = context.getResources(); int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { return resources.getDimensionPixelSize(resourceId); } return 0; } public static int getNavigationBarHeight(Context context){ Resources resources = context.getResources(); int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { return resources.getDimensionPixelSize(resourceId); } return 0; } public static void shareURL(Context context,String title, String url){ Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT,title+": "+url); sendIntent.setType("text/plain"); Intent clipboardIntent = new Intent(context, CopyToClipboardActivity.class); clipboardIntent.setData(Uri.parse(url)); Intent chooserIntent = Intent.createChooser(sendIntent,context.getString(R.string.share_with)); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { clipboardIntent }); context.startActivity(chooserIntent); } public static void shareGallery(Context context, GenericGallery gallery) { shareURL(context, gallery.getTitle(),"https://"+ Utility.getHost()+"/g/"+gallery.getId()); } public static void setTint(Drawable drawable){ if(drawable==null)return; DrawableCompat.setTint(drawable,theme== ThemeScheme.LIGHT?Color.BLACK:Color.WHITE); } private static void loadNotificationChannel(@NonNull Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel1 = new NotificationChannel(CHANNEL_ID1, context.getString(R.string.channel1_name), NotificationManager.IMPORTANCE_DEFAULT); NotificationChannel channel2 = new NotificationChannel(CHANNEL_ID2, context.getString(R.string.channel2_name), NotificationManager.IMPORTANCE_DEFAULT); NotificationChannel channel3 = new NotificationChannel(CHANNEL_ID3, context.getString(R.string.channel3_name), NotificationManager.IMPORTANCE_DEFAULT); channel1.setDescription(context.getString(R.string.channel1_description)); channel2.setDescription(context.getString(R.string.channel2_description)); channel3.setDescription(context.getString(R.string.channel3_description)); NotificationManager notificationManager = context.getSystemService(NotificationManager.class); if (notificationManager != null) { notificationManager.createNotificationChannel(channel1); notificationManager.createNotificationChannel(channel2); notificationManager.createNotificationChannel(channel3); } } } public static List<File>getUsableFolders(Context context){ List<File>strings=new ArrayList<>(); if(Build.VERSION.SDK_INT<Build.VERSION_CODES.Q) strings.add(Environment.getExternalStorageDirectory()); if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return strings; File[]files=context.getExternalFilesDirs(null); strings.addAll(Arrays.asList(files)); return strings; } public static boolean hasStoragePermission(Context context) { return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||ContextCompat.checkSelfPermission(context,Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED; } public static boolean isJPEGCorrupted(String path){ if(!new File(path).exists())return true; try (RandomAccessFile fh = new RandomAccessFile(path, "r")) { long length = fh.length(); if (length < 10L) { return true; } fh.seek(length - 2); byte[] eoi = new byte[2]; fh.read(eoi); return eoi[0] != (byte)0xFF || eoi[1] != (byte)0xD9; // FF D9 }catch (IOException e){ LogUtility.e(e.getMessage(),e);} return true; } @Nullable public static File findGalleryFolder(int id){ if(DOWNLOADFOLDER==null)return null; DOWNLOADFOLDER.mkdirs(); String fileName="."+id; File[] tmp=DOWNLOADFOLDER.listFiles(); if(tmp==null)return null; for (File tmp2 : tmp) { if (tmp2.isDirectory()&&new File(tmp2,fileName).exists()) { return tmp2; } } return null; } public static void initActivity(AppCompatActivity context){ initScreenSize(context); initGallerySize(); //Locale locale=new Locale() Resources resources=context.getResources(); Locale locale=initLanguage(context); Configuration c=new Configuration(context.getResources().getConfiguration()); c.locale=locale; resources.updateConfiguration(c, resources.getDisplayMetrics()); switch (initTheme(context)){ case LIGHT:context.setTheme(R.style.LightTheme);break; case DARK:context.setTheme(R.style.DarkTheme);break; } } public static void recursiveDelete(File file){ if(file==null||!file.exists())return; if(file.isDirectory()){ File[] files = file.listFiles(); if(files==null)return; for(File x:files)recursiveDelete(x); } file.delete(); } @NonNull public static String getVersionName(Context context){ try { PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return pInfo.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return "0.0.0"; } }