package org.fox.ttcomics2; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import com.github.javiersantos.appupdater.AppUpdater; import com.github.javiersantos.appupdater.enums.UpdateFrom; import com.shamanland.fab.FloatingActionButton; import org.fox.ttcomics2.sync.SyncClient; import org.fox.ttcomics2.sync.SyncFolderService; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import androidx.appcompat.widget.Toolbar; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; import icepick.State; public class MainActivity extends CommonActivity implements SharedPreferences.OnSharedPreferenceChangeListener { private final String TAG = this.getClass().getSimpleName(); private ProgressDialog m_progressDialog; private boolean m_needRestart; private ComicsPagerAdapter m_adapter; @State protected String m_baseDir; private ViewPager m_pager; private BroadcastReceiver m_serviceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (SyncFolderService.INTENT_ACTION_FILE_PROCESSED.equals(intent.getAction())) { int count = intent.getExtras().getInt("count"); int index = intent.getExtras().getInt("index"); m_progressDialog.setCancelable(false); m_progressDialog.setTitle("Synchronizing..."); m_progressDialog.setMessage("File " + index + " of " + count); m_progressDialog.show(); } if (SyncFolderService.INTENT_ACTION_SCAN_COMPLETE.equals(intent.getAction())) { m_progressDialog.dismiss(); updateComicsList(false); } } }; @SuppressLint("NewApi") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); m_prefs.registerOnSharedPreferenceChangeListener(this); setContentView(R.layout.activity_main); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); setTitle(R.string.app_name); m_progressDialog = new ProgressDialog(this); FloatingActionButton fab = findViewById(R.id.fab); if (m_prefs.getBoolean("enable_fab", true)) { fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { updateComicsList(true); } }); } else { fab.setVisibility(View.GONE); } m_adapter = new ComicsPagerAdapter(getSupportFragmentManager()); m_pager = findViewById(R.id.comics_pager); m_pager.setAdapter(m_adapter); m_pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(final int position) { new Handler().postDelayed(new Runnable() { @Override public void run() { ComicListFragment frag = (ComicListFragment) m_adapter.getItem(position); if (frag != null && frag.isAdded()) { frag.refresh(); } } }, 100); } @Override public void onPageScrollStateChanged(int state) { } }); if (savedInstanceState == null) { int selectedTab = getIntent().getIntExtra("selectedTab", 0); Log.d(TAG, "selTab=" + selectedTab); m_pager.setCurrentItem(selectedTab); if (getIntent().getStringExtra("baseDir") != null) { m_baseDir = getIntent().getStringExtra("baseDir"); } else { m_baseDir = m_prefs.getString("comics_directory", ""); } } String[] needPermissions = checkPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}); if (needPermissions.length > 0) { ActivityCompat.requestPermissions(this, needPermissions, REQUEST_PERMISSIONS_RESULT); } else { initSyncClient(); setupDefaultDirectory(); } checkUpdates(); } protected void checkUpdates() { if (BuildConfig.DEBUG || BuildConfig.ENABLE_UPDATER) { new AppUpdater(this) .setUpdateFrom(UpdateFrom.JSON) .setUpdateJSON(String.format("https://srv.tt-rss.org/fdroid/updates/%1$s.json", this.getPackageName())) .start(); } } protected String[] checkPermissions(String[] permissions) { ArrayList tmp = new ArrayList(); for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "need permission: " + permission); tmp.add(permission); } } return tmp.toArray(new String[tmp.size()]); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_PERMISSIONS_RESULT: if (grantResults.length > 0) { boolean needRestart = false; for (int i = 0; i < grantResults.length; i++) { String permission = permissions[i]; if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { needRestart = true; } else { toast(R.string.permission_denied_storage); } } } if (needRestart) { finish(); startActivity(getIntent()); } } } } private void setupDefaultDirectory() { if (m_prefs.getString("comics_directory", null) == null) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(R.string.dialog_need_prefs_message) .setCancelable(false) .setPositiveButton(R.string.dialog_need_prefs_preferences, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Intent intent = new Intent(MainActivity.this, PreferencesActivity.class); startActivityForResult(intent, 0); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); } } @Override public void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(); filter.addAction(SyncFolderService.INTENT_ACTION_FILE_PROCESSED); filter.addAction(SyncFolderService.INTENT_ACTION_SCAN_COMPLETE); filter.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(m_serviceReceiver, filter); //if (m_enableFab != m_prefs.getBoolean("enable_fab", true)) { if (m_needRestart) { Log.d(TAG, "shared preferences changed, restarting"); finish(); startActivity(getIntent()); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); menu.findItem(R.id.menu_sync_directory).setVisible(m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()); return true; } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_sync_directory: if (true) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Get synchronized last read page for listed files?") .setCancelable(true) .setPositiveButton("Continue", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { updateLastRead(m_baseDir); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); } return true; case android.R.id.home: onBackPressed(); return true; default: Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); return super.onOptionsItemSelected(item); } } private void updateLastRead(String baseDir) { Intent serviceIntent = new Intent(MainActivity.this, SyncFolderService.class); serviceIntent.putExtra("baseDir", baseDir); startService(serviceIntent); } @Override public void onComicArchiveSelected(String fileName) { super.onComicArchiveSelected(fileName); File file = new File(fileName); if (file.isDirectory()) { Intent intent = new Intent(MainActivity.this, MainActivity.class); intent.putExtra("selectedTab", m_pager.getCurrentItem()); intent.putExtra("baseDir", fileName); startActivity(intent); } else if (file.canRead()) { Intent intent = new Intent(MainActivity.this, ViewComicActivity.class); intent.putExtra("fileName", fileName); startActivityForResult(intent, REQUEST_VIEWCOMIC); } else { toast(getString(R.string.error_cant_open_file, fileName)); ComicListFragment frag = (ComicListFragment) m_adapter.getPrimaryItem(); if (frag != null && frag.isAdded()) { frag.rescan(); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == REQUEST_VIEWCOMIC && resultCode == Activity.RESULT_OK) { String fileName = intent.getStringExtra("fileName"); Log.d(TAG, "finished viewing comic: " + fileName); if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { toast(R.string.sync_uploading); m_syncClient.setPosition(sha1(new File(fileName).getName()), m_databaseHelper.getLastPosition(fileName)); } updateComicsList(false); } System.gc(); super.onActivityResult(requestCode, resultCode, intent); } private void updateComicsList(boolean rescan) { ComicListFragment frag = (ComicListFragment) m_adapter.getPrimaryItem(); if (frag != null && frag.isAdded()) { if (rescan) frag.rescan(); else frag.refresh(); } } public void resetProgress(final String fileName) { if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { m_databaseHelper.setLastPosition(fileName, 0); m_databaseHelper.setLastMaxPosition(fileName, 0); updateComicsList(false); if (m_prefs.getBoolean("use_position_sync", false) && m_syncClient.hasOwner()) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(R.string.reset_remove_synced_progress) .setCancelable(true) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { m_syncClient.clearData(sha1(new File(fileName).getName()), new SyncClient.DataClearedListener() { @Override public void onDataCleared(boolean result) { updateComicsList(false); } }); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); } } } @Override public void onPause() { super.onPause(); unregisterReceiver(m_serviceReceiver); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { String[] filter = new String[] { "enable_fab", "comics_directory", "use_position_sync" }; m_needRestart = Arrays.asList(filter).indexOf(key) != -1; } private class ComicsPagerAdapter extends FragmentStatePagerAdapter{ private int[] m_pageTitles = { R.string.tab_all_comics, R.string.tab_unread, R.string.tab_unfinished, R.string.tab_read }; private Fragment m_primaryItem; public ComicsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { ComicListFragment frag = new ComicListFragment(); frag.setMode(position); frag.setBaseDirectory(m_baseDir); return frag; } @Override public int getCount() { return 4; } @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { m_primaryItem = ((Fragment) object); super.setPrimaryItem(container, position, object); } @Override public CharSequence getPageTitle(int position) { return getString(m_pageTitles[position]); } public Fragment getPrimaryItem() { return m_primaryItem; } } }