Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TipsAdapter.java « tips « exception « ui « deck « nextcloud « niedermann « it « java « main « src « app - github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9ebe14ad19d5703a294a47a10152e9cbe2a28bc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package it.niedermann.nextcloud.deck.ui.exception.tips;

import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
import static it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment.INTENT_EXTRA_BUTTON_TEXT;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView;

import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException;
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import com.nextcloud.android.sso.exceptions.TokenMismatchException;
import com.nextcloud.android.sso.exceptions.UnknownErrorException;
import com.nextcloud.android.sso.model.FilesAppType;

import org.json.JSONException;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.LinkedList;
import java.util.List;

import it.niedermann.nextcloud.deck.BuildConfig;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.exceptions.DeckException;
import it.niedermann.nextcloud.deck.exceptions.OfflineException;
import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException;
import it.niedermann.nextcloud.deck.model.Account;

public class TipsAdapter extends RecyclerView.Adapter<TipsViewHolder> {

    private static final Intent INTENT_APP_INFO = new Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
            .setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID))
            .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_deck_info);

    @NonNull
    private final Consumer<Intent> actionButtonClickedListener;
    @NonNull
    private final List<TipsModel> tips = new LinkedList<>();

    public TipsAdapter(@NonNull Consumer<Intent> actionButtonClickedListener) {
        this.actionButtonClickedListener = actionButtonClickedListener;
    }

    @NonNull
    @Override
    public TipsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        final var view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tip, parent, false);
        return new TipsViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull TipsViewHolder holder, int position) {
        holder.bind(tips.get(position), actionButtonClickedListener);
    }

    @Override
    public int getItemCount() {
        return tips.size();
    }

    public void setThrowable(@NonNull Context context, @Nullable Account account, @NonNull Throwable throwable) {
        if (throwable instanceof TokenMismatchException) {
            add(R.string.error_dialog_tip_token_mismatch_retry);
            add(R.string.error_dialog_tip_clear_storage_might_help);
            add(R.string.error_dialog_tip_clear_storage, INTENT_APP_INFO);
        } else if (throwable instanceof NextcloudFilesAppAccountNotFoundException) {
            // TODO we can give better hints here...
            add(R.string.error_dialog_tip_token_mismatch_retry);
            add(R.string.error_dialog_tip_clear_storage_might_help);
            add(R.string.error_dialog_tip_clear_storage, INTENT_APP_INFO);
        } else if (throwable instanceof NextcloudFilesAppNotSupportedException) {
            add(R.string.error_dialog_min_version, new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.nextcloud.client"))
                    .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_update_files_app));
        } else if (throwable instanceof OfflineException) {
            add(((OfflineException) throwable).getReason().getMessage());
            add(R.string.error_dialog_tip_sync_only_on_wifi);
        } else if (throwable instanceof NextcloudApiNotRespondingException) {
            add(R.string.error_dialog_tip_disable_battery_optimizations, new Intent().setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS).putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_battery_settings));
            add(R.string.error_dialog_tip_files_force_stop);
            add(R.string.error_dialog_tip_files_delete_storage);
        } else if (throwable instanceof SocketTimeoutException || throwable instanceof ConnectException) {
            add(R.string.error_dialog_timeout_instance);
            add(R.string.error_dialog_timeout_toggle, new Intent(Settings.ACTION_WIFI_SETTINGS).putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_network));
        } else if (throwable instanceof JSONException || throwable instanceof NullPointerException) {
            add(R.string.error_dialog_check_server);
        } else if (throwable instanceof NextcloudHttpRequestFailedException) {
            int statusCode = ((NextcloudHttpRequestFailedException) throwable).getStatusCode();
            switch (statusCode) {
                case 302 -> add(R.string.error_dialog_redirect);
                case 500 -> {
                    if (account != null) {
                        add(R.string.error_dialog_check_server_logs, new Intent(Intent.ACTION_VIEW)
                                .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs)
                                .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_server_logs))));
                    } else {
                        add(R.string.error_dialog_check_server_logs);
                    }
                }
                case 503 -> add(R.string.error_dialog_check_maintenance);
                case 507 -> add(R.string.error_dialog_insufficient_storage);
            }
        } else if (throwable instanceof UploadAttachmentFailedException) {
            add(R.string.error_dialog_attachment_upload_failed);
        } else if (throwable instanceof ClassNotFoundException) {
            final Throwable cause = ((ClassNotFoundException) throwable).getCause();
            if (cause != null) {
                final String message = cause.getMessage();
                if (message != null && message.toLowerCase().contains("certificate")) {
                    final Intent filesOpenIntent = getOpenFilesIntent(context);
                    if (filesOpenIntent == null) {
                        add(R.string.error_dialog_certificate);
                    } else {
                        add(R.string.error_dialog_certificate, filesOpenIntent);
                    }
                }
            }
        } else if (throwable instanceof DeckException) {
            switch (((DeckException) throwable).getHint()) {
                case CAPABILITIES_VERSION_NOT_PARSABLE:
                    if (account != null) {
                        add(R.string.error_dialog_version_not_parsable, new Intent(Intent.ACTION_VIEW)
                                .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_install)
                                .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_install_deck))));
                    } else {
                        add(R.string.error_dialog_version_not_parsable);
                    }
                    add(R.string.error_dialog_account_might_not_be_authorized);
                    break;
                case UNKNOWN_ACCOUNT_USER_ID:
                    add(R.string.error_dialog_user_not_found_in_database);
                    break;
                case CAPABILITIES_NOT_PARSABLE:
                default:
                    if (account != null) {
                        add(R.string.error_dialog_capabilities_not_parsable, new Intent(Intent.ACTION_VIEW)
                                .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_server_logs)
                                .setData(Uri.parse(account.getUrl() + context.getString(R.string.url_fragment_server_logs))));
                    } else {
                        add(R.string.error_dialog_capabilities_not_parsable);
                    }
            }
            // Files app might no longer be authenticated: https://github.com/stefan-niedermann/nextcloud-deck/issues/621#issuecomment-665533567
            add(R.string.error_dialog_tip_clear_storage_might_help);
            add(R.string.error_dialog_tip_clear_storage, INTENT_APP_INFO);
        } else if (throwable instanceof RuntimeException) {
            if (throwable.getMessage() != null && throwable.getMessage().toLowerCase().contains("database")) {
                final var intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.url_report_bug)))
                        .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_report_issue);
                add(R.string.error_dialog_tip_database_upgrade_failed, intent);
                add(R.string.error_dialog_tip_clear_storage, INTENT_APP_INFO);
            }
        } else if (throwable instanceof UnknownErrorException) {
            if ("com.nextcloud.android.sso.QueryParam".equals(throwable.getMessage())) {
                add(R.string.error_dialog_min_version, new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.nextcloud.client"))
                        .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_update_files_app));
            } else {
                if (account != null) {
                    add(R.string.error_dialog_unknown_error, new Intent(Intent.ACTION_VIEW)
                            .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_in_browser)
                            .setData(Uri.parse(account.getUrl())));
                } else {
                    add(R.string.error_dialog_unknown_error);
                }
            }
        }
    }

    public void add(@StringRes int text) {
        add(text, null);
    }

    public void add(@StringRes int text, @Nullable Intent primaryAction) {
        tips.add(new TipsModel(text, primaryAction));
        notifyItemInserted(tips.size());
    }

    @Nullable
    private static Intent getOpenFilesIntent(@NonNull Context context) {
        final var pm = context.getPackageManager();
        for (final var filesAppType : FilesAppType.values()) {
            try {
                pm.getPackageInfo(filesAppType.packageId, PackageManager.GET_ACTIVITIES);
                return pm.getLaunchIntentForPackage(filesAppType.packageId)
                        .putExtra(INTENT_EXTRA_BUTTON_TEXT, R.string.error_action_open_nextcloud_app);
            } catch (PackageManager.NameNotFoundException ignored) {
            }
        }
        return null;
    }
}