diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 30351ab..e86d793 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,5 +1,6 @@
plugins {
alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
}
android {
@@ -29,6 +30,9 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
+ kotlinOptions {
+ jvmTarget = "11"
+ }
}
dependencies {
@@ -37,6 +41,7 @@ dependencies {
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
+ implementation(libs.core.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 767e215..ce02c9b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,9 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.zitzhen.coco_community">
+
+
@@ -15,21 +18,49 @@
android:theme="@style/Theme.CoCocommunity"
tools:targetApi="31">
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/zitzhen/coco_community/MainActivity.java b/app/src/main/java/com/zitzhen/coco_community/MainActivity.java
deleted file mode 100644
index eed2590..0000000
--- a/app/src/main/java/com/zitzhen/coco_community/MainActivity.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.zitzhen.coco_community;
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.webkit.WebResourceError;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.TextView;
-import androidx.annotation.RequiresApi;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.constraintlayout.widget.ConstraintLayout;
-import com.google.android.material.button.MaterialButton;
-
-public class MainActivity extends AppCompatActivity {
-
- private WebView webView;
- private View errorLayout;
- private MaterialButton retryButton;
- private TextView errorCodeTextView;
-
- @SuppressLint("SetJavaScriptEnabled")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // 创建帧布局作为根容器
- ConstraintLayout rootLayout = new ConstraintLayout(this);
- ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(
- ConstraintLayout.LayoutParams.MATCH_PARENT,
- ConstraintLayout.LayoutParams.MATCH_PARENT
- );
- rootLayout.setLayoutParams(layoutParams);
- setContentView(rootLayout);
-
- // 创建WebView
- webView = new WebView(this);
- webView.setId(View.generateViewId());
- ConstraintLayout.LayoutParams webViewLayoutParams = new ConstraintLayout.LayoutParams(
- ConstraintLayout.LayoutParams.MATCH_PARENT,
- ConstraintLayout.LayoutParams.MATCH_PARENT
- );
- webView.setLayoutParams(webViewLayoutParams);
- rootLayout.addView(webView);
-
- // 创建错误布局 - 使用正确的资源ID
- errorLayout = getLayoutInflater().inflate(getResources().getLayout(R.layout.error), rootLayout, false);
- errorLayout.setId(View.generateViewId());
- errorLayout.setVisibility(View.GONE);
- rootLayout.addView(errorLayout);
-
- // 获取错误页面组件 - 使用正确的资源ID
- retryButton = errorLayout.findViewById(getResources().getIdentifier("retryButton", "id", getPackageName()));
- errorCodeTextView = errorLayout.findViewById(getResources().getIdentifier("errorcode", "id", getPackageName()));
-
- // 设置重试按钮点击事件
- retryButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 隐藏错误页面,显示WebView
- errorLayout.setVisibility(View.GONE);
- webView.setVisibility(View.VISIBLE);
- // 重新加载网页
- webView.reload();
- }
- });
-
- // WebView基础配置
- webView.getSettings().setJavaScriptEnabled(true);
- webView.getSettings().setDomStorageEnabled(true);
- webView.getSettings().setDatabaseEnabled(true);
- webView.getSettings().setCacheMode(android.webkit.WebSettings.LOAD_DEFAULT);
-
- // 设置自定义WebViewClient处理错误
- webView.setWebViewClient(new WebViewClient() {
- // 处理API 23+的错误
- @RequiresApi(api = Build.VERSION_CODES.M)
- @Override
- public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
- super.onReceivedError(view, request, error);
- if (request != null && request.isForMainFrame()) {
- showErrorPage(error != null ? error.getErrorCode() : -1,
- error != null ? error.getDescription().toString() : "Unknown error");
- }
- }
-
- // 处理旧版本错误
- @Override
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- super.onReceivedError(view, errorCode, description, failingUrl);
- showErrorPage(errorCode, description != null ? description : "Unknown error");
- }
-
- // 处理HTTP错误 (状态码 >= 400)
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- @Override
- public void onReceivedHttpError(WebView view, WebResourceRequest request, android.webkit.WebResourceResponse errorResponse) {
- super.onReceivedHttpError(view, request, errorResponse);
- if (request != null && request.isForMainFrame()) {
- int statusCode = errorResponse != null ? errorResponse.getStatusCode() : -1;
- if (statusCode < 200 || statusCode >= 300) {
- showErrorPage(statusCode, "HTTP Error: " + statusCode);
- }
- }
- }
-
- // 所有链接在WebView内部打开
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- view.loadUrl(url);
- return true;
- }
- });
-
- // 加载网页
- webView.loadUrl("https://cc.zitzhen.cn/");
- }
-
- private void showErrorPage(final int errorCode, final String errorDescription) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- // 在错误页面上显示错误代码
- errorCodeTextView.setText("错误代码: " + errorCode + "\n" + errorDescription);
-
- // 记录错误日志
- Log.e("WebViewError", "Error " + errorCode + ": " + errorDescription);
-
- // 显示错误页面,隐藏WebView
- webView.setVisibility(View.GONE);
- errorLayout.setVisibility(View.VISIBLE);
- }
- });
- }
-
- // 处理返回键
- @Override
- public void onBackPressed() {
- if (webView.getVisibility() == View.VISIBLE && webView.canGoBack()) {
- webView.goBack();
- } else {
- super.onBackPressed();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/zitzhen/coco_community/MainActivity.kt b/app/src/main/java/com/zitzhen/coco_community/MainActivity.kt
new file mode 100644
index 0000000..3b9ccfa
--- /dev/null
+++ b/app/src/main/java/com/zitzhen/coco_community/MainActivity.kt
@@ -0,0 +1,18 @@
+package com.zitzhen.coco_community
+
+import android.content.Intent
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+
+class MainActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // 跳转到登录页面
+ val intent = Intent(this, LoginActivity::class.java)
+ startActivity(intent)
+
+ // 结束MainActivity,这样用户按下返回键时不会回到空白的MainActivity
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zitzhen/coco_community/login.kt b/app/src/main/java/com/zitzhen/coco_community/login.kt
new file mode 100644
index 0000000..a36ada2
--- /dev/null
+++ b/app/src/main/java/com/zitzhen/coco_community/login.kt
@@ -0,0 +1,176 @@
+package com.zitzhen.coco_community
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import org.json.JSONObject
+
+class LoginActivity : AppCompatActivity() {
+
+ companion object {
+ private const val TAG = "LoginActivity"
+ private const val GITHUB_OAUTH_URL = "https://github.com/login/oauth/authorize?client_id=Ov23lii4E31EzV9VMW7B&redirect_uri=https://cc.zitzhen.cn/auth/github?client=mobile"
+ private const val REDIRECT_URI = "https://cc.zitzhen.cn/auth/github"
+ }
+
+ private lateinit var mainLayout: LinearLayout
+ private lateinit var webView: WebView
+ private lateinit var githubLoginButton: Button
+ private lateinit var returnButton: Button
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_github_login)
+
+ // 初始化视图
+ initViews()
+
+ // 设置按钮点击事件
+ setupClickListeners()
+
+ // 初始化WebView
+ initWebView()
+ }
+
+ private fun initViews() {
+ mainLayout = findViewById(R.id.main_layout)
+ webView = findViewById(R.id.webview)
+ githubLoginButton = findViewById(R.id.github_login_button)
+ returnButton = findViewById(R.id.retun)
+ }
+
+ private fun setupClickListeners() {
+ // 设置GitHub登录按钮点击事件监听器
+ githubLoginButton.setOnClickListener {
+ startOAuthFlow()
+ }
+
+ // 设置返回按钮点击事件
+ returnButton.setOnClickListener {
+ finish() // 关闭当前Activity
+ }
+ }
+
+ private fun initWebView() {
+ // 配置WebView
+ webView.settings.javaScriptEnabled = true
+ webView.settings.domStorageEnabled = true
+
+ // 设置WebViewClient来监听页面加载和重定向
+ webView.webViewClient = object : WebViewClient() {
+ override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
+ url?.let {
+ Log.d(TAG, "WebView loading URL: $url")
+
+ // 检查是否是OAuth回调URL
+ if (url.startsWith(REDIRECT_URI)) {
+ // 处理OAuth回调
+ processOAuthCallback(url)
+ return true // 阻止WebView继续加载
+ }
+ }
+ return false // 允许WebView加载其他URL
+ }
+
+ override fun onPageFinished(view: WebView?, url: String?) {
+ super.onPageFinished(view, url)
+ Log.d(TAG, "Page finished loading: $url")
+ }
+ }
+ }
+
+ private fun startOAuthFlow() {
+ // 隐藏主界面,显示WebView
+ mainLayout.visibility = View.GONE
+ webView.visibility = View.VISIBLE
+
+ // 加载GitHub OAuth授权页面
+ webView.loadUrl(GITHUB_OAUTH_URL)
+ Log.d(TAG, "开始OAuth流程,加载URL: $GITHUB_OAUTH_URL")
+ }
+
+ private fun processOAuthCallback(url: String) {
+ try {
+ // 解析URL获取查询参数
+ val uri = android.net.Uri.parse(url)
+ val code = uri.getQueryParameter("code")
+ val error = uri.getQueryParameter("error")
+ val errorDescription = uri.getQueryParameter("error_description")
+
+ if (error != null) {
+ // 处理错误情况
+ Log.e(TAG, "OAuth error: $error - $errorDescription")
+ showError("登录失败: $error")
+ return
+ }
+
+ if (code != null) {
+ // 成功获取授权码,构建JSON响应
+ val responseJson = JSONObject().apply {
+ put("code", code)
+ put("status", "success")
+ put("message", "授权成功")
+ }
+
+ Log.d(TAG, "OAuth成功,授权码: $code")
+ Log.d(TAG, "返回的JSON: ${responseJson.toString()}")
+
+ // 显示成功消息并返回主界面
+ showSuccess("GitHub登录成功!")
+
+ // 这里可以添加后续逻辑,比如将授权码发送到服务器获取access token
+ // 或者跳转到主页面
+ } else {
+ Log.e(TAG, "未收到授权码")
+ showError("登录失败:未收到授权信息")
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "处理OAuth回调时出错", e)
+ showError("登录失败:处理错误")
+ }
+ }
+
+ private fun showSuccess(message: String) {
+ // 隐藏WebView,显示主界面
+ webView.visibility = View.GONE
+ mainLayout.visibility = View.VISIBLE
+
+ // 显示成功消息
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show()
+
+ // 这里可以添加后续逻辑,比如跳转到主页面
+ // val intent = Intent(this, MainActivity::class.java)
+ // startActivity(intent)
+ // finish()
+ }
+
+ private fun showError(message: String) {
+ // 隐藏WebView,显示主界面
+ webView.visibility = View.GONE
+ mainLayout.visibility = View.VISIBLE
+
+ // 显示错误消息
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show()
+ }
+
+ override fun onBackPressed() {
+ // 如果WebView可见,按返回键时返回WebView的上一个页面或隐藏WebView
+ if (webView.visibility == View.VISIBLE) {
+ if (webView.canGoBack()) {
+ webView.goBack()
+ } else {
+ // 如果WebView没有历史记录,隐藏WebView显示主界面
+ webView.visibility = View.GONE
+ mainLayout.visibility = View.VISIBLE
+ }
+ } else {
+ super.onBackPressed()
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/github_icon.xml b/app/src/main/res/drawable/github_icon.xml
new file mode 100644
index 0000000..34241ea
--- /dev/null
+++ b/app/src/main/res/drawable/github_icon.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_github_login.xml b/app/src/main/res/layout/activity_github_login.xml
new file mode 100644
index 0000000..a2ed623
--- /dev/null
+++ b/app/src/main/res/layout/activity_github_login.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 3756278..922f551 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.android) apply false
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e225fa7..aabde52 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -7,6 +7,8 @@ appcompat = "1.6.1"
material = "1.10.0"
activity = "1.8.0"
constraintlayout = "2.1.4"
+kotlin = "2.2.0"
+coreKtx = "1.10.1"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -16,7 +18,9 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }