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 @@ + + + + + + + + + + +