Add hosts UI
This commit is contained in:
1 parent
facb931cb6
commit
029bca22ed
13 files changed
+566
-15
No files matched your search
@@ -31,6 +31,7 @@ import com.hippo.beerbelly.SimpleDiskCache;
|
||||
import com.hippo.conaco.Conaco;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhCookieStore;
|
||||
import com.hippo.ehviewer.client.EhDns;
|
||||
import com.hippo.ehviewer.client.EhEngine;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.download.DownloadManager;
|
||||
@@ -81,6 +82,7 @@ public class EhApplication extends SceneApplication implements Thread.UncaughtEx
|
||||
private LruCache<Long, GalleryDetail> mGalleryDetailCache;
|
||||
private SimpleDiskCache mSpiderInfoCache;
|
||||
private DownloadManager mDownloadManager;
|
||||
private Hosts mHosts;
|
||||
|
||||
private final List<Activity> mActivityList = new ArrayList<>();
|
||||
|
||||
@@ -238,6 +240,7 @@ public class EhApplication extends SceneApplication implements Thread.UncaughtEx
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.cookieJar(getEhCookieStore(application))
|
||||
.dns(new EhDns(application))
|
||||
.build();
|
||||
}
|
||||
return application.mOkHttpClient;
|
||||
@@ -303,6 +306,15 @@ public class EhApplication extends SceneApplication implements Thread.UncaughtEx
|
||||
return application.mDownloadManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Hosts getHosts(@NonNull Context context) {
|
||||
EhApplication application = ((EhApplication) context.getApplicationContext());
|
||||
if (application.mHosts == null) {
|
||||
application.mHosts = new Hosts(application, "hosts.db");
|
||||
}
|
||||
return application.mHosts;
|
||||
}
|
||||
|
||||
private boolean handleException(Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2018 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
/*
|
||||
* Created by Hippo on 2018/3/23.
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.Hosts;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import okhttp3.Dns;
|
||||
|
||||
public class EhDns implements Dns {
|
||||
|
||||
private final Hosts hosts;
|
||||
|
||||
public EhDns(Context context) {
|
||||
hosts = EhApplication.getHosts(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
|
||||
if (hostname == null) throw new UnknownHostException("hostname == null");
|
||||
|
||||
InetAddress inetAddress = hosts.get(hostname);
|
||||
if (inetAddress != null) {
|
||||
return Collections.singletonList(inetAddress);
|
||||
}
|
||||
|
||||
try {
|
||||
return Arrays.asList(InetAddress.getAllByName(hostname));
|
||||
} catch (NullPointerException e) {
|
||||
UnknownHostException unknownHostException =
|
||||
new UnknownHostException("Broken system behaviour for dns lookup of " + hostname);
|
||||
unknownHostException.initCause(e);
|
||||
throw unknownHostException;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright 2018 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.ui;
|
||||
|
||||
/*
|
||||
* Created by Hippo on 2018/3/23.
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.Hosts;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ripple.Ripple;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HostsActivity extends ToolbarActivity
|
||||
implements EasyRecyclerView.OnItemClickListener, View.OnClickListener {
|
||||
|
||||
private static final String DIALOG_TAG_ADD_HOST = AddHostDialogFragment.class.getName();
|
||||
private static final String DIALOG_TAG_EDIT_HOST = EditHostDialogFragment.class.getName();
|
||||
|
||||
private static final String KEY_HOST = "com.hippo.ehviewer.ui.HostsActivity.HOST";
|
||||
private static final String KEY_IP = "com.hippo.ehviewer.ui.HostsActivity.IP";
|
||||
|
||||
private Hosts hosts;
|
||||
private List<Pair<String, String>> data;
|
||||
|
||||
private EasyRecyclerView recyclerView;
|
||||
private View tip;
|
||||
private HostsAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
hosts = EhApplication.getHosts(this);
|
||||
data = hosts.getAll();
|
||||
|
||||
setContentView(R.layout.activity_hosts);
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
recyclerView = findViewById(R.id.recycler_view);
|
||||
tip = findViewById(R.id.tip);
|
||||
FloatingActionButton fab = findViewById(R.id.fab);
|
||||
|
||||
adapter = new HostsAdapter();
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
|
||||
LinearDividerItemDecoration decoration = new LinearDividerItemDecoration(
|
||||
LinearDividerItemDecoration.VERTICAL,
|
||||
getResources().getColor(R.color.divider),
|
||||
LayoutUtils.dp2pix(this, 1));
|
||||
decoration.setShowLastDivider(true);
|
||||
recyclerView.addItemDecoration(decoration);
|
||||
recyclerView.setSelector(Ripple.generateRippleDrawable(this, false));
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setOnItemClickListener(this);
|
||||
recyclerView.setPadding(
|
||||
recyclerView.getPaddingLeft(),
|
||||
recyclerView.getPaddingTop(),
|
||||
recyclerView.getPaddingRight(),
|
||||
recyclerView.getPaddingBottom() + getResources().getDimensionPixelOffset(R.dimen.gallery_padding_bottom_fab));
|
||||
|
||||
fab.setOnClickListener(this);
|
||||
|
||||
recyclerView.setVisibility(data.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
tip.setVisibility(data.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemClick(EasyRecyclerView easyRecyclerView, View view, int position, long id) {
|
||||
Pair<String, String> pair = data.get(position);
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_HOST, pair.first);
|
||||
args.putString(KEY_IP, pair.second);
|
||||
|
||||
DialogFragment fragment = new EditHostDialogFragment();
|
||||
fragment.setArguments(args);
|
||||
fragment.show(getSupportFragmentManager(), DIALOG_TAG_EDIT_HOST);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
new AddHostDialogFragment().show(getSupportFragmentManager(), DIALOG_TAG_ADD_HOST);
|
||||
}
|
||||
|
||||
private void notifyHostsChanges() {
|
||||
data = hosts.getAll();
|
||||
recyclerView.setVisibility(data.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
tip.setVisibility(data.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private class HostsHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public final TextView host;
|
||||
public final TextView ip;
|
||||
|
||||
public HostsHolder(View itemView) {
|
||||
super(itemView);
|
||||
host = itemView.findViewById(R.id.host);
|
||||
ip = itemView.findViewById(R.id.ip);
|
||||
}
|
||||
}
|
||||
|
||||
private class HostsAdapter extends RecyclerView.Adapter<HostsHolder> {
|
||||
|
||||
private final LayoutInflater inflater = getLayoutInflater();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HostsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new HostsHolder(inflater.inflate(R.layout.item_hosts, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull HostsHolder holder, int position) {
|
||||
Pair<String, String> pair = data.get(position);
|
||||
holder.host.setText(pair.first);
|
||||
holder.ip.setText(pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return data.size();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class HostDialogFragment extends DialogFragment {
|
||||
|
||||
private TextView host;
|
||||
private TextView ip;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_hosts, null, false);
|
||||
host = view.findViewById(R.id.host);
|
||||
ip = view.findViewById(R.id.ip);
|
||||
|
||||
Bundle arguments = getArguments();
|
||||
if (savedInstanceState == null && arguments != null) {
|
||||
host.setText(arguments.getString(KEY_HOST));
|
||||
ip.setText(arguments.getString(KEY_IP));
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()).setView(view);
|
||||
onCreateDialogBuilder(builder);
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(d -> onCreateDialog((AlertDialog) d));
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
protected abstract void onCreateDialogBuilder(AlertDialog.Builder builder);
|
||||
|
||||
protected abstract void onCreateDialog(AlertDialog dialog);
|
||||
|
||||
protected void put(AlertDialog dialog) {
|
||||
TextView host = dialog.findViewById(R.id.host);
|
||||
TextView ip = dialog.findViewById(R.id.ip);
|
||||
String hostString = host.getText().toString().trim().toLowerCase(Locale.US);
|
||||
String ipString = ip.getText().toString().trim();
|
||||
|
||||
if (!Hosts.isValidHost(hostString)) {
|
||||
TextInputLayout hostInputLayout = dialog.findViewById(R.id.host_input_layout);
|
||||
hostInputLayout.setError(getContext().getString(R.string.invalid_host));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Hosts.isValidIp(ipString)) {
|
||||
TextInputLayout ipInputLayout = dialog.findViewById(R.id.ip_input_layout);
|
||||
ipInputLayout.setError(getContext().getString(R.string.invalid_ip));
|
||||
return;
|
||||
}
|
||||
|
||||
HostsActivity activity = (HostsActivity) dialog.getOwnerActivity();
|
||||
activity.hosts.put(hostString, ipString);
|
||||
activity.notifyHostsChanges();
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
protected void delete(AlertDialog dialog) {
|
||||
TextView host = dialog.findViewById(R.id.host);
|
||||
String hostString = host.getText().toString().trim().toLowerCase(Locale.US);
|
||||
|
||||
HostsActivity activity = (HostsActivity) dialog.getOwnerActivity();
|
||||
activity.hosts.delete(hostString);
|
||||
activity.notifyHostsChanges();
|
||||
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AddHostDialogFragment extends HostDialogFragment {
|
||||
|
||||
@Override
|
||||
protected void onCreateDialogBuilder(AlertDialog.Builder builder) {
|
||||
builder.setTitle(R.string.add_host);
|
||||
builder.setPositiveButton(R.string.add_host_add, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateDialog(AlertDialog dialog) {
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> put(dialog));
|
||||
}
|
||||
}
|
||||
|
||||
public static class EditHostDialogFragment extends HostDialogFragment {
|
||||
|
||||
@Override
|
||||
protected void onCreateDialogBuilder(AlertDialog.Builder builder) {
|
||||
builder.setTitle(R.string.edit_host);
|
||||
builder.setPositiveButton(R.string.edit_host_confirm, null);
|
||||
builder.setNegativeButton(R.string.edit_host_delete, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateDialog(AlertDialog dialog) {
|
||||
dialog.findViewById(R.id.host_input_layout).setEnabled(false);
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> put(dialog));
|
||||
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(v -> delete(dialog));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user