Merge pull request #11 from apptreesoftware/main
Add support for phone links
This commit is contained in:
commit
4a7b20605f
|
@ -21,6 +21,6 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>8.0</string>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
|
|
@ -14,9 +14,9 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
|
||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
COCOAPODS: 1.11.3
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
|
@ -156,7 +156,7 @@
|
|||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
97C146ED1CF9000F007C117D = {
|
||||
|
@ -340,7 +340,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
@ -414,7 +414,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -463,7 +463,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -41,5 +41,7 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -46,14 +46,19 @@ class _AppState extends State<App> {
|
|||
"text": "O4. This text contains a @user tag",
|
||||
"types": [LinkType.userTag]
|
||||
},
|
||||
{
|
||||
"text": "O5. This text contains a phone number: (555) 444 2223",
|
||||
"types": [LinkType.phone]
|
||||
},
|
||||
{
|
||||
"text":
|
||||
"O5. My website url: https://hello.com/GOOGLE search using: www.google.com, social media is facebook.com, additional link http://example.com/method?param=fullstackoverflow.dev, hashtag #trending & mention @dev.user",
|
||||
"O6. My website url: https://hello.com/GOOGLE search using: www.google.com, social media is facebook.com, additional link http://example.com/method?param=fullstackoverflow.dev, hashtag #trending & mention @dev.user +18009999999",
|
||||
"types": [
|
||||
LinkType.phone,
|
||||
LinkType.email,
|
||||
LinkType.url,
|
||||
LinkType.hashTag,
|
||||
LinkType.userTag
|
||||
LinkType.userTag,
|
||||
]
|
||||
},
|
||||
];
|
||||
|
@ -96,13 +101,14 @@ class _AppState extends State<App> {
|
|||
LinkType.hashTag: TextStyle(color: Colors.green),
|
||||
LinkType.userTag: TextStyle(color: Colors.deepPurple),
|
||||
LinkType.url: TextStyle(color: Colors.pink),
|
||||
LinkType.phone: TextStyle(color: Colors.deepOrange),
|
||||
},
|
||||
linkStyle: textStyle.copyWith(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
onTap: (link) =>
|
||||
showSnackbar("link pressed: ${link.value!}"),
|
||||
onTap: (link) => showSnackbar(
|
||||
"link pressed: ${link.value!}. Type: ${link.type}"),
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -7,7 +7,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.9.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -21,7 +21,7 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -35,7 +35,7 @@ packages:
|
|||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -63,7 +63,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -122,28 +122,28 @@ packages:
|
|||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.12"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
version: "0.1.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.8.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -218,7 +218,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.9.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -239,21 +239,21 @@ packages:
|
|||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.9"
|
||||
version: "0.4.12"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1 +1 @@
|
|||
enum LinkType { url, email, hashTag, userTag }
|
||||
enum LinkType { url, email, hashTag, userTag, phone }
|
||||
|
|
|
@ -5,7 +5,8 @@ String urlRegExp = r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+';
|
|||
String hashtagRegExp = r'(#+[a-zA-Z0-9(_)]{1,})';
|
||||
|
||||
String userTagRegExp = r'(?<![\w@])@([\w@]+(?:[.!][\w@]+)*)';
|
||||
|
||||
String phoneRegExp =
|
||||
r'\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*';
|
||||
String emailRegExp =
|
||||
r"([a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+)";
|
||||
|
||||
|
@ -39,6 +40,11 @@ RegExp constructRegExpFromLinkType(List<LinkType> types) {
|
|||
? buffer.write("($emailRegExp)")
|
||||
: buffer.write("($emailRegExp)|");
|
||||
break;
|
||||
case LinkType.phone:
|
||||
isLast
|
||||
? buffer.write("($phoneRegExp)")
|
||||
: buffer.write("($phoneRegExp)|");
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +55,8 @@ LinkType getMatchedType(String match) {
|
|||
late LinkType type;
|
||||
if (RegExp(emailRegExp).hasMatch(match)) {
|
||||
type = LinkType.email;
|
||||
} else if (RegExp(phoneRegExp).hasMatch(match)) {
|
||||
type = LinkType.phone;
|
||||
} else if (RegExp(userTagRegExp).hasMatch(match)) {
|
||||
type = LinkType.userTag;
|
||||
} else if (RegExp(urlRegExp).hasMatch(match)) {
|
||||
|
|
28
pubspec.lock
28
pubspec.lock
|
@ -28,7 +28,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.9.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -42,7 +42,7 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -56,7 +56,7 @@ packages:
|
|||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -91,7 +91,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -171,21 +171,21 @@ packages:
|
|||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.12"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
version: "0.1.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.8.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -213,7 +213,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -295,7 +295,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.9.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -316,35 +316,35 @@ packages:
|
|||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.21.1"
|
||||
version: "1.21.4"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.9"
|
||||
version: "0.4.12"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.13"
|
||||
version: "0.4.16"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -10,7 +10,9 @@ void main() {
|
|||
const hashtagText = "#helloWorld and #dev are trending";
|
||||
const emailText =
|
||||
"My email address is hey@stanleee.me and dev@gmail.com, yah!";
|
||||
const text = urlText + hashtagText + emailText;
|
||||
|
||||
const phoneText = "My phone number is (222)322-3222 or +15552223333";
|
||||
const text = urlText + hashtagText + emailText + phoneText;
|
||||
|
||||
const emails = ["hello@world.com", "foo.bar@js.com"];
|
||||
|
||||
|
@ -46,6 +48,14 @@ void main() {
|
|||
'@hello_world_123'
|
||||
];
|
||||
|
||||
const phoneNums = [
|
||||
"1112223333",
|
||||
"(111)222 3333",
|
||||
"+5444333222",
|
||||
"+91 (123) 456-7890",
|
||||
"123-456-7890"
|
||||
];
|
||||
|
||||
///
|
||||
test("Should match all emails", () {
|
||||
for (final email in emails) {
|
||||
|
@ -69,6 +79,11 @@ void main() {
|
|||
expect(RegExp(userTagRegExp).hasMatch(tag), isTrue);
|
||||
}
|
||||
});
|
||||
test("Should match all phones", () {
|
||||
for (final tag in phoneNums) {
|
||||
expect(RegExp(phoneRegExp).hasMatch(tag), isTrue);
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
"Should construct regex pattern from LinkTypes and match required output",
|
||||
|
@ -76,13 +91,15 @@ void main() {
|
|||
final urlRegExp = constructRegExpFromLinkType([LinkType.url]);
|
||||
final hashtagRegExp = constructRegExpFromLinkType([LinkType.hashTag]);
|
||||
final emailRegExp = constructRegExpFromLinkType([LinkType.email]);
|
||||
final phoneRegExp = constructRegExpFromLinkType([LinkType.phone]);
|
||||
final textRegExp = constructRegExpFromLinkType(
|
||||
[LinkType.url, LinkType.hashTag, LinkType.email]);
|
||||
[LinkType.url, LinkType.hashTag, LinkType.email, LinkType.phone]);
|
||||
|
||||
expect(urlRegExp.allMatches(urlText).length, 4);
|
||||
expect(hashtagRegExp.allMatches(hashtagText).length, 2);
|
||||
expect(emailRegExp.allMatches(emailText).length, 2);
|
||||
expect(textRegExp.allMatches(text).length, 8);
|
||||
expect(phoneRegExp.allMatches(phoneText).length, 2);
|
||||
expect(textRegExp.allMatches(text).length, 10);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue