Skip to content

Commit

Permalink
✨ Comic detail uni link
Browse files Browse the repository at this point in the history
  • Loading branch information
niuhuan committed Mar 27, 2023
1 parent 57b5c29 commit 8a183d0
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 41 deletions.
2 changes: 1 addition & 1 deletion android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="opensource.dasiy">
package="opensource.daisy">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
38 changes: 27 additions & 11 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="opensource.dasiy">
package="opensource.daisy">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
Expand All @@ -16,28 +16,44 @@
</queries>

<application
android:label="daisy"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:label="daisy">
<activity
android:name="opensource.dasiy.MainActivity"
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">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<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" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https"
android:host="m.idmzj.com"
android:pathPrefix="/info/" />

<data android:scheme="http"
android:host="m.idmzj.com"
android:pathPrefix="/info/" />

</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package opensource.dasiy
package opensource.daisy

import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.provider.Settings
import android.view.Display
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
Expand All @@ -17,7 +20,7 @@ import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.util.concurrent.Executors

class MainActivity: FlutterActivity() {
class MainActivity : FlutterActivity() {

private val pool = Executors.newCachedThreadPool { runnable ->
Thread(runnable).also { it.isDaemon = true }
Expand Down Expand Up @@ -56,7 +59,10 @@ class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Method Channel
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "cross").setMethodCallHandler { call, result ->
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
"cross"
).setMethodCallHandler { call, result ->
result.withCoroutine {
when (call.method) {
"root" -> context!!.filesDir.absolutePath
Expand All @@ -68,6 +74,9 @@ class MainActivity: FlutterActivity() {
setMode(call.argument("mode")!!)
}
"androidGetVersion" -> Build.VERSION.SDK_INT
"androidAppInfo" -> {
goAppInfo()
}
else -> {
notImplementedToken
}
Expand All @@ -86,16 +95,17 @@ class MainActivity: FlutterActivity() {
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)?.let { uri ->
contentResolver.openOutputStream(uri)?.use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
?.let { uri ->
contentResolver.openOutputStream(uri)?.use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
}
}
}
}

Expand Down Expand Up @@ -150,4 +160,10 @@ class MainActivity: FlutterActivity() {
}
}

fun goAppInfo() {
var packageURI = Uri.fromParts("package", packageName, null)
var intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI)
startActivity(intent)
}

}
2 changes: 1 addition & 1 deletion android/app/src/profile/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="opensource.dasiy">
package="opensource.daisy">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
56 changes: 56 additions & 0 deletions lib/commons.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:crypto/crypto.dart';
import 'package:daisy/screens/comic_detail_redirect_screen.dart';
import 'package:daisy/screens/comic_detail_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uni_links/uni_links.dart';

import 'cross.dart';

Expand Down Expand Up @@ -297,3 +301,55 @@ String generateMD5(String data) {
Digest digest = md5.convert(content);
return digest.toString();
}

processLink(String? uri, BuildContext context) {
print("processLink : $uri");
if (uri == null) return;
if (RegExp(r"^dmzj://comic/([0-9A-z]+)/$").allMatches(uri!).isNotEmpty) {
String comicId =
RegExp(r"^dmzj://comic/([0-9A-z]+)/$").allMatches(uri!).first.group(1)!;
if (RegExp(r"^\d+$").hasMatch(comicId)) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return ComicDetailScreen(comicId: int.parse(comicId));
},
));
} else {
print("ComicDetailRedirectScreen : $comicId");
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return ComicDetailRedirectScreen(comicIdString: comicId);
},
));
}
return;
} else if (RegExp(r"^https?://m\.idmzj\.com/info/(\w+)\.html$")
.allMatches(uri!)
.isNotEmpty) {
String comicId = RegExp(r"^https?://m\.idmzj\.com/info/(\w+)\.html$")
.allMatches(uri!)
.first
.group(1)!;
if (RegExp(r"^\d+$").hasMatch(comicId)) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return ComicDetailScreen(comicId: int.parse(comicId));
},
));
} else {
print("ComicDetailRedirectScreen : $comicId");
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return ComicDetailRedirectScreen(comicIdString: comicId);
},
));
}
return;
}
}

StreamSubscription<String?> linkSubscript(BuildContext context) {
return linkStream.listen((uri) async {
processLink(uri, context);
});
}
6 changes: 5 additions & 1 deletion lib/cross.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ class Cross {
Future<List<String>> loadAndroidModes() async {
return List.of(await _channel.invokeMethod("androidGetModes"))
.map((e) => "$e")
.toList();
.toList();
}

Future setAndroidMode(String androidDisplayMode) {
return _channel
.invokeMethod("androidSetMode", {"mode": androidDisplayMode});
}

Future androidAppInfo() {
return _channel.invokeMethod("androidAppInfo", "");
}
}

/// 打开web页面
Expand Down
39 changes: 25 additions & 14 deletions lib/screens/about_screen.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:daisy/configs/android_display_mode.dart';
import 'package:daisy/configs/auto_clean.dart';
import 'package:daisy/configs/login.dart';
Expand All @@ -22,7 +24,6 @@ class AboutScreen extends StatefulWidget {
}

class _AboutState extends State<AboutScreen> {

@override
void initState() {
loginEvent.subscribe(_l);
Expand All @@ -35,10 +36,8 @@ class _AboutState extends State<AboutScreen> {
super.dispose();
}

_l(_){
setState(() {

});
_l(_) {
setState(() {});
}

@override
Expand Down Expand Up @@ -72,6 +71,18 @@ class _AboutState extends State<AboutScreen> {
const Divider(),
novelReaderTypeSetting(context),
const Divider(),
...Platform.isAndroid
? [
ListTile(
title: const Text("转到APP详情"),
subtitle: const Text("设置URL关联等"),
onTap: () {
cross.androidAppInfo();
},
),
const Divider(),
]
: [],
],
),
);
Expand Down Expand Up @@ -186,21 +197,21 @@ class _AboutState extends State<AboutScreen> {
];
} else if (loginInfo.status == 1) {
return [
ListTile(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return const LoginScreen();
},
));
},
ListTile(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return const LoginScreen();
},
));
},
title: const Text("未登录"),
),
];
} else if (loginInfo.status == 2) {
return [
ListTile(
onTap: (){
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return const LoginScreen();
Expand Down
23 changes: 23 additions & 0 deletions lib/screens/app_screen.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import 'dart:async';
import 'dart:io';

import 'package:daisy/screens/comics_screen.dart';
import 'package:daisy/screens/novels_screen.dart';
import 'package:event/event.dart';
import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';

import '../commons.dart';
import '../configs/last_module.dart';

final Event<AppScreenEventArgs> appScreenEvent = Event<AppScreenEventArgs>();
Expand All @@ -27,15 +32,33 @@ class AppScreen extends StatefulWidget {

class _AppScreenState extends State<AppScreen> {
late final _controller = PageController(initialPage: widget.initModule);
late final StreamSubscription<String?> _ls;

@override
void initState() {
appScreenEvent.subscribe(_onEvent);
_ls = linkSubscript(context);
if (Platform.isAndroid || Platform.isIOS) {
firstLink();
}
super.initState();
}

firstLink() async {
try {
var initUrl = (await getInitialUri())?.toString();
processLink(initUrl, context);
// Use the uri and warn the user, if it is not correct,
// but keep in mind it could be `null`.
} on FormatException {
// Handle exception by warning the user their action did not succeed
// return?
}
}

@override
void dispose() {
_ls.cancel();
appScreenEvent.unsubscribe(_onEvent);
_controller.dispose();
super.dispose();
Expand Down
Loading

0 comments on commit 8a183d0

Please sign in to comment.