Skip to content

Commit

Permalink
Prevent asking for Contact Permission repeatedly
Browse files Browse the repository at this point in the history
Solved by only asking for permission once.

close: #6805
Co-authored-by: ivk <ivk@tutao.de>
  • Loading branch information
BijinDev and charlag committed Nov 7, 2024
1 parent 08892e5 commit 656981f
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 18 deletions.
23 changes: 17 additions & 6 deletions src/calendar-app/calendarLocator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { InfoMessageHandler } from "../common/gui/InfoMessageHandler.js"
import { NativeInterfaces } from "../common/native/main/NativeInterfaceFactory.js"
import { EntropyFacade } from "../common/api/worker/facades/EntropyFacade.js"
import { SqlCipherFacade } from "../common/native/common/generatedipc/SqlCipherFacade.js"
import { assertNotNull, defer, DeferredObject, lazy, lazyAsync, LazyLoaded, lazyMemoized, noOp, ofClass } from "@tutao/tutanota-utils"
import { assertNotNull, defer, DeferredObject, lazy, lazyAsync, LazyLoaded, lazyMemoized, noOp } from "@tutao/tutanota-utils"
import { RecipientsModel } from "../common/api/main/RecipientsModel.js"
import { NoZoneDateProvider } from "../common/api/common/utils/NoZoneDateProvider.js"
import { CalendarEvent, CalendarEventAttendee, Contact, Mail, MailboxProperties } from "../common/api/entities/tutanota/TypeRefs.js"
Expand All @@ -64,8 +64,7 @@ import { CalendarViewModel } from "./calendar/view/CalendarViewModel.js"
import { CalendarEventModel, CalendarOperation } from "./calendar/gui/eventeditor-model/CalendarEventModel.js"
import { CalendarEventsRepository } from "../common/calendar/date/CalendarEventsRepository.js"
import { showProgressDialog } from "../common/gui/dialogs/ProgressDialog.js"
import { RecipientsSearchModel } from "../common/misc/RecipientsSearchModel.js"
import { PermissionError } from "../common/api/common/error/PermissionError.js"
import { ContactSuggestionProvider, RecipientsSearchModel } from "../common/misc/RecipientsSearchModel.js"
import { NativeInterfaceMain } from "../common/native/main/NativeInterfaceMain.js"
import { NativeFileApp } from "../common/native/common/FileApp.js"
import { NativePushServiceApp } from "../common/native/main/NativePushServiceApp.js"
Expand Down Expand Up @@ -112,6 +111,7 @@ import { DbError } from "../common/api/common/error/DbError.js"
import { WorkerRandomizer } from "../common/api/worker/workerInterfaces.js"
import { lang } from "../common/misc/LanguageViewModel.js"
import type { CalendarContactPreviewViewModel } from "./calendar/gui/eventpopup/CalendarContactPreviewViewModel.js"
import { ContactSuggestion } from "../common/native/common/generatedipc/ContactSuggestion"

assertMainOrNode()

Expand Down Expand Up @@ -364,12 +364,23 @@ class CalendarLocator {

async recipientsSearchModel(): Promise<RecipientsSearchModel> {
const { RecipientsSearchModel } = await import("../common/misc/RecipientsSearchModel.js")
const suggestionsProvider = isApp()
? (query: string) => this.mobileContactsFacade.findSuggestions(query).catch(ofClass(PermissionError, () => []))
: null
const suggestionsProvider = await this.contactSuggestionProvider()
return new RecipientsSearchModel(await this.recipientsModel(), this.contactModel, suggestionsProvider, this.entityClient)
}

private async contactSuggestionProvider(): Promise<ContactSuggestionProvider> {
if (isApp()) {
const { MobileContactSuggestionProvider } = await import("../common/native/main/MobileContactSuggestionProvider.js")
return new MobileContactSuggestionProvider(this.mobileContactsFacade)
} else {
return {
async getContactSuggestions(_query: String): Promise<readonly ContactSuggestion[]> {
return []
},
}
}
}

get deviceConfig(): DeviceConfig {
return deviceConfig
}
Expand Down
31 changes: 26 additions & 5 deletions src/common/misc/RecipientsSearchModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ import { ContactSuggestion } from "../native/common/generatedipc/ContactSuggesti

const MaxNativeSuggestions = 10

export type RecipientSearchResultItem = { type: "recipient"; value: Recipient } | { type: "contactlist"; value: ContactListInfo }
export type RecipientSearchResultItem =
| { type: "recipient"; value: Recipient }
| {
type: "contactlist"
value: ContactListInfo
}
export type RecipientSearchResultFilter = (item: RecipientSearchResultItem) => boolean

export interface ContactSuggestionProvider {
getContactSuggestions(query: String): Promise<readonly ContactSuggestion[]>
}

export class RecipientsSearchModel {
private searchResults: Array<RecipientSearchResultItem> = []
private loading: Promise<void> | null = null
Expand All @@ -27,7 +36,7 @@ export class RecipientsSearchModel {
constructor(
private readonly recipientsModel: RecipientsModel,
private readonly contactModel: ContactModel,
private readonly suggestionsProvider: ((query: String) => Promise<readonly ContactSuggestion[]>) | null,
private readonly suggestionsProvider: ContactSuggestionProvider | null,
private readonly entityClient: EntityClient,
) {}

Expand Down Expand Up @@ -59,8 +68,20 @@ export class RecipientsSearchModel {
])
if (query === this.currentQuery) {
this.searchResults = [
...newContactListSuggestions.map((value) => ({ type: "contactlist", value } satisfies RecipientSearchResultItem)),
...newContactSuggestions.map((value) => ({ type: "recipient", value } satisfies RecipientSearchResultItem)),
...newContactListSuggestions.map(
(value) =>
({
type: "contactlist",
value,
} satisfies RecipientSearchResultItem),
),
...newContactSuggestions.map(
(value) =>
({
type: "recipient",
value,
} satisfies RecipientSearchResultItem),
),
].filter(this.filter ?? ((_) => true))
this.previousQuery = query
}
Expand Down Expand Up @@ -139,7 +160,7 @@ export class RecipientsSearchModel {
if (!this.suggestionsProvider) {
return []
}
const recipients = await this.suggestionsProvider(text)
const recipients = await this.suggestionsProvider.getContactSuggestions(text)
return recipients.map(({ name, mailAddress }) => ({ name, address: mailAddress }))
}

Expand Down
26 changes: 26 additions & 0 deletions src/common/native/main/MobileContactSuggestionProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { PermissionError } from "../../api/common/error/PermissionError"
import { MobileContactsFacade } from "../common/generatedipc/MobileContactsFacade"
import { ContactSuggestion } from "../common/generatedipc/ContactSuggestion"
import { ContactSuggestionProvider } from "../../misc/RecipientsSearchModel"

export class MobileContactSuggestionProvider implements ContactSuggestionProvider {
private gotPermissionError: boolean = false

constructor(private readonly mobileContactsFacade: MobileContactsFacade) {}

async getContactSuggestions(query: string): Promise<readonly ContactSuggestion[]> {
if (this.gotPermissionError) {
return []
}
try {
return await this.mobileContactsFacade.findSuggestions(query)
} catch (e) {
if (e instanceof PermissionError) {
this.gotPermissionError = true
return []
} else {
throw e
}
}
}
}
30 changes: 23 additions & 7 deletions src/mail-app/mailLocator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import { InfoMessageHandler } from "../common/gui/InfoMessageHandler.js"
import { NativeInterfaces } from "../common/native/main/NativeInterfaceFactory.js"
import { EntropyFacade } from "../common/api/worker/facades/EntropyFacade.js"
import { SqlCipherFacade } from "../common/native/common/generatedipc/SqlCipherFacade.js"
import { assert, assertNotNull, defer, DeferredObject, lazy, lazyAsync, LazyLoaded, lazyMemoized, noOp, ofClass } from "@tutao/tutanota-utils"
import { assert, assertNotNull, defer, DeferredObject, lazy, lazyAsync, LazyLoaded, lazyMemoized, noOp } from "@tutao/tutanota-utils"
import { RecipientsModel } from "../common/api/main/RecipientsModel.js"
import { NoZoneDateProvider } from "../common/api/common/utils/NoZoneDateProvider.js"
import { CalendarEvent, CalendarEventAttendee, Contact, Mail, MailboxProperties } from "../common/api/entities/tutanota/TypeRefs.js"
Expand Down Expand Up @@ -78,8 +78,7 @@ import { CalendarViewModel } from "../calendar-app/calendar/view/CalendarViewMod
import { CalendarEventModel, CalendarOperation } from "../calendar-app/calendar/gui/eventeditor-model/CalendarEventModel.js"
import { CalendarEventsRepository } from "../common/calendar/date/CalendarEventsRepository.js"
import { showProgressDialog } from "../common/gui/dialogs/ProgressDialog.js"
import { RecipientsSearchModel } from "../common/misc/RecipientsSearchModel.js"
import { PermissionError } from "../common/api/common/error/PermissionError.js"
import { ContactSuggestionProvider, RecipientsSearchModel } from "../common/misc/RecipientsSearchModel.js"
import { ConversationViewModel, ConversationViewModelFactory } from "./mail/view/ConversationViewModel.js"
import { CreateMailViewerOptions } from "./mail/view/MailViewer.js"
import { MailViewerViewModel } from "./mail/view/MailViewerViewModel.js"
Expand Down Expand Up @@ -138,6 +137,8 @@ import { ParsedEvent } from "../common/calendar/import/CalendarImporter.js"
import { lang } from "../common/misc/LanguageViewModel.js"
import type { CalendarContactPreviewViewModel } from "../calendar-app/calendar/gui/eventpopup/CalendarContactPreviewViewModel.js"
import { KeyLoaderFacade } from "../common/api/worker/facades/KeyLoaderFacade.js"
import { MobileContactSuggestionProvider } from "../common/native/main/MobileContactSuggestionProvider"
import { ContactSuggestion } from "../common/native/common/generatedipc/ContactSuggestion"

assertMainOrNode()

Expand Down Expand Up @@ -439,12 +440,23 @@ class MailLocator {

async recipientsSearchModel(): Promise<RecipientsSearchModel> {
const { RecipientsSearchModel } = await import("../common/misc/RecipientsSearchModel.js")
const suggestionsProvider = isApp()
? (query: string) => this.mobileContactsFacade.findSuggestions(query).catch(ofClass(PermissionError, () => []))
: null
const suggestionsProvider = await this.contactSuggestionProvider()
return new RecipientsSearchModel(await this.recipientsModel(), this.contactModel, suggestionsProvider, this.entityClient)
}

private async contactSuggestionProvider(): Promise<ContactSuggestionProvider> {
if (isApp()) {
const { MobileContactSuggestionProvider } = await import("../common/native/main/MobileContactSuggestionProvider.js")
return new MobileContactSuggestionProvider(this.mobileContactsFacade)
} else {
return {
async getContactSuggestions(_query: String): Promise<readonly ContactSuggestion[]> {
return []
},
}
}
}

readonly conversationViewModelFactory: lazyAsync<ConversationViewModelFactory> = async () => {
const { ConversationViewModel } = await import("../mail-app/mail/view/ConversationViewModel.js")
const factory = await this.mailViewerViewModelFactory()
Expand Down Expand Up @@ -1128,7 +1140,11 @@ class MailLocator {
for (const [id, name] of CLIENT_ONLY_CALENDARS.entries()) {
const calendarId = `${this.logins.getUserController().userId}#${id}`
const config = configs.get(calendarId)
if (!config) deviceConfig.updateClientOnlyCalendars(calendarId, { name: lang.get(name), color: DEFAULT_CLIENT_ONLY_CALENDAR_COLORS.get(id)! })
if (!config)
deviceConfig.updateClientOnlyCalendars(calendarId, {
name: lang.get(name),
color: DEFAULT_CLIENT_ONLY_CALENDAR_COLORS.get(id)!,
})
}
}

Expand Down

0 comments on commit 656981f

Please sign in to comment.