Skip to content

Commit 19a490c

Browse files
committed
added an android route to redirect users to the app or to the store after 1.5 seconds
1 parent 1b15d19 commit 19a490c

5 files changed

Lines changed: 142 additions & 0 deletions

File tree

firebase.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
"source": "/vi{,/**}",
3838
"destination": "/vi/index.html"
3939
},
40+
{
41+
"source": "/android/**",
42+
"destination": "/en/android.html"
43+
},
4044
{
4145
"source": "/**",
4246
"destination": "/en/index.html"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright 2025 The Ground Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the 'License');
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an 'AS IS' BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {Component, OnInit} from '@angular/core';
18+
import {Router} from '@angular/router';
19+
import {firstValueFrom} from 'rxjs';
20+
21+
import {AppConfigService} from 'app/services/app-config/app-config.service';
22+
23+
@Component({
24+
selector: 'ground-android-page',
25+
template: `
26+
<div *ngIf="playStoreId$ | async as playStoreId">
27+
<a
28+
[href]="'https://play.google.com/store/apps/details?id=' + playStoreId"
29+
>
30+
Go to Play Store
31+
</a>
32+
</div>
33+
`,
34+
})
35+
export class AndroidPageComponent implements OnInit {
36+
fullPath = '';
37+
playStoreId$ = this.appConfigService.getPlayStoreId();
38+
39+
constructor(
40+
private appConfigService: AppConfigService,
41+
private router: Router
42+
) {}
43+
44+
async ngOnInit(): Promise<void> {
45+
this.fullPath = this.router.url;
46+
47+
const playStoreId = await firstValueFrom(this.playStoreId$);
48+
49+
if (!playStoreId) return;
50+
51+
const timeout = 1500; // ms
52+
53+
// Fallback: redirect to Play Store if app doesn't open
54+
const fallback = setTimeout(() => {
55+
window.location.href = `https://play.google.com/store/apps/details?id=${playStoreId}`;
56+
}, timeout);
57+
58+
// Try opening the app via intent URL
59+
window.location.href = `intent://${this.fullPath}#Intent;scheme=https;package=${playStoreId};end`;
60+
61+
// Cancel fallback if app is opened (browser loses focus)
62+
const blurHandler = () => {
63+
clearTimeout(fallback);
64+
window.removeEventListener('blur', blurHandler);
65+
};
66+
window.addEventListener('blur', blurHandler);
67+
}
68+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Copyright 2025 The Ground Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the 'License');
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an 'AS IS' BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {CommonModule} from '@angular/common';
18+
import {NgModule} from '@angular/core';
19+
import {RouterModule} from '@angular/router';
20+
21+
import {AndroidPageComponent} from 'app/pages/android/android.component';
22+
23+
@NgModule({
24+
declarations: [AndroidPageComponent],
25+
imports: [CommonModule, RouterModule],
26+
exports: [AndroidPageComponent],
27+
})
28+
export class AndroidModule {}

web/src/app/routing.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {NavigationService} from 'app/services/navigation/navigation.service';
3030

3131
import {ShareSurveyComponent} from './components/share-survey/share-survey.component';
3232
import {AboutComponent} from './pages/about/about.component';
33+
import {AndroidPageComponent} from './pages/android/android.component';
3334
import {EditDetailsComponent} from './pages/edit-survey/edit-details/edit-details.component';
3435
import {EditJobComponent} from './pages/edit-survey/edit-job/edit-job.component';
3536
import {EditSurveyComponent} from './pages/edit-survey/edit-survey.component';
@@ -104,6 +105,11 @@ const routes: Routes = [
104105
path: NavigationService.ABOUT,
105106
component: AboutComponent,
106107
},
108+
{
109+
path: `${NavigationService.ANDROID_SEGMENT}`,
110+
component: AndroidPageComponent,
111+
children: [{path: '**', component: AndroidPageComponent}],
112+
},
107113
{
108114
path: NavigationService.TERMS,
109115
component: TermsComponent,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright 2025 The Ground Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the 'License');
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an 'AS IS' BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {SideNavMode} from './navigation.service';
18+
19+
export class UrlParams {
20+
protected sideNavMode: SideNavMode | null;
21+
22+
constructor(
23+
readonly surveyId: string | null,
24+
readonly loiId: string | null,
25+
readonly submissionId: string | null,
26+
readonly taskId: string | null
27+
) {
28+
if (this.loiId) {
29+
this.sideNavMode = SideNavMode.JOB_LIST;
30+
}
31+
if (this.submissionId) {
32+
this.sideNavMode = SideNavMode.SUBMISSION;
33+
}
34+
this.sideNavMode = null;
35+
}
36+
}

0 commit comments

Comments
 (0)