Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search_server_in_network #167

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This file should be version controlled.

version:
revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
revision: 4b12645012342076800eb701bcdfe18f87da21cf
channel: stable

project_type: app
Expand All @@ -13,26 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: android
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: ios
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: linux
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: macos
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: web
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf
- platform: windows
create_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
base_revision: 2ad6cd72c040113b47ee9055e722606a490ef0da
create_revision: 4b12645012342076800eb701bcdfe18f87da21cf
base_revision: 4b12645012342076800eb701bcdfe18f87da21cf

# User provided section

Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.8.10'
ext.kotlin_version = '1.8.20'
repositories {
google()
mavenCentral()
Expand Down
4 changes: 3 additions & 1 deletion lib/src/constants/db_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import 'package:flutter/material.dart';
import 'enum.dart';

enum DBKeys {
serverUrl('http://127.0.0.1:4567'),
serverUrl('http://127.0.0.1'),
serverPort(4567),
serverPortToggle(true),
sourceLanguageFilter(["all", "lastUsed", "en", "localsourcelang"]),
extensionLanguageFilter(["installed", "update", "en", "all"]),
sourceLastUsed(null),
Expand Down
8 changes: 7 additions & 1 deletion lib/src/constants/endpoints.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import 'db_keys.dart';

abstract class Endpoints {
// base url
static String baseApi({String? baseUrl, bool appendApiToUrl = true}) =>
static String baseApi({
String? baseUrl,
int? port,
bool addPort = true,
bool appendApiToUrl = true,
}) =>
"${baseUrl ?? DBKeys.serverUrl.initial}"
"${port != null && addPort ? ":$port" : ''}"
"${appendApiToUrl ? '/api/v1' : ''}";

// receiveTimeout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import '../../../../utils/extensions/custom_extensions.dart';
import '../../../../utils/launch_url_in_web.dart';
import '../../../../utils/misc/toast/toast.dart';
import '../../data/backup/backup_repository.dart';
import '../../widgets/server_port_tile/server_port_tile.dart';
import '../../widgets/server_url_tile/server_url_tile.dart';
import 'widgets/backup_missing_dialog.dart';

Expand Down Expand Up @@ -67,7 +68,11 @@ class BackupScreen extends ConsumerWidget {
final toast = ref.read(toastProvider(context));
launchUrlInWeb(
context,
Endpoints.baseApi(baseUrl: ref.read(serverUrlProvider)) +
Endpoints.baseApi(
baseUrl: ref.read(serverUrlProvider),
port: ref.read(serverPortProvider),
addPort: ref.watch(serverPortToggleProvider).ifNull(),
) +
BackupUrl.export,
toast,
);
Expand Down
11 changes: 9 additions & 2 deletions lib/src/features/settings/presentation/server/server_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

import '../../../../constants/endpoints.dart';
import '../../../../constants/enum.dart';
import '../../../../global_providers/global_providers.dart';

import '../../../../utils/extensions/custom_extensions.dart';
import '../../../../utils/launch_url_in_web.dart';
import '../../../../utils/misc/toast/toast.dart';
import '../../widgets/server_port_tile/server_port_tile.dart';
import '../../widgets/server_url_tile/server_url_tile.dart';
import 'widget/auth_type_tile.dart';
import 'widget/credential_popup/credentials_popup.dart';
Expand All @@ -30,6 +32,7 @@ class ServerScreen extends ConsumerWidget {
body: ListView(
children: [
const ServerUrlTile(),
const ServerPortTile(),
const AuthTypeTile(),
if (authType != null && authType != AuthType.none)
ListTile(
Expand All @@ -47,11 +50,15 @@ class ServerScreen extends ConsumerWidget {
leading: const Icon(Icons.web_rounded),
title: Text(context.l10n!.webUI),
onTap: () {
final url = ref.read(serverUrlProvider);
final url = Endpoints.baseApi(
baseUrl: ref.read(serverUrlProvider),
port: ref.read(serverPortProvider),
addPort: ref.watch(serverPortToggleProvider).ifNull(),
);
if (url.isNotBlank) {
launchUrlInWeb(
context,
url!,
url,
ref.read(toastProvider(context)),
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) 2022 Contributors to the Suwayomi project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../../../../constants/db_keys.dart';

import '../../../../utils/extensions/custom_extensions.dart';
import '../../../../utils/mixin/shared_preferences_client_mixin.dart';
import '../../../../widgets/pop_button.dart';

part 'server_port_tile.g.dart';

@riverpod
class ServerPort extends _$ServerPort with SharedPreferenceClientMixin<int> {
@override
int? build() => initialize(
ref,
key: DBKeys.serverPort.name,
initial: DBKeys.serverPort.initial,
);
}

@riverpod
class ServerPortToggle extends _$ServerPortToggle
with SharedPreferenceClientMixin<bool> {
@override
bool? build() => initialize(
ref,
key: DBKeys.serverPortToggle.name,
initial: DBKeys.serverPortToggle.initial,
);
}

class ServerPortTile extends ConsumerWidget {
const ServerPortTile({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final serverPort = ref.watch(serverPortProvider);
final serverToggle = ref.watch(serverPortToggleProvider).ifNull();
return ListTile(
leading: const Icon(Icons.dns_rounded),
title: Text(context.l10n!.serverPort),
subtitle: serverToggle && serverPort != null
? Text(serverPort.toString())
: null,
trailing: Switch(
value: serverToggle,
onChanged: (value) {
ref.read(serverPortToggleProvider.notifier).update(value);
},
),
onTap: serverToggle
? () => showDialog(
context: context,
builder: (context) => ServerPortField(initialPort: serverPort),
)
: null,
);
}
}

class ServerPortField extends HookConsumerWidget {
const ServerPortField({
this.initialPort,
super.key,
});
final int? initialPort;

void _update(int? port, WidgetRef ref) {
ref.read(serverPortProvider.notifier).update(port);
}

@override
Widget build(BuildContext context, WidgetRef ref) {
final controller = useTextEditingController(
text: (initialPort ?? '').toString(),
);
return AlertDialog(
title: Text(context.l10n!.serverPort),
content: TextField(
autofocus: true,
controller: controller,
onSubmitted: (value) {
_update(int.tryParse(controller.text), ref);
context.pop();
},
keyboardType: TextInputType.number,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration(
counter: const SizedBox.shrink(),
border: const OutlineInputBorder(),
hintText: (context.l10n!.serverPortHintText),
),
),
actions: [
const PopButton(),
ElevatedButton(
onPressed: () {
_update(int.tryParse(controller.text), ref);
context.pop();
},
child: Text(context.l10n!.save),
),
],
);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2023 Contributors to the Suwayomi project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:network_info_plus/network_info_plus.dart';

import '../../../../constants/db_keys.dart';
import '../../../../utils/extensions/custom_extensions.dart';
import '../../../../utils/misc/toast/toast.dart';
import '../../../../widgets/async_buttons/async_text_button.dart';
import '../server_port_tile/server_port_tile.dart';
import 'server_url_tile.dart';

class ServerSearchButton extends ConsumerWidget {
const ServerSearchButton({
Key? key,
this.text,
}) : super(key: key);
final String? text;
void _update(String url, WidgetRef ref) {
final tempUrl = url.endsWith('/') ? url.substring(0, url.length - 1) : url;
ref.read(serverUrlProvider.notifier).update(tempUrl);
}

Future<String?> getServerAddress(int? port) async {
final ip = await NetworkInfo().getWifiIP();
if (ip.isBlank) return null;

port ??= 4567;
String serverIp = ip!;

if (await pingIp(serverIp, port)) return DBKeys.serverUrl.initial;

final String subnet = ip.substring(0, ip.lastIndexOf('.'));

for (var i = 0; i < 254; i++) {
serverIp = '$subnet.$i';
if (await pingIp(serverIp, port)) return "http://$serverIp";
}
return null;
}

Future<bool> pingIp(String ip, int port) async {
bool isValidIp = false;
await Socket.connect(ip, port, timeout: const Duration(milliseconds: 50))
.then(
(socket) async {
await InternetAddress(socket.address.address).reverse().then(
(value) => isValidIp = true,
onError: (_) => isValidIp = true,
);
socket.destroy();
},
onError: (_) => null,
);
return isValidIp;
}

@override
Widget build(BuildContext context, WidgetRef ref) {
final port = ref.watch(serverPortProvider);
final addPort = ref.watch(serverPortToggleProvider).ifNull();
if (!addPort) return const SizedBox.shrink();
return AsyncTextButton(
icon: const Icon(Icons.search),
onPressed: port != null
? () async {
final value = await getServerAddress(port);
if (value != null) {
_update(value, ref);
} else {
if (context.mounted) {
ref
.watch(toastProvider(context))
.showError(context.l10n!.noServerFound);
}
}
}
: null,
child: Text(context.l10n!.findServer),
);
}
}
Loading