Skip to content

Commit

Permalink
Merge pull request #74 from e-picsa/feat/deep-linking
Browse files Browse the repository at this point in the history
Feat: App deep linking
  • Loading branch information
chrismclarke authored Oct 21, 2022
2 parents ed82560 + 92d7127 commit 5eba800
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 9 deletions.
4 changes: 2 additions & 2 deletions apps/picsa-apps/extension-app-native/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ android {
applicationId "io.picsa.extension"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 3011000
versionName "3.11.0"
versionCode 3012000
versionName "3.12.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter android:autoVerify="true">
<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="io.picsa.extension" />
</intent-filter>

</activity>

<provider
Expand Down
5 changes: 5 additions & 0 deletions apps/picsa-apps/extension-app/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
"inlineStyleLanguage": "scss",
"assets": [
"apps/picsa-apps/extension-app/src/assets",
{
"glob": "**/*",
"input": "apps/picsa-apps/extension-app/src/static",
"output": "/"
},
{
"glob": "**/*",
"input": "libs/shared-assets/favicon",
Expand Down
5 changes: 5 additions & 0 deletions apps/picsa-apps/extension-app/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { HttpClientModule, HttpClient } from '@angular/common/http';
import { MobxAngularModule } from 'mobx-angular';
import {
PicsaDbModule,
PicsaDeepLinksModule,
PicsaNativeModule,
PicsaTranslateModule,
} from '@picsa/shared/modules';
Expand All @@ -37,6 +38,10 @@ import { ErrorHandlerService } from '@picsa/shared/services/core/error-handler.s
PicsaDbModule.forRoot(),
PicsaNativeModule.forRoot(),
PicsaTranslateModule.forRoot(),
PicsaDeepLinksModule.forRoot({
baseUrl: 'https://picsa.app',
appDynamicLink: 'https://picsa.page.link/dynamic',
}),
PicsaTranslateModule,
PicsaCommonComponentsModule,
HttpClientModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "io.picsa.extension",
"sha256_cert_fingerprints": [
"E8:13:EC:21:32:37:45:EA:08:2D:E3:1C:D0:B4:91:05:07:9E:E9:E0:55:BE:4B:75:DC:4C:BB:44:82:C6:3C:4E"
]
}
}
]
2 changes: 1 addition & 1 deletion libs/environments/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import packageJson from '../../../package.json';

export const APP_VERSION = {
number: packageJson.version,
date: '2022-10-19',
date: '2022-10-21',
};
10 changes: 9 additions & 1 deletion libs/shared/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"plugins": ["@angular-eslint"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@angular-eslint/component-selector": ["warn"],
"@angular-eslint/component-selector": [
"warn",
{
"type": "element",
"prefix": "picsa",
"style": "kebab-case"
}
],
"@angular-eslint/component-class-suffix": ["warn"]
}
},
Expand Down
82 changes: 82 additions & 0 deletions libs/shared/src/modules/deep-links/app-open-prompt.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Component } from '@angular/core';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { DeepLinksService } from './deep-links.service';

/**
* Show a link to open the app in native platform version, using dynamic app link
*/
@Component({
selector: 'picsa-app-open-prompt',
template: `
<div>
<h2>Open With...</h2>
<a [href]="appDynamicLink" target="_blank" rel="noopener">
<div class="open-option">
<div class="picsa-app-icon">PICSA</div>
<h3>PICSA App</h3>
<button mat-raised-button color="primary">Open</button>
</div>
</a>
<div class="open-option" (click)="dismiss()">
<mat-icon class="open-icon">language</mat-icon>
<h3>Browser</h3>
<button mat-stroked-button>Continue</button>
</div>
<div class="spacer"></div>
</div>
`,
styles: [
`
.picsa-app-icon {
background: #8a2644;
border-radius: 10px;
color: white;
padding: 4px;
line-height: 48px;
height: 48px;
width: 48px;
text-align: center;
font-size: 16px;
}
.open-option {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
h3 {
flex: 1;
text-align: left;
margin-left: 1rem;
}
a {
text-decoration: none;
color: unset;
}
button {
width: 90px;
}
.open-icon {
font-size: 48px;
height: 48px;
width: 48px;
padding: 4px;
}
.spacer {
height: 1rem;
}
`,
],
})
export class AppOpenPromptComponent {
appDynamicLink: string;
constructor(
deepLinksService: DeepLinksService,
private bottomSheet: MatBottomSheet
) {
this.appDynamicLink = deepLinksService.config.appDynamicLink;
}

dismiss() {
this.bottomSheet.dismiss();
}
}
26 changes: 26 additions & 0 deletions libs/shared/src/modules/deep-links/deep-links.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { AppOpenPromptComponent } from './app-open-prompt.component';
import { DeepLinksService, DeepLinksServiceConfig } from './deep-links.service';

@NgModule({
imports: [MatIconModule, MatBottomSheetModule, MatButtonModule],
exports: [],
declarations: [AppOpenPromptComponent],
})
export class PicsaDeepLinksModule {
constructor(deepLinksService: DeepLinksService) {
deepLinksService.init();
}
// https://angular.io/guide/singleton-services#providing-a-singleton-service
static forRoot(
config: DeepLinksServiceConfig
): ModuleWithProviders<PicsaDeepLinksModule> {
return {
ngModule: PicsaDeepLinksModule,
providers: [{ provide: DeepLinksServiceConfig, useValue: config }],
};
}
}
62 changes: 62 additions & 0 deletions libs/shared/src/modules/deep-links/deep-links.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Injectable, NgZone, Optional } from '@angular/core';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { Router } from '@angular/router';
import { App, URLOpenListenerEvent } from '@capacitor/app';
import { Capacitor } from '@capacitor/core';
import { AppOpenPromptComponent } from './app-open-prompt.component';

export class DeepLinksServiceConfig {
/** Web url associated with deep links */
baseUrl: string;
/** E.g. firebase dynamic link */
appDynamicLink: string;
}

@Injectable({ providedIn: 'root' })
/**
* Provide support for opening deep links within app
* https://capacitorjs.com/docs/guides/deep-links#angular
*/
export class DeepLinksService {
constructor(
@Optional() public config: DeepLinksServiceConfig,
private zone: NgZone,
private router: Router,
private bottomSheet: MatBottomSheet
) {}

public init() {
if (Capacitor.isNativePlatform()) {
const baseUrl = this.config?.baseUrl || location.origin;
App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
this.zone.run(() => {
const slug = event.url.replace(`${baseUrl}/`, '');
if (slug) {
this.router.navigateByUrl(slug);
}
});
});
} else {
if (this.isMobile()) {
// open prompt after slight delay to allow time for app to render
setTimeout(() => {
this.toggleAppOpenTargetSheet();
}, 2500);
}
}
}

private isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
}

/**
* Present a bottom sheet to encourage user to use native version of app if running
* on mobile
*/
private toggleAppOpenTargetSheet() {
this.bottomSheet.open(AppOpenPromptComponent);
}
}
15 changes: 11 additions & 4 deletions libs/shared/src/modules/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import {PicsaNativeModule} from './native';
import {PicsaDbModule} from './db.module';
import {PicsaTranslateModule, PicsaTranslateService} from './translate'
import { PicsaNativeModule } from './native';
import { PicsaDbModule } from './db.module';
import { PicsaTranslateModule, PicsaTranslateService } from './translate';
import { PicsaDeepLinksModule } from './deep-links/deep-links.module';

export {PicsaNativeModule, PicsaDbModule, PicsaTranslateModule, PicsaTranslateService}
export {
PicsaNativeModule,
PicsaDbModule,
PicsaTranslateModule,
PicsaTranslateService,
PicsaDeepLinksModule,
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "picsa-apps",
"version": "3.11.0",
"version": "3.12.0",
"license": "See LICENSE",
"scripts": {
"ng": "nx",
Expand Down

0 comments on commit 5eba800

Please sign in to comment.