mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-06-06 05:49:03 +08:00
style: format code
This commit is contained in:
@@ -54,12 +54,12 @@ android {
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
signingConfigs{
|
||||
release{
|
||||
def keystoreFile=file("keystore.jks")
|
||||
def keyAliasEnv=System.getenv("SIGNING_KEY_ALIAS")
|
||||
def keystorePasswordEnv=System.getenv("SIGNING_STORE_PASSWORD")
|
||||
def keyPasswordEnv=System.getenv("SIGNING_STORE_PASSWORD")
|
||||
signingConfigs {
|
||||
release {
|
||||
def keystoreFile = file("keystore.jks")
|
||||
def keyAliasEnv = System.getenv("SIGNING_KEY_ALIAS")
|
||||
def keystorePasswordEnv = System.getenv("SIGNING_STORE_PASSWORD")
|
||||
def keyPasswordEnv = System.getenv("SIGNING_STORE_PASSWORD")
|
||||
|
||||
storeFile keystoreFile
|
||||
storePassword keystorePasswordEnv
|
||||
@@ -70,9 +70,9 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
if(System.getenv("CI")=="true"){
|
||||
if (System.getenv("CI") == "true") {
|
||||
signingConfig signingConfigs.release
|
||||
}else {
|
||||
} else {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:name=".MyApplication"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
<provider
|
||||
android:authorities="com.lifegpc.ehf.ClipboardImageProvider"
|
||||
android:name=".provider.ClipboardImageProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
android:authorities="com.lifegpc.ehf.ClipboardImageProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_provider_config"/>
|
||||
android:resource="@xml/file_provider_config" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.lifegpc.ehf
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.lifegpc.ehf.annotation.ChannelMethod
|
||||
import com.lifegpc.ehf.data.mmkv.SAFSettings
|
||||
@@ -13,18 +11,24 @@ import com.lifegpc.ehf.util.MethodChannelUtils
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.Exception
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
private val safAuthorizationCode = 0x10086
|
||||
private var safAuthorizationResult: MethodChannel.Result? = null
|
||||
private var afterAuthSuccess:(()->Unit)?=null
|
||||
private var afterAuthSuccess: (() -> Unit)? = null
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
MethodChannelUtils.registerMethodChannel("lifegpc.eh_downloader_flutter/saf", flutterEngine, this)
|
||||
MethodChannelUtils.registerMethodChannel("lifegpc.eh_downloader_flutter/clipboard",flutterEngine,ClipboardUtils)
|
||||
MethodChannelUtils.registerMethodChannel(
|
||||
"lifegpc.eh_downloader_flutter/saf",
|
||||
flutterEngine,
|
||||
this
|
||||
)
|
||||
MethodChannelUtils.registerMethodChannel(
|
||||
"lifegpc.eh_downloader_flutter/clipboard",
|
||||
flutterEngine,
|
||||
ClipboardUtils
|
||||
)
|
||||
}
|
||||
|
||||
@ChannelMethod(responseManually = true)
|
||||
@@ -36,43 +40,43 @@ class MainActivity : FlutterActivity() {
|
||||
content: ByteArray
|
||||
) {
|
||||
this.safAuthorizationResult = channelResult
|
||||
if (!checkSafPermission()) {
|
||||
authSAF(channelResult) {
|
||||
doWriteFile(filename, dir, mimeType, content)
|
||||
channelResult.success(null)
|
||||
}
|
||||
} else {
|
||||
doWriteFile(filename, dir, mimeType,content)
|
||||
if (!checkSafPermission()) {
|
||||
authSAF(channelResult) {
|
||||
doWriteFile(filename, dir, mimeType, content)
|
||||
channelResult.success(null)
|
||||
}
|
||||
} else {
|
||||
doWriteFile(filename, dir, mimeType, content)
|
||||
channelResult.success(null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doWriteFile(filename: String, dir: String, mimeType: String, content: ByteArray) {
|
||||
var documentDir = DocumentFile.fromTreeUri(this, Uri.parse(SAFSettings.authorizedUri))!!
|
||||
val pathPart=dir.split('/','\\')
|
||||
val pathPart = dir.split('/', '\\')
|
||||
pathPart.forEach {
|
||||
if (it.isNotEmpty()){
|
||||
if (it.isNotEmpty()) {
|
||||
documentDir = documentDir.createDirectory(it)!!
|
||||
}
|
||||
}
|
||||
|
||||
val filenameWithoutExtension=if (filename.indexOf('.')!=-1){
|
||||
filename.substring(0,filename.lastIndexOf('.'))
|
||||
}else{
|
||||
val filenameWithoutExtension = if (filename.indexOf('.') != -1) {
|
||||
filename.substring(0, filename.lastIndexOf('.'))
|
||||
} else {
|
||||
filename
|
||||
}
|
||||
val file=documentDir.createFile(mimeType,filenameWithoutExtension)!!
|
||||
val uri=file.uri
|
||||
val file = documentDir.createFile(mimeType, filenameWithoutExtension)!!
|
||||
val uri = file.uri
|
||||
contentResolver.openOutputStream(uri)!!.use {
|
||||
it.write(content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun authSAF(result: MethodChannel.Result,onSuccess:(()->Unit)?=null) {
|
||||
private fun authSAF(result: MethodChannel.Result, onSuccess: (() -> Unit)? = null) {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
startActivityForResult(intent, safAuthorizationCode)
|
||||
safAuthorizationResult = result
|
||||
this.afterAuthSuccess=onSuccess
|
||||
this.afterAuthSuccess = onSuccess
|
||||
}
|
||||
|
||||
private fun onSafAuthSuccess(data: Intent) {
|
||||
@@ -115,7 +119,7 @@ class MainActivity : FlutterActivity() {
|
||||
safAuthorizationResult?.error("Permission denied", null, null)
|
||||
safAuthorizationResult = null
|
||||
}
|
||||
afterAuthSuccess=null
|
||||
afterAuthSuccess = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,19 @@ package com.lifegpc.ehf
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
|
||||
class MyApplication:Application() {
|
||||
companion object{
|
||||
class MyApplication : Application() {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private var mApplicationContext:Context?=null
|
||||
private var mApplicationContext: Context? = null
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("_applicationContext")
|
||||
val applicationContext:Context
|
||||
val applicationContext: Context
|
||||
get() = mApplicationContext!!
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
mApplicationContext=applicationContext
|
||||
mApplicationContext = applicationContext
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,6 @@ package com.lifegpc.ehf.annotation
|
||||
* 否则,则会将实现方法的返回值返回给 [io.flutter.plugin.common.MethodChannel.Result]
|
||||
*/
|
||||
annotation class ChannelMethod(
|
||||
val methodName:String="",
|
||||
val responseManually:Boolean=false
|
||||
val methodName: String = "",
|
||||
val responseManually: Boolean = false
|
||||
)
|
||||
|
||||
@@ -3,6 +3,6 @@ package com.lifegpc.ehf.data.mmkv
|
||||
import com.dylanc.mmkv.MMKVOwner
|
||||
import com.dylanc.mmkv.mmkvString
|
||||
|
||||
object SAFSettings:MMKVOwner(mmapID = "SAFSettings") {
|
||||
object SAFSettings : MMKVOwner(mmapID = "SAFSettings") {
|
||||
var authorizedUri by mmkvString("")
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.lifegpc.ehf.provider
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.content.FileProvider
|
||||
|
||||
class ClipboardImageProvider:FileProvider()
|
||||
class ClipboardImageProvider : FileProvider()
|
||||
@@ -10,25 +10,27 @@ import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
object ClipboardUtils {
|
||||
private const val AUTHORITY="com.lifegpc.ehf.ClipboardImageProvider"
|
||||
@ChannelMethod
|
||||
fun copyImageToClipboard(mimeType:String,byteArray: ByteArray){
|
||||
val file= saveToImageCache(mimeType, byteArray)
|
||||
val uri=FileProvider.getUriForFile(MyApplication.applicationContext, AUTHORITY,file)
|
||||
private const val AUTHORITY = "com.lifegpc.ehf.ClipboardImageProvider"
|
||||
|
||||
val cbm=MyApplication.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData=ClipData("image", arrayOf(mimeType),ClipData.Item(uri))
|
||||
@ChannelMethod
|
||||
fun copyImageToClipboard(mimeType: String, byteArray: ByteArray) {
|
||||
val file = saveToImageCache(mimeType, byteArray)
|
||||
val uri = FileProvider.getUriForFile(MyApplication.applicationContext, AUTHORITY, file)
|
||||
|
||||
val cbm =
|
||||
MyApplication.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData = ClipData("image", arrayOf(mimeType), ClipData.Item(uri))
|
||||
cbm.setPrimaryClip(clipData)
|
||||
}
|
||||
|
||||
private fun saveToImageCache(mimeType:String,byteArray: ByteArray):File{
|
||||
val dir=File(MyApplication.applicationContext.filesDir,"images")
|
||||
if (!dir.exists()){
|
||||
private fun saveToImageCache(mimeType: String, byteArray: ByteArray): File {
|
||||
val dir = File(MyApplication.applicationContext.filesDir, "images")
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs()
|
||||
}
|
||||
val name=UUID.randomUUID().toString()
|
||||
val name = UUID.randomUUID().toString()
|
||||
|
||||
val file=File(dir,"$name.${mimeTypeToExtName(mimeType)}")
|
||||
val file = File(dir, "$name.${mimeTypeToExtName(mimeType)}")
|
||||
|
||||
file.outputStream().use {
|
||||
it.write(byteArray)
|
||||
@@ -37,10 +39,10 @@ object ClipboardUtils {
|
||||
return file
|
||||
}
|
||||
|
||||
private fun mimeTypeToExtName(mimeType: String)=when(mimeType){
|
||||
"image/png"->"png"
|
||||
"image/jpeg"->"png"
|
||||
"image/gif"->"gif"
|
||||
else->throw IllegalArgumentException("$mimeType is not supported")
|
||||
private fun mimeTypeToExtName(mimeType: String) = when (mimeType) {
|
||||
"image/png" -> "png"
|
||||
"image/jpeg" -> "png"
|
||||
"image/gif" -> "gif"
|
||||
else -> throw IllegalArgumentException("$mimeType is not supported")
|
||||
}
|
||||
}
|
||||
@@ -4,69 +4,84 @@ import android.util.Log
|
||||
import com.lifegpc.ehf.annotation.ChannelMethod
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.lang.Exception
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
object MethodChannelUtils {
|
||||
@JvmStatic
|
||||
fun registerMethodChannel(channelName: String, flutterEngine: FlutterEngine, obj: Any,ignoreNotImplemented:Boolean=true) {
|
||||
fun registerMethodChannel(
|
||||
channelName: String,
|
||||
flutterEngine: FlutterEngine,
|
||||
obj: Any,
|
||||
ignoreNotImplemented: Boolean = true
|
||||
) {
|
||||
val methodsMapping = mutableMapOf<String, Method>()
|
||||
val methods = obj::class.java.declaredMethods
|
||||
methods.forEach {
|
||||
val annotation = it.getAnnotation(ChannelMethod::class.java) ?: return@forEach
|
||||
val methodName = annotation.methodName.takeIf(String::isNotBlank) ?: it.name
|
||||
methodsMapping[methodName]=it
|
||||
methodsMapping[methodName] = it
|
||||
}
|
||||
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channelName).setMethodCallHandler { call, result ->
|
||||
val invokeMethodName=call.method
|
||||
val targetMethod=methodsMapping[invokeMethodName]
|
||||
if (targetMethod==null){
|
||||
Log.w("MethodChannel","$channelName/$invokeMethodName not implemented.")
|
||||
if (!ignoreNotImplemented){
|
||||
MethodChannel(
|
||||
flutterEngine.dartExecutor.binaryMessenger,
|
||||
channelName
|
||||
).setMethodCallHandler { call, result ->
|
||||
val invokeMethodName = call.method
|
||||
val targetMethod = methodsMapping[invokeMethodName]
|
||||
if (targetMethod == null) {
|
||||
Log.w("MethodChannel", "$channelName/$invokeMethodName not implemented.")
|
||||
if (!ignoreNotImplemented) {
|
||||
result.notImplemented()
|
||||
}else{
|
||||
result.error("Not implemented",null,null)
|
||||
} else {
|
||||
result.error("Not implemented", null, null)
|
||||
}
|
||||
return@setMethodCallHandler
|
||||
}else{
|
||||
val argv=call.arguments?.takeIf { it is List<*> } as List<*>? ?:return@setMethodCallHandler result.error("Argument must be List",null,null)
|
||||
val argTypes=targetMethod.parameterTypes
|
||||
val targetArgc=argTypes.size
|
||||
} else {
|
||||
val argv = call.arguments?.takeIf { it is List<*> } as List<*>?
|
||||
?: return@setMethodCallHandler result.error("Argument must be List", null, null)
|
||||
val argTypes = targetMethod.parameterTypes
|
||||
val targetArgc = argTypes.size
|
||||
|
||||
val invokeTargetObject=if (Modifier.isStatic(targetMethod.modifiers)) null else obj
|
||||
targetMethod.isAccessible=true
|
||||
val invokeTargetObject =
|
||||
if (Modifier.isStatic(targetMethod.modifiers)) null else obj
|
||||
targetMethod.isAccessible = true
|
||||
|
||||
if (targetArgc==argv.size){
|
||||
if (targetArgc == argv.size) {
|
||||
try {
|
||||
val res=targetMethod.invoke(invokeTargetObject,*(argv.toTypedArray()))
|
||||
if (res is Unit){
|
||||
val res = targetMethod.invoke(invokeTargetObject, *(argv.toTypedArray()))
|
||||
if (res is Unit) {
|
||||
result.success(null)
|
||||
}else{
|
||||
} else {
|
||||
result.success(res)
|
||||
}
|
||||
}catch (e:Exception){
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
result.error("Error",e.toString(),e.stackTraceToString())
|
||||
result.error("Error", e.toString(), e.stackTraceToString())
|
||||
}
|
||||
}else if (targetArgc==argv.size+1&&argTypes[0]==MethodChannel.Result::class.java){
|
||||
} else if (targetArgc == argv.size + 1 && argTypes[0] == MethodChannel.Result::class.java) {
|
||||
try {
|
||||
val responseManually=targetMethod.getAnnotation(ChannelMethod::class.java)!!.responseManually
|
||||
val res=targetMethod.invoke(invokeTargetObject,result,*(argv.toTypedArray()))
|
||||
if (!responseManually){
|
||||
if (res is Unit){
|
||||
val responseManually =
|
||||
targetMethod.getAnnotation(ChannelMethod::class.java)!!.responseManually
|
||||
val res =
|
||||
targetMethod.invoke(invokeTargetObject, result, *(argv.toTypedArray()))
|
||||
if (!responseManually) {
|
||||
if (res is Unit) {
|
||||
result.success(null)
|
||||
}else{
|
||||
} else {
|
||||
result.success(res)
|
||||
}
|
||||
}
|
||||
}catch (e:Exception){
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
result.error("Error",e.toString(),e.stackTraceToString())
|
||||
result.error("Error", e.toString(), e.stackTraceToString())
|
||||
}
|
||||
}else{
|
||||
result.error("Error","Parameter count error, required: $targetArgc, found: $argv",null)
|
||||
} else {
|
||||
result.error(
|
||||
"Error",
|
||||
"Parameter count error, required: $targetArgc, found: $argv",
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
<paths>
|
||||
<files-path
|
||||
name="images"
|
||||
path="images"/>
|
||||
path="images" />
|
||||
</paths>
|
||||
@@ -3,5 +3,5 @@
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
|
||||
@@ -26,6 +26,7 @@ class ApiResult<T> {
|
||||
return throw error!;
|
||||
}
|
||||
}
|
||||
|
||||
(int, String) unwrapErr() {
|
||||
if (ok) {
|
||||
return throw 'unwrap_err called on ok ApiResult';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eh_downloader_flutter/api/file.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
import 'api_result.dart';
|
||||
import 'gallery.dart';
|
||||
import 'status.dart';
|
||||
@@ -47,6 +49,7 @@ enum SortByGid {
|
||||
none,
|
||||
asc,
|
||||
desc;
|
||||
|
||||
bool? toBool() {
|
||||
switch (this) {
|
||||
case SortByGid.asc:
|
||||
|
||||
@@ -8,9 +8,13 @@ class MeilisearchInfo {
|
||||
required this.host,
|
||||
required this.key,
|
||||
});
|
||||
|
||||
final String host;
|
||||
final String key;
|
||||
factory MeilisearchInfo.fromJson(Map<String, dynamic> json) => _$MeilisearchInfoFromJson(json);
|
||||
|
||||
factory MeilisearchInfo.fromJson(Map<String, dynamic> json) =>
|
||||
_$MeilisearchInfoFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$MeilisearchInfoToJson(this);
|
||||
}
|
||||
|
||||
@@ -23,6 +27,7 @@ class ServerStatus {
|
||||
this.meilisearch,
|
||||
required this.noUser,
|
||||
});
|
||||
|
||||
@JsonKey(name: 'ffmpeg_api_enabled')
|
||||
final bool ffmpegApiEnabled;
|
||||
@JsonKey(name: 'ffmpeg_binary_enabled')
|
||||
@@ -32,6 +37,9 @@ class ServerStatus {
|
||||
final MeilisearchInfo? meilisearch;
|
||||
@JsonKey(name: 'no_user')
|
||||
final bool noUser;
|
||||
factory ServerStatus.fromJson(Map<String, dynamic> json) => _$ServerStatusFromJson(json);
|
||||
|
||||
factory ServerStatus.fromJson(Map<String, dynamic> json) =>
|
||||
_$ServerStatusFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$ServerStatusToJson(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../api/gallery.dart';
|
||||
|
||||
String _getTag(Tag tag) {
|
||||
@@ -16,13 +17,15 @@ class TagTooltip extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final name = _getTag(tag);
|
||||
final t = SelectableText(name);
|
||||
return tag.intro != null && tag.intro!.isNotEmpty ? Tooltip(
|
||||
message: tag.intro!,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4.0),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
child: t,
|
||||
) : t;
|
||||
return tag.intro != null && tag.intro!.isNotEmpty
|
||||
? Tooltip(
|
||||
message: tag.intro!,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4.0),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
child: t,
|
||||
)
|
||||
: t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,52 @@
|
||||
import 'base.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'base.dart';
|
||||
|
||||
class SharedPreferencesConfig implements Config {
|
||||
SharedPreferencesConfig(this._prefs);
|
||||
|
||||
final SharedPreferences _prefs;
|
||||
|
||||
@override
|
||||
Future<bool> clear() {
|
||||
return _prefs.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
bool containsKey(String key) {
|
||||
return _prefs.containsKey(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Object? get(String key) {
|
||||
return _prefs.get(key);
|
||||
}
|
||||
|
||||
@override
|
||||
String? getString(String key) {
|
||||
return _prefs.getString(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setString(String key, String value) {
|
||||
return _prefs.setString(key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
int? getInt(String key) {
|
||||
return _prefs.getInt(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setInt(String key, int value) {
|
||||
return _prefs.setInt(key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
bool? getBool(String key) {
|
||||
return _prefs.getBool(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setBool(String key, bool value) {
|
||||
return _prefs.setBool(key, value);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'globals.dart';
|
||||
import 'login.dart';
|
||||
|
||||
@@ -176,10 +177,11 @@ class _CreateRootUserPage extends State<CreateRootUserPage>
|
||||
ElevatedButton(
|
||||
onPressed: !_isCreated && _isValid
|
||||
? () {
|
||||
setState(() {
|
||||
setState(() {
|
||||
_isCreated = true;
|
||||
});
|
||||
_createRootUser(_username, _password).then((re) {
|
||||
_createRootUser(_username, _password)
|
||||
.then((re) {
|
||||
if (re) {
|
||||
clearAllStates(context);
|
||||
context.canPop()
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class Clipboard{
|
||||
final MethodChannel _clipboardChannel=const MethodChannel("lifegpc.eh_downloader_flutter/clipboard");
|
||||
class Clipboard {
|
||||
final MethodChannel _clipboardChannel =
|
||||
const MethodChannel("lifegpc.eh_downloader_flutter/clipboard");
|
||||
|
||||
Future<void> copyImageToClipboard(String mimeType,Uint8List bytes)async{
|
||||
return _clipboardChannel.invokeMethod("copyImageToClipboard",[mimeType,bytes]);
|
||||
Future<void> copyImageToClipboard(String mimeType, Uint8List bytes) async {
|
||||
return _clipboardChannel
|
||||
.invokeMethod("copyImageToClipboard", [mimeType, bytes]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:image/image.dart';
|
||||
|
||||
Future<Uint8List> jpgToPng(Uint8List data) async {
|
||||
return encodePng(decodeJpg(data)!);
|
||||
return encodePng(decodeJpg(data)!);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user