[Sync] New manual sync dialog. Remove most APIv1 dependencies.

This commit is contained in:
Kuba Szczodrzyński 2019-11-13 21:57:47 +01:00
parent dfdc6817a1
commit 85b5667a7e
14 changed files with 191 additions and 510 deletions

View File

@ -45,13 +45,14 @@ import pl.szczodrzynski.edziennik.network.ServerRequest
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
import pl.szczodrzynski.edziennik.sync.SyncWorker import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
@ -469,7 +470,7 @@ class MainActivity : AppCompatActivity() {
.withIcon(CommunityMaterial.Icon2.cmd_sync) .withIcon(CommunityMaterial.Icon2.cmd_sync)
.withOnClickListener(View.OnClickListener { .withOnClickListener(View.OnClickListener {
bottomSheet.close() bottomSheet.close()
app.apiEdziennik.guiSyncFeature(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done, fragmentToFeature(navTargetId)) SyncViewListDialog(this, navTargetId)
}), }),
BottomSheetSeparatorItem(false), BottomSheetSeparatorItem(false),
BottomSheetPrimaryItem(false) BottomSheetPrimaryItem(false)

View File

@ -7,39 +7,36 @@ package pl.szczodrzynski.edziennik.api.v2
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
const val FEATURE_ALL = 0 internal const val FEATURE_TIMETABLE = 1
const val FEATURE_TIMETABLE = 1 internal const val FEATURE_AGENDA = 2
const val FEATURE_AGENDA = 2 internal const val FEATURE_GRADES = 3
const val FEATURE_GRADES = 3 internal const val FEATURE_HOMEWORK = 4
const val FEATURE_HOMEWORK = 4 internal const val FEATURE_BEHAVIOUR = 5
const val FEATURE_BEHAVIOUR = 5 internal const val FEATURE_ATTENDANCE = 6
const val FEATURE_ATTENDANCE = 6 internal const val FEATURE_MESSAGES_INBOX = 7
const val FEATURE_MESSAGES_INBOX = 7 internal const val FEATURE_MESSAGES_SENT = 8
const val FEATURE_MESSAGES_SENT = 8 internal const val FEATURE_ANNOUNCEMENTS = 9
const val FEATURE_ANNOUNCEMENTS = 9
const val FEATURE_ALWAYS_NEEDED = 100 internal const val FEATURE_ALWAYS_NEEDED = 100
const val FEATURE_STUDENT_INFO = 101 internal const val FEATURE_STUDENT_INFO = 101
const val FEATURE_STUDENT_NUMBER = 109 internal const val FEATURE_STUDENT_NUMBER = 109
const val FEATURE_SCHOOL_INFO = 102 internal const val FEATURE_SCHOOL_INFO = 102
const val FEATURE_CLASS_INFO = 103 internal const val FEATURE_CLASS_INFO = 103
const val FEATURE_TEAM_INFO = 104 internal const val FEATURE_TEAM_INFO = 104
const val FEATURE_LUCKY_NUMBER = 105 internal const val FEATURE_LUCKY_NUMBER = 105
const val FEATURE_TEACHERS = 106 internal const val FEATURE_TEACHERS = 106
const val FEATURE_SUBJECTS = 107 internal const val FEATURE_SUBJECTS = 107
const val FEATURE_CLASSROOMS = 108 internal const val FEATURE_CLASSROOMS = 108
const val FEATURE_PUSH_CONFIG = 120 internal const val FEATURE_PUSH_CONFIG = 120
const val FEATURE_MESSAGE_GET = 201
object Features { object Features {
private fun getAllNecessary(): List<Int> = listOf( private fun getAllNecessary(): List<Int> = listOf(

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.sync
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
import kotlin.coroutines.CoroutineContext
class SyncViewListDialog(
val activity: MainActivity,
val currentViewId: Int? = null
) : CoroutineScope {
companion object {
private const val TAG = "SyncViewListDialog"
}
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private val app by lazy { activity.application as App }
private lateinit var b: DialogLessonDetailsBinding
private lateinit var dialog: AlertDialog
init { run {
job = Job()
val viewIds = arrayOf(
MainActivity.DRAWER_ITEM_TIMETABLE,
MainActivity.DRAWER_ITEM_AGENDA,
MainActivity.DRAWER_ITEM_GRADES,
MainActivity.DRAWER_ITEM_HOMEWORK,
MainActivity.DRAWER_ITEM_BEHAVIOUR,
MainActivity.DRAWER_ITEM_ATTENDANCE,
MainActivity.DRAWER_ITEM_MESSAGES,
MainActivity.DRAWER_ITEM_MESSAGES,
MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
)
val items = arrayOf<String>(
app.getString(R.string.menu_timetable),
app.getString(R.string.menu_agenda),
app.getString(R.string.menu_grades),
app.getString(R.string.menu_homework),
app.getString(R.string.menu_notices),
app.getString(R.string.menu_attendance),
app.getString(R.string.title_messages_inbox_single),
app.getString(R.string.title_messages_sent_single),
app.getString(R.string.menu_announcements)
)
val everything = currentViewId == MainActivity.DRAWER_ITEM_HOME
val checkedItems = booleanArrayOf(
everything || currentViewId == MainActivity.DRAWER_ITEM_TIMETABLE,
everything || currentViewId == MainActivity.DRAWER_ITEM_AGENDA,
everything || currentViewId == MainActivity.DRAWER_ITEM_GRADES,
everything || currentViewId == MainActivity.DRAWER_ITEM_HOMEWORK,
everything || currentViewId == MainActivity.DRAWER_ITEM_BEHAVIOUR,
everything || currentViewId == MainActivity.DRAWER_ITEM_ATTENDANCE,
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection != 1,
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection == 1,
everything || currentViewId == MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
)
val userChooses = checkedItems.toMutableList()
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.dialog_sync_view_list_title)
.setMultiChoiceItems(items, checkedItems) { _, which, isChecked ->
userChooses[which] = isChecked
}
.setPositiveButton(R.string.ok) { _, _ ->
dialog.dismiss()
val selectedViewIds = userChooses.mapIndexed { index, it ->
if (it)
viewIds[index] to when (index) {
7 -> 1
else -> 0
}
else
null
}.let {
listOfNotNull(*it.toTypedArray())
}
activity.swipeRefreshLayout.isRefreshing = true
EdziennikTask.syncProfile(
App.profileId,
selectedViewIds
).enqueue(activity)
}
.setNegativeButton(R.string.cancel) { _, _ ->
dialog.dismiss()
}
.show()
}}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
*/
package pl.szczodrzynski.edziennik.ui.modules.error
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
import kotlin.coroutines.CoroutineContext
class ErrorDialog(
val activity: AppCompatActivity,
val exception: Exception
) : CoroutineScope {
companion object {
private const val TAG = "ErrorDialog"
}
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private val app by lazy { activity.application as App }
private lateinit var b: DialogLessonDetailsBinding
private lateinit var dialog: AlertDialog
init { run {
job = Job()
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.error_occured)
.setMessage(exception.message + "\n" + Log.getStackTraceString(exception))
.setPositiveButton(R.string.ok) { _, _ ->
dialog.dismiss()
}
.show()
}}
}

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-11-13. * Copyright (c) Kuba Szczodrzyński 2019-11-13.
*/ */
package pl.szczodrzynski.edziennik.ui.dialogs.error package pl.szczodrzynski.edziennik.ui.modules.error
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity

View File

@ -17,7 +17,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError; import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.ActivityLoginBinding; import pl.szczodrzynski.edziennik.databinding.ActivityLoginBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
public class LoginActivity extends AppCompatActivity { public class LoginActivity extends AppCompatActivity {

View File

@ -17,7 +17,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError; import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieBinding; import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN; import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN;
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_SCHOOL_NAME; import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_SCHOOL_NAME;

View File

@ -17,7 +17,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError; import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding; import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_DATA_INVALID; import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_DATA_INVALID;
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED; import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED;

View File

@ -17,7 +17,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError; import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikBinding; import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_ARCHIVED; import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_ARCHIVED;
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN; import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN;

View File

@ -35,7 +35,7 @@ import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError; import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanBinding; import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.error.ErrorSnackbar; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
import pl.szczodrzynski.edziennik.ui.modules.webpush.QrScannerActivity; import pl.szczodrzynski.edziennik.ui.modules.webpush.QrScannerActivity;
import pl.szczodrzynski.edziennik.utils.Utils; import pl.szczodrzynski.edziennik.utils.Utils;

View File

@ -45,6 +45,7 @@ import pl.szczodrzynski.edziennik.MainActivity;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull; import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
import pl.szczodrzynski.edziennik.databinding.MessagesDetailsBinding; import pl.szczodrzynski.edziennik.databinding.MessagesDetailsBinding;
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog;
import pl.szczodrzynski.edziennik.utils.Themes; import pl.szczodrzynski.edziennik.utils.Themes;
import pl.szczodrzynski.edziennik.utils.Utils; import pl.szczodrzynski.edziennik.utils.Utils;
@ -320,7 +321,7 @@ public class MessagesDetailsFragment extends Fragment {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
app.apiEdziennik.guiReportException(activity, 355, e); new ErrorDialog(activity, e);
} }
} }
} }
@ -458,7 +459,7 @@ public class MessagesDetailsFragment extends Fragment {
.positiveText(R.string.ok) .positiveText(R.string.ok)
.neutralColor(R.string.report) .neutralColor(R.string.report)
.onNeutral((dialog, which) -> { .onNeutral((dialog, which) -> {
app.apiEdziennik.guiReportException(activity, 433, event.exception); new ErrorDialog(activity, event.exception);
}) })
.show(); .show();
} }
@ -466,7 +467,7 @@ public class MessagesDetailsFragment extends Fragment {
} }
} }
catch (Exception e) { catch (Exception e) {
app.apiEdziennik.guiReportException(activity, 425, e); new ErrorDialog(activity, e);
} }
} }

View File

@ -1,474 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.messages;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.MimeTypeMap;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.StackingBehavior;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.databinding.FragmentMessagesWebBinding;
import pl.szczodrzynski.edziennik.utils.Anim;
import pl.szczodrzynski.edziennik.utils.Themes;
import static android.app.Activity.RESULT_OK;
import static android.content.Context.DOWNLOAD_SERVICE;
import static pl.szczodrzynski.edziennik.utils.Utils.readableFileSize;
public class MessagesWebFragment extends Fragment {
private static final String TAG = "RegisterMessagesWeb";
private App app = null;
private Activity activity = null;
private FragmentMessagesWebBinding b = null;
private WebView webView;
private ProgressBar progressBar;
private TextView error;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
if (getActivity() == null || getContext() == null)
return null;
app = (App) activity.getApplication();
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
if (app.profile == null)
return inflater.inflate(R.layout.fragment_loading, container, false);
// activity, context and profile is valid
b = DataBindingUtil.inflate(inflater, R.layout.fragment_messages_web, container, false);
return b.getRoot();
}
private boolean isStoragePermissionGranted(Activity a) {
if (Build.VERSION.SDK_INT >= 23) {
if (a.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted");
return true;
} else {
Log.v(TAG,"Permission is revoked");
ActivityCompat.requestPermissions(a, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted");
return true;
}
}
private String getFileNameFromDisposition(String header)
{
return header.substring(header.indexOf("\"") + 1, header.lastIndexOf("\""));
}
private File downloadingFile;
private void enqueueFile(String url, String filename, File downloadingFile, String cookieString) {
this.downloadingFile = downloadingFile;
long downloadReference;
DownloadManager downloadManager;
downloadManager = (DownloadManager)app.getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setTitle(filename);
request.setDescription(getString(R.string.downloading));
request.addRequestHeader("Cookie", cookieString);
try {
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
}
catch (IllegalStateException e)
{
e.printStackTrace();
Toast.makeText(app, "Failed to get external storage files directory", Toast.LENGTH_SHORT).show();
}
downloadReference = downloadManager.enqueue(request);
}
private static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return type;
}
private void openFile(File url) {
Toast.makeText(app, getString(R.string.opening_file, url.getName()), Toast.LENGTH_SHORT).show();
try {
Uri uri = FileProvider.getUriForFile(app, app.getApplicationContext().getPackageName() + ".provider", url);
//Uri uri = Uri.fromFile(url);
Intent intent = new Intent(Intent.ACTION_VIEW);
if (url.toString().contains(".doc") || url.toString().contains(".docx")) {
// Word document
intent.setDataAndType(uri, "application/msword");
} else if (url.toString().contains(".pdf")) {
// PDF file
intent.setDataAndType(uri, "application/pdf");
} else if (url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
// Powerpoint file
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
} else if (url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
// Excel file
intent.setDataAndType(uri, "application/vnd.ms-excel");
} else if (url.toString().contains(".zip") || url.toString().contains(".rar")) {
// WAV audio file
intent.setDataAndType(uri, "application/x-wav");
} else if (url.toString().contains(".rtf")) {
// RTF file
intent.setDataAndType(uri, "application/rtf");
} else if (url.toString().contains(".wav") || url.toString().contains(".mp3")) {
// WAV audio file
intent.setDataAndType(uri, "audio/x-wav");
} else if (url.toString().contains(".gif")) {
// GIF file
intent.setDataAndType(uri, "image/gif");
} else if (url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
// JPG file
intent.setDataAndType(uri, "image/jpeg");
} else if (url.toString().contains(".txt")) {
// Text file
intent.setDataAndType(uri, "text/plain");
} else if (url.toString().contains(".3gp") || url.toString().contains(".mpg") ||
url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
// Video files
intent.setDataAndType(uri, "video/*");
} else {
intent.setDataAndType(uri, "*/*");
}
intent.setDataAndType(uri, getMimeType(uri.toString()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
app.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(app, R.string.opening_file_no_app, Toast.LENGTH_SHORT).show();
}
}
private void downloadFile(Activity a, String url, String filename, long contentLength, String cookieString) {
if (!isStoragePermissionGranted(a))
return;
new MaterialDialog.Builder(a)
.title(R.string.downloading_file)
.content(getString((R.string.download_file_question), filename, readableFileSize(contentLength)))
.positiveText(R.string.yes)
.negativeText(R.string.no)
.onPositive((dialog, which) -> {
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File existingFile = new File(downloadsDir, filename);
if (existingFile.exists()) {
new MaterialDialog.Builder(a)
.title(R.string.downloading_file)
.content(getString(R.string.downloading_file_exists_choose, filename))
.stackingBehavior(StackingBehavior.ADAPTIVE)
.positiveText(R.string.downloading_file_exists_overwrite)
.negativeText(R.string.downloading_file_exists_open)
.neutralText(R.string.downloading_file_exists_create_new)
.onPositive(((dialog1, which1) -> {
if (!existingFile.delete())
{
new MaterialDialog.Builder(a)
.title(R.string.downloading_file)
.content(R.string.downloading_file_cannot_remove)
.positiveText(R.string.ok)
.negativeText(R.string.cancel)
.onPositive(((dialog2, which2) -> enqueueFile(url, filename, existingFile, cookieString)))
.show();
return;
}
enqueueFile(url, filename, existingFile, cookieString);
}))
.onNegative(((dialog1, which1) -> openFile(existingFile)))
.onNeutral((dialog1, which1) -> enqueueFile(url, filename, existingFile, cookieString))
.show();
return;
}
enqueueFile(url, filename, existingFile, cookieString);
})
.show();
}
private String photoPath;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> fileCallback;
private final static int REQUEST_FILE_CHOOSER = 1;
private boolean justLoaded = false;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(Build.VERSION.SDK_INT >= 21){
Uri[] results = null;
//Check if response is positive
if(resultCode == RESULT_OK){
if(requestCode == REQUEST_FILE_CHOOSER){
if(null == fileCallback){
return;
}
if(data == null){
//Capture Photo if no image available
if (photoPath != null) {
results = new Uri[]{Uri.parse(photoPath)};
}
}else{
String dataString = data.getDataString();
if(dataString != null){
results = new Uri[]{Uri.parse(dataString)};
}
}
}
}
fileCallback.onReceiveValue(results);
fileCallback = null;
} else {
if (requestCode == REQUEST_FILE_CHOOSER) {
if(null == mUM) return;
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
mUM.onReceiveValue(result);
mUM = null;
}
}
}
private File createImageFile() throws IOException{
@SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "img_"+timeStamp+"_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return File.createTempFile(imageFileName,".jpg",storageDir);
}
@SuppressLint("SetJavaScriptEnabled")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
return;
webView = b.messagesWebView;
progressBar = b.messagesWebProgressBar;
error = b.messagesWebError;
justLoaded = true;
new Handler().postDelayed(() -> activity.runOnUiThread(() -> {
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
return;
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (downloadingFile != null) {
openFile(downloadingFile);
downloadingFile = null;
}
}
};
activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
app.apiEdziennik.initMessagesWebView(webView, app, /*app.profile.messagesWebFullVersion*/false, false);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
String filename = getFileNameFromDisposition(contentDisposition);
try {
URL urlObj = new URL(url);
Log.d(TAG, "Host "+urlObj.getProtocol()+"://"+urlObj.getHost());
Log.d(TAG, "Cookies "+CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
downloadFile(getActivity(), url, filename, contentLength, CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
} catch (MalformedURLException e) {
e.printStackTrace();
}
Anim.fadeOut(progressBar, 400, null);
});
webView.setWebViewClient(new WebViewClient() {
boolean loadingFinished = true;
boolean redirect = false;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String request) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
webView.loadUrl(request);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
MessagesWebFragment.this.error.setVisibility(View.GONE);
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
if (progressBar.getVisibility() != View.VISIBLE)
Anim.fadeIn(progressBar, 400, null);
}
@Override
public void onPageFinished(WebView view, String url) {
if (!redirect) {
loadingFinished = true;
}
if (loadingFinished && !redirect) {
//HIDE LOADING IT HAS FINISHED
//String cookies = CookieManager.getInstance().getCookie(url);
//Log.d(TAG, "All the cookies in a string:" + cookies);
Anim.fadeOut(progressBar, 400, null);
/*if (app.profile.messagesWebFullVersion && justLoaded && app.profile.loginType == Register.LOGIN_TYPE_MOBIDZIENNIK) {
if (!webView.getUrl().contains("wiadomosci")) {
// redirect to messages view
webView.loadUrl("https://" + app.getLoginData("serverName", "") + ".mobidziennik.pl/mobile/wiadomosci");
}
justLoaded = false;
}*/
} else {
redirect = false;
}
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
return;
MessagesWebFragment.this.error.setVisibility(View.VISIBLE);
MessagesWebFragment.this.error.setText(getString(R.string.error_occured_format, error.toString()));
super.onReceivedError(view, request, error);
}
});
if(Build.VERSION.SDK_INT >= 21) {
webView.getSettings().setMixedContentMode(0);
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if(Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.setWebChromeClient(new WebChromeClient(){
//For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams){
if(fileCallback != null){
fileCallback.onReceiveValue(null);
}
fileCallback = filePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(takePictureIntent.resolveActivity(app.getPackageManager()) != null){
File photoFile = null;
try{
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", photoPath);
}catch(IOException ex){
Log.e(TAG, "Image file creation failed", ex);
}
if(photoFile != null){
photoPath = "file:" + photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
}else{
takePictureIntent = null;
}
}
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
Intent[] intentArray;
if(takePictureIntent != null){
intentArray = new Intent[]{takePictureIntent};
}else{
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, R.string.choose_file);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, REQUEST_FILE_CHOOSER);
return true;
}
});
}), 200);
}
/*public void loadVersion(boolean fullVersion) {
if (app.profile.messagesWebFullVersion != fullVersion) {
app.profile.messagesWebFullVersion = fullVersion;
app.profile.savePending = true;
justLoaded = true;
app.apiEdziennik.initMessagesWebView(webView, app, fullVersion, true);
}
}*/
public void performReload() {
webView.reload();
}
public boolean processBackKey()
{
if (webView.canGoBack())
{
webView.goBack();
return true;
}
return false;
}
}

View File

@ -51,6 +51,7 @@ import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull; import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableBinding; import pl.szczodrzynski.edziennik.databinding.FragmentTimetableBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog; import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog;
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment; import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler; import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler;
import pl.szczodrzynski.edziennik.utils.Themes; import pl.szczodrzynski.edziennik.utils.Themes;
@ -422,7 +423,7 @@ public class TimetableFragment extends Fragment {
linearLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.row_timetable_block_item, null); linearLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.row_timetable_block_item, null);
} }
catch (Exception e) { catch (Exception e) {
app.apiEdziennik.guiReportException(activity, 385, e); new ErrorDialog(activity, e);
return; return;
} }

View File

@ -1024,4 +1024,5 @@
<string name="dialog_event_manual_no_lessons">Nie ma lekcji tego dnia</string> <string name="dialog_event_manual_no_lessons">Nie ma lekcji tego dnia</string>
<string name="dialog_profile_remove_success">Profil został usunięty.</string> <string name="dialog_profile_remove_success">Profil został usunięty.</string>
<string name="snackbar_error_text">Wystąpił błąd</string> <string name="snackbar_error_text">Wystąpił błąd</string>
<string name="dialog_sync_view_list_title">Synchronizacja ręczna</string>
</resources> </resources>