diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 00000000..a9d36e9d
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,43 @@
+{
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "commitConvention": "angular",
+ "contributors": [
+ {
+ "login": "graycreate",
+ "name": "GRAY",
+ "avatar_url": "https://avatars.githubusercontent.com/u/5203798?v=4",
+ "profile": "https://github.com/graycreate",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "shiqizhenyes",
+ "name": "zack",
+ "avatar_url": "https://avatars.githubusercontent.com/u/10935531?v=4",
+ "profile": "http://sqz.mobi",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "Mystery00",
+ "name": "Mystery0 M",
+ "avatar_url": "https://avatars.githubusercontent.com/u/19162205?v=4",
+ "profile": "https://blog.mystery0.vip",
+ "contributions": [
+ "code"
+ ]
+ }
+ ],
+ "contributorsPerLine": 7,
+ "skipCi": true,
+ "repoType": "github",
+ "repoHost": "https://github.com",
+ "projectName": "Android",
+ "projectOwner": "v2er-app"
+}
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 00000000..740c2ee9
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,26 @@
+name: Android CI
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: set up JDK 11
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ cache: gradle
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build with Gradle
+ run: ./gradlew build
diff --git a/README.md b/README.md
index f8eaabd1..2a0d5ee8 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,41 @@
# V2er-Android
+
+[](#contributors-)
+
A beautiful V2EX client built for Android platform.
-You could download it from [Google Play](https://play.google.com/store/apps/details?id=me.ghui.v2er) or [CoolApk](https://www.coolapk.com/apk/155428)
+You could download it from [Google Play](https://play.google.com/store/apps/details?id=me.ghui.v2er)
-
+
-# Contribute
-TODO
+## Contributors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+For details please visit [insights](https://github.com/v2er-app/Android/graphs/contributors)
# Licensing
The source code is licensed under GPL. License is available [here](./LICENSE).
diff --git a/app/build.gradle b/app/build.gradle
index 972c4cbf..5125aac5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,16 +2,19 @@ apply plugin: 'com.android.application'
//apply plugin: "com.flurry.android.symbols"
android {
- compileSdkVersion 30
+ compileSdkVersion 33
defaultConfig {
applicationId "me.ghui.v2er"
minSdkVersion 27
- targetSdkVersion 30
+ targetSdkVersion 33
versionCode rootProject.ext.app.versionCode
versionName rootProject.ext.app.versionName
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
+ manifestPlaceholders = [
+ APPLICATION_ID: applicationId
+ ]
}
signingConfigs {
release {
@@ -58,6 +61,7 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
exclude group: 'com.google.code.findbugs'
@@ -72,6 +76,7 @@ dependencies {
implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android:flexbox:0.2.6'
+ implementation "com.google.android.material:material:1.4.0"
implementation "androidx.annotation:annotation:1.2.0"
// 3rd part Dependencies...
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e6a8516a..2822fa6d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,14 +1,17 @@
-
+
@@ -16,8 +19,8 @@
android:name="android.max_aspect"
android:value="2.1" />
+ android:theme="@style/SplashTheme"
+ android:exported="true">
@@ -59,66 +62,52 @@
+ android:label="@string/page_daily_hot" />
+ android:label="登录V2EX" />
+ android:label="两步验证" />
+ android:label="Sign in With Google" />
+ android:label="主页" />
+ android:label="特别关注" />
+ android:label="收藏" />
+ android:label="节点" />
diff --git a/app/src/main/assets/v2ex.com.cer b/app/src/main/assets/v2ex.com.cer
new file mode 100644
index 00000000..e9060ddd
--- /dev/null
+++ b/app/src/main/assets/v2ex.com.cer
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCjCCBLGgAwIBAgIQDDQDGM1v+PJ15gZd51KyYzAKBggqhkjOPQQDAjBKMQsw
+CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
+Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjIwNTAxMDAwMDAwWhcNMjMwNTAx
+MjM1OTU5WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
+A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjER
+MA8GA1UEAxMIdjJleC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQa3Xed
+Yo0WA1IiCBkOo7jsJFV/iyI34W+WbQ72CqT54tGbN4Dh75Cb3XZVlPF6CVwPOfhN
+Guf1DNLe8pMWT5sco4IDWTCCA1UwHwYDVR0jBBgwFoAUpc436uuwdQ6UZ4i0RfrZ
+JBCHlh8wHQYDVR0OBBYEFDDEWpUY1uZB2VTEKMdyTWbWOXOXMB8GA1UdEQQYMBaC
+CioudjJleC5jb22CCHYyZXguY29tMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
+BggrBgEFBQcDAQYIKwYBBQUHAwIwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2Ny
+bDMuZGlnaWNlcnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNybDA3oDWgM4Yx
+aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNy
+bDA+BgNVHSAENzA1MDMGBmeBDAECAjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3
+LmRpZ2ljZXJ0LmNvbS9DUFMwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhho
+dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNl
+cnRzLmRpZ2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcnQwDAYDVR0T
+AQH/BAIwADCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYArfe++nz/EMiLnT2c
+Hj4YarRnKV3PsQwkyoWGNOvcgooAAAGAfVYWOQAABAMARzBFAiEAr8T/GHTEZ5ST
+FAd9K5krr4KkwBLRmrVJgTxJrodC1PUCIHYVe+eHWr12bt+FYd6ei3pIpJLIg9oX
+/HyWznIKy1l3AHYANc8ZG7+xbFe/D61MbULLu7YnICZR6j/hKu+oA8M71kwAAAGA
+fVYWIAAABAMARzBFAiEAu4gv2QeBcejY2pm7uupdyFNDSA+vksdk2WK6FEXcBtkC
+IFPdKOugZw3f4dO5wvz2iFqDz/CJ862G/6hPFGaYPbm3AHYAs3N3B+GEUPhjhtYF
+qdwRCUp5LbFnDAuH3PADDnk2pZoAAAGAfVYWUgAABAMARzBFAiB0fFp55Dbc4sA3
+LYC0zO6rhlI8q1aFF3p8VDdeeBXCAAIhAI6+C33azX4d+rg18TTMCBIF+bXtiztx
+fjO5Lp/uPso0MAoGCCqGSM49BAMCA0cAMEQCIApn7EQolzU9Qeexj0S/XWw7UB5n
+C/iL4PezrNnbjmqfAiB6sodlkyGMV8kUtuv9aRVkhSFkge630DbVm1Dhfb2aqg==
+-----END CERTIFICATE-----
diff --git a/app/src/main/java/me/ghui/v2er/bus/event/DayNightModeEvent.java b/app/src/main/java/me/ghui/v2er/bus/event/DayNightModeEvent.java
index ac9a8645..5a194d42 100644
--- a/app/src/main/java/me/ghui/v2er/bus/event/DayNightModeEvent.java
+++ b/app/src/main/java/me/ghui/v2er/bus/event/DayNightModeEvent.java
@@ -20,7 +20,7 @@ private DayNightModeEvent(@DarkModelUtils.DayNightMode int mode) {
this.mode = mode;
}
- public int getMode() {
+ public @DarkModelUtils.DayNightMode int getMode() {
return mode;
}
diff --git a/app/src/main/java/me/ghui/v2er/general/App.java b/app/src/main/java/me/ghui/v2er/general/App.java
index ea615bdf..e7515e67 100644
--- a/app/src/main/java/me/ghui/v2er/general/App.java
+++ b/app/src/main/java/me/ghui/v2er/general/App.java
@@ -2,6 +2,8 @@
import android.app.Application;
import android.preference.PreferenceManager;
+import android.util.Log;
+
import androidx.annotation.Nullable;
import com.flurry.android.FlurryAgent;
@@ -13,6 +15,8 @@
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
+import java.util.Calendar;
+
import io.reactivex.plugins.RxJavaPlugins;
import me.ghui.v2er.BuildConfig;
import me.ghui.v2er.R;
@@ -32,6 +36,7 @@ public class App extends Application {
private static App sInstance;
private AppComponent mAppComponent;
private IWXAPI mWechat;
+ public int unReadMsgCount = 0;
public static App get() {
return sInstance;
diff --git a/app/src/main/java/me/ghui/v2er/general/Navigator.java b/app/src/main/java/me/ghui/v2er/general/Navigator.java
index 41b8da12..721013fb 100644
--- a/app/src/main/java/me/ghui/v2er/general/Navigator.java
+++ b/app/src/main/java/me/ghui/v2er/general/Navigator.java
@@ -5,11 +5,17 @@
import android.content.Context;
import android.content.Intent;
import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.util.Pair;
+
import android.view.View;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
/**
@@ -75,6 +81,23 @@ public Navigator addFlag(int flag) {
return this;
}
+ public Navigator shareElement(View... sourceViews) {
+ Pair[] sharedElements;
+ List sourceViewList = new ArrayList<>(sourceViews.length);
+ Collections.addAll(sourceViewList, sourceViews);
+ sourceViewList.removeIf(sourceView -> sourceView.getTransitionName() == null || sourceView.getTransitionName().isEmpty());
+ sharedElements = new Pair[sourceViewList.size()];
+ for (int i = 0; i < sourceViewList.size(); i++) {
+ sharedElements[i] = new Pair<>(sourceViewList.get(i),
+ sourceViewList.get(i).getTransitionName());
+ }
+ if (sharedElements.length > 0) {
+ mOptionsCompat = ActivityOptionsCompat.
+ makeSceneTransitionAnimation((Activity) mFrom.get(), sharedElements);
+ }
+ return this;
+ }
+
public Navigator shareElement(View sourceView) {
if (sourceView != null && sourceView.getTransitionName() != null) {
mOptionsCompat = ActivityOptionsCompat.
diff --git a/app/src/main/java/me/ghui/v2er/general/PageHost.java b/app/src/main/java/me/ghui/v2er/general/PageHost.java
index dff7fbcf..608e0a3c 100644
--- a/app/src/main/java/me/ghui/v2er/general/PageHost.java
+++ b/app/src/main/java/me/ghui/v2er/general/PageHost.java
@@ -8,6 +8,7 @@
import me.ghui.v2er.module.settings.ContactFragment;
import me.ghui.v2er.module.settings.SettingFragment;
import me.ghui.v2er.util.Utils;
+import me.ghui.v2er.widget.BaseToolBar;
public class PageHost extends BaseActivity {
public static final String PAGE_ID = "PageHost.pageId";
@@ -21,7 +22,6 @@ protected int attachLayoutRes() {
@Override
protected void init() {
super.init();
- Utils.setPaddingForStatusBar(mRootView);
mPage = (Page) getIntent().getSerializableExtra(PAGE_ID);
if (mPage == null) {
throw new RuntimeException("wrong page id");
@@ -38,6 +38,14 @@ public void reloadMode(int mode) {
.reload();
}
+ @Override
+ protected void configToolBar(BaseToolBar toolBar) {
+ super.configToolBar(toolBar);
+ if (toolBar != null) {
+ toolBar.displayHomeAsUpButton(this);
+ }
+ }
+
private Fragment getFragment(Page pageID) {
Fragment fragment;
String title;
diff --git a/app/src/main/java/me/ghui/v2er/helper/BottomNavigationViewHelper.java b/app/src/main/java/me/ghui/v2er/helper/BottomNavigationViewHelper.java
new file mode 100644
index 00000000..9f1c4f8b
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/helper/BottomNavigationViewHelper.java
@@ -0,0 +1,100 @@
+package me.ghui.v2er.helper;
+
+import android.content.Context;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.appcompat.view.menu.MenuView;
+
+import com.flyco.tablayout.widget.MsgView;
+import com.google.android.material.badge.BadgeDrawable;
+import com.google.android.material.bottomnavigation.BottomNavigationItemView;
+import com.google.android.material.bottomnavigation.BottomNavigationMenuView;
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+import com.google.android.material.internal.NavigationMenuView;
+import com.google.android.material.navigation.NavigationBarItemView;
+import com.google.android.material.navigation.NavigationBarMenuView;
+import com.google.android.material.navigationrail.NavigationRailView;
+
+import me.ghui.v2er.R;
+import me.ghui.v2er.util.UnreadMsgUtils;
+
+public class BottomNavigationViewHelper {
+
+ /**
+ * 设置图片尺寸
+ * @param view
+ * @param width
+ * @param height
+ */
+ public static void setImageSize(BottomNavigationView view, int width, int height) {
+ BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
+ try {
+ for (int i = 0; i < menuView.getChildCount(); i++) {
+ BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
+ ImageView imageView = item.findViewById(com.google.android.material.R.id.icon);
+ imageView.getLayoutParams().width = width;
+ imageView.getLayoutParams().height = height;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void showBadgeView(Context context, NavigationRailView navigationRailView, int viewIndex,
+ int showNumber) {
+ NavigationBarMenuView menuView = (NavigationBarMenuView) navigationRailView.getChildAt(0);
+ NavigationBarItemView itemView = (NavigationBarItemView) menuView.getChildAt(viewIndex);
+ ImageView itemIcon = itemView.findViewById(R.id.navigation_bar_item_icon_view);
+ final View badgeView = LayoutInflater.from(context).inflate(R.layout.message_count_layout,
+ itemView, false);
+ MsgView mcMsgView = badgeView.findViewById(R.id.mcMsgView);
+ final FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(badgeView.getLayoutParams());
+ itemIcon.post(() -> {
+ frameLayoutParams.gravity = Gravity.TOP | Gravity.END;
+ UnreadMsgUtils.show(context, mcMsgView, showNumber, (width, height) -> {
+ frameLayoutParams.rightMargin = itemView.getWidth() / 2 - width; //图片的宽度的一半
+ frameLayoutParams.topMargin = height / 2;
+ itemView.addView(badgeView, frameLayoutParams);
+ });
+ });
+ }
+
+
+ public static void showBadgeView(Context context, BottomNavigationView bottomNavigationView, int viewIndex,
+ int showNumber) {
+ BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);
+ BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(viewIndex);
+ ImageView itemIcon = itemView.findViewById(R.id.navigation_bar_item_icon_view);
+ final View badgeView = LayoutInflater.from(context).inflate(R.layout.message_count_layout,
+ itemView, false);
+ MsgView mcMsgView = badgeView.findViewById(R.id.mcMsgView);
+ final FrameLayout.LayoutParams frameLayoutParams = new FrameLayout.LayoutParams(badgeView.getLayoutParams());
+ itemIcon.post(() -> {
+ frameLayoutParams.gravity = Gravity.TOP | Gravity.END;
+ UnreadMsgUtils.show(context, mcMsgView, showNumber, (width, height) -> {
+ frameLayoutParams.rightMargin = itemView.getWidth() / 2 - width;//图片的宽度的一半
+ itemView.addView(badgeView, frameLayoutParams);
+ });
+ });
+ }
+
+ public static void hideMsg(Context context, BottomNavigationView bottomNavigationView, int viewIndex) {
+ BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);
+ BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(viewIndex);
+ int childCount = itemView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View childView = itemView.getChildAt(i);
+ if (childView instanceof FrameLayout) {
+ itemView.removeView(childView);
+ break;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ghui/v2er/injector/component/ExploreComponent.java b/app/src/main/java/me/ghui/v2er/injector/component/ExploreComponent.java
new file mode 100644
index 00000000..adc6e13f
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/injector/component/ExploreComponent.java
@@ -0,0 +1,16 @@
+package me.ghui.v2er.injector.component;
+
+import dagger.Component;
+import me.ghui.v2er.injector.module.ExploreModule;
+import me.ghui.v2er.injector.scope.PerFragment;
+import me.ghui.v2er.module.home.ExploreFragment;
+
+/**
+ * Created by ghui on 22/05/2017.
+ */
+
+@PerFragment
+@Component(dependencies = AppComponent.class, modules = ExploreModule.class)
+public interface ExploreComponent {
+ void inject(ExploreFragment mExploreFragment);
+}
diff --git a/app/src/main/java/me/ghui/v2er/injector/component/MineComponent.java b/app/src/main/java/me/ghui/v2er/injector/component/MineComponent.java
new file mode 100644
index 00000000..b1e5a51b
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/injector/component/MineComponent.java
@@ -0,0 +1,12 @@
+package me.ghui.v2er.injector.component;
+
+import dagger.Component;
+import me.ghui.v2er.injector.module.MineModule;
+import me.ghui.v2er.injector.scope.PerFragment;
+import me.ghui.v2er.module.home.MineFragment;
+
+@PerFragment
+@Component(dependencies = AppComponent.class, modules = MineModule.class)
+public interface MineComponent {
+ void inject(MineFragment fragment);
+}
diff --git a/app/src/main/java/me/ghui/v2er/injector/component/NodesNavComponent.java b/app/src/main/java/me/ghui/v2er/injector/component/NodesNavComponent.java
deleted file mode 100644
index 1dda8c78..00000000
--- a/app/src/main/java/me/ghui/v2er/injector/component/NodesNavComponent.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package me.ghui.v2er.injector.component;
-
-import dagger.Component;
-import me.ghui.v2er.injector.module.NodesNavModule;
-import me.ghui.v2er.injector.scope.PerFragment;
-import me.ghui.v2er.module.home.NodesNavFragment;
-
-/**
- * Created by ghui on 22/05/2017.
- */
-
-@PerFragment
-@Component(dependencies = AppComponent.class, modules = NodesNavModule.class)
-public interface NodesNavComponent {
- void inject(NodesNavFragment navFragment);
-}
diff --git a/app/src/main/java/me/ghui/v2er/injector/module/ExploreModule.java b/app/src/main/java/me/ghui/v2er/injector/module/ExploreModule.java
new file mode 100644
index 00000000..5462a3a5
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/injector/module/ExploreModule.java
@@ -0,0 +1,163 @@
+package me.ghui.v2er.injector.module;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+
+import dagger.Module;
+import dagger.Provides;
+import me.ghui.v2er.R;
+import me.ghui.v2er.adapter.base.CommonAdapter;
+import me.ghui.v2er.adapter.base.ItemViewDelegate;
+import me.ghui.v2er.adapter.base.MultiItemTypeAdapter;
+import me.ghui.v2er.adapter.base.ViewHolder;
+import me.ghui.v2er.general.GlideApp;
+import me.ghui.v2er.module.home.ExploreContract;
+import me.ghui.v2er.module.home.ExploreFragment;
+import me.ghui.v2er.module.home.ExplorePresenter;
+import me.ghui.v2er.module.node.NodeTopicActivity;
+import me.ghui.v2er.module.topic.TopicActivity;
+import me.ghui.v2er.module.user.UserHomeActivity;
+import me.ghui.v2er.network.bean.DailyHotInfo;
+import me.ghui.v2er.network.bean.ExplorePageInfo;
+import me.ghui.v2er.network.bean.NewsInfo;
+import me.ghui.v2er.network.bean.NodesNavInfo;
+import me.ghui.v2er.network.bean.TopicBasicInfo;
+import me.ghui.v2er.util.ViewUtils;
+import me.ghui.v2er.widget.NavNodesWrapper;
+
+/**
+ * Created by ghui on 22/05/2017.
+ */
+
+@Module
+public class ExploreModule {
+
+ private ExploreFragment mExploreFragment;
+ private WeakReference weakContext;
+
+ public ExploreModule(ExploreFragment mExploreFragment) {
+ this.mExploreFragment = mExploreFragment;
+ if (mExploreFragment.getContext() != null) {
+ weakContext = new WeakReference<>(mExploreFragment.getContext());
+ }
+ }
+
+ @Provides
+ public MultiItemTypeAdapter provideAdapter() {
+ if (weakContext.get() != null) {
+ MultiItemTypeAdapter multiItemTypeAdapter = new
+ MultiItemTypeAdapter(mExploreFragment.getContext());
+
+ multiItemTypeAdapter.addItemViewDelegate(new ItemViewDelegate(weakContext.get()) {
+
+ @Override
+ public int getItemViewLayoutId() {
+ return R.layout.common_list_item;
+ }
+
+ @Override
+ public void convert(ViewHolder holder, Serializable serializable, int position) {
+ super.convert(holder, serializable, position);
+ DailyHotInfo.Item item = (DailyHotInfo.Item) serializable;
+ GlideApp.with(mContext)
+ .load(item.getMember().getAvatar())
+ .placeholder(R.drawable.avatar_placeholder_drawable)
+ .into((ImageView) holder.getView(R.id.avatar_img));
+ holder.setText(R.id.user_name_tv, item.getMember().getUserName());
+ holder.setText(R.id.time_tv, item.getTime());
+ holder.setText(R.id.tagview, item.getNode().getTitle());
+ holder.setText(R.id.title_tv, item.getTitle());
+ TextView commentTV = holder.getTextView(R.id.comment_num_tv);
+ commentTV.setText("评论" + item.getReplies());
+ ViewUtils.highlightCommentNum(commentTV);
+
+ holder.setOnClickListener(v -> {
+ DailyHotInfo.Item.Member member = item.getMember();
+ UserHomeActivity.open(member.getUserName(), mContext, holder.getImgView(R.id.avatar_img), member.getAvatar());
+ },
+ R.id.avatar_img, R.id.user_name_tv);
+
+ holder.setOnClickListener(v -> {
+ View shareView = holder.getView(R.id.avatar_img);
+ TopicBasicInfo basicInfo = new TopicBasicInfo.Builder(item.getTitle(), item.getMember().getAvatar())
+ .author(item.getMember().getUserName())
+ .tag(item.getNode().getTitle())
+ .tagLink(item.getNode().getUrl().substring(item.getNode().getUrl().indexOf("/go")))
+ .commentNum(item.getReplies())
+ .build();
+ TopicActivity.open(item.getUrl(),
+ weakContext.get(), shareView, basicInfo);
+ }, R.id.common_list_item_root_layout);
+
+ holder.setOnClickListener(v ->
+ NodeTopicActivity.open(item.getNode().getUrl(), mContext),
+ R.id.tagview);
+ }
+
+ @Override
+ public boolean isForViewType(@Nullable Serializable item, int position) {
+ return item instanceof DailyHotInfo.Item;
+ }
+ });
+
+ multiItemTypeAdapter.addItemViewDelegate(new ItemViewDelegate(weakContext.get()) {
+ @Override
+ public int getItemViewLayoutId() {
+ return R.layout.common_title;
+ }
+
+ @Override
+ public void convert(ViewHolder holder, Serializable serializable, int position) {
+ super.convert(holder, serializable, position);
+ String title = (String) serializable;
+ holder.setText(R.id.common_title, title);
+ }
+
+ @Override
+ public boolean isForViewType(@Nullable Serializable item, int position) {
+ return item instanceof String;
+ }
+ });
+
+ multiItemTypeAdapter.addItemViewDelegate(new ItemViewDelegate(weakContext.get()) {
+ @Override
+ public int getItemViewLayoutId() {
+ return R.layout.nodes_nav_item;
+ }
+
+ @Override
+ public void convert(ViewHolder holder, Serializable serializable, int position) {
+ super.convert(holder, serializable, position);
+ NodesNavInfo.Item item = (NodesNavInfo.Item) serializable;
+ holder.setText(R.id.node_nav_category_tv, item.getCategory());
+ NavNodesWrapper nodesWrapper = holder.getView(R.id.nodes_nav_node_wrapper);
+ nodesWrapper.setData(item.getNodes());
+ }
+
+ @Override
+ public boolean isForViewType(@Nullable Serializable item, int position) {
+ return item instanceof NodesNavInfo.Item;
+ }
+
+ });
+ return multiItemTypeAdapter;
+ } else {
+ return null;
+ }
+
+ }
+
+ @Provides
+ public ExploreContract.IPresenter providePresenter() {
+ return new ExplorePresenter(mExploreFragment);
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/injector/module/MineModule.java b/app/src/main/java/me/ghui/v2er/injector/module/MineModule.java
new file mode 100644
index 00000000..3a5764c7
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/injector/module/MineModule.java
@@ -0,0 +1,29 @@
+package me.ghui.v2er.injector.module;
+
+import dagger.Module;
+import dagger.Provides;
+import me.ghui.v2er.adapter.base.MultiItemTypeAdapter;
+import me.ghui.v2er.injector.scope.PerFragment;
+import me.ghui.v2er.module.home.MineContract;
+import me.ghui.v2er.module.home.MineFragment;
+import me.ghui.v2er.module.home.MinePresenter;
+import me.ghui.v2er.module.home.MsgContract;
+import me.ghui.v2er.module.home.MsgPresenter;
+import me.ghui.v2er.network.bean.UserPageInfo;
+
+@Module
+public class MineModule {
+
+ private MineFragment mView;
+
+ public MineModule(MineFragment mView) {
+ this.mView = mView;
+ }
+
+ @PerFragment
+ @Provides
+ public MineContract.IPresenter providePresenter() {
+ return new MinePresenter(mView);
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/injector/module/NodesNavModule.java b/app/src/main/java/me/ghui/v2er/injector/module/NodesNavModule.java
deleted file mode 100644
index 14db1cd9..00000000
--- a/app/src/main/java/me/ghui/v2er/injector/module/NodesNavModule.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package me.ghui.v2er.injector.module;
-
-import dagger.Module;
-import dagger.Provides;
-import me.ghui.v2er.R;
-import me.ghui.v2er.adapter.base.CommonAdapter;
-import me.ghui.v2er.adapter.base.ViewHolder;
-import me.ghui.v2er.module.home.NodesNavConstract;
-import me.ghui.v2er.module.home.NodesNavFragment;
-import me.ghui.v2er.module.home.NodesNavPresenter;
-import me.ghui.v2er.network.bean.NodesNavInfo;
-import me.ghui.v2er.widget.NavNodesWrapper;
-
-/**
- * Created by ghui on 22/05/2017.
- */
-
-@Module
-public class NodesNavModule {
- private NodesNavFragment mNavFragment;
-
- public NodesNavModule(NodesNavFragment navFragment) {
- mNavFragment = navFragment;
- }
-
- @Provides
- public CommonAdapter provideAdapter() {
- return new CommonAdapter(mNavFragment.getContext(), R.layout.nodes_nav_item) {
- @Override
- protected void convert(ViewHolder holder, NodesNavInfo.Item item, int position) {
- holder.setText(R.id.node_nav_category_tv, item.getCategory());
- NavNodesWrapper nodesWrapper = holder.getView(R.id.nodes_nav_node_wrapper);
- nodesWrapper.setData(item.getNodes());
- }
- };
- }
-
- @Provides
- public NodesNavConstract.IPresenter providePresenter() {
- return new NodesNavPresenter(mNavFragment);
- }
-
-}
diff --git a/app/src/main/java/me/ghui/v2er/module/append/AppendTopicActivity.java b/app/src/main/java/me/ghui/v2er/module/append/AppendTopicActivity.java
index d282dace..d881e601 100644
--- a/app/src/main/java/me/ghui/v2er/module/append/AppendTopicActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/append/AppendTopicActivity.java
@@ -3,8 +3,11 @@
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
+import android.view.MenuItem;
import android.widget.EditText;
+import androidx.annotation.NonNull;
+
import butterknife.BindView;
import io.reactivex.Observable;
import me.ghui.v2er.R;
@@ -65,19 +68,22 @@ protected void startInject() {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- //设置右上角的填充菜单
- toolBar.inflateMenu(R.menu.append_topic_menu);
- Utils.setPaddingForStatusBar(toolBar);
- Utils.setPaddingForNavbar(mRootView);
- toolBar.setOnMenuItemClickListener(item -> {
- String content = mContentET.getText().toString();
- if (Check.isEmpty(content)) {
- Voast.show("请输入附言内容");
- return false;
- }
- mPresenter.sendAppend(content);
- return true;
- });
+ }
+
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.append_topic_menu;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ String content = mContentET.getText().toString();
+ if (Check.isEmpty(content)) {
+ Voast.show("请输入附言内容");
+ return false;
+ }
+ mPresenter.sendAppend(content);
+ return true;
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/base/BaseActivity.java b/app/src/main/java/me/ghui/v2er/module/base/BaseActivity.java
index 29b51173..7401422d 100644
--- a/app/src/main/java/me/ghui/v2er/module/base/BaseActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/base/BaseActivity.java
@@ -2,16 +2,19 @@
import android.content.Context;
import android.content.Intent;
+import android.graphics.Color;
import android.os.Bundle;
import androidx.annotation.CallSuper;
import androidx.annotation.ColorInt;
import androidx.annotation.LayoutRes;
+import androidx.annotation.MenuRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.google.android.material.appbar.AppBarLayout;
+import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.appcompat.app.AppCompatActivity;
@@ -20,11 +23,15 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toolbar;
import com.r0adkll.slidr.model.SlidrInterface;
import com.trello.rxlifecycle2.LifecycleTransformer;
@@ -32,6 +39,7 @@
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import java.lang.reflect.Field;
import java.util.Stack;
import javax.inject.Inject;
@@ -87,7 +95,7 @@ public abstract class BaseActivity extends Rx
@Nullable
protected SlidrInterface mSlidrInterface;
protected DayNightModeEvent mDayNightModeEvent;
-
+ private boolean displayStatusBarArea = true;
protected static String KEY(String key) {
return Utils.KEY(key);
@@ -105,6 +113,16 @@ public void setFirstLoadingDelay(long delay) {
@LayoutRes
protected abstract int attachLayoutRes();
+
+ /**
+ * 显示状态栏区域
+ * 在attachToolbar调用,或者之前
+ * @param displayStatusBarArea
+ */
+ public void displayStatusBarArea(boolean displayStatusBarArea) {
+ this.displayStatusBarArea = displayStatusBarArea;
+ }
+
/**
* Set a default Toolbar, if you don't want certain page to have a toolbar,
* just return null;
@@ -115,7 +133,14 @@ public void setFirstLoadingDelay(long delay) {
protected BaseToolBar attachToolbar() {
int layoutId = attachToolBar() == 0 ? R.layout.appbar_wrapper_toolbar : attachToolBar();
mToolbarWrapper = (AppBarLayout) getLayoutInflater().inflate(layoutId, null);
- return (BaseToolBar) mToolbarWrapper.findViewById(R.id.inner_toolbar);
+ BaseToolBar baseToolBar = mToolbarWrapper.findViewById(R.id.inner_toolbar);
+ if (baseToolBar != null) {
+ baseToolBar.setTitleTextColor(Theme.getColor(R.attr.icon_tint_color, this));
+ baseToolBar.setSubtitleTextColor(Theme.getColor(R.attr.icon_tint_color, this));
+ return baseToolBar;
+ } else {
+ return null;
+ }
}
@LayoutRes
@@ -150,8 +175,7 @@ public boolean onToolbarDoubleTaped() {
protected void setTitle(String title, String subTitle) {
if (mToolbar != null) {
- mToolbar.setTitle(title);
- mToolbar.setSubtitle(subTitle);
+ mToolbar.setTitle(title, subTitle);
}
}
@@ -159,6 +183,27 @@ protected void setTitle(String title) {
setTitle(title, null);
}
+ public @MenuRes int attachOptionsMenuRes() {
+ return 0;
+ }
+
+ /**
+ * 配置右侧可选菜单
+ * @param menu
+ */
+ public void configOptionsMenu(Menu menu) {
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (attachOptionsMenuRes() != 0) {
+ getMenuInflater().inflate(attachOptionsMenuRes(), menu);
+ configOptionsMenu(menu);
+ }
+ return super.onCreateOptionsMenu(menu);
+ }
+
/**
* if you want to support ptr, then attach a PtrHandler to it
*
@@ -343,6 +388,26 @@ protected void autoLoad() {
}
}
+ /**
+ * 查找Appbar
+ * @param viewGroup
+ */
+ private void findAppbar(ViewGroup viewGroup) {
+ if (viewGroup instanceof BaseToolBar) {
+ mToolbar = (BaseToolBar) viewGroup;
+ } else {
+ int childCount = viewGroup.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View childView = viewGroup.getChildAt(i);
+ if (childView instanceof ViewGroup) {
+ findAppbar((ViewGroup) childView);
+ } else {
+ continue;
+ }
+ }
+ }
+ }
+
protected ViewGroup onCreateRootView() {
if ((mToolbar = attachToolbar()) != null) {
LinearLayout rootView = new LinearLayout(this);
@@ -377,6 +442,15 @@ protected ViewGroup onCreateRootView() {
mRootView.setId(R.id.act_root_view_framelayout);
mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mRootView.addView(mContentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ if (displayStatusBarArea) {
+ mRootView.setFitsSystemWindows(true);
+ } else {
+ mRootView.setFitsSystemWindows(false);
+ findAppbar(mRootView);
+ if (mToolbar != null) {
+ Utils.setPaddingForStatusBar(mToolbar);
+ }
+ }
mRootView.setBackgroundColor(pageColor());
return mRootView;
}
diff --git a/app/src/main/java/me/ghui/v2er/module/create/CreateTopicActivity.java b/app/src/main/java/me/ghui/v2er/module/create/CreateTopicActivity.java
index f8fe2b37..78c70a8a 100644
--- a/app/src/main/java/me/ghui/v2er/module/create/CreateTopicActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/create/CreateTopicActivity.java
@@ -2,6 +2,8 @@
import android.content.Intent;
import com.google.android.material.textfield.TextInputLayout;
+
+import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
@@ -36,7 +38,7 @@
*/
public class CreateTopicActivity extends BaseActivity implements CreateTopicContract.IView,
- Toolbar.OnMenuItemClickListener, NodeSelectFragment.OnSelectedListener {
+ NodeSelectFragment.OnSelectedListener {
@BindView(R.id.create_topic_title_layout)
TextInputLayout mTitleTextInputLayout;
@BindView(R.id.create_topic_title_et)
@@ -102,17 +104,19 @@ protected void autoLoad() {
}
}
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.post_topic_menu;
+ }
+
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- toolBar.inflateMenu(R.menu.post_topic_menu);//设置右上角的填充菜单
- toolBar.setOnMenuItemClickListener(this);
- Utils.setPaddingForStatusBar(toolBar);
- Utils.setPaddingForNavbar(mRootView);
+ toolBar.displayHomeAsUpButton(this);
}
@Override
- public boolean onMenuItemClick(MenuItem menuItem) {
+ public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_create_topic:
String title = mTitleEt.getText().toString();
diff --git a/app/src/main/java/me/ghui/v2er/module/create/NodeSelectFragment.java b/app/src/main/java/me/ghui/v2er/module/create/NodeSelectFragment.java
index 04c49bc4..71fd491b 100644
--- a/app/src/main/java/me/ghui/v2er/module/create/NodeSelectFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/create/NodeSelectFragment.java
@@ -3,6 +3,8 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import androidx.annotation.Nullable;
@@ -10,15 +12,19 @@
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckedTextView;
+import android.widget.EditText;
import android.widget.Filter;
import android.widget.Filterable;
+import android.widget.ImageView;
import android.widget.Toast;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@@ -31,6 +37,7 @@
import me.ghui.v2er.adapter.base.ViewHolder;
import me.ghui.v2er.network.bean.NodesInfo;
import me.ghui.v2er.util.ScaleUtils;
+import me.ghui.v2er.util.Theme;
import me.ghui.v2er.util.Utils;
import me.ghui.v2er.widget.BaseRecyclerView;
@@ -104,6 +111,31 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
});
SearchView searchView = (SearchView) mToolbar.getMenu().findItem(R.id.action_search_node).getActionView();
searchView.setQueryHint("搜索全部节点");
+ EditText searchTextView = searchView
+ .findViewById(androidx.appcompat.R.id.search_src_text);
+ ImageView searchButton = searchView
+ .findViewById(androidx.appcompat.R.id.search_button);
+ ImageView goButton = searchView
+ .findViewById(androidx.appcompat.R.id.search_go_btn);
+ ImageView closeButton = searchView
+ .findViewById(androidx.appcompat.R.id.search_close_btn);
+ ImageView voiceButton = searchView
+ .findViewById(androidx.appcompat.R.id.search_voice_btn);
+ searchTextView.setTextColor(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ searchTextView.setHintTextColor(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ searchButton.getDrawable().setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ goButton.getDrawable().setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ closeButton.getDrawable().setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ voiceButton.getDrawable().setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ try {
+ Class> searchViewClass = searchView.getClass();
+ Field mSearchHintIconField = searchViewClass.getDeclaredField("mSearchHintIcon");
+ mSearchHintIconField.setAccessible(true);
+ Drawable mSearchHintIcon = (Drawable) mSearchHintIconField.get(searchView);
+ if (mSearchHintIcon != null) {
+ mSearchHintIcon.setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ }
+ }catch (Exception ignore) {}
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
diff --git a/app/src/main/java/me/ghui/v2er/module/drawer/care/SpecialCareActivity.java b/app/src/main/java/me/ghui/v2er/module/drawer/care/SpecialCareActivity.java
index 3f1264a3..f9a4db3d 100644
--- a/app/src/main/java/me/ghui/v2er/module/drawer/care/SpecialCareActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/drawer/care/SpecialCareActivity.java
@@ -55,7 +55,7 @@ protected void startInject() {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
+ toolBar.displayHomeAsUpButton(this);
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/drawer/dailyhot/DailyHotActivity.java b/app/src/main/java/me/ghui/v2er/module/drawer/dailyhot/DailyHotActivity.java
index 7ce08027..f5a67839 100644
--- a/app/src/main/java/me/ghui/v2er/module/drawer/dailyhot/DailyHotActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/drawer/dailyhot/DailyHotActivity.java
@@ -62,7 +62,6 @@ protected SwipeRefreshLayout.OnRefreshListener attachOnRefreshListener() {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/drawer/star/StarActivity.java b/app/src/main/java/me/ghui/v2er/module/drawer/star/StarActivity.java
index 8adbb8fd..acca2313 100644
--- a/app/src/main/java/me/ghui/v2er/module/drawer/star/StarActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/drawer/star/StarActivity.java
@@ -67,13 +67,12 @@ protected int attachLayoutRes() {
protected void configToolBar() {
mToolbar.setTitle(getTitle());
- mToolbar.setElevation(0);
+ mToolbar.displayHomeAsUpButton(this);
mToolbar.setOnDoubleTapListener(this);
mToolbar.setNavigationOnClickListener(view -> {
if (isTaskRoot()) finishToHome();
else onBackPressed();
});
- Utils.setPaddingForStatusBar(mToolbar);
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/gallery/GalleryActivity.java b/app/src/main/java/me/ghui/v2er/module/gallery/GalleryActivity.java
index 785e3ed7..40a525e4 100644
--- a/app/src/main/java/me/ghui/v2er/module/gallery/GalleryActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/gallery/GalleryActivity.java
@@ -37,12 +37,12 @@
* Created by ghui on 22/10/2017.
*/
-public class GalleryActivity extends BaseActivity implements SwipeToDismissTouchListener.Callback, Toolbar.OnMenuItemClickListener {
+public class GalleryActivity extends BaseActivity implements SwipeToDismissTouchListener.Callback {
public static final String EXTRA_IMG_DATA = Utils.KEY("extra_img_data");
@BindView(R.id.gallery_viewpager)
ViewPager mViewPager;
@BindView(R.id.gallery_toolbar)
- Toolbar mToolBar;
+ BaseToolBar mToolBar;
@BindView(R.id.indicator_tv)
TextView mIndicatorTv;
private ImagesInfo mData;
@@ -86,10 +86,7 @@ protected BaseToolBar attachToolbar() {
@Override
protected void init() {
- Utils.setPaddingForStatusBar(mToolBar);
- mToolBar.inflateMenu(R.menu.gallery_toolbar_menu);
- mToolBar.setOverflowIcon(getDrawable(R.drawable.ic_more_vert_white));
- mToolBar.setOnMenuItemClickListener(this);
+ mToolBar.displayHomeAsUpButton(this);
mToolBar.setNavigationOnClickListener(v -> GalleryActivity.this.onBackPressed());
mData = (ImagesInfo) getIntent().getSerializableExtra(EXTRA_IMG_DATA);
@@ -165,7 +162,12 @@ public void onConsume(String path) {
}
@Override
- public boolean onMenuItemClick(MenuItem item) {
+ public int attachOptionsMenuRes() {
+ return R.menu.gallery_toolbar_menu;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_open_in_browser:
Utils.openInBrowser(getCurrentImage(), this);
diff --git a/app/src/main/java/me/ghui/v2er/module/general/WapActivity.java b/app/src/main/java/me/ghui/v2er/module/general/WapActivity.java
index adc1c5f9..9443710a 100644
--- a/app/src/main/java/me/ghui/v2er/module/general/WapActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/general/WapActivity.java
@@ -4,7 +4,11 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.http.SslError;
+
+import androidx.annotation.NonNull;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import android.view.MenuItem;
import android.view.ViewGroup;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
@@ -88,32 +92,37 @@ protected void configWebView(WebSettings settings) {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
- mToolbar.inflateMenu(R.menu.wapview_menu);
- mToolbar.setOnMenuItemClickListener(menuItem -> {
- switch (menuItem.getItemId()) {
- case R.id.action_refresh:
- showLoading();
- refresh();
- break;
- case R.id.action_share:
- ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(toolBar.getTitle().toString())
- .link(mCurrentUrl)
- .content("链接分享")
- .build();
- ShareManager shareManager = new ShareManager(shareData, this);
- shareManager.showShareDialog();
- break;
- case R.id.action_copy_url:
- Utils.copyToClipboard(this, mCurrentUrl);
- toast("链接已拷贝成功");
- break;
- case R.id.action_open_in_browser:
- Utils.openInBrowser(mCurrentUrl, this);
- break;
- }
- return false;
- });
+ }
+
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.wapview_menu;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_refresh:
+ showLoading();
+ refresh();
+ break;
+ case R.id.action_share:
+ ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(mToolbar.getTitle().toString())
+ .link(mCurrentUrl)
+ .content("链接分享")
+ .build();
+ ShareManager shareManager = new ShareManager(shareData, this);
+ shareManager.showShareDialog();
+ break;
+ case R.id.action_copy_url:
+ Utils.copyToClipboard(this, mCurrentUrl);
+ toast("链接已拷贝成功");
+ break;
+ case R.id.action_open_in_browser:
+ Utils.openInBrowser(mCurrentUrl, this);
+ break;
+ }
+ return false;
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/home/CheckInContract.java b/app/src/main/java/me/ghui/v2er/module/home/CheckInContract.java
index e6cf468a..85cb23bb 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/CheckInContract.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/CheckInContract.java
@@ -1,6 +1,9 @@
package me.ghui.v2er.module.home;
import me.ghui.v2er.module.base.BaseContract;
+import me.ghui.v2er.network.GeneralError;
+import me.ghui.v2er.network.IGeneralErrorHandler;
+import me.ghui.v2er.network.bean.IBase;
import me.ghui.v2er.widget.FollowProgressBtn;
/**
@@ -8,15 +11,30 @@
*/
public class CheckInContract {
- public interface IView extends BaseContract.IView {
- // void onGetCheckInInfo(DailyInfo dailyInfo);
- FollowProgressBtn checkInBtn();
+
+ public abstract static class ICheckInCallBack implements IGeneralErrorHandler {
+
+ void onHasChekIn(String checkInDays) {}
+
+ void onCheckInSuccess(String checkInDays) {}
+
+ void onCheckInFail() {}
+
+ @Override
+ public void handleError(GeneralError generalError) {
+
+ }
+
}
public interface IPresenter extends BaseContract.IPresenter {
- void checkIn(boolean needAutoCheckIn);
+
+ void checkIn();
+
+ void checkInToDay();
int checkInDays();
+
}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/CheckInPresenter.java b/app/src/main/java/me/ghui/v2er/module/home/CheckInPresenter.java
index 83c2a715..406c8814 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/CheckInPresenter.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/CheckInPresenter.java
@@ -5,6 +5,7 @@
import me.ghui.v2er.network.APIService;
import me.ghui.v2er.network.GeneralConsumer;
import me.ghui.v2er.network.bean.DailyInfo;
+import me.ghui.v2er.util.RxUtils;
import me.ghui.v2er.util.UserUtils;
import me.ghui.v2er.util.Utils;
@@ -16,35 +17,40 @@
*/
public class CheckInPresenter implements CheckInContract.IPresenter {
- private CheckInContract.IView mView;
+ private CheckInContract.ICheckInCallBack callBack;
private String checkInDaysStr;
+ boolean needAutoCheckIn = false;
+ boolean checkToDay = false;
- public CheckInPresenter(CheckInContract.IView view) {
- mView = view;
+ public CheckInPresenter(CheckInContract.ICheckInCallBack callBack) {
+ this.callBack = callBack;
}
@Override
public void start() {
- checkIn(Pref.readBool(R.string.pref_key_auto_checkin));
+ needAutoCheckIn = Pref.readBool(R.string.pref_key_auto_checkin);
+ checkIn();
}
@Override
- public void checkIn(boolean needAutoCheckIn) {
- if (!UserUtils.isLogin()) return;
- mView.checkInBtn().startUpdate();
+ public void checkIn() {
APIService.get().dailyInfo()
- .compose(mView.rx(null))
- .subscribe(new GeneralConsumer(mView) {
+ .compose(RxUtils.io_main())
+ .subscribe(new GeneralConsumer(callBack) {
@Override
public void onConsume(DailyInfo checkInInfo) {
if (checkInInfo.hadCheckedIn()) {
checkInDaysStr = checkInInfo.getCheckinDays();
- mView.checkInBtn().setStatus(FINISHED, "已签到/" + checkInDaysStr + "天", R.drawable.progress_button_done_icon);
+ if (callBack != null) {
+ callBack.onHasChekIn(checkInDaysStr);
+ }
} else {
if (needAutoCheckIn) {
checkIn(checkInInfo.once());
- } else {
- mView.checkInBtn().setStatus(NORMAL, "签到", R.drawable.progress_button_checkin_icon);
+ }
+ if (checkToDay) {
+ checkToDay = false;
+ checkIn(checkInInfo.once());
}
}
}
@@ -52,32 +58,37 @@ public void onConsume(DailyInfo checkInInfo) {
@Override
public void onError(Throwable e) {
super.onError(e);
- mView.checkInBtn().setStatus(NORMAL, "签到", R.drawable.progress_button_checkin_icon);
}
});
}
+ @Override
+ public void checkInToDay() {
+ checkToDay = true;
+ checkIn();
+ }
+
@Override
public int checkInDays() {
return Utils.getIntFromString(checkInDaysStr);
}
-
private void checkIn(String once) {
- mView.checkInBtn().startUpdate();
APIService.get()
.checkIn(once)
- .compose(mView.rx(null))
- .subscribe(new GeneralConsumer(mView) {
+ .compose(RxUtils.io_main())
+ .subscribe(new GeneralConsumer(callBack) {
@Override
public void onConsume(DailyInfo checkInInfo) {
if (checkInInfo.hadCheckedIn()) {
checkInDaysStr = checkInInfo.getCheckinDays();
- mView.toast("签到成功/" + checkInDaysStr + "天");
- mView.checkInBtn().setStatus(FINISHED, "已签到/" + checkInDaysStr + "天", R.drawable.progress_button_done_icon);
+ if (callBack != null) {
+ callBack.onCheckInSuccess(checkInDaysStr);
+ }
} else {
- mView.toast("签到遇到问题!");
- mView.checkInBtn().setStatus(NORMAL, "签到", R.drawable.progress_button_checkin_icon);
+ if (callBack != null) {
+ callBack.onCheckInFail();
+ }
}
}
});
diff --git a/app/src/main/java/me/ghui/v2er/module/home/NodesNavConstract.java b/app/src/main/java/me/ghui/v2er/module/home/ExploreContract.java
similarity index 70%
rename from app/src/main/java/me/ghui/v2er/module/home/NodesNavConstract.java
rename to app/src/main/java/me/ghui/v2er/module/home/ExploreContract.java
index 00b1bd4d..a4b4fbc4 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/NodesNavConstract.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/ExploreContract.java
@@ -1,16 +1,17 @@
package me.ghui.v2er.module.home;
import me.ghui.v2er.module.base.BaseContract;
+import me.ghui.v2er.network.bean.ExplorePageInfo;
import me.ghui.v2er.network.bean.NodesNavInfo;
/**
* Created by ghui on 22/05/2017.
*/
-public class NodesNavConstract {
+public class ExploreContract {
public interface IView extends BaseContract.IView {
- void fillView(NodesNavInfo navInfo);
+ void fillView(ExplorePageInfo pageInfo);
}
public interface IPresenter extends BaseContract.IPresenter {
diff --git a/app/src/main/java/me/ghui/v2er/module/home/NodesNavFragment.java b/app/src/main/java/me/ghui/v2er/module/home/ExploreFragment.java
similarity index 54%
rename from app/src/main/java/me/ghui/v2er/module/home/NodesNavFragment.java
rename to app/src/main/java/me/ghui/v2er/module/home/ExploreFragment.java
index 07e1e7f7..cf88faf5 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/NodesNavFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/ExploreFragment.java
@@ -5,55 +5,60 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.View;
+import java.io.Serializable;
+
import javax.inject.Inject;
import butterknife.BindView;
import me.ghui.v2er.R;
import me.ghui.v2er.adapter.base.CommonAdapter;
-import me.ghui.v2er.injector.component.DaggerNodesNavComponent;
-import me.ghui.v2er.injector.module.NodesNavModule;
+import me.ghui.v2er.adapter.base.MultiItemTypeAdapter;
+import me.ghui.v2er.injector.component.DaggerExploreComponent;
+import me.ghui.v2er.injector.module.ExploreModule;
+import me.ghui.v2er.network.bean.ExplorePageInfo;
+import me.ghui.v2er.network.bean.ExplorePageInfoWrapper;
import me.ghui.v2er.network.bean.NodesNavInfo;
-import me.ghui.v2er.network.bean.NodesNavInfoWrapper;
import me.ghui.v2er.widget.BaseRecyclerView;
/**
* Created by ghui on 22/03/2017.
*/
-public class NodesNavFragment extends BaseHomeFragment implements NodesNavConstract.IView {
+public class ExploreFragment extends BaseHomeFragment implements ExploreContract.IView {
@Inject
- CommonAdapter mAdapter;
+ MultiItemTypeAdapter mAdapter;
@BindView(R.id.base_recyclerview)
BaseRecyclerView mRecyclerView;
- private NodesNavInfoWrapper mNodesNavInfoWrapper;
+
+ private ExplorePageInfoWrapper mExplorePageInfoWrapper;
private LinearLayoutManager mLayoutManager;
- public static NodesNavFragment newInstance(RestoreData restoreData) {
+ public static ExploreFragment newInstance(RestoreData restoreData) {
Bundle args = new Bundle();
if (restoreData != null) {
args.putSerializable(KEY_DATA, restoreData);
}
- NodesNavFragment fragment = new NodesNavFragment();
+ ExploreFragment fragment = new ExploreFragment();
fragment.setArguments(args);
return fragment;
}
- public static NodesNavFragment newInstance() {
+ public static ExploreFragment newInstance() {
return newInstance(null);
}
- public RestoreData getRestoreData() {
+ public RestoreData getRestoreData() {
int pos = mLayoutManager.findFirstVisibleItemPosition();
int offset = 0;
View firstChild = mRecyclerView.getChildAt(0);
if (firstChild != null) {
offset = firstChild.getTop();
}
- if (mNodesNavInfoWrapper == null) {
+ if (mExplorePageInfoWrapper == null) {
return null;
}
- return new RestoreData<>(1, pos, offset, mNodesNavInfoWrapper);
+ return new RestoreData<>(1, pos, offset, mExplorePageInfoWrapper);
}
@Override
@@ -63,9 +68,9 @@ protected int attachLayoutRes() {
@Override
protected void startInject() {
- DaggerNodesNavComponent.builder()
+ DaggerExploreComponent.builder()
.appComponent(getAppComponent())
- .nodesNavModule(new NodesNavModule(this))
+ .exploreModule(new ExploreModule(this))
.build().inject(this);
}
@@ -73,10 +78,10 @@ protected void startInject() {
protected void init() {
mRecyclerView.setLayoutManager(mLayoutManager = new LinearLayoutManager(getContext()));
mRecyclerView.setAdapter(mAdapter);
- RestoreData restoreData = (RestoreData) getArguments().getSerializable(KEY_DATA);
+ RestoreData restoreData = (RestoreData) getArguments().getSerializable(KEY_DATA);
if (restoreData != null) {
- mNodesNavInfoWrapper = restoreData.info;
- fillView(restoreData.info.nodesNavInfo);
+ mExplorePageInfoWrapper = restoreData.info;
+ fillView(mExplorePageInfoWrapper.explorePageInfo);
post(()-> mLayoutManager.scrollToPositionWithOffset(restoreData.scrollPos, restoreData.scrollOffset));
hideLoading();
}
@@ -89,14 +94,17 @@ protected SwipeRefreshLayout.OnRefreshListener attachOnRefreshListener() {
@Override
protected void lazyLoad() {
- if (mNodesNavInfoWrapper == null || mNodesNavInfoWrapper.nodesNavInfo == null) {
+ if (mExplorePageInfoWrapper == null || mExplorePageInfoWrapper.explorePageInfo == null) {
super.lazyLoad();
}
}
@Override
- public void fillView(NodesNavInfo navInfo) {
- mNodesNavInfoWrapper = NodesNavInfoWrapper.wrapper(navInfo);
- mAdapter.setData(navInfo);
+ public void fillView(ExplorePageInfo pageInfo) {
+ mExplorePageInfoWrapper = ExplorePageInfoWrapper.wrapper(pageInfo);
+ pageInfo.setDailyHotInfoTitle(getString(R.string.daily_hot));
+ pageInfo.setNodesNavInfoTitle(getString(R.string.node_navigation));
+ mAdapter.setData(pageInfo.getItems());
}
+
}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/ExplorePresenter.java b/app/src/main/java/me/ghui/v2er/module/home/ExplorePresenter.java
new file mode 100644
index 00000000..e70b29c3
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/module/home/ExplorePresenter.java
@@ -0,0 +1,64 @@
+package me.ghui.v2er.module.home;
+
+import me.ghui.v2er.network.APIService;
+import me.ghui.v2er.network.GeneralConsumer;
+import me.ghui.v2er.network.bean.DailyHotInfo;
+import me.ghui.v2er.network.bean.ExplorePageInfo;
+import me.ghui.v2er.network.bean.NodesNavInfo;
+
+/**
+ * Created by ghui on 22/05/2017.
+ */
+
+public class ExplorePresenter implements ExploreContract.IPresenter {
+
+ private ExploreContract.IView mView;
+ private ExplorePageInfo pageInfo;
+
+ public ExplorePresenter(ExploreContract.IView view) {
+ mView = view;
+ pageInfo = new ExplorePageInfo();
+ }
+
+ /**
+ * 请求今日热议信息
+ */
+ private void requestDailyHotInfo() {
+ APIService.get()
+ .dailyHot()
+ .compose(mView.rx())
+ .subscribe(new GeneralConsumer(mView) {
+ @Override
+ public void onConsume(DailyHotInfo items) {
+ if (items.isValid()) {
+ pageInfo.dailyHotInfo = items;
+ mView.fillView(pageInfo);
+ }
+ }
+ });
+ }
+
+ /**
+ * 请求节点信息
+ */
+ private void requestNodesNavInfo() {
+ APIService.get().nodesNavInfo()
+ .compose(mView.rx())
+ .subscribe(new GeneralConsumer(mView) {
+ @Override
+ public void onConsume(NodesNavInfo items) {
+ if (items.isValid()) {
+ pageInfo.nodesNavInfo = items;
+ mView.fillView(pageInfo);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void start() {
+ requestDailyHotInfo();
+ requestNodesNavInfo();
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/MainActivity.java b/app/src/main/java/me/ghui/v2er/module/home/MainActivity.java
index 444605c7..ecce5dd0 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/MainActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/MainActivity.java
@@ -1,18 +1,20 @@
package me.ghui.v2er.module.home;
import android.annotation.SuppressLint;
-import android.content.Intent;
+import android.content.res.Configuration;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
import android.widget.TextView;
-import androidx.appcompat.widget.SwitchCompat;
+import androidx.annotation.NonNull;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -20,84 +22,73 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
-import com.bumptech.glide.request.target.Target;
-import com.flyco.tablayout.listener.OnTabSelectListener;
import com.flyco.tablayout.widget.MsgView;
import com.google.android.material.appbar.AppBarLayout;
-import com.google.android.material.navigation.NavigationView;
+import com.google.android.material.bottomnavigation.BottomNavigationItemView;
+import com.google.android.material.bottomnavigation.BottomNavigationMenuView;
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+import com.google.android.material.navigation.NavigationBarView;
+import com.google.android.material.navigationrail.NavigationRailView;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import java.util.Calendar;
+
import butterknife.BindView;
import me.ghui.v2er.R;
import me.ghui.v2er.bus.Bus;
import me.ghui.v2er.bus.event.TextSizeChangeEvent;
import me.ghui.v2er.general.ActivityReloader;
-import me.ghui.v2er.general.GlideApp;
-import me.ghui.v2er.general.Navigator;
-import me.ghui.v2er.general.Page;
+import me.ghui.v2er.general.App;
+import me.ghui.v2er.helper.BottomNavigationViewHelper;
import me.ghui.v2er.module.base.BaseActivity;
-import me.ghui.v2er.module.create.CreateTopicActivity;
-import me.ghui.v2er.module.drawer.care.SpecialCareActivity;
-import me.ghui.v2er.module.drawer.dailyhot.DailyHotActivity;
-import me.ghui.v2er.module.drawer.star.StarActivity;
-import me.ghui.v2er.module.login.LoginActivity;
-import me.ghui.v2er.module.settings.UserManualActivity;
-import me.ghui.v2er.module.user.UserHomeActivity;
-import me.ghui.v2er.network.bean.UserInfo;
-import me.ghui.v2er.util.DarkModelUtils;
-import me.ghui.v2er.util.L;
+import me.ghui.v2er.network.GeneralError;
import me.ghui.v2er.util.ScaleUtils;
import me.ghui.v2er.util.Theme;
+import me.ghui.v2er.util.UnreadMsgUtils;
import me.ghui.v2er.util.UserUtils;
import me.ghui.v2er.util.Utils;
import me.ghui.v2er.util.ViewUtils;
import me.ghui.v2er.widget.BaseToolBar;
-import me.ghui.v2er.widget.CSlidingTabLayout;
import me.ghui.v2er.widget.FollowProgressBtn;
-import me.ghui.v2er.widget.dialog.ConfirmDialog;
-import me.ghui.v2er.widget.listener.AppBarStateChangeListener;
-public class MainActivity extends BaseActivity implements View.OnClickListener,
- UpdateUnReadMsgDelegate, CheckInContract.IView, OnTabSelectListener,
+public class MainActivity extends BaseActivity implements View.OnClickListener, UpdateUnReadMsgDelegate,
HomeFilterMenu.OnMenuItemClickListener {
- private static final String TAB_INDEX = KEY("tab_index");
private static final String PAGE_ONE_DATA = KEY("page_one_data");
private static final String PAGE_TWO_DATA = KEY("page_two_data");
private static final String PAGE_THREE_DATA = KEY("page_three_data");
+ private static final String PAGE_FOUR_DATA = KEY("page_four_data");
private static final String TOPIC_IS_APPBAR_EXPANDED = KEY("toolbar_is_appbar_expanded");
public static boolean isAlive;
- private final String[] TAB_TITLES = {" 全部", "消息", "节点"};
- @BindView(R.id.left_draw_layout)
- DrawerLayout mDrawerLayout;
- @BindView(R.id.navigationview_main)
- NavigationView mNavigationView;
- @BindView(R.id.tablayout_main)
- CSlidingTabLayout mSlidingTabLayout;
+ private final int[] titles = {R.string.feed, R.string.explore,
+ R.string.message, R.string.mine};
+ private final int[] bottomNavigationViewItemIds = {R.id.feed_page, R.id.explore_page,
+ R.id.message_page, R.id.mine_page};
+ @BindView(R.id.main_logo)
+ ImageView mLogoView;
+ BottomNavigationView mBottomNavigationView;
@BindView(R.id.viewpager_main)
ViewPager mViewPager;
@BindView(R.id.main_toolbar)
BaseToolBar mToolbar;
- @BindView(R.id.tab_menu_container)
- ViewGroup mTabMenuContainer;
+ @BindView(R.id.main_container)
+ ViewGroup mMainContainer;
@BindView(R.id.main_appbar)
AppBarLayout mAppBarLayout;
+ DrawerLayout mainDrawerLayout;
+ NavigationRailView mainNavigationRailView;
+
private NewsFragment mNewsFragment;
private MsgFragment mMsgFragment;
- private NodesNavFragment mNavFragment;
- private View mNavHeaderView;
- private ImageView mAvatarImg;
- private TextView mUserNameTv;
- private FollowProgressBtn mCheckInBtn;
+ private ExploreFragment mExploreFragment;
+ private MineFragment mMineFragment;
private CheckInPresenter mCheckInPresenter;
- private TextView mTab1View;
- private MenuItem mNightMenuItem;
- private SwitchCompat mNightSwitch;
- private HomeFilterMenu mFilterMenu;
- private boolean isAppbarExpanted = true;
+ private boolean isAppbarExpanded = true;
+
+
@Override
protected int attachLayoutRes() {
@@ -114,27 +105,32 @@ protected BaseToolBar attachToolbar() {
return null;
}
- @SuppressLint({"CheckResult", "WrongConstant"})
- protected void configToolBar() {
- Utils.setPaddingForStatusBar(mAppBarLayout);
+ @Override
+ protected void configToolBar(BaseToolBar toolBar) {
+ super.configToolBar(toolBar);
+ setSupportActionBar(mToolbar);
+ }
+
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.main_toolbar_menu;
+ }
+
+ @Override
+ public void configOptionsMenu(Menu menu) {
+ super.configOptionsMenu(menu);
mToolbar.setOnDoubleTapListener(this);
- mToolbar.setElevation(0);
- mToolbar.setNavigationIcon(R.drawable.nav);
- mToolbar.getNavigationIcon().setTint(Theme.getColor(R.attr.icon_tint_color, this));
- mToolbar.inflateMenu(R.menu.main_toolbar_menu);//设置右上角的填充菜单
- mToolbar.setNavigationOnClickListener(v -> {
- if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
- mDrawerLayout.closeDrawer(Gravity.START);
- } else {
- mDrawerLayout.openDrawer(Gravity.START);
- }
- });
- mToolbar.setOnMenuItemClickListener(item -> {
- if (item.getItemId() == R.id.action_search) {
- pushFragment(SearchFragment.newInstance());
- }
- return true;
- });
+ mToolbar.setTitle("");
+ mLogoView.setVisibility(View.VISIBLE);
+ mToolbar.setViewTileCenter(mLogoView);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == R.id.action_search) {
+ pushFragment(SearchFragment.newInstance());
+ }
+ return true;
}
@Override
@@ -149,242 +145,185 @@ public boolean onToolbarDoubleTaped() {
return false;
}
-
- private void refreshDayNightItem() {
- mNightMenuItem.setTitle(DarkModelUtils.isAutoModeEnabled() ? "深色模式(自动)" : "深色模式");
- mNightSwitch.setChecked(DarkModelUtils.isDarkMode());
+ private void changeTitle(int position) {
+ switch (position) {
+ case 0:
+ mToolbar.setTitle("");
+ mLogoView.setVisibility(View.VISIBLE);
+ mToolbar.setViewTileCenter(mLogoView);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ mLogoView.setVisibility(View.GONE);
+ mToolbar.setTitle(titles[position]);
+ mToolbar.setTileCenter(true);
+ mToolbar.setTitleTextColor(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ break;
+ }
}
- @Override
- protected void init() {
- isAlive = true;
- configToolBar();
-
- mNavigationView.setItemIconTintList(null);
- mNavHeaderView = mNavigationView.getHeaderView(0);
- mAvatarImg = mNavHeaderView.findViewById(R.id.avatar_img);
- mUserNameTv = mNavHeaderView.findViewById(R.id.user_name_tv);
- mCheckInBtn = mNavHeaderView.findViewById(R.id.check_in_progress_btn);
- mAvatarImg.setOnClickListener(this);
- mUserNameTv.setOnClickListener(this);
- mCheckInBtn.setOnClickListener(this);
- mNightMenuItem = mNavigationView.getMenu().findItem(R.id.day_night_item);
-
- mAvatarImg.setOnLongClickListener(v -> {
- new ConfirmDialog.Builder(getActivity())
- .title("退出登录")
- .msg("确定退出吗?")
- .positiveText(R.string.ok, dialog -> {
- UserUtils.clearLogin();
- Navigator.from(getActivity())
- .setFlag(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .to(MainActivity.class).start();
- })
- .negativeText(R.string.cancel)
- .build().show();
- return false;
- });
+ private void initCheckIn() {
+ if (UserUtils.isLogin()) {
+ mCheckInPresenter = new CheckInPresenter(new CheckInContract.ICheckInCallBack() {
+
+ @Override
+ public void onHasChekIn(String checkInDays) {
- mNightSwitch = mNightMenuItem.getActionView().findViewById(R.id.drawer_switch);
- updateDrawLayout();
- mNavigationView.setNavigationItemSelectedListener(item -> {
+ }
+
+ @Override
+ public void onCheckInSuccess(String checkInDays) {
+ toast("签到成功/" + checkInDays + "天");
+ }
+
+ @Override
+ public void onCheckInFail() {
+ toast("签到遇到问题!");
+ }
+
+ });
+ mCheckInPresenter.start();
+ }
+ }
+
+ private void initBottomNavigationView() {
+ mBottomNavigationView = findViewById(R.id.main_bottom_navigation_view);
+ BottomNavigationViewHelper.setImageSize(mBottomNavigationView,
+ getResources().getDimensionPixelSize(R.dimen.bottom_navigation_view_icon_small_size),
+ getResources().getDimensionPixelSize(R.dimen.bottom_navigation_view_icon_small_size));
+ mBottomNavigationView.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
- case R.id.hot_nav_item:
- Navigator.from(getContext()).to(DailyHotActivity.class).start();
+ case R.id.feed_page:
+ mViewPager.setCurrentItem(0);
break;
- case R.id.care_nav_item:
- Navigator.from(getContext()).to(SpecialCareActivity.class).start();
+ case R.id.explore_page:
+ mViewPager.setCurrentItem(1);
break;
- case R.id.star_nav_item:
- Navigator.from(getContext()).to(StarActivity.class).start();
+ case R.id.message_page:
+ mViewPager.setCurrentItem(2);
break;
- case R.id.setting_nav_item:
- Navigator.from(getContext()).to(Page.SETTING).start();
+ case R.id.mine_page:
+ mViewPager.setCurrentItem(3);
break;
- case R.id.faq_nav_item:
- startActivity(new Intent(getContext(), UserManualActivity.class));
+ default:
+ return false;
+ }
+ return true;
+ });
+ }
+
+ private void initLeftNavigationView() {
+ mainNavigationRailView = findViewById(R.id.mainNavigationRailView);
+ mainNavigationRailView.setOnItemSelectedListener(item -> {
+ switch (item.getItemId()) {
+ case R.id.feed_page:
+ mViewPager.setCurrentItem(0);
break;
- case R.id.create_nav_item:
- if (UserUtils.notLoginAndProcessToLogin(false, getContext())) return true;
- Navigator.from(getContext()).to(CreateTopicActivity.class).start();
+ case R.id.explore_page:
+ mViewPager.setCurrentItem(1);
break;
- case R.id.day_night_item:
- onNightMenuItemClicked(DarkModelUtils.isDarkMode());
+ case R.id.message_page:
+ mViewPager.setCurrentItem(2);
break;
+ case R.id.mine_page:
+ mViewPager.setCurrentItem(3);
+ break;
+ default:
+ return false;
}
- delay(50, () -> mDrawerLayout.closeDrawer(Gravity.START, false));
return true;
});
+ }
+ private void initNavigationView() {
+ int screenOrientation = getResources().getConfiguration().orientation;
+ switch (screenOrientation) {
+ case Configuration.ORIENTATION_LANDSCAPE: {
+ initLeftNavigationView();
+ break;
+ }
+ case Configuration.ORIENTATION_PORTRAIT: {
+ initBottomNavigationView();
+ break;
+ }
+ case Configuration.ORIENTATION_SQUARE:
+ case Configuration.ORIENTATION_UNDEFINED:
+ break;
+ }
+ }
-
- Menu menu = mNavigationView.getMenu();
- for (int i = 0; i < menu.size(); i++) {
- menu.getItem(i).getIcon().setTint(Theme.getColor(R.attr.icon_tint_color, this));
+ private void showUnReadMsg() {
+ int screenOrientation = getResources().getConfiguration().orientation;
+ if (App.get().unReadMsgCount > 0) {
+ if (screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
+ BottomNavigationViewHelper.showBadgeView(this, mBottomNavigationView,
+ 2, App.get().unReadMsgCount);
+ } else {
+ BottomNavigationViewHelper.showBadgeView(this, mainNavigationRailView,
+ 2, App.get().unReadMsgCount);
+ }
}
- mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
+ }
+
+ @Override
+ protected void init() {
+ isAlive = true;
+ mViewPager.setAdapter(new SlidePagerAdapter(getSupportFragmentManager()));
+ mViewPager.setOffscreenPageLimit(3);
+ mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+
@Override
- public void onDrawerOpened(View drawerView) {
- updateDrawLayout();
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
}
- });
- mAppBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
@Override
- public void onStateChanged(AppBarLayout appBarLayout, AppBarStateChangeListener.State state) {
- isAppbarExpanted = state == State.EXPANDED;
+ public void onPageSelected(int position) {
+ int screenOrientation = getResources().getConfiguration().orientation;
+ if (screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
+ mBottomNavigationView.setSelectedItemId(bottomNavigationViewItemIds[position]);
+ } else {
+ mainNavigationRailView.setSelectedItemId(bottomNavigationViewItemIds[position]);
+ }
+ changeTitle(position);
}
- });
- TAB_TITLES[0] = TabInfo.getSelectTab().title;
- mViewPager.setAdapter(new SlidePagerAdapter(getSupportFragmentManager()));
- mViewPager.setOffscreenPageLimit(2);
- mSlidingTabLayout.setViewPager(mViewPager, TAB_TITLES);
- mSlidingTabLayout.setOnTabSelectListener(this);
- configNewsTabTitle();
- initCheckIn();
+ @Override
+ public void onPageScrollStateChanged(int state) {
- int index = getIntent().getIntExtra(TAB_INDEX, 0);
- mSlidingTabLayout.setCurrentTab(index);
- isAppbarExpanted = getIntent().getBooleanExtra(TOPIC_IS_APPBAR_EXPANDED, true);
- mAppBarLayout.setExpanded(isAppbarExpanted);
+ }
+ });
+ initNavigationView();
+ showUnReadMsg();
+ isAppbarExpanded = getIntent().getBooleanExtra(TOPIC_IS_APPBAR_EXPANDED, true);
+ initCheckIn();
}
@Override
protected void reloadMode(int mode) {
ActivityReloader.target(this)
- .putExtra(TAB_INDEX, mSlidingTabLayout.getCurrentTab())
- .putExtra(TOPIC_IS_APPBAR_EXPANDED, isAppbarExpanted)
+ .putExtra(TOPIC_IS_APPBAR_EXPANDED, isAppbarExpanded)
.putExtra(PAGE_ONE_DATA, mNewsFragment.getRestoreData())
- .putExtra(PAGE_TWO_DATA, mMsgFragment.getRestoreData())
- .putExtra(PAGE_THREE_DATA, mNavFragment.getRestoreData())
+ .putExtra(PAGE_TWO_DATA, mExploreFragment.getRestoreData())
+ .putExtra(PAGE_THREE_DATA, mMsgFragment.getRestoreData())
.reload();
}
- private void onNightMenuItemClicked(boolean isNightMode) {
- int wanttedMode = isNightMode ? DarkModelUtils.DEFAULT_MODE : DarkModelUtils.DARK_MODE;
- if (DarkModelUtils.isAutoModeEnabled()) {
- new ConfirmDialog.Builder(MainActivity.this)
- .title("要关闭自动切换模式吗?")
- .msg("当前为自动切换模式,确定关闭自动切换吗")
- .positiveText("关闭", dialog -> {
- DarkModelUtils.saveEnableAutoSwitch(false);
- DarkModelUtils.saveModeMannually(wanttedMode);
- reloadMode(wanttedMode);
- }).negativeText("暂时不用")
- .build().show();
- } else {
- mNightSwitch.toggle();
- DarkModelUtils.saveModeMannually(wanttedMode);
- reloadMode(wanttedMode);
- }
- }
-
- private void configNewsTabTitle() {
- int padding = ScaleUtils.dp(6f);
- mSlidingTabLayout.setTitleViewVerticalPadding(0, padding);
- mSlidingTabLayout.setTitleViewVerticalPadding(1, padding);
- mSlidingTabLayout.setTitleViewVerticalPadding(2, padding);
- mTab1View = mSlidingTabLayout.getTitleView(0);
- mTab1View.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.animate_triangle_down, 0);
- mTab1View.setCompoundDrawablePadding(ScaleUtils.dp(6));
- }
-
- private void initCheckIn() {
- mCheckInPresenter = new CheckInPresenter(this);
- mCheckInPresenter.start();
- }
-
- private void updateDrawLayout() {
- UserInfo userInfo = UserUtils.getUserInfo();
- if (userInfo != null) {
- mUserNameTv.setText(userInfo.getUserName());
- GlideApp.with(getContext())
- .load(userInfo.getAvatar())
- .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
- .placeholder(R.drawable.avatar_placeholder_drawable)
- .into(mAvatarImg);
- } else {
- mUserNameTv.setText("请先登录");
- mAvatarImg.setImageResource(R.drawable.default_avatar_drawable);
- }
- refreshDayNightItem();
- }
-
@Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.avatar_img:
- case R.id.user_name_tv:
- if (UserUtils.isLogin()) {
- UserHomeActivity.open(UserUtils.getUserInfo().getUserName(), this, null, UserUtils.getUserInfo().getAvatar());
- } else {
- Navigator.from(this).to(LoginActivity.class).start();
- }
- mDrawerLayout.closeDrawers();
- break;
- case R.id.check_in_progress_btn:
- if (!UserUtils.isLogin()) {
- toast("请先登录!");
- return;
- }
- if (mCheckInBtn.isNormal()) {
- mCheckInPresenter.checkIn(true);
- } else if (mCheckInBtn.isFinished()) {
- toast("已连续签到" + mCheckInPresenter.checkInDays() + "天");
- } else {
- toast("正在签到请稍后...");
- }
- break;
- }
- }
-
- private int getCurrentTab() {
- return mSlidingTabLayout.getCurrentTab();
- }
+ public void onClick(View v) { }
@SuppressLint("WrongConstant")
@Override
public void onBackPressed() {
- if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
- mDrawerLayout.closeDrawer(Gravity.START);
- return;
- }
-
- if (!isBackableEmpty()) {
- super.onBackPressed();
- return;
- }
-
- if (getCurrentTab() != 0) {
- mSlidingTabLayout.setCurrentTab(0);
- return;
- }
-
- if (mFilterMenu != null && mFilterMenu.isShowing()) {
- mFilterMenu.hide();
- return;
- }
+ isBackableEmpty();
super.onBackPressed();
}
@Override
public void updateUnReadMsg(int position, int count) {
- if (count <= 0) {//hide
- mSlidingTabLayout.hideMsg(position);
- } else {
- mSlidingTabLayout.showMsg(position, count);
- //config sliding msgview
- float padding = getResources().getDimension(R.dimen.mediumTextSize) / 2f;
- mSlidingTabLayout.setMsgMargin(1, padding * 0.92f, padding * 0.28f);
- MsgView msgView = mSlidingTabLayout.getMsgView(1);
- float textSize = getResources().getDimension(R.dimen.tinyTextSize);
- msgView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) msgView.getLayoutParams();
- lp.width = Math.round(textSize * (count + "").length() * 1.5f);
- lp.height = Math.round(textSize * 1.5f);
- msgView.setLayoutParams(lp);
- }
+ App.get().unReadMsgCount = count;
+ showUnReadMsg();
}
@Override
@@ -401,48 +340,20 @@ protected void onDestroy() {
}
private Fragment getCurrentFragment() {
- int pos = getCurrentTab();
+ int pos = mViewPager.getCurrentItem();
switch (pos) {
case 0:
return mNewsFragment;
case 1:
- return mMsgFragment;
+ return mExploreFragment;
case 2:
- return mNavFragment;
+ return mMsgFragment;
+ case 3:
+ return mMineFragment;
}
return null;
}
- @Override
- public FollowProgressBtn checkInBtn() {
- return mCheckInBtn;
- }
-
- @Override
- public void onTabSelect(int position) {
- L.d("onTabSelect");
- if (position == 0) {
- mTab1View.getCompoundDrawables()[2].setTint(Theme.getColor(R.attr.tablayout_selected_color, this));
- } else {
- mTab1View.getCompoundDrawables()[2].setTint(Theme.getColor(R.attr.tablayout_unselected_color, this));
- if (mFilterMenu != null && mFilterMenu.isShowing()) {
- mFilterMenu.hide();
- }
- }
- }
-
- @Override
- public void onTabReselect(int position) {
- L.d("onTabReSelect");
- if (position == 0) {
- if (mFilterMenu == null) {
- mFilterMenu = new HomeFilterMenu(mTabMenuContainer, mTab1View);
- mFilterMenu.setOnItemClickListner(this);
- }
- mFilterMenu.toggle();
- }
- }
-
@Override
public void onMenuItemClicked(TabInfo tabInfo) {
ChangeTabTypeDelegate delegate = mNewsFragment;
@@ -454,7 +365,6 @@ public void onTextSizeChanged(TextSizeChangeEvent event) {
recreate();
}
-
public interface ChangeTabTypeDelegate {
void changeTabType(TabInfo tabInfo);
}
@@ -478,14 +388,17 @@ public Fragment getItem(int position) {
break;
case 1:
restoreData = (BaseHomeFragment.RestoreData) getIntent().getSerializableExtra(PAGE_TWO_DATA);
- MsgFragment msgFragment = MsgFragment.newInstance(restoreData);
- msgFragment.setUpdateUnReadMsgDelegate(MainActivity.this);
- fragment = msgFragment;
+ fragment = ExploreFragment.newInstance(restoreData);
break;
case 2:
restoreData = (BaseHomeFragment.RestoreData) getIntent().getSerializableExtra(PAGE_THREE_DATA);
- fragment = NodesNavFragment.newInstance(restoreData);
+ MsgFragment msgFragment = MsgFragment.newInstance(restoreData);
+ msgFragment.setUpdateUnReadMsgDelegate(MainActivity.this);
+ fragment = msgFragment;
break;
+ case 3:
+ restoreData = (BaseHomeFragment.RestoreData) getIntent().getSerializableExtra(PAGE_FOUR_DATA);
+ fragment = MineFragment.newInstance(restoreData);
}
return fragment;
}
@@ -498,20 +411,21 @@ public Object instantiateItem(ViewGroup container, int position) {
mNewsFragment = (NewsFragment) fragment;
break;
case 1:
- mMsgFragment = (MsgFragment) fragment;
+ mExploreFragment = (ExploreFragment) fragment;
break;
case 2:
- mNavFragment = (NodesNavFragment) fragment;
+ mMsgFragment = (MsgFragment) fragment;
break;
+ case 3:
+ mMineFragment = (MineFragment) fragment;
}
return fragment;
}
@Override
public int getCount() {
- return TAB_TITLES.length;
+ return titles.length;
}
- }
- ;
+ };
}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/MineContract.java b/app/src/main/java/me/ghui/v2er/module/home/MineContract.java
new file mode 100644
index 00000000..ed7be974
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/module/home/MineContract.java
@@ -0,0 +1,20 @@
+package me.ghui.v2er.module.home;
+
+import me.ghui.v2er.module.base.BaseContract;
+import me.ghui.v2er.network.bean.NotificationInfo;
+
+/**
+ * Created by ghui on 10/05/2017.
+ */
+
+public class MineContract {
+
+ public interface IView extends BaseContract.IView {
+// void fillView(NotificationInfo info, boolean isLoadMore);
+ }
+
+ public interface IPresenter extends BaseContract.IPresenter {
+
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/MineFragment.java b/app/src/main/java/me/ghui/v2er/module/home/MineFragment.java
new file mode 100644
index 00000000..3f758a8b
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/module/home/MineFragment.java
@@ -0,0 +1,245 @@
+package me.ghui.v2er.module.home;
+
+import android.os.Bundle;
+
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.bumptech.glide.request.target.Target;
+
+import javax.inject.Inject;
+
+import butterknife.BindView;
+import de.hdodenhof.circleimageview.CircleImageView;
+import me.ghui.v2er.R;
+import me.ghui.v2er.adapter.base.MultiItemTypeAdapter;
+import me.ghui.v2er.adapter.base.ViewHolder;
+import me.ghui.v2er.general.GlideApp;
+import me.ghui.v2er.general.Navigator;
+import me.ghui.v2er.general.Page;
+import me.ghui.v2er.injector.component.DaggerMineComponent;
+import me.ghui.v2er.injector.module.MineModule;
+import me.ghui.v2er.module.create.CreateTopicActivity;
+import me.ghui.v2er.module.drawer.care.SpecialCareActivity;
+import me.ghui.v2er.module.drawer.star.StarActivity;
+import me.ghui.v2er.module.login.LoginActivity;
+import me.ghui.v2er.module.user.UserHomeActivity;
+import me.ghui.v2er.network.bean.NewsInfo;
+import me.ghui.v2er.network.bean.NotificationInfo;
+import me.ghui.v2er.network.bean.UserInfo;
+import me.ghui.v2er.util.UserUtils;
+import me.ghui.v2er.widget.BaseRecyclerView;
+import me.ghui.v2er.widget.FollowProgressBtn;
+import me.ghui.v2er.widget.LoadMoreRecyclerView;
+import me.ghui.v2er.widget.SectionItemView;
+
+/**
+ * 首页我的页面
+ */
+public class MineFragment extends BaseHomeFragment implements MineContract.IView,
+ View.OnClickListener, SectionItemView.OnSectionClickListener {
+
+ @BindView(R.id.mine_root_layout)
+ ConstraintLayout mRootLayout;
+ @BindView(R.id.mine_avatar_img)
+ CircleImageView mAvatarImage;
+ @BindView(R.id.mine_username_button)
+ Button mUserNameButton;
+ @BindView(R.id.mine_user_info_page_button)
+ Button mUserInfoPageButton;
+ @BindView(R.id.mine_check_in_progress_btn)
+ FollowProgressBtn mCheckInButton;
+
+ @BindView(R.id.mine_sec_post)
+ SectionItemView mSecPost;
+ @BindView(R.id.mine_sec_themes)
+ SectionItemView mSecThemes;
+ @BindView(R.id.mine_sec_bookmark)
+ SectionItemView mSecBookmark;
+ @BindView(R.id.mine_sec_focus)
+ SectionItemView mSecFocus;
+ @BindView(R.id.mine_sec_settings)
+ SectionItemView mSecSettings;
+
+ private CheckInPresenter mCheckInPresenter;
+
+ private void initCheckIn() {
+ if (UserUtils.isLogin()) {
+ mCheckInButton.setVisibility(View.VISIBLE);
+ mCheckInPresenter = new CheckInPresenter(new CheckInContract.ICheckInCallBack() {
+
+ @Override
+ public void onHasChekIn(String checkInDays) {
+ mCheckInButton.setStatus(FollowProgressBtn.FINISHED,
+ getString(R.string.number_of_days_checked_in, checkInDays), R.drawable.progress_button_done_icon);
+ }
+
+ @Override
+ public void onCheckInSuccess(String checkInDays) {
+ toast(getString(R.string.number_of_days_check_in_succeed, checkInDays));
+ mCheckInButton.setStatus(FollowProgressBtn.FINISHED,
+ getString(R.string.number_of_days_checked_in, checkInDays), R.drawable.progress_button_done_icon);
+ }
+
+ @Override
+ public void onCheckInFail() {
+ toast(getString(R.string.problems_with_check_in));
+ mCheckInButton.setStatus(FollowProgressBtn.NORMAL, getString(R.string.check_in),
+ R.drawable.progress_button_checkin_icon);
+ }
+
+ });
+ mCheckInPresenter.start();
+ }
+ }
+
+ public static MineFragment newInstance(BaseHomeFragment.RestoreData restoreData) {
+ Bundle args = new Bundle();
+ if (restoreData != null) {
+ args.putSerializable(KEY_DATA, restoreData);
+ }
+ MineFragment fragment = new MineFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ protected int attachLayoutRes() {
+ return R.layout.fragment_mine;
+ }
+
+ @Override
+ protected void startInject() {
+ DaggerMineComponent.builder()
+ .appComponent(getAppComponent())
+ .mineModule(new MineModule(this))
+ .build()
+ .inject(this);
+ }
+
+ private UserInfo userInfo;
+ private void initDisplayUserName() {
+ userInfo = UserUtils.getUserInfo();
+ if (userInfo == null) {
+ mUserNameButton.setContentDescription(getText(R.string.please_login_first));
+ mUserNameButton.setText(R.string.please_login_first);
+ mAvatarImage.setImageResource(R.drawable.default_avatar_drawable);
+ } else {
+ mUserNameButton.setContentDescription(userInfo.getUserName());
+ mUserNameButton.setText(userInfo.getUserName());
+ if (getContext() != null) {
+ GlideApp.with(getContext())
+ .load(userInfo.getAvatar())
+ .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+ .placeholder(R.drawable.avatar_placeholder_drawable)
+ .into(mAvatarImage);
+ }
+ }
+ }
+
+ @Override
+ protected void init() {
+ hideLoading();
+ mAvatarImage.setOnClickListener(this);
+ mUserNameButton.setOnClickListener(this);
+ mUserInfoPageButton.setOnClickListener(this);
+ mCheckInButton.setOnClickListener(this);
+ mSecPost.setOnSectionClickListener(this);
+ mSecThemes.setOnSectionClickListener(this);
+ mSecBookmark.setOnSectionClickListener(this);
+ mSecFocus.setOnSectionClickListener(this);
+ mSecSettings.setOnSectionClickListener(this);
+ initDisplayUserName();
+ initCheckIn();
+ }
+
+ private void goToUserInfoPage() {
+ if (UserUtils.isLogin()) {
+ if (getContext() != null) {
+ UserHomeActivity.open(userInfo.getUserName(), getContext(),
+ userInfo.getAvatar(), mAvatarImage, mUserNameButton);
+ }
+ } else {
+ if (getContext() != null) {
+ Navigator.from(getContext()).to(LoginActivity.class).start();
+ }
+ }
+ }
+
+ /**
+ * 发帖
+ */
+ private void goToPost() {
+ if (UserUtils.notLoginAndProcessToLogin(false, getContext())) {
+ return;
+ }
+ if (UserUtils.isLogin()) {
+ Navigator.from(getContext()).to(CreateTopicActivity.class).start();
+ }
+ }
+
+ /**
+ * 收藏
+ */
+ private void goToBookmark() {
+ if (UserUtils.notLoginAndProcessToLogin(false, getContext())) {
+ return;
+ }
+ if (UserUtils.isLogin()) {
+ Navigator.from(getContext()).to(StarActivity.class).start();
+ }
+ }
+
+ /**
+ * 关注
+ */
+ private void goToFocus() {
+ if (UserUtils.notLoginAndProcessToLogin(false, getContext())) {
+ return;
+ }
+ if (UserUtils.isLogin()) {
+ Navigator.from(getContext()).to(SpecialCareActivity.class).start();
+ }
+ }
+
+ /**
+ * 设置
+ */
+ private void goToSetting() {
+ Navigator.from(getContext()).to(Page.SETTING).start();
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.mine_check_in_progress_btn:
+ mCheckInButton.startUpdate();
+ mCheckInPresenter.checkInToDay();
+ break;
+ case R.id.mine_avatar_img:
+ case R.id.mine_username_button:
+ case R.id.mine_user_info_page_button:
+ goToUserInfoPage();
+ break;
+ case R.id.mine_sec_post:
+ goToPost();
+ break;
+ case R.id.mine_sec_bookmark:
+ goToBookmark();
+ break;
+ case R.id.mine_sec_focus:
+ goToFocus();
+ break;
+ case R.id.mine_sec_settings:
+ goToSetting();
+ break;
+ default:
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ghui/v2er/module/home/MinePresenter.java b/app/src/main/java/me/ghui/v2er/module/home/MinePresenter.java
new file mode 100644
index 00000000..caab1ae7
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/module/home/MinePresenter.java
@@ -0,0 +1,16 @@
+package me.ghui.v2er.module.home;
+
+public class MinePresenter implements MineContract.IPresenter {
+
+ private MineContract.IView mView;
+
+ public MinePresenter(MineContract.IView mView) {
+ this.mView = mView;
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/NewsFragment.java b/app/src/main/java/me/ghui/v2er/module/home/NewsFragment.java
index f417ef28..81be2837 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/NewsFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/NewsFragment.java
@@ -124,6 +124,19 @@ protected void init() {
protected void lazyLoad() {
if (mNewsInfo == null) {
super.lazyLoad();
+ } else {
+ RestoreData restoreData = getRestoreData();
+ if (restoreData != null) {
+ mNewsInfo = restoreData.info;
+ mRecyclerView.setWillLoadPage(restoreData.page);
+ if (mNewsInfo.getItems() != null) {
+ fillView(mNewsInfo, false);
+ post(() -> mLayoutManager.scrollToPositionWithOffset(restoreData.scrollPos, restoreData.scrollOffset));
+ hideLoading();
+ } else {
+ mPresenter.start();
+ }
+ }
}
}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/NodesNavPresenter.java b/app/src/main/java/me/ghui/v2er/module/home/NodesNavPresenter.java
deleted file mode 100644
index 1c7e7324..00000000
--- a/app/src/main/java/me/ghui/v2er/module/home/NodesNavPresenter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package me.ghui.v2er.module.home;
-
-import me.ghui.v2er.network.APIService;
-import me.ghui.v2er.network.GeneralConsumer;
-import me.ghui.v2er.network.bean.NodesNavInfo;
-
-/**
- * Created by ghui on 22/05/2017.
- */
-
-public class NodesNavPresenter implements NodesNavConstract.IPresenter {
-
- private NodesNavConstract.IView mView;
-
- public NodesNavPresenter(NodesNavConstract.IView view) {
- mView = view;
- }
-
- @Override
- public void start() {
- APIService.get().nodesNavInfo()
- .compose(mView.rx())
- .subscribe(new GeneralConsumer(mView) {
- @Override
- public void onConsume(NodesNavInfo items) {
- mView.fillView(items);
- }
- });
- }
-
-}
diff --git a/app/src/main/java/me/ghui/v2er/module/home/SearchFragment.java b/app/src/main/java/me/ghui/v2er/module/home/SearchFragment.java
index 9713b435..75be42cf 100644
--- a/app/src/main/java/me/ghui/v2er/module/home/SearchFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/home/SearchFragment.java
@@ -86,7 +86,6 @@ protected boolean showLoadingOnCreateView() {
@Override
protected void init() {
- Utils.setPaddingForStatusBar(mSearchRootView);
mCardView.setCardBackgroundColor(Theme.getColor(R.attr.dialog_bg_color, getContext()));
mResultRecyV.addDivider(DarkModelUtils.isDarkMode() ? 0XFF000000 : 0XFFF5F5F5, 6);
mResultRecyV.setLayoutManager(new LinearLayoutManager(getContext()));
diff --git a/app/src/main/java/me/ghui/v2er/module/login/LoginActivity.java b/app/src/main/java/me/ghui/v2er/module/login/LoginActivity.java
index 8ca8a0f0..75c61faa 100644
--- a/app/src/main/java/me/ghui/v2er/module/login/LoginActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/login/LoginActivity.java
@@ -3,10 +3,12 @@
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.textfield.TextInputLayout;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -77,7 +79,6 @@ protected void startInject() {
@Override
protected void init() {
super.init();
- Utils.setPaddingForNavbar(mRootView);
}
@Override
@@ -88,21 +89,25 @@ protected void reloadMode(int mode) {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
- toolBar.setElevation(0);
- toolBar.inflateMenu(R.menu.login_toolbar_menu);
- toolBar.setOnMenuItemClickListener(item -> {
- if (item.getItemId() == R.id.action_register) {
- Utils.openInBrowser(Constants.BASE_URL + "/signup?r=ghui", this);
- } else if (item.getItemId() == R.id.action_forgot_psw) {
- Utils.openInBrowser(Constants.BASE_URL + "/forgot", this);
- } else if (item.getItemId() == R.id.action_faq) {
- Navigator.from(this).to(UserManualActivity.class).start();
- } else if (item.getItemId() == R.id.action_about) {
- Utils.openInBrowser(Constants.BASE_URL + "/about", this);
- }
- return true;
- });
+ }
+
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.login_toolbar_menu;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == R.id.action_register) {
+ Utils.openInBrowser(Constants.BASE_URL + "/signup?r=ghui", this);
+ } else if (item.getItemId() == R.id.action_forgot_psw) {
+ Utils.openInBrowser(Constants.BASE_URL + "/forgot", this);
+ } else if (item.getItemId() == R.id.action_faq) {
+ Navigator.from(this).to(UserManualActivity.class).start();
+ } else if (item.getItemId() == R.id.action_about) {
+ Utils.openInBrowser(Constants.BASE_URL + "/about", this);
+ }
+ return true;
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/login/SignInWithGoogleActivity.java b/app/src/main/java/me/ghui/v2er/module/login/SignInWithGoogleActivity.java
index 14c85e8e..79aa9cef 100644
--- a/app/src/main/java/me/ghui/v2er/module/login/SignInWithGoogleActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/login/SignInWithGoogleActivity.java
@@ -40,7 +40,7 @@ public static void open(Context context, String once) {
@Override
protected void configWebView(WebSettings settings) {
super.configWebView(settings);
- settings.setUserAgentString(APIService.WAP_USER_AGENT);
+ settings.setUserAgentString(APIService.WAP_Android_USER_AGENT);
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
@@ -63,7 +63,7 @@ public void onBackPressed() {
protected boolean checkIntercept(String currentUrl) {
L.d("url: " + currentUrl);
if (currentUrl.startsWith(Constants.BASE_URL + "/mission/daily")) {
- mWebView.getSettings().setUserAgentString(APIService.WAP_USER_AGENT);
+ mWebView.getSettings().setUserAgentString(APIService.WAP_Android_USER_AGENT);
doGetUserInfo();
return true;
}
diff --git a/app/src/main/java/me/ghui/v2er/module/node/NodeTopicActivity.java b/app/src/main/java/me/ghui/v2er/module/node/NodeTopicActivity.java
index 88e2de94..33b88de5 100644
--- a/app/src/main/java/me/ghui/v2er/module/node/NodeTopicActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/node/NodeTopicActivity.java
@@ -5,10 +5,14 @@
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
+
+import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
@@ -162,6 +166,7 @@ protected int attachLayoutRes() {
@Override
protected BaseToolBar attachToolbar() {
+ displayStatusBarArea(false);
return null;
}
@@ -186,42 +191,20 @@ protected boolean supportShareElement() {
}
@Override
- protected void init() {
- getWindow().setStatusBarColor(Color.TRANSPARENT);
- Utils.setPaddingForStatusBar(mToolbar);
- setEnterSharedElementCallback(mCallback);
- mToolbar.setOnDoubleTapListener(this);
- mToolbar.inflateMenu(R.menu.node_info_toolbar_menu);
- mLoveMenuItem = mToolbar.getMenu().findItem(R.id.action_star);
- mToolbar.setNavigationOnClickListener(view -> onBackPressed());
- mToolbar.setOnMenuItemClickListener(item -> {
- if (item.getItemId() == R.id.action_star) {
- onStarBtnClicked();
- } else if (item.getItemId() == R.id.action_share) {
- if (mNodeInfo == null) return false;
- String desc = mNodeInfo.getHeader();
- String title = mNodeInfo.getTitle();
-// ShareManager.shareText(title, mNodeInfo.getUrl(), this);
- ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(title)
- .content(Vtml.fromHtml(desc).toString())
- .link(mNodeInfo.getUrl())
- .img(mNodeInfo.getAvatar())
- .build();
- ShareManager shareManager = new ShareManager(shareData, this);
- shareManager.showShareDialog();
- } else if (item.getItemId() == R.id.action_block) {
+ protected void configToolBar(BaseToolBar toolBar) {
+ super.configToolBar(toolBar);
+ }
- }
- return true;
- });
- mRecyclerView.setAppBarTracking(this);
- mRecyclerView.setOnLoadMoreListener(this);
-// mRecyclerView.addDivider();
- mLayoutManager = new LinearLayoutManager(this);
- mRecyclerView.setLayoutManager(mLayoutManager);
- mRecyclerView.setAdapter(mAdapter);
- mAdapter.setOnItemClickListener(this);
+ @Override
+ public int attachOptionsMenuRes() {
+ return R.menu.node_info_toolbar_menu;
+ }
+
+ @Override
+ public void configOptionsMenu(Menu menu) {
+ super.configOptionsMenu(menu);
+ mLoveMenuItem = menu.findItem(R.id.action_star);
mAppBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
@Override
public void onStateChanged(AppBarLayout appBarLayout, State state) {
@@ -251,9 +234,43 @@ public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
mAppBarIdle = (mAppBarOffset >= 0) || (mAppBarOffset <= mAppBarMaxOffset);
}
});
+ }
- mAppBarLayout.post(() -> mAppBarMaxOffset = -mAppBarLayout.getTotalScrollRange());
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (item.getItemId() == R.id.action_star) {
+ onStarBtnClicked();
+ } else if (item.getItemId() == R.id.action_share) {
+ if (mNodeInfo == null) return false;
+ String desc = mNodeInfo.getHeader();
+ String title = mNodeInfo.getTitle();
+// ShareManager.shareText(title, mNodeInfo.getUrl(), this);
+ ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(title)
+ .content(Vtml.fromHtml(desc).toString())
+ .link(mNodeInfo.getUrl())
+ .img(mNodeInfo.getAvatar())
+ .build();
+ ShareManager shareManager = new ShareManager(shareData, this);
+ shareManager.showShareDialog();
+ } else if (item.getItemId() == R.id.action_block) {
+
+ }
+ return true;
+ }
+ @Override
+ protected void init() {
+ getWindow().setStatusBarColor(Color.TRANSPARENT);
+ setEnterSharedElementCallback(mCallback);
+ mToolbar.displayHomeAsUpButton(this);
+ mToolbar.setOnDoubleTapListener(this);
+ mRecyclerView.setAppBarTracking(this);
+ mRecyclerView.setOnLoadMoreListener(this);
+ mLayoutManager = new LinearLayoutManager(this);
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ mRecyclerView.setAdapter(mAdapter);
+ mAdapter.setOnItemClickListener(this);
+ mAppBarLayout.post(() -> mAppBarMaxOffset = -mAppBarLayout.getTotalScrollRange());
if (mNodeInfo != null) {
fillHeaderView(mNodeInfo);
}
@@ -422,7 +439,7 @@ public void afterUnIgnoreNode() {
private void toggleStar(boolean isStared) {
mLoveMenuItem.setIcon(isStared ?
- R.drawable.ic_star_selected : R.drawable.ic_star_normal);
+ R.drawable.ic_bookmarked : R.drawable.ic_bookmark);
mLoveMenuItem.getIcon().setTint(Theme.getColor(R.attr.icon_tint_color, this));
if (isStared) {
mStarBtn.setStatus(FollowProgressBtn.FINISHED, "已收藏", R.drawable.progress_button_done_icon);
diff --git a/app/src/main/java/me/ghui/v2er/module/settings/ContactFragment.java b/app/src/main/java/me/ghui/v2er/module/settings/ContactFragment.java
index 6c268f98..b5adc819 100644
--- a/app/src/main/java/me/ghui/v2er/module/settings/ContactFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/settings/ContactFragment.java
@@ -44,7 +44,6 @@ public void onActivityCreated(Bundle savedInstanceState) {
ListView list = rootView.findViewById(android.R.id.list);
if (list != null) {
// list.setDivider(getActivity().getDrawable(R.drawable.common_divider));
- Utils.setPaddingForNavbar(list);
}
}
diff --git a/app/src/main/java/me/ghui/v2er/module/settings/SettingFragment.java b/app/src/main/java/me/ghui/v2er/module/settings/SettingFragment.java
index ec0942bc..53b41878 100644
--- a/app/src/main/java/me/ghui/v2er/module/settings/SettingFragment.java
+++ b/app/src/main/java/me/ghui/v2er/module/settings/SettingFragment.java
@@ -56,6 +56,7 @@ public void onCreate(Bundle savedInstanceState) {
loginPreference = findPreference(getString(R.string.pref_key_value_toggle_log));
loginPreference.setOnPreferenceClickListener(this);
loginPreference.setTitle(UserUtils.isLogin() ? R.string.logout_str : R.string.login_str);
+ findPreference(getString(R.string.pref_key_help_and_feedback)).setOnPreferenceClickListener(this);
findPreference(getString(R.string.pref_key_auto_checkin)).setOnPreferenceClickListener(this);
findPreference(getString(R.string.pref_key_highlight_topic_owner_reply_item)).setOnPreferenceClickListener(this);
findPreference(getString(R.string.pref_key_is_scan_in_reverse)).setOnPreferenceClickListener(this::onPreferenceClick);
@@ -85,8 +86,6 @@ public void onActivityCreated(Bundle savedInstanceState) {
ListView list = rootView.findViewById(android.R.id.list);
if (list != null) {
list.setDivider(null);
-// list.setDivider(getActivity().getDrawable(R.drawable.common_divider));
- Utils.setPaddingForNavbar(list);
}
}
@@ -102,6 +101,9 @@ public boolean onPreferenceClick(Preference preference) {
Voast.show("成功清理" + size + "缓存");
}
return true;
+ } else if (key.equals(getString(R.string.pref_key_help_and_feedback))) {
+ startActivity(new Intent(getContext(), UserManualActivity.class));
+ return true;
} else if (key.equals(getString(R.string.pref_key_check_update))) {
Utils.openStorePage();
return true;
diff --git a/app/src/main/java/me/ghui/v2er/module/settings/UserManualActivity.java b/app/src/main/java/me/ghui/v2er/module/settings/UserManualActivity.java
index 304c9e85..d4015e36 100644
--- a/app/src/main/java/me/ghui/v2er/module/settings/UserManualActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/settings/UserManualActivity.java
@@ -22,8 +22,6 @@ protected int attachLayoutRes() {
@Override
protected void configToolBar(BaseToolBar toolBar) {
super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
- Utils.setPaddingForNavbar(mHtmlView);
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/topic/HtmlView.java b/app/src/main/java/me/ghui/v2er/module/topic/HtmlView.java
index bbbfeebd..f90990df 100644
--- a/app/src/main/java/me/ghui/v2er/module/topic/HtmlView.java
+++ b/app/src/main/java/me/ghui/v2er/module/topic/HtmlView.java
@@ -3,7 +3,13 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
@@ -29,6 +35,7 @@
import java.util.List;
import io.reactivex.Observable;
+import me.ghui.v2er.util.AdvertisementFilterUtil;
import me.ghui.v2er.util.Assets;
import me.ghui.v2er.util.Check;
import me.ghui.v2er.BuildConfig;
@@ -53,19 +60,19 @@ public class HtmlView extends WebView {
public HtmlView(Context context) {
super(context);
- init();
+ init(context);
}
public HtmlView(Context context, AttributeSet attrs) {
super(context, attrs);
- init();
+ init(context);
}
public void setOnHtmlRenderListener(OnHtmlRenderListener onHtmlRenderListener) {
this.onHtmlRenderListener = onHtmlRenderListener;
}
- private void init() {
+ private void init(Context context) {
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG);
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(true);
@@ -79,7 +86,7 @@ private void init() {
settings.setTextZoom(100);
settings.setAllowUniversalAccessFromFileURLs(true);
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
- setWebViewClient(new V2exWebViewClient());
+ setWebViewClient(new V2exWebViewClient(context));
setVerticalScrollBarEnabled(false);
addJavascriptInterface(new ImgClickJSInterface(), "imagelistener");
setBackgroundColor(DarkModelUtils.isDarkMode() ?
@@ -130,8 +137,38 @@ public interface OnHtmlRenderListener {
void onRenderCompleted();
}
+ private Message v2exWebViewClientMsg;
+ private V2exWebViewClientHandler v2exWebViewClientHandler;
+ private int advertisementFilterMsg = 0x11;
+ private WebView v2exWebView;
+
+ private class V2exWebViewClientHandler extends Handler {
+
+ V2exWebViewClientHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ super.handleMessage(msg);
+ try {
+ String clearAdvertisementJs = AdvertisementFilterUtil.clearAdvertisementDivJs(getContext());
+ if (v2exWebView != null) {
+ v2exWebView.loadUrl(clearAdvertisementJs);
+ }
+ }catch (Exception ignored) {}
+ }
+
+ }
+
+
private class V2exWebViewClient extends WebViewClient {
+ V2exWebViewClient(Context context) {
+ v2exWebViewClientHandler = new V2exWebViewClientHandler(context.getMainLooper());
+ v2exWebViewClientMsg = new Message();
+ }
+
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return super.shouldInterceptRequest(view, url);
@@ -156,11 +193,16 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
+ v2exWebView = view;
+ v2exWebViewClientMsg.what = advertisementFilterMsg;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
+ if (v2exWebViewClientHandler != null && v2exWebViewClientMsg != null) {
+ v2exWebViewClientHandler.sendMessage(v2exWebViewClientMsg);
+ }
// download the imgs in mImgs list
downloadImgs();
if (onHtmlRenderListener != null) {
@@ -183,9 +225,11 @@ private void downloadImgs() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
// TODO: 2018/12/23 click load again
- String localPath = "file:///android_asset/html/image_holder_failed.png";
- HtmlView.this.loadUrl("javascript:reloadImg(" + "'" + url + "'" + "," + "'" + localPath + "'" + ");");
- Voast.debug("load image failed");
+ HtmlView.this.post(() -> {
+ String localPath = "file:///android_asset/html/image_holder_failed.png";
+ HtmlView.this.loadUrl("javascript:reloadImg(" + "'" + url + "'" + "," + "'" + localPath + "'" + ");");
+ Voast.debug("load image failed");
+ });
return false;
}
diff --git a/app/src/main/java/me/ghui/v2er/module/topic/TopicActivity.java b/app/src/main/java/me/ghui/v2er/module/topic/TopicActivity.java
index 01bb777d..feac277c 100644
--- a/app/src/main/java/me/ghui/v2er/module/topic/TopicActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/topic/TopicActivity.java
@@ -6,6 +6,8 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsClient;
import com.google.android.material.bottomsheet.BottomSheetDialog;
@@ -18,6 +20,7 @@
import android.text.Html;
import android.text.TextWatcher;
import android.transition.Transition;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -207,124 +210,137 @@ protected void parseExtras(Intent intent) {
}
@Override
- protected void configToolBar(BaseToolBar toolBar) {
- super.configToolBar(toolBar);
- Utils.setPaddingForStatusBar(toolBar);
- mToolbar.inflateMenu(R.menu.topic_info_toolbar_menu);
- Menu menu = mToolbar.getMenu();
+ public int attachOptionsMenuRes() {
+ return R.menu.topic_info_toolbar_menu;
+ }
+
+
+ @Override
+ public void configOptionsMenu(Menu menu) {
+ super.configOptionsMenu(menu);
mLoveMenuItem = menu.findItem(R.id.action_star);
mThxMenuItem = menu.findItem(R.id.action_thx);
mAppendItem = menu.findItem(R.id.action_append);
mFadeItem = menu.findItem(R.id.action_fade);
mStickyItem = menu.findItem(R.id.action_sticky);
mReportMenuItem = menu.findItem(R.id.action_report);
- MenuItem replyMenuItem = menu.findItem(R.id.action_reply);
- mIsHideReplyBtn = Pref.readBool(R.string.pref_key_hide_reply_btn);
- replyMenuItem.setVisible(mIsHideReplyBtn);
- MenuItem scanOrderMenuItem = menu.findItem(R.id.action_scan_order);
+ scanOrderMenuItem = menu.findItem(R.id.action_scan_order);
scanOrderMenuItem.setTitle(mIsScanInOrder ? "顺序浏览" : "逆序浏览");
- mToolbar.setOnMenuItemClickListener(item -> {
- if (mTopicInfo == null) {
- if (item.getItemId() == R.id.action_open_in_browser) {
- String topicLink = Utils.generateTopicLinkById(mTopicId);
- Utils.openInBrowser(topicLink, this);
+ }
+
+ private MenuItem scanOrderMenuItem;
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ if (mTopicInfo == null) {
+ if (item.getItemId() == R.id.action_open_in_browser) {
+ String topicLink = Utils.generateTopicLinkById(mTopicId);
+ Utils.openInBrowser(topicLink, this);
+ } else {
+ toast("请等到加载完成");
+ }
+ return true;
+ }
+ TopicInfo.HeaderInfo headerInfo = mTopicInfo.getHeaderInfo();
+
+ switch (item.getItemId()) {
+ case R.id.action_star:
+ if (headerInfo.hadStared()) {
+ mPresenter.unStarTopic(mTopicId, mTopicInfo.getOnce());
} else {
- toast("请等到加载完成");
+ mPresenter.starTopic(mTopicId, mTopicInfo.getOnce());
}
- return true;
- }
- TopicInfo.HeaderInfo headerInfo = mTopicInfo.getHeaderInfo();
-
- switch (item.getItemId()) {
- case R.id.action_star:
- if (headerInfo.hadStared()) {
- mPresenter.unStarTopic(mTopicId, mTopicInfo.getOnce());
- } else {
- mPresenter.starTopic(mTopicId, mTopicInfo.getOnce());
- }
- break;
- case R.id.action_append:
- AppendTopicActivity.open(mTopicId, TopicActivity.this);
- break;
- case R.id.action_thx:
- if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
- if (mTopicInfo.getHeaderInfo().isSelf()) {
- toast("自己不能感谢自己");
- return false;
- }
- if (!headerInfo.canSendThanks()) {
- toast("感谢发送失败,可能因为您刚注册不久");
- return true;
- }
- if (!headerInfo.hadThanked()) {
- mPresenter.thxCreator(mTopicId, getOnce());
- } else {
- toast(R.string.already_thx_cannot_return);
- return true;
- }
- break;
- case R.id.action_block:
- if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
- new ConfirmDialog.Builder(getActivity())
- .msg("确定忽略此主题吗?")
- .positiveText(R.string.ok, dialog -> mPresenter.ignoreTopic(mTopicId, mTopicInfo.getOnce()))
- .negativeText(R.string.cancel)
- .build().show();
- break;
- case R.id.action_report:
- if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
- new ConfirmDialog.Builder(getActivity())
- .msg("确定要举报这个主题吗?")
- .positiveText(R.string.ok, dialog -> mPresenter.reportTopic())
- .negativeText(R.string.cancel)
- .build().show();
- break;
- case R.id.action_sticky:
- if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
- new ConfirmDialog.Builder(getActivity())
- .msg("你确认要将此主题置顶 10 分钟?该操作价格为 200 铜币。")
- .positiveText(R.string.ok, dialog -> mPresenter.stickyTopic())
- .negativeText(R.string.cancel)
- .build().show();
- break;
- case R.id.action_fade:
- if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
- new ConfirmDialog.Builder(getActivity())
- .msg("你确认要将此主题下沉 1 天?")
- .positiveText(R.string.ok, dialog -> mPresenter.fadeTopic())
- .negativeText(R.string.cancel)
- .build().show();
- break;
- case R.id.action_share:
- ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(headerInfo.getTitle())
- .content(Vtml.fromHtml(mTopicInfo.getContentInfo().getFormattedHtml()).toString())
- .link(UriUtils.topicLink(mTopicId))
- .img(headerInfo.getAvatar())
- .build();
- ShareManager shareManager = new ShareManager(shareData, this);
- shareManager.showShareDialog();
- break;
- case R.id.action_open_in_browser:
+ break;
+ case R.id.action_append:
+ AppendTopicActivity.open(mTopicId, TopicActivity.this);
+ break;
+ case R.id.action_thx:
+ if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
+ if (mTopicInfo.getHeaderInfo().isSelf()) {
+ toast("自己不能感谢自己");
+ return false;
+ }
+ if (!headerInfo.canSendThanks()) {
+ toast("感谢发送失败,可能因为您刚注册不久");
+ return true;
+ }
+ if (!headerInfo.hadThanked()) {
+ mPresenter.thxCreator(mTopicId, getOnce());
+ } else {
+ toast(R.string.already_thx_cannot_return);
+ return true;
+ }
+ break;
+ case R.id.action_block:
+ if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
+ new ConfirmDialog.Builder(getActivity())
+ .msg("确定忽略此主题吗?")
+ .positiveText(R.string.ok, dialog -> mPresenter.ignoreTopic(mTopicId, mTopicInfo.getOnce()))
+ .negativeText(R.string.cancel)
+ .build().show();
+ break;
+ case R.id.action_report:
+ if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
+ new ConfirmDialog.Builder(getActivity())
+ .msg("确定要举报这个主题吗?")
+ .positiveText(R.string.ok, dialog -> mPresenter.reportTopic())
+ .negativeText(R.string.cancel)
+ .build().show();
+ break;
+ case R.id.action_sticky:
+ if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
+ new ConfirmDialog.Builder(getActivity())
+ .msg("你确认要将此主题置顶 10 分钟?该操作价格为 200 铜币。")
+ .positiveText(R.string.ok, dialog -> mPresenter.stickyTopic())
+ .negativeText(R.string.cancel)
+ .build().show();
+ break;
+ case R.id.action_fade:
+ if (UserUtils.notLoginAndProcessToLogin(false, this)) return false;
+ new ConfirmDialog.Builder(getActivity())
+ .msg("你确认要将此主题下沉 1 天?")
+ .positiveText(R.string.ok, dialog -> mPresenter.fadeTopic())
+ .negativeText(R.string.cancel)
+ .build().show();
+ break;
+ case R.id.action_share:
+ ShareManager.ShareData shareData = new ShareManager.ShareData.Builder(headerInfo.getTitle())
+ .content(Vtml.fromHtml(mTopicInfo.getContentInfo().getFormattedHtml()).toString())
+ .link(UriUtils.topicLink(mTopicId))
+ .img(headerInfo.getAvatar())
+ .build();
+ ShareManager shareManager = new ShareManager(shareData, this);
+ shareManager.showShareDialog();
+ break;
+ case R.id.action_open_in_browser:
// Utils.copyToClipboard(this, mTopicInfo.getTopicLink());
// toast("链接已拷贝成功");
- Utils.openInBrowser(mTopicInfo.getTopicLink(), this);
- break;
- case R.id.action_reply:
- animateEditInnerWrapper(true);
- break;
- case R.id.action_scan_order:
- // reload
- mIsScanInOrder = !mIsScanInOrder;
- scanOrderMenuItem.setTitle(mIsScanInOrder ? "顺序浏览" : "逆序浏览");
- Pref.saveBool(R.string.pref_key_is_scan_in_reverse, !mIsScanInOrder);
- mLoadMoreRecyclerView.setLoadOrder(mIsScanInOrder);
- // 重新加载
- loadFromStart();
- showLoading();
- break;
- }
- return true;
- });
+ Utils.openInBrowser(mTopicInfo.getTopicLink(), this);
+ break;
+ case R.id.action_reply:
+ animateEditInnerWrapper(true);
+ break;
+ case R.id.action_scan_order:
+ // reload
+ mIsScanInOrder = !mIsScanInOrder;
+ scanOrderMenuItem.setTitle(mIsScanInOrder ? "顺序浏览" : "逆序浏览");
+ Pref.saveBool(R.string.pref_key_is_scan_in_reverse, !mIsScanInOrder);
+ mLoadMoreRecyclerView.setLoadOrder(mIsScanInOrder);
+ // 重新加载
+ loadFromStart();
+ showLoading();
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ protected void configToolBar(BaseToolBar toolBar) {
+ super.configToolBar(toolBar);
+ Log.d(this.getClass().getSimpleName(), "configToolBar");
+ if (mToolbar != null) {
+ mToolbar.displayHomeAsUpButton(this);
+ }
}
@@ -384,11 +400,11 @@ protected void reloadMode(int mode) {
@Override
protected void init() {
AndroidBug5497Workaround.assistActivity(this);
- Utils.setPaddingForNavbar(mReplyLayout);
setEnterSharedElementCallback(mCallback);
setFirstLoadingDelay(300);
shareElementAnimation();
// mReplyFabBtn.setVisibility(!mIsLogin || mIsHideReplyBtn ? View.GONE : VISIBLE);
+ mIsHideReplyBtn = Pref.readBool(R.string.pref_key_hide_reply_btn);
if (!mIsLogin || mIsHideReplyBtn) {
mReplyFabBtn.hide();
} else mReplyFabBtn.show();
@@ -580,6 +596,7 @@ public String getOnce() {
@Override
public void fillView(TopicInfo topicInfo, int page) {
+ Log.d(this.getClass().getSimpleName(), "fillView");
mTopicInfo = topicInfo;
if (mNeedWaitForTransitionEnd) return;
if (topicInfo == null) {
@@ -610,13 +627,13 @@ public void fillView(TopicInfo topicInfo, int page) {
onRenderCompleted();
}
TopicInfo.HeaderInfo headerInfo = mTopicInfo.getHeaderInfo();
- updateStarStatus(headerInfo.hadStared(), false);
- updateThxCreatorStatus(headerInfo.hadThanked(), false);
- updateReportMenuItem(mTopicInfo.hasReportPermission(), mTopicInfo.hasReported());
- boolean isSelf = mTopicInfo.getHeaderInfo().isSelf();
- mAppendItem.setVisible(isSelf && mTopicInfo.getHeaderInfo().canAppend());
- mFadeItem.setVisible(isSelf && mTopicInfo.canfade());
- mStickyItem.setVisible(isSelf && mTopicInfo.canSticky());
+ updateStarStatus(headerInfo.hadStared(), false);
+ updateThxCreatorStatus(headerInfo.hadThanked(), false);
+ updateReportMenuItem(mTopicInfo.hasReportPermission(), mTopicInfo.hasReported());
+ boolean isSelf = mTopicInfo.getHeaderInfo().isSelf();
+ mAppendItem.setVisible(isSelf && mTopicInfo.getHeaderInfo().canAppend());
+ mFadeItem.setVisible(isSelf && mTopicInfo.canfade());
+ mStickyItem.setVisible(isSelf && mTopicInfo.canSticky());
if (!mIsHideReplyBtn && mIsLogin) {
// mReplyFabBtn.setVisibility(VISIBLE);
mReplyFabBtn.show();
@@ -775,7 +792,7 @@ public void onAnimationCancel(Animator animation) {
private void updateStarStatus(boolean isStared, boolean needUpdateData) {
mLoveMenuItem.setIcon(isStared ?
- R.drawable.ic_star_selected : R.drawable.ic_star_normal);
+ R.drawable.ic_bookmarked : R.drawable.ic_bookmark);
mLoveMenuItem.getIcon().setTint(Theme.getColor(R.attr.icon_tint_color, this));
if (needUpdateData) {
mTopicInfo.getHeaderInfo().updateStarStatus(isStared);
@@ -913,7 +930,6 @@ public void onKeyboardShown() {
@Override
public void onKeyboardHidden() {
L.d("onKeyboardHidden");
- Utils.setPaddingForNavbar(mReplyLayout);
}
@Override
diff --git a/app/src/main/java/me/ghui/v2er/module/topic/TopicReplyItemDelegate.java b/app/src/main/java/me/ghui/v2er/module/topic/TopicReplyItemDelegate.java
index e10c6f8b..f7bc92d4 100644
--- a/app/src/main/java/me/ghui/v2er/module/topic/TopicReplyItemDelegate.java
+++ b/app/src/main/java/me/ghui/v2er/module/topic/TopicReplyItemDelegate.java
@@ -1,12 +1,21 @@
package me.ghui.v2er.module.topic;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import androidx.annotation.Nullable;
+
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
import android.util.TypedValue;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
import me.ghui.v2er.util.Check;
import me.ghui.v2er.R;
@@ -72,6 +81,20 @@ public void convert(ViewHolder holder, TopicInfo.Item item, int position) {
img.setImageResource(replyInfo.hadThanked() ? R.drawable.love_checked_icon : R.drawable.love_normal_icon);
holder.setText(R.id.time_tv, replyInfo.getTime());
TextView contentView = holder.getView(R.id.content_tv);
+ Context context = holder.getConvertView().getContext();
+ if (context != null) {
+ ClipboardManager clipboardManager = (ClipboardManager) context
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ TextView finalContentView = contentView;
+ contentView.setOnLongClickListener(v -> {
+ if (clipboardManager != null) {
+ ClipData clip = ClipData.newPlainText(context.getString(R.string.app_name), finalContentView.getText());
+ clipboardManager.setPrimaryClip(clip);
+ Toast.makeText(context, R.string.copy_text_success, Toast.LENGTH_LONG).show();
+ }
+ return true;
+ });
+ }
contentView.setTextSize(TypedValue.COMPLEX_UNIT_PX, FontSizeUtil.getContentSize());
if (Check.notEmpty(replyInfo.getReplyContent())) {
contentView.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/me/ghui/v2er/module/user/UserHomeActivity.java b/app/src/main/java/me/ghui/v2er/module/user/UserHomeActivity.java
index 06ff6663..3461ce31 100644
--- a/app/src/main/java/me/ghui/v2er/module/user/UserHomeActivity.java
+++ b/app/src/main/java/me/ghui/v2er/module/user/UserHomeActivity.java
@@ -2,6 +2,7 @@
import android.app.SharedElementCallback;
import android.content.Context;
+import android.content.Entity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
@@ -22,6 +23,9 @@
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -118,6 +122,35 @@ public void onMapSharedElements(List names, Map sharedElem
private int mAppBarMaxOffset;
private LinearLayoutManager mLayoutManager;
+ public static void open(String userName, Context context, String avatar, View... sourceViews) {
+ Navigator navigator = Navigator.from(context)
+ .to(UserHomeActivity.class)
+ .putExtra(UserHomeActivity.USER_NAME_KEY, userName)
+ .putExtra(UserHomeActivity.USER_AVATAR_KEY, avatar);
+ List sourceViewList = new ArrayList<>(sourceViews.length);
+ Collections.addAll(sourceViewList, sourceViews);
+ if (sourceViews.length > 0) {
+ Iterator sourceViewIterator = sourceViewList.iterator();
+ while (sourceViewIterator.hasNext()) {
+ View sourceView = sourceViewIterator.next();
+ if (sourceView instanceof ImageView) {
+ ImageView imgView = (ImageView) sourceView;
+ if (ViewUtils.isSameImgRes(imgView, R.drawable.avatar_placeholder_drawable) || imgView.getDrawable() == null) {
+ sourceViewIterator.remove();
+ }
+ }
+ navigator.putExtra(KEY(sourceView.getTransitionName()+"_key"),
+ sourceView.getTransitionName());
+ }
+ }
+ if (sourceViewList.size() > 0) {
+ View[] shareViews = new View[sourceViewList.size()];
+ sourceViewList.toArray(shareViews);
+ navigator.shareElement(shareViews);
+ }
+ navigator.start();
+ }
+
public static void open(String userName, Context context, View sourceView, String avatar) {
if (sourceView != null && sourceView instanceof ImageView) {
ImageView imgview = (ImageView) sourceView;
@@ -141,9 +174,16 @@ protected int attachLayoutRes() {
@Override
protected BaseToolBar attachToolbar() {
+ displayStatusBarArea(false);
return null;
}
+ @Override
+ protected void configToolBar(BaseToolBar toolBar) {
+ super.configToolBar(toolBar);
+ mToolbar.displayHomeAsUpButton(this);
+ }
+
@Override
protected void parseExtras(Intent intent) {
mUserName = intent.getStringExtra(USER_NAME_KEY);
@@ -181,7 +221,6 @@ public void finishAfterTransition() {
protected void init() {
getWindow().setStatusBarColor(Color.TRANSPARENT);
mAvatarImg.setTransitionName(mTransitionName);
- Utils.setPaddingForStatusBar(mToolbar);
setEnterSharedElementCallback(mCallback);
mToolbar.setOnDoubleTapListener(this);
mToolbar.setNavigationOnClickListener(view -> onBackPressed());
diff --git a/app/src/main/java/me/ghui/v2er/network/APIService.java b/app/src/main/java/me/ghui/v2er/network/APIService.java
index 0f380f5f..56fe5257 100644
--- a/app/src/main/java/me/ghui/v2er/network/APIService.java
+++ b/app/src/main/java/me/ghui/v2er/network/APIService.java
@@ -1,11 +1,14 @@
package me.ghui.v2er.network;
+import android.util.Log;
+
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
@@ -18,6 +21,7 @@
import me.ghui.v2er.BuildConfig;
import me.ghui.v2er.util.Check;
import me.ghui.v2er.util.L;
+import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
@@ -37,7 +41,10 @@
*/
public class APIService {
- public static final String WAP_USER_AGENT = "Mozilla/5.0 (Linux; Android 9.0; V2er Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36";
+
+ public static final String WAP_Android_USER_AGENT = "Mozilla/5.0 (Linux; Android 9.0; V2er Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36";
+
+ public static final String WAP_IOS_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
public static final String WEB_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4; V2er) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36";
public static final String UA_KEY = "user-agent";
@@ -116,10 +123,36 @@ public Response intercept(Chain chain) throws IOException {
String ua = request.header(UA_KEY);
if (Check.isEmpty(ua)) {
request = request.newBuilder()
- .addHeader("user-agent", WAP_USER_AGENT)
+ .addHeader("user-agent", WAP_Android_USER_AGENT)
+ .build();
+ }
+ if (request.url().toString().endsWith("png")) {
+ request = request.newBuilder()
+ .removeHeader("user-agent")
+ .addHeader("user-agent", WAP_Android_USER_AGENT)
.build();
}
try {
+ if (request.url().host().startsWith(".")) {
+ try {
+ HttpUrl.Builder httpUrlBuilder = request.url().newBuilder()
+ .host(Constants.WWW_HOST_NAME)
+ .setEncodedPathSegment(0, "t");
+ List encodedPathSegments = request.url().encodedPathSegments();
+ for (int i = 0; i < request.url().encodedPathSegments().size(); i++) {
+ if (i < encodedPathSegments.size() - 1) {
+ httpUrlBuilder.setEncodedPathSegment(i + 1, encodedPathSegments.get(i));
+ } else {
+ httpUrlBuilder.addEncodedPathSegment(encodedPathSegments.get(i));
+ }
+ }
+ request = request.newBuilder()
+ .url(httpUrlBuilder.build())
+ .build();
+ }catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
return chain.proceed(request);
} catch (Exception e) {
e.printStackTrace();
diff --git a/app/src/main/java/me/ghui/v2er/network/APIs.java b/app/src/main/java/me/ghui/v2er/network/APIs.java
index 8259319e..1beb4205 100644
--- a/app/src/main/java/me/ghui/v2er/network/APIs.java
+++ b/app/src/main/java/me/ghui/v2er/network/APIs.java
@@ -96,10 +96,12 @@ public interface APIs {
@Html
@GET("/my/following")
+ @Headers("user-agent: " + APIService.WAP_IOS_USER_AGENT)
Observable specialCareInfo(@Query("p") int page);
@Html
@GET("/my/topics")
+ @Headers("user-agent: " + APIService.WAP_IOS_USER_AGENT)
Observable topicStarInfo(@Query("p") int page);
@Html
diff --git a/app/src/main/java/me/ghui/v2er/network/Constants.java b/app/src/main/java/me/ghui/v2er/network/Constants.java
index 35332e9b..6b716630 100644
--- a/app/src/main/java/me/ghui/v2er/network/Constants.java
+++ b/app/src/main/java/me/ghui/v2er/network/Constants.java
@@ -9,5 +9,6 @@ public interface Constants {
String HTTP_SCHEME = "http:";
String BASE_URL = HTTPS_SCHEME + "//www.v2ex.com";
String HOST_NAME = "v2ex.com";
+ String WWW_HOST_NAME = "www.v2ex.com";
String PACKAGE_NAME = "me.ghui.v2ex";
}
diff --git a/app/src/main/java/me/ghui/v2er/network/GeneralConsumer.java b/app/src/main/java/me/ghui/v2er/network/GeneralConsumer.java
index 2a5202ed..416566e2 100644
--- a/app/src/main/java/me/ghui/v2er/network/GeneralConsumer.java
+++ b/app/src/main/java/me/ghui/v2er/network/GeneralConsumer.java
@@ -55,53 +55,55 @@ public void onNext(T t) {
3. no premission to open the page
*/
GeneralError generalError = new GeneralError(ResultCode.NETWORK_ERROR, "Unknown Error");
- String response = t.getResponse();
- generalError.setResponse(response);
- Observable.just(response)
- .compose(RxUtils.io_main())
- .map(s -> {
- BaseInfo resultInfo = APIService.fruit().fromHtml(s, LoginParam.class);
- if (resultInfo == null) return null;
- if (!resultInfo.isValid()) {
- resultInfo = APIService.fruit().fromHtml(s, NewsInfo.class);
- }
- if (!resultInfo.isValid()) {
- resultInfo = APIService.fruit().fromHtml(s, TwoStepLoginInfo.class);
- }
- // 31/07/2017 More tries...
- return resultInfo;
- })
- .subscribe(new BaseConsumer() {
- @Override
- public void onConsume(BaseInfo resultInfo) {
- if (resultInfo == null || !resultInfo.isValid()) {
- onGeneralError(generalError);
- return;
+ if (t.getResponse() != null) {
+ String response = t.getResponse();
+ generalError.setResponse(response);
+ Observable.just(response)
+ .compose(RxUtils.io_main())
+ .map(s -> {
+ BaseInfo resultInfo = APIService.fruit().fromHtml(s, LoginParam.class);
+ if (resultInfo == null) return null;
+ if (!resultInfo.isValid()) {
+ resultInfo = APIService.fruit().fromHtml(s, NewsInfo.class);
+ }
+ if (!resultInfo.isValid()) {
+ resultInfo = APIService.fruit().fromHtml(s, TwoStepLoginInfo.class);
}
- if (resultInfo instanceof LoginParam) {
- if (UserUtils.isLogin()) {
- generalError.setErrorCode(ResultCode.LOGIN_EXPIRED);
- generalError.setMessage("登录已过期,请重新登录");
- UserUtils.clearLogin();
- } else {
- generalError.setErrorCode(ResultCode.LOGIN_NEEDED);
- generalError.setMessage("需要您先去登录");
+ // 31/07/2017 More tries...
+ return resultInfo;
+ })
+ .subscribe(new BaseConsumer() {
+ @Override
+ public void onConsume(BaseInfo resultInfo) {
+ if (resultInfo == null || !resultInfo.isValid()) {
+ onGeneralError(generalError);
+ return;
+ }
+ if (resultInfo instanceof LoginParam) {
+ if (UserUtils.isLogin()) {
+ generalError.setErrorCode(ResultCode.LOGIN_EXPIRED);
+ generalError.setMessage("登录已过期,请重新登录");
+ UserUtils.clearLogin();
+ } else {
+ generalError.setErrorCode(ResultCode.LOGIN_NEEDED);
+ generalError.setMessage("需要您先去登录");
+ }
+ } else if (resultInfo instanceof NewsInfo) {
+ generalError.setErrorCode(ResultCode.REDIRECT_TO_HOME);
+ generalError.setMessage("Redirecting to home");
+ } else if (resultInfo instanceof TwoStepLoginInfo) {
+ generalError.setErrorCode(ResultCode.LOGIN_TWO_STEP);
+ generalError.setMessage("Two Step Login");
}
- } else if (resultInfo instanceof NewsInfo) {
- generalError.setErrorCode(ResultCode.REDIRECT_TO_HOME);
- generalError.setMessage("Redirecting to home");
- } else if (resultInfo instanceof TwoStepLoginInfo) {
- generalError.setErrorCode(ResultCode.LOGIN_TWO_STEP);
- generalError.setMessage("Two Step Login");
+ onGeneralError(generalError);
}
- onGeneralError(generalError);
- }
- @Override
- public void onError(Throwable e) {
- onGeneralError(e);
- }
- });
+ @Override
+ public void onError(Throwable e) {
+ onGeneralError(e);
+ }
+ });
+ }
}
}
diff --git a/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfo.java b/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfo.java
new file mode 100644
index 00000000..c951b332
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfo.java
@@ -0,0 +1,56 @@
+package me.ghui.v2er.network.bean;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExplorePageInfo extends BaseInfo {
+
+ private final List items = new ArrayList<>();
+
+ public List getItems() {
+ if (items.size() > 0) {
+ items.clear();
+ }
+ if (dailyHotInfo != null) {
+ items.add(dailyHotInfoTitle);
+ items.addAll(dailyHotInfo);
+ }
+ if (nodesNavInfo != null) {
+ items.add(nodesNavInfoTitle);
+ items.addAll(nodesNavInfo);
+ }
+ return items;
+ }
+
+ public DailyHotInfo dailyHotInfo;
+ public String dailyHotInfoTitle;
+
+ public void setDailyHotInfo(DailyHotInfo dailyHotInfo, String title) {
+ this.dailyHotInfo = dailyHotInfo;
+ this.dailyHotInfoTitle = title;
+ }
+
+ public void setDailyHotInfoTitle(String dailyHotInfoTitle) {
+ this.dailyHotInfoTitle = dailyHotInfoTitle;
+ }
+
+ public NodesNavInfo nodesNavInfo;
+ private String nodesNavInfoTitle;
+
+ public void setNodesNavInfo(NodesNavInfo nodesNavInfo, String title) {
+ this.nodesNavInfo = nodesNavInfo;
+ this.nodesNavInfoTitle = title;
+ }
+
+ public void setNodesNavInfoTitle(String nodesNavInfoTitle) {
+ this.nodesNavInfoTitle = nodesNavInfoTitle;
+ }
+
+ @Override
+ public boolean isValid() {
+ return this.dailyHotInfo.isValid() || this.nodesNavInfo.isValid();
+ }
+
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfoWrapper.java b/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfoWrapper.java
new file mode 100644
index 00000000..af549ea3
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/network/bean/ExplorePageInfoWrapper.java
@@ -0,0 +1,23 @@
+package me.ghui.v2er.network.bean;
+
+import java.io.Serializable;
+
+public class ExplorePageInfoWrapper extends BaseInfo implements Serializable {
+
+ public ExplorePageInfo explorePageInfo;
+
+
+ private ExplorePageInfoWrapper(ExplorePageInfo explorePageInfo) {
+ this.explorePageInfo = explorePageInfo;
+ }
+
+ public static ExplorePageInfoWrapper wrapper(ExplorePageInfo explorePageInfo) {
+ return new ExplorePageInfoWrapper(explorePageInfo);
+ }
+
+ @Override
+ public boolean isValid() {
+ if (explorePageInfo == null) return false;
+ return explorePageInfo.isValid();
+ }
+}
diff --git a/app/src/main/java/me/ghui/v2er/network/bean/NodesNavInfoWrapper.java b/app/src/main/java/me/ghui/v2er/network/bean/NodesNavInfoWrapper.java
deleted file mode 100644
index 5a84f8d8..00000000
--- a/app/src/main/java/me/ghui/v2er/network/bean/NodesNavInfoWrapper.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package me.ghui.v2er.network.bean;
-
-import java.io.Serializable;
-
-public class NodesNavInfoWrapper extends BaseInfo implements Serializable {
-
- public NodesNavInfo nodesNavInfo;
-
- private NodesNavInfoWrapper(NodesNavInfo nodesNavInfo) {
- this.nodesNavInfo = nodesNavInfo;
- }
-
- public static NodesNavInfoWrapper wrapper(NodesNavInfo nodesNavInfo) {
- return new NodesNavInfoWrapper(nodesNavInfo);
- }
-
- @Override
- public boolean isValid() {
- if (nodesNavInfo == null) return false;
- return nodesNavInfo.isValid();
- }
-}
diff --git a/app/src/main/java/me/ghui/v2er/util/AdvertisementFilterUtil.java b/app/src/main/java/me/ghui/v2er/util/AdvertisementFilterUtil.java
new file mode 100644
index 00000000..b33fb384
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/util/AdvertisementFilterUtil.java
@@ -0,0 +1,50 @@
+package me.ghui.v2er.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import me.ghui.v2er.R;
+
+public class AdvertisementFilterUtil {
+
+ public static String clearAdvertisementDivJs(Context context){
+ StringBuilder js = new StringBuilder("javascript:");
+ Resources res = context.getResources();
+ String[] adDivs = res.getStringArray(R.array.advertisementBlockDiv);
+ for(int i=0;i 0) {
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ if (view instanceof TextView) {
+ if (mTitleView != null) {
+ mSubTitleView = (TextView) view;
+ break;
+ }
+ mTitleView = (TextView) view;
+ }
+ }
+ }
+ }
+
+ /**
+ * 必须有主标题标题剧中才会生效
+ * @param isCenter
+ */
+ public void setTileCenter(boolean isCenter) {
+ if (isCenter) {
+ initTitleViewAndSubTitleView();
+ if (mTitleView != null) {
+ mTitleView.setGravity(Gravity.CENTER);
+ Toolbar.LayoutParams layoutParams = (Toolbar.LayoutParams) mTitleView.getLayoutParams();
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.gravity = Gravity.CENTER;
+ mTitleView.setLayoutParams(layoutParams);
+ if (mSubTitleView != null) {
+ mSubTitleView.setGravity(Gravity.CENTER);
+ Toolbar.LayoutParams subTitleLayoutParams = (Toolbar.LayoutParams) mSubTitleView.getLayoutParams();
+ subTitleLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ subTitleLayoutParams.gravity = Gravity.CENTER;
+ mSubTitleView.setLayoutParams(subTitleLayoutParams);
+ }
+ float marginStart = 0;
+ float marginEnd = 0;
+ if (getNavigationIcon() != null) {
+ marginEnd = ScaleUtils.dp(GENERATED_ITEM_MARGIN + GENERATED_ITEM_PADDING * 3);
+ } else if (getMenu().size() > 0) {
+ marginStart = ScaleUtils.dp(MIN_CELL_SIZE - GENERATED_ITEM_PADDING * 3);
+ }
+ setTitleMargin((int) marginStart, 0, (int) marginEnd, 0);
+ }
+ }
+ }
+
+ private View mViewTitleView;
+
+ public void setViewTileCenter(View viewTitleView) {
+ this.mViewTitleView = viewTitleView;
+ if (mViewTitleView != null) {
+ Toolbar.LayoutParams layoutParams = (Toolbar.LayoutParams) mViewTitleView.getLayoutParams();
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.gravity = Gravity.CENTER;
+ float marginStart = 0;
+ float marginEnd = 0;
+ if (getNavigationIcon() != null) {
+ marginEnd = ScaleUtils.dp(GENERATED_ITEM_MARGIN + GENERATED_ITEM_PADDING * 3);
+ } else if (getMenu().size() > 0) {
+ marginStart = ScaleUtils.dp(MIN_CELL_SIZE - GENERATED_ITEM_PADDING * 3);
+ }
+ layoutParams.setMargins((int) marginStart, 0, (int) marginEnd, 0);
+ mViewTitleView.setLayoutParams(layoutParams);
+ }
+ }
+
+ @Override
+ public void setElevation(float elevation) {
+ super.setElevation(elevation);
+ ViewGroup barParentViewGroup = (ViewGroup) this.getParent();
+ if (barParentViewGroup != null) {
+ if (barParentViewGroup instanceof AppBarLayout) {
+ barParentViewGroup.setElevation(elevation);
+ }
+ }
+ }
+
+ /**
+ * 设置默认返回按键, 并默认可用
+ */
+ public void displayHomeAsUpButton(AppCompatActivity activity) {
+ activity.setSupportActionBar(this);
+ if (activity.getSupportActionBar() != null) {
+ activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ activity.getSupportActionBar().setHomeButtonEnabled(true);
+ }
+ if (getNavigationIcon() != null) {
+ this.getNavigationIcon().setTint(Theme.getColor(R.attr.icon_tint_color, getContext()));
+ }
+ setNavigationOnClickListener(v -> activity.onBackPressed());
}
+ /**
+ * 设置右边菜单
+ * 如果调用 displayHomeAsUpButton 会导致此方法失效,可以在onCreateOptionsMenu方法中创建菜单,或
+ * 在BaseActivity的attachOptionsMenuRes 方法返回菜单资源
+ * @param resId
+ */
@Override
public void inflateMenu(int resId) {
super.inflateMenu(resId);
diff --git a/app/src/main/java/me/ghui/v2er/widget/SectionItemView.java b/app/src/main/java/me/ghui/v2er/widget/SectionItemView.java
new file mode 100644
index 00000000..5169391e
--- /dev/null
+++ b/app/src/main/java/me/ghui/v2er/widget/SectionItemView.java
@@ -0,0 +1,103 @@
+package me.ghui.v2er.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import me.ghui.v2er.R;
+import me.ghui.v2er.util.ScaleUtils;
+import me.ghui.v2er.util.Utils;
+
+public class SectionItemView extends RelativeLayout implements View.OnClickListener {
+ private Drawable icon;
+ private String title;
+ private boolean showDivider;
+ private TextView sectionTitle;
+ private ImageView sectionIcon;
+ private DividerView sectionDivider;
+
+ private OnSectionClickListener onSectionClickListener;
+
+ public void setOnSectionClickListener(OnSectionClickListener onSectionClickListener) {
+ this.onSectionClickListener = onSectionClickListener;
+ }
+
+ public interface OnSectionClickListener {
+ void onClick(View v);
+ }
+
+ public SectionItemView(@NonNull Context context) {
+ super(context);
+ initView(context, null);
+ }
+
+ public SectionItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ initView(context, attrs);
+ }
+
+ public SectionItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initView(context, attrs);
+ }
+
+ public SectionItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initView(context, attrs);
+ }
+
+ private void initAttrs(Context context, AttributeSet attrs) {
+ if (attrs != null) {
+ TypedArray styledAttrs = getContext().getTheme().obtainStyledAttributes(attrs,
+ R.styleable.SectionItemView, 0, 0);
+ icon = styledAttrs.getDrawable(R.styleable.SectionItemView_icon);
+ title = styledAttrs.getString(R.styleable.SectionItemView_title);
+ showDivider = styledAttrs.getBoolean(R.styleable.SectionItemView_show_divider, true);
+ styledAttrs.recycle();
+ }
+ }
+
+ private ViewGroup rootView;
+ private RelativeLayout sectionLayout;
+
+ private void initView(Context context, AttributeSet attrs) {
+ initAttrs(context, attrs);
+ rootView = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.section_item_view_layout, this, true);
+ sectionLayout = rootView.findViewById(R.id.section_layout);
+ sectionTitle = rootView.findViewById(R.id.section_title);
+ sectionIcon = rootView.findViewById(R.id.section_icon);
+ sectionDivider = rootView.findViewById(R.id.section_divider);
+ sectionLayout.setOnClickListener(this);
+ if (icon != null) {
+ sectionIcon.setImageDrawable(icon);
+ }
+ if (!TextUtils.isEmpty(title)) {
+ sectionTitle.setText(title);
+ }
+ if (!showDivider) {
+ sectionDivider.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (onSectionClickListener != null) {
+ onSectionClickListener.onClick(this);
+ }
+ }
+
+}
diff --git a/app/src/main/java/me/ghui/v2er/widget/richtext/RichTextConfig.java b/app/src/main/java/me/ghui/v2er/widget/richtext/RichTextConfig.java
index 679d5032..b01884f4 100644
--- a/app/src/main/java/me/ghui/v2er/widget/richtext/RichTextConfig.java
+++ b/app/src/main/java/me/ghui/v2er/widget/richtext/RichTextConfig.java
@@ -5,10 +5,16 @@
import android.text.SpannableStringBuilder;
import android.widget.TextView;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
import me.ghui.v2er.general.Vtml;
import me.ghui.v2er.module.imgviewer.ImagesInfo;
import me.ghui.v2er.network.APIService;
import me.ghui.v2er.util.ScaleUtils;
+import me.ghui.v2er.util.Utils;
/**
@@ -77,13 +83,31 @@ public RichTextConfig supportUrlClick(boolean supportUrlClick) {
return this;
}
+ private Document parseCfEmail(String sourceText) {
+ Document sourceDocument = Jsoup.parseBodyFragment(sourceText);
+ Elements cfElements = sourceDocument.select("a");
+ for (Element cfElement : cfElements) {
+ String cfEmail = cfElement.attr("data-cfemail");
+ String cfHref = cfElement.attr("href");
+ System.out.println(cfEmail);
+ if (!cfEmail.isEmpty()) {
+ String email = Utils.cfDecodeEmail(cfEmail.replaceAll("\"", ""));
+ cfElement.text(email);
+ cfElement.removeAttr("data-cfemail");
+ cfElement.attr("href", "mailto:"+email);
+ }
+// System.out.println(cfElement);
+ }
+ return sourceDocument;
+ }
+
public void into(TextView textView) {
if (!noImg && mImageGetter == null) {
mImageHolder = new ImageHolder(textView, maxSize, mLoadingDrawable, mLoaderrorDrawable);
mImageGetter = new GlideImageGetter(textView, mImageHolder);
}
if (sourceText == null) sourceText = "";
- SpannableStringBuilder spanned = (SpannableStringBuilder) Html.fromHtml(sourceText, mImageGetter, mTagHandler);
+ SpannableStringBuilder spanned = (SpannableStringBuilder) Html.fromHtml(parseCfEmail(sourceText).toString(), mImageGetter, mTagHandler);
CharSequence content = Vtml.removePadding(spanned);
textView.setText(content);
ImagesInfo.Images images = APIService.fruit().fromHtml(sourceText, ImagesInfo.Images.class);
diff --git a/app/src/main/res/drawable-xxhdpi/ic_send.png b/app/src/main/res/drawable-xxhdpi/ic_send.png
deleted file mode 100644
index 5da547f8..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_send.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_share.png b/app/src/main/res/drawable-xxhdpi/ic_share.png
deleted file mode 100644
index 5ff85810..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_share.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_star_normal.png b/app/src/main/res/drawable-xxhdpi/ic_star_normal.png
deleted file mode 100644
index 3a99755e..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_star_normal.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_star_selected.png b/app/src/main/res/drawable-xxhdpi/ic_star_selected.png
deleted file mode 100644
index d2e62d28..00000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_star_selected.png and /dev/null differ
diff --git a/app/src/main/res/drawable/ic_arrow_back_black.xml b/app/src/main/res/drawable/ic_arrow_back_black.xml
deleted file mode 100644
index 010ad884..00000000
--- a/app/src/main/res/drawable/ic_arrow_back_black.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_arrow_back_white.xml b/app/src/main/res/drawable/ic_arrow_back_white.xml
deleted file mode 100644
index 0d96512f..00000000
--- a/app/src/main/res/drawable/ic_arrow_back_white.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_arrow_right.xml b/app/src/main/res/drawable/ic_arrow_right.xml
new file mode 100755
index 00000000..a9850bbe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_right.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml
new file mode 100644
index 00000000..6e302829
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bookmark.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_bookmarked.xml b/app/src/main/res/drawable/ic_bookmarked.xml
new file mode 100644
index 00000000..20b742b4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bookmarked.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_favorites.xml b/app/src/main/res/drawable/ic_favorites.xml
new file mode 100644
index 00000000..2ab4e6a6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_favorites.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
index af0694d4..75ab35dd 100644
--- a/app/src/main/res/drawable/ic_launcher_foreground.xml
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -6,12 +6,6 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_paper_plane.xml b/app/src/main/res/drawable/ic_paper_plane.xml
new file mode 100644
index 00000000..e5f820d4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_paper_plane.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_pencil.xml b/app/src/main/res/drawable/ic_pencil.xml
new file mode 100644
index 00000000..5401933f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pencil.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_sets.xml b/app/src/main/res/drawable/ic_sets.xml
new file mode 100644
index 00000000..9be725d0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_sets.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml
new file mode 100644
index 00000000..9eef0785
--- /dev/null
+++ b/app/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_shortcuts_bookmark.xml b/app/src/main/res/drawable/ic_shortcuts_bookmark.xml
new file mode 100644
index 00000000..4b4e2bb4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shortcuts_bookmark.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_shortcuts_star.xml b/app/src/main/res/drawable/ic_shortcuts_star.xml
deleted file mode 100644
index 0d67e67f..00000000
--- a/app/src/main/res/drawable/ic_shortcuts_star.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/main_bottom_navigation_selector.xml b/app/src/main/res/drawable/main_bottom_navigation_selector.xml
new file mode 100644
index 00000000..f76a1247
--- /dev/null
+++ b/app/src/main/res/drawable/main_bottom_navigation_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/act_main.xml b/app/src/main/res/layout-land/act_main.xml
new file mode 100644
index 00000000..892385be
--- /dev/null
+++ b/app/src/main/res/layout-land/act_main.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/act_gallery.xml b/app/src/main/res/layout/act_gallery.xml
index d8599798..577921cc 100644
--- a/app/src/main/res/layout/act_gallery.xml
+++ b/app/src/main/res/layout/act_gallery.xml
@@ -26,14 +26,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-
+ app:contentInsetStart="0dp">
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/act_login.xml b/app/src/main/res/layout/act_login.xml
index eb94b4c4..1c99d2e7 100644
--- a/app/src/main/res/layout/act_login.xml
+++ b/app/src/main/res/layout/act_login.xml
@@ -2,12 +2,13 @@
@@ -17,13 +18,13 @@
android:layout_height="wrap_content"
android:autofillHints="username"
android:inputType="textWebEditText"
- android:textColor="?attr/icon_tint_color"
+ android:textColor="?attr/bodyTextColor"
android:textSize="@dimen/largeTextSize" />
@@ -48,7 +49,7 @@
diff --git a/app/src/main/res/layout/act_main.xml b/app/src/main/res/layout/act_main.xml
index ee1f137a..408fa2d9 100644
--- a/app/src/main/res/layout/act_main.xml
+++ b/app/src/main/res/layout/act_main.xml
@@ -1,61 +1,54 @@
-
-
-
-
-
-
-
+
+
-
-
-
+ android:gravity="center"
+ android:scaleType="fitCenter"
+ android:src="@drawable/v2ex_title_logo"
+ android:visibility="gone"
+ app:tint="?attr/icon_tint_color" />
+
-
-
+
-
+
-
-
-
-
-
-
+
+
-
\ No newline at end of file
+ android:contentDescription="@string/acc_bottom_nav_menu"
+ app:layout_constraintTop_toBottomOf="@+id/main_container"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:labelVisibilityMode="labeled"
+ app:itemIconTint="@drawable/main_bottom_navigation_selector"
+ app:itemTextColor="@drawable/main_bottom_navigation_selector"
+ app:menu="@menu/bottom_menu_main" />
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/act_new_topic.xml b/app/src/main/res/layout/act_new_topic.xml
index 6bdb282f..4397819e 100644
--- a/app/src/main/res/layout/act_new_topic.xml
+++ b/app/src/main/res/layout/act_new_topic.xml
@@ -10,8 +10,11 @@
android:id="@+id/create_topic_title_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint="标题"
- android:textColorHint="?attr/icon_tint_color">
+ style="@style/MaterialComponents.TextInputLayout.FilledBox"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ android:hint="标题">
+ app:tint="?attr/icon_tint_color" />
+ app:tint="?attr/icon_tint_color" />
+
diff --git a/app/src/main/res/layout/act_user_page.xml b/app/src/main/res/layout/act_user_page.xml
index 33b6de8e..7d74cf4f 100644
--- a/app/src/main/res/layout/act_user_page.xml
+++ b/app/src/main/res/layout/act_user_page.xml
@@ -57,6 +57,7 @@
android:layout_width="wrap_content"
android:gravity="center"
android:paddingTop="6dp"
+ android:transitionName="@string/share_element_username"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/user_img"
tools:text="ghui" />
@@ -113,8 +114,9 @@
android:id="@+id/user_info_toobar"
style="@style/BaseToolBar"
android:background="@android:color/transparent"
- app:layout_collapseMode="pin"
- app:navigationIcon="@drawable/ic_arrow_back_black" />
+ app:titleTextColor="?attr/icon_tint_color"
+ app:subtitleTextColor="?attr/icon_tint_color"
+ app:layout_collapseMode="pin" />
diff --git a/app/src/main/res/layout/appbar_wrapper_toolbar.xml b/app/src/main/res/layout/appbar_wrapper_toolbar.xml
index e49ad609..9190938a 100644
--- a/app/src/main/res/layout/appbar_wrapper_toolbar.xml
+++ b/app/src/main/res/layout/appbar_wrapper_toolbar.xml
@@ -1,7 +1,8 @@
diff --git a/app/src/main/res/layout/common_list_item.xml b/app/src/main/res/layout/common_list_item.xml
index eb929626..e15dee19 100644
--- a/app/src/main/res/layout/common_list_item.xml
+++ b/app/src/main/res/layout/common_list_item.xml
@@ -1,6 +1,7 @@
+
+
-
-
diff --git a/app/src/main/res/layout/common_recyclerview_layout.xml b/app/src/main/res/layout/common_recyclerview_layout.xml
index c29b98be..0010da2f 100644
--- a/app/src/main/res/layout/common_recyclerview_layout.xml
+++ b/app/src/main/res/layout/common_recyclerview_layout.xml
@@ -3,5 +3,6 @@
android:id="@+id/base_recyclerview"
style="@style/BaseRecyclerView"
android:clipToPadding="false"
- android:paddingTop="16dp" />
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"/>
diff --git a/app/src/main/res/layout/common_title.xml b/app/src/main/res/layout/common_title.xml
new file mode 100644
index 00000000..79294985
--- /dev/null
+++ b/app/src/main/res/layout/common_title.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/frag_search_layout.xml b/app/src/main/res/layout/frag_search_layout.xml
index d7458118..034373c6 100644
--- a/app/src/main/res/layout/frag_search_layout.xml
+++ b/app/src/main/res/layout/frag_search_layout.xml
@@ -49,6 +49,7 @@
style="@style/SearchInput"
android:layout_width="0dp"
android:layout_height="match_parent"
+ android:contentDescription="@string/acc_search_edittext"
android:layout_weight="1"
android:gravity="center_vertical"
android:hint="Powered by sov2ex"
@@ -63,7 +64,7 @@
android:layout_height="@dimen/searchbar_size"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
- android:contentDescription="clear text"
+ android:contentDescription="@string/acc_search_clear"
android:focusable="true"
android:padding="17.5dp"
android:src="@drawable/ic_close_black"
diff --git a/app/src/main/res/layout/fragment_mine.xml b/app/src/main/res/layout/fragment_mine.xml
new file mode 100644
index 00000000..2f117439
--- /dev/null
+++ b/app/src/main/res/layout/fragment_mine.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/message_count_layout.xml b/app/src/main/res/layout/message_count_layout.xml
new file mode 100644
index 00000000..19c2ef1d
--- /dev/null
+++ b/app/src/main/res/layout/message_count_layout.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/mine_section_layout.xml b/app/src/main/res/layout/mine_section_layout.xml
new file mode 100644
index 00000000..224c3715
--- /dev/null
+++ b/app/src/main/res/layout/mine_section_layout.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/mine_user_info_simple_layout.xml b/app/src/main/res/layout/mine_user_info_simple_layout.xml
new file mode 100644
index 00000000..e1c45fa7
--- /dev/null
+++ b/app/src/main/res/layout/mine_user_info_simple_layout.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/navigation_header.xml b/app/src/main/res/layout/navigation_header.xml
deleted file mode 100644
index f4ff4c45..00000000
--- a/app/src/main/res/layout/navigation_header.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/node_select.xml b/app/src/main/res/layout/node_select.xml
index ff74e7ba..99764c6a 100644
--- a/app/src/main/res/layout/node_select.xml
+++ b/app/src/main/res/layout/node_select.xml
@@ -10,6 +10,8 @@
style="@style/BaseToolBar"
android:layout_height="@dimen/toolbar_size"
android:background="@android:color/transparent"
+ app:titleTextColor="?attr/icon_tint_color"
+ app:subtitleTextColor="?attr/icon_tint_color"
app:elevation="2dp"
app:navigationIcon="@null"
app:title="选择节点" />
diff --git a/app/src/main/res/layout/notification_item.xml b/app/src/main/res/layout/notification_item.xml
index 1630a5b7..cdb5dbcb 100644
--- a/app/src/main/res/layout/notification_item.xml
+++ b/app/src/main/res/layout/notification_item.xml
@@ -7,11 +7,13 @@
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
- android:padding="12dp">
+ android:padding="16dp">
@@ -23,6 +25,8 @@
android:lines="2"
android:maxLines="2"
android:paddingLeft="8dp"
+ app:layout_constraintTop_toTopOf="@+id/avatar_img"
+ app:layout_constraintBottom_toBottomOf="@+id/avatar_img"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/avatar_img"
tools:text="aliuwr 感谢了你在主题 › 推荐个 V2EX 的非官方安卓客户端呗!!! 里的回复" />
diff --git a/app/src/main/res/layout/section_item_view_layout.xml b/app/src/main/res/layout/section_item_view_layout.xml
new file mode 100644
index 00000000..f688b5de
--- /dev/null
+++ b/app/src/main/res/layout/section_item_view_layout.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/topic_reply_item.xml b/app/src/main/res/layout/topic_reply_item.xml
index 32bc378c..ea94bde5 100644
--- a/app/src/main/res/layout/topic_reply_item.xml
+++ b/app/src/main/res/layout/topic_reply_item.xml
@@ -74,6 +74,7 @@
android:layout_marginRight="12dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="3dp"
+ android:contentDescription="@string/acc_thanks"
android:src="@drawable/love_normal_icon"
android:tint="?attr/icon_tint_color"
app:layout_constraintRight_toRightOf="parent"
@@ -95,6 +96,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
+ android:contentDescription="@string/acc_more_in_reply_item"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="3dp"
android:src="@drawable/ic_more"
diff --git a/app/src/main/res/menu/append_topic_menu.xml b/app/src/main/res/menu/append_topic_menu.xml
index b181c4c8..2948c6eb 100644
--- a/app/src/main/res/menu/append_topic_menu.xml
+++ b/app/src/main/res/menu/append_topic_menu.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_menu_main.xml b/app/src/main/res/menu/bottom_menu_main.xml
new file mode 100644
index 00000000..4fdd822f
--- /dev/null
+++ b/app/src/main/res/menu/bottom_menu_main.xml
@@ -0,0 +1,31 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/login_toolbar_menu.xml b/app/src/main/res/menu/login_toolbar_menu.xml
index 6204f104..abdb0b1e 100644
--- a/app/src/main/res/menu/login_toolbar_menu.xml
+++ b/app/src/main/res/menu/login_toolbar_menu.xml
@@ -11,7 +11,7 @@
app:showAsAction="never" />
\ No newline at end of file
diff --git a/app/src/main/res/menu/navigation_menu.xml b/app/src/main/res/menu/navigation_menu.xml
deleted file mode 100644
index 70ba5384..00000000
--- a/app/src/main/res/menu/navigation_menu.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/node_info_toolbar_menu.xml b/app/src/main/res/menu/node_info_toolbar_menu.xml
index da65c167..43f1ac10 100644
--- a/app/src/main/res/menu/node_info_toolbar_menu.xml
+++ b/app/src/main/res/menu/node_info_toolbar_menu.xml
@@ -4,7 +4,7 @@
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/search_note_menu.xml b/app/src/main/res/menu/search_note_menu.xml
index e295c077..1719f58c 100644
--- a/app/src/main/res/menu/search_note_menu.xml
+++ b/app/src/main/res/menu/search_note_menu.xml
@@ -4,6 +4,7 @@
diff --git a/app/src/main/res/menu/topic_info_toolbar_menu.xml b/app/src/main/res/menu/topic_info_toolbar_menu.xml
index db60c61a..8e69961c 100644
--- a/app/src/main/res/menu/topic_info_toolbar_menu.xml
+++ b/app/src/main/res/menu/topic_info_toolbar_menu.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
-
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 0bc9c421..00000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index e79454c6..00000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 6be08481..00000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index 5aea901d..00000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_explore.png b/app/src/main/res/mipmap-xhdpi/ic_explore.png
new file mode 100644
index 00000000..0ed5cd98
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_explore.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_feed.png b/app/src/main/res/mipmap-xhdpi/ic_feed.png
new file mode 100644
index 00000000..1752f3bd
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_feed.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_message.png b/app/src/main/res/mipmap-xhdpi/ic_message.png
new file mode 100644
index 00000000..623d5fa5
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_message.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_mine.png b/app/src/main/res/mipmap-xhdpi/ic_mine.png
new file mode 100644
index 00000000..678ad825
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_mine.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_explore.png b/app/src/main/res/mipmap-xxhdpi/ic_explore.png
new file mode 100644
index 00000000..bf6a4cf5
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_explore.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_feed.png b/app/src/main/res/mipmap-xxhdpi/ic_feed.png
new file mode 100644
index 00000000..8cdf2f88
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_feed.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_message.png b/app/src/main/res/mipmap-xxhdpi/ic_message.png
new file mode 100644
index 00000000..1f8405a9
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_message.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_mine.png b/app/src/main/res/mipmap-xxhdpi/ic_mine.png
new file mode 100644
index 00000000..896a9771
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_mine.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_explore.png b/app/src/main/res/mipmap-xxxhdpi/ic_explore.png
new file mode 100644
index 00000000..28a88254
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_explore.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_feed.png b/app/src/main/res/mipmap-xxxhdpi/ic_feed.png
new file mode 100644
index 00000000..e1886ba7
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_feed.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_message.png b/app/src/main/res/mipmap-xxxhdpi/ic_message.png
new file mode 100644
index 00000000..8170d61f
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_message.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_mine.png b/app/src/main/res/mipmap-xxxhdpi/ic_mine.png
new file mode 100644
index 00000000..2b344787
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_mine.png differ
diff --git a/app/src/main/res/values-v29/themes.xml b/app/src/main/res/values-v29/themes.xml
index 7ebe8165..53bce06d 100644
--- a/app/src/main/res/values-v29/themes.xml
+++ b/app/src/main/res/values-v29/themes.xml
@@ -1,9 +1,9 @@
-
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 97af0e6d..3f0630d5 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -33,4 +33,13 @@
- 1
+
+ - adsbygoogle
+ - adsbygoogle-noablate
+ - sidebar_compliance
+
+
+ - wwads-cn
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index bf6b0421..35568114 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -15,6 +15,11 @@
+
+
+
+
+
@@ -31,4 +36,6 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 3ff46dcb..22be3552 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -11,6 +11,7 @@
#555555
#a3a1a1
@android:color/white
+ @android:color/black
#d4d4d4
#3A3636
#66000000
@@ -20,4 +21,5 @@
#A2A2A2
#1A000000
#1AFFFFFF
+ #FF5252
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 35cac2dd..b6c62aef 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -9,8 +9,8 @@
9dp
30dp
36dp
- 75dp
- 80dp
+ 65dp
+ 75dp
0.5dp
16dp
@@ -20,4 +20,6 @@
16dp
73dp
35dp
+ 24dp
+ 20dp
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
index 36caeaee..c387fef6 100644
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -1,6 +1,7 @@
pref_key_clear_cache
+ pref_key_help_and_feedback
pref_key_check_update
pref_key_rate
pref_key_os
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6f1d7237..dd98d5cc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,6 +1,7 @@
V2er
今日热议
+ 节点导航
me.ghui.v2er.widget.behavior.NewsNewFabBehavior
https://ghui.me
https://www.v2ex.com
@@ -37,4 +38,38 @@
1. 支持V2er项目的长期开发、激励开发者做的更好.
V2er目前依然存在大量需要完善的功能与待优化的体验, 你的支持能让V2er保持更新, 不断进步.
2. 作为答谢你将解锁所有高级版特性包括:自动签到、自动切换日夜主题、逆序浏览、添加附言、下沉/置顶帖子,以及后续不断到来的新功能.
+
+ 最新
+ 发现
+ 通知
+ 我的
+ 个人主页
+
+ 主题
+ 收藏
+ 关注
+ 设置
+
+ 请先登录
+ 帮助与反馈
+
+
+ 返回键
+ 发送感谢
+ 回复列表中更多
+ 回复
+ 发送回复
+ 搜索
+ 首页底部菜单
+ 搜索输入框
+ 清除搜索输入框
+ 头像
+ 复制文本成功
+ 标题
+
+ 签到
+ 已签到%1$s天
+ 签到成功%1$s天
+ 签到遇到问题!
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e43ecda0..9014aef2 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -18,6 +18,15 @@
- ?attr/hintTextColor
+
+
+
+
-
-
@@ -111,6 +125,7 @@
- @color/colorPrimary
- 1dp
+ - @string/acc_avatar