Page 7 Stage 2
This commit is contained in:
parent
da8d47f2b2
commit
4d35371e4a
10 changed files with 231 additions and 28 deletions
|
@ -10,10 +10,10 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId = "uk.kagurach.android101"
|
||||
minSdk = 31
|
||||
minSdk = 28
|
||||
targetSdk = 34
|
||||
versionCode = 160
|
||||
versionName = "1.6"
|
||||
versionCode = 172
|
||||
versionName = "1.7.2"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
@ -89,4 +89,6 @@ dependencies {
|
|||
|
||||
implementation(libs.moshi)
|
||||
implementation(libs.okhttp3)
|
||||
|
||||
implementation(libs.ffmpeg.min)
|
||||
}
|
|
@ -5,7 +5,10 @@
|
|||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<uses-permission android:name="READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
|
|
|
@ -60,6 +60,16 @@ public class MainActivity extends KaBaseActivity {
|
|||
new String[]{Manifest.permission.POST_NOTIFICATIONS},
|
||||
101);
|
||||
}
|
||||
if (ContextCompat
|
||||
.checkSelfPermission
|
||||
(MainActivity.this, Manifest.permission.READ_MEDIA_AUDIO)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
textViewAppendString(tv, "Acquiring READ_MEDIA_AUDIO");
|
||||
ActivityCompat.requestPermissions
|
||||
(MainActivity.this,
|
||||
new String[]{Manifest.permission.READ_MEDIA_AUDIO},
|
||||
102);
|
||||
}
|
||||
textViewAppendString(tv, "Check Finished");
|
||||
textViewAppendString(tv, "提示:常按有惊喜");
|
||||
}
|
||||
|
|
|
@ -2,7 +2,12 @@ package uk.kagurach.android101
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.AudioAttributes
|
||||
import android.media.MediaPlayer
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
|
@ -19,18 +24,27 @@ import androidx.core.view.WindowInsetsCompat
|
|||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.arthenica.ffmpegkit.FFmpegKit
|
||||
import com.arthenica.ffmpegkit.ReturnCode
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import uk.kagurach.android101.helper.ToastHelper
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
val Context.tgDatastore by preferencesDataStore(name = "tg_settings")
|
||||
val DefaultAPI = stringPreferencesKey("default_api")
|
||||
|
@ -59,6 +73,10 @@ class Page7 : KaBaseActivity() {
|
|||
findViewById<Button>(R.id.P7SetAPI).setOnClickListener(FrameButtonHandler())
|
||||
findViewById<ImageButton>(R.id.P7CloseResultButton).setOnClickListener(FrameButtonHandler())
|
||||
findViewById<ImageButton>(R.id.P7CloseAPIButton).setOnClickListener(FrameButtonHandler())
|
||||
|
||||
findViewById<Button>(R.id.P7ListenAudio).setOnClickListener(RecordButtonHandler())
|
||||
findViewById<Button>(R.id.P7RecordAudio).setOnClickListener(RecordButtonHandler())
|
||||
findViewById<Button>(R.id.P7SendAudio).setOnClickListener(ButtonHandler(this))
|
||||
}
|
||||
|
||||
inner class ButtonHandler(val activity: Activity) : OnClickListener {
|
||||
|
@ -77,12 +95,11 @@ class Page7 : KaBaseActivity() {
|
|||
when (v.id) {
|
||||
R.id.P7SaveAndSetAPI -> { // 测试并保存API
|
||||
tgHandler.testSelf { result ->
|
||||
if (result.contains("""{"ok":true}""")) {
|
||||
if (result.contains("\"ok\":true")) {
|
||||
runBlocking { // 成功
|
||||
storage.setDefaultAPI(botAPI)
|
||||
storage.setDefaultID(chatID)
|
||||
}
|
||||
ToastHelper.ShowToast("OK", baseContext)
|
||||
}
|
||||
runOnUiThread {
|
||||
resultTextField.text = result
|
||||
|
@ -101,6 +118,17 @@ class Page7 : KaBaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
R.id.P7SendAudio ->{ // 发送音频
|
||||
tgHandler.postAudio(
|
||||
audioUri,
|
||||
baseContext,
|
||||
){result ->
|
||||
runOnUiThread {
|
||||
resultTextField.text = result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> resultTextField.text = "?"
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +149,54 @@ class Page7 : KaBaseActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class RecordButtonHandler : OnClickListener {
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.P7RecordAudio -> {
|
||||
val recordIntent = Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
|
||||
try {
|
||||
startActivityForResult(recordIntent, 0)
|
||||
} catch (e : android.content.ActivityNotFoundException){
|
||||
Log.e("Recorder@Android101",e.printStackTrace().toString())
|
||||
}
|
||||
}
|
||||
|
||||
R.id.P7ListenAudio -> {
|
||||
if (audioUri!=Uri.EMPTY){
|
||||
val mMediaPlayer = MediaPlayer()
|
||||
mMediaPlayer.reset()
|
||||
mMediaPlayer.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.build()
|
||||
)
|
||||
mMediaPlayer.setDataSource(baseContext,audioUri)
|
||||
mMediaPlayer.prepare()
|
||||
mMediaPlayer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
0 -> { // 录音
|
||||
if (resultCode == RESULT_OK && data != null){
|
||||
audioUri = data.data
|
||||
ToastHelper.ShowToast("Saved at ${audioUri}",this)
|
||||
findViewById<Button>(R.id.P7ListenAudio).isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var audioUri = Uri.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
class telegramHandler(val BOT_KEY: String, val CHATID: String) {
|
||||
|
@ -130,20 +206,6 @@ class telegramHandler(val BOT_KEY: String, val CHATID: String) {
|
|||
fun testSelf(callBack: (String) -> Unit) {
|
||||
val api = "getMe"
|
||||
val finalUri = "${basicUri}/${api}"
|
||||
postData(finalUri, callBack)
|
||||
}
|
||||
|
||||
fun postText(text: String, callBack: (String) -> Unit) {
|
||||
if (text.isEmpty()) {
|
||||
callBack("Input Something!!")
|
||||
}
|
||||
|
||||
val api = "sendMessage"
|
||||
val finalUri = "${basicUri}/${api}?chat_id=${CHATID}&text=${text}"
|
||||
postData(finalUri, callBack)
|
||||
}
|
||||
|
||||
private fun postData(finalUri: String, callBack: (String) -> Unit) {
|
||||
val request = Request.Builder().url(finalUri).post("".toRequestBody()).build()
|
||||
val call = client.newCall(request)
|
||||
call.enqueue(object : Callback {
|
||||
|
@ -159,6 +221,78 @@ class telegramHandler(val BOT_KEY: String, val CHATID: String) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun postText(text: String, callBack: (String) -> Unit) {
|
||||
if (text.isEmpty()) {
|
||||
callBack("Input Something!!")
|
||||
}
|
||||
|
||||
val api = "sendMessage"
|
||||
val finalUri = "${basicUri}/${api}?chat_id=${CHATID}&text=${text}"
|
||||
val request = Request.Builder().url(finalUri).post("".toRequestBody()).build()
|
||||
val call = client.newCall(request)
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
Log.e("TgHelper", e.printStackTrace().toString())
|
||||
callBack("${e.printStackTrace()}")
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val responseCode = response.code
|
||||
val responseBody = response.body?.string()
|
||||
callBack("${responseCode},${responseBody}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun postAudio(audioUri: Uri,context: Context,callBack: (String) -> Unit) {
|
||||
if (audioUri == Uri.EMPTY){
|
||||
callBack("Sorry Please Record First")
|
||||
}
|
||||
// Copy to local
|
||||
val inputStream: InputStream = context.contentResolver.openInputStream(audioUri)?:return
|
||||
val bytes = inputStream.readBytes()
|
||||
val file = File(context.cacheDir.path + "/source.m4a")
|
||||
file.writeBytes(bytes)
|
||||
|
||||
|
||||
// Convert to ogg
|
||||
val session = FFmpegKit.execute("-i ${context.cacheDir.path}/source.m4a -acodec libvorbis -aq 4 -vn -ac 2 -map_metadata 0 -y -f ogg ${context.cacheDir.path}/decoded.ogg")
|
||||
if (!ReturnCode.isSuccess(session.getReturnCode())) {
|
||||
// FAILURE
|
||||
Log.d("FFmpeg@Android101", String.format("Command failed with state %s and rc %s.%s",
|
||||
session.getState(), session.getReturnCode(), session.getFailStackTrace()))
|
||||
return
|
||||
}
|
||||
|
||||
val api = "sendVoice"
|
||||
val finalUri = "${basicUri}/${api}?chat_id=${CHATID}&voice=attach%3A%2F%2Fvoice"
|
||||
val requestBody = MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("voice","decoded.ogg",
|
||||
RequestBody.create("audio/ogg".toMediaTypeOrNull(),File("${context.cacheDir.path}/decoded.ogg"))
|
||||
)
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url(finalUri)
|
||||
.header("Content-Type","multipart/form-data")
|
||||
.post(requestBody)
|
||||
.build()
|
||||
val call = client.newCall(request)
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
Log.e("TgHelper", e.printStackTrace().toString())
|
||||
callBack("${e.printStackTrace()}")
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val responseCode = response.code
|
||||
val responseBody = response.body?.string()
|
||||
callBack("${responseCode},${responseBody}")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -193,4 +327,4 @@ class TGStorage(val context: Context) {
|
|||
private val getDefaultIDFlow: Flow<String> = context.tgDatastore.data.map { preferences ->
|
||||
preferences[DefaultID] ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="500dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="6"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/tv_hello"
|
||||
|
@ -28,6 +28,7 @@
|
|||
android:textSize="15sp"
|
||||
android:visibility="visible" />
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
|
@ -38,6 +39,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:text="@string/settings"
|
||||
/>
|
||||
|
||||
|
@ -49,7 +51,7 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_weight="1.5"
|
||||
android:text="@string/next_page"
|
||||
android:enabled="false"
|
||||
android:backgroundTint="?colorSecondary" />
|
||||
|
|
|
@ -32,7 +32,9 @@
|
|||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp" />
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -41,7 +43,8 @@
|
|||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="350dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="8"
|
||||
android:layout_marginStart="10dp">
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
|
@ -59,7 +62,8 @@
|
|||
android:text="@string/ai_ready"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="130dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="3"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
|
|
|
@ -32,10 +32,47 @@
|
|||
android:id="@+id/P7SendMessageButton"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="match_parent"
|
||||
android:text="send message"
|
||||
android:text="@string/send_text"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="15dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/P7RecordAudio"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/record_audio"
|
||||
android:textAllCaps="false"
|
||||
android:backgroundTint="?colorTertiary"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/P7ListenAudio"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/play"
|
||||
android:textAllCaps="false"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:backgroundTint="?colorSecondary"
|
||||
android:enabled="false"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/P7SendAudio"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/send"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp"
|
||||
|
|
|
@ -59,4 +59,8 @@
|
|||
<string name="show_callback">显示回调</string>
|
||||
<string name="save_and_test">测试并保存</string>
|
||||
<string name="require_api">请输入API Key 和 Chat ID</string>
|
||||
<string name="send_text">发送文字</string>
|
||||
<string name="record_audio">录音</string>
|
||||
<string name="send">发送</string>
|
||||
<string name="play">播放</string>
|
||||
</resources>
|
|
@ -61,4 +61,8 @@
|
|||
<string name="show_callback">Show Callback</string>
|
||||
<string name="save_and_test">Save And Test</string>
|
||||
<string name="require_api">Please Fill API Key and Chat ID</string>
|
||||
<string name="send_text">Send text</string>
|
||||
<string name="record_audio">Record Audio</string>
|
||||
<string name="send">Send</string>
|
||||
<string name="play">Play</string>
|
||||
</resources>
|
|
@ -24,6 +24,7 @@ datastoreRxjava3 = "1.1.1"
|
|||
androidxWork = "2.9.0"
|
||||
okHttp3 = "4.9.3"
|
||||
moshiJson = "1.15.1"
|
||||
ffmpegKit = "6.0-2"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
@ -58,6 +59,8 @@ androidx-work = { group = "androidx.work", name="work-runtime", version.ref = "a
|
|||
okhttp3 = { group = "com.squareup.okhttp3", name="okhttp",version.ref="okHttp3"}
|
||||
moshi = {group="com.squareup.moshi",name="moshi-kotlin",version.ref="moshiJson"}
|
||||
|
||||
ffmpeg-min = {group="com.arthenica",name="ffmpeg-kit-full",version.ref="ffmpegKit"}
|
||||
|
||||
[plugins]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
|
|
Loading…
Reference in a new issue