Program-wide avatar cache

Add a program-wide avatar cache― whenever a contact or user's avatar has
changed, it gets cached in ~/config/settings/Caya/Cache/$account/People
(for contacts) or $account/Users (for everyone else).

ImageCache is now used, only for caching the kPersonIcon resource image―
it might be useful later for other commonly used images (status
indicators, etc).

Fixes #4
This commit is contained in:
Jaidyn Ann 2021-06-13 17:34:30 -05:00
parent b2489a5551
commit 6c43311982
8 changed files with 151 additions and 51 deletions

View File

@ -117,11 +117,9 @@ CayaCachePath()
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return NULL;
path.Append("Caya/Cache");
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
return path.Path();
}
@ -133,7 +131,6 @@ CayaAccountCachePath(const char* accountName)
if (path.InitCheck() != B_OK)
return NULL;
path.Append(accountName);
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
return path.Path();
@ -147,7 +144,6 @@ CayaRoomsCachePath(const char* accountName)
if (path.InitCheck() != B_OK)
return NULL;
path.Append("Rooms");
if (create_directory(path.Path(), 0755) != B_OK)
return NULL;
return path.Path();
@ -158,13 +154,36 @@ const char*
CayaRoomCachePath(const char* accountName, const char* roomIdentifier)
{
BPath path(CayaRoomsCachePath(accountName));
if (path.InitCheck() != B_OK)
return NULL;
if (path.InitCheck() != B_OK) return NULL;
path.Append(roomIdentifier);
return path.Path();
}
const char*
CayaUserCachePath(const char* accountName, const char* userIdentifier)
{
BPath path(CayaAccountCachePath(accountName));
if (path.InitCheck() != B_OK) return NULL;
path.Append("Users");
if (create_directory(path.Path(), 0755) != B_OK) return NULL;
path.Append(userIdentifier);
return path.Path();
}
const char*
CayaContactCachePath(const char* accountName, const char* userIdentifier)
{
BPath path(CayaAccountCachePath(accountName));
if (path.InitCheck() != B_OK) return NULL;
path.Append("People");
if (create_directory(path.Path(), 0755) != B_OK) return NULL;
path.Append(userIdentifier);
return path.Path();
}
rgb_color
CayaTintColor(rgb_color color, int severity)
{

View File

@ -27,6 +27,8 @@ const char* CayaCachePath();
const char* CayaAccountCachePath(const char* accountName);
const char* CayaRoomsCachePath(const char* accountName);
const char* CayaRoomCachePath(const char* accountName, const char* roomIdentifier);
const char* CayaUserCachePath(const char* accountName, const char* userIdentifier);
const char* CayaContactCachePath(const char* accountName, const char* userIdentifier);
rgb_color CayaTintColor(rgb_color color, int severity);
rgb_color CayaForegroundColor(rgb_color background);

View File

@ -9,6 +9,8 @@
*/
#include "Contact.h"
#include "CayaUtils.h"
#include "ProtocolLooper.h"
#include "RosterItem.h"
@ -37,3 +39,13 @@ Contact::SetNotifyAvatarBitmap(BBitmap* bitmap)
}
void
Contact::_EnsureCachePath()
{
if (fCachePath.InitCheck() == B_OK)
return;
fCachePath.SetTo(CayaContactCachePath(fLooper->Protocol()->GetName(),
fID.String()));
}

View File

@ -9,6 +9,7 @@
#include <String.h>
#include <Message.h>
#include <Messenger.h>
#include <Path.h>
#include "CayaConstants.h"
#include "User.h"
@ -28,6 +29,8 @@ public:
void SetNotifyAvatarBitmap(BBitmap* bitmap);
private:
virtual void _EnsureCachePath();
RosterItem* fRosterItem;
};

View File

@ -1,5 +1,6 @@
/*
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -11,13 +12,21 @@
#include <AppDefs.h>
#include <Bitmap.h>
#include <Debug.h>
#include <Resources.h>
#include <TranslationUtils.h>
#include <libinterface/BitmapUtils.h>
#include "CayaResources.h"
#include "CayaUtils.h"
ImageCache* ImageCache::fInstance = NULL;
ImageCache::ImageCache()
{
_LoadResource(kPersonIcon, "kPersonIcon");
}
@ -30,24 +39,25 @@ ImageCache::~ImageCache()
}
BBitmap*
ImageCache::GetImage(BString which, BString name)
ImageCache*
ImageCache::Get()
{
if (fInstance == NULL)
if (fInstance == NULL) {
fInstance = new ImageCache();
}
return fInstance;
}
BBitmap*
ImageCache::GetImage(const char* keyName)
{
// Loads the bitmap if found
bool found;
BBitmap* bitmap = fInstance->fBitmaps.ValueFor(name, &found);
BBitmap* bitmap = fBitmaps.ValueFor(BString(keyName), &found);
if (!found) {
bitmap = LoadImage(which.String(), name.String());
if (bitmap)
fInstance->fBitmaps.AddItem(name, bitmap);
if (found == true)
return bitmap;
} else
return bitmap;
return NULL;
}
@ -55,22 +65,16 @@ ImageCache::GetImage(BString which, BString name)
void
ImageCache::AddImage(BString name, BBitmap* which)
{
if (fInstance == NULL)
fInstance = new ImageCache();
fInstance->fBitmaps.AddItem(name, which);
fBitmaps.AddItem(name, which);
}
void
ImageCache::DeleteImage(BString name)
{
if (fInstance == NULL)
fInstance = new ImageCache();
BBitmap* bitmap = fInstance->fBitmaps.ValueFor(name);
BBitmap* bitmap = fBitmaps.ValueFor(name);
if (bitmap) {
fInstance->fBitmaps.RemoveItemFor(name);
fBitmaps.RemoveItemFor(name);
delete bitmap;
}
}
@ -86,14 +90,13 @@ ImageCache::Release()
}
BBitmap*
ImageCache::LoadImage(const char* fullName, const char* shortName)
void
ImageCache::_LoadResource(int identifier, const char* key)
{
BBitmap* bitmap = BTranslationUtils::GetBitmap(fullName);
if (!bitmap)
bitmap = BTranslationUtils::GetBitmap('PNG ', shortName);
if (!bitmap)
printf("ImageCache: Can't load bitmap! %s\n", fullName);
return bitmap;
BResources* res = CayaResources();
BBitmap* bitmap = IconFromResources(res, identifier, B_LARGE_ICON);
if (bitmap != NULL && bitmap->IsValid() == true)
fBitmaps.AddItem(BString(key), bitmap);
}

View File

@ -14,12 +14,13 @@ class BBitmap;
class ImageCache {
public:
/* Returns the image corresponding to the which constant */
static BBitmap* GetImage(BString fullPath,
BString symbolicName);
static ImageCache* Get();
static void AddImage(BString name, BBitmap* which);
static void DeleteImage(BString name);
/* Returns the image corresponding to the which constant */
BBitmap* GetImage(const char* keyName);
void AddImage(BString name, BBitmap* which);
void DeleteImage(BString name);
/* Frees the singleton instance of the cache, must be
* called when the application quits.
@ -31,11 +32,12 @@ protected:
~ImageCache();
private:
static BBitmap* LoadImage(const char* resourceName,
const char*);
void _LoadResource(int identifier, const char* key);
static ImageCache* fInstance;
KeyMap<BString, BBitmap*> fBitmaps;
};
#endif // _IMAGE_CACHE_H

View File

@ -1,6 +1,7 @@
/*
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2012, Dario Casalinuovo. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -9,12 +10,16 @@
*/
#include "User.h"
#include <libinterface/BitmapUtils.h>
#include <Bitmap.h>
#include <BitmapStream.h>
#include <TranslationUtils.h>
#include <TranslatorRoster.h>
#include "CayaProtocolAddOn.h"
#include "CayaResources.h"
#include "CayaUtils.h"
#include "Conversation.h"
#include "ImageCache.h"
#include "NotifyMessage.h"
#include "ProtocolLooper.h"
#include "ProtocolManager.h"
@ -31,6 +36,7 @@ User::User(BString id, BMessenger msgn)
fListItem(NULL),
fItemColor(CayaForegroundColor(ui_color(B_LIST_BACKGROUND_COLOR))),
fStatus(CAYA_OFFLINE),
fAvatarBitmap(NULL),
fPopUp(NULL)
{
}
@ -125,6 +131,8 @@ User::GetName() const
BBitmap*
User::AvatarBitmap() const
{
if (fAvatarBitmap == NULL)
return ImageCache::Get()->GetImage("kPersonIcon");
return fAvatarBitmap;
}
@ -168,15 +176,13 @@ User::GetNotifyPersonalStatus() const
void
User::SetProtocolLooper(ProtocolLooper* looper)
{
if (looper) {
if (looper != NULL) {
fLooper = looper;
// By default we use the Person icon as avatar icon
BResources* res = CayaResources();
BBitmap* bitmap = IconFromResources(res,
kPersonIcon, B_LARGE_ICON);
SetNotifyAvatarBitmap(bitmap);
BBitmap* avatar = _GetCachedAvatar();
if (avatar != NULL && avatar->IsValid()) {
fAvatarBitmap = avatar;
NotifyPointer(PTR_AVATAR_BITMAP, (void*)avatar);
}
}
}
@ -196,6 +202,7 @@ User::SetNotifyAvatarBitmap(BBitmap* bitmap)
{
if ((fAvatarBitmap != bitmap) && (bitmap != NULL)) {
fAvatarBitmap = bitmap;
_SetCachedAvatar(bitmap);
NotifyPointer(PTR_AVATAR_BITMAP, (void*)bitmap);
}
}
@ -228,3 +235,47 @@ User::Conversations()
}
void
User::_EnsureCachePath()
{
if (fCachePath.InitCheck() == B_OK)
return;
fCachePath.SetTo(CayaUserCachePath(fLooper->Protocol()->GetName(),
fID.String()));
}
BBitmap*
User::_GetCachedAvatar()
{
_EnsureCachePath();
// Try loading cached avatar
BFile cacheFile(fCachePath.Path(), B_READ_ONLY);
BBitmap* bitmap = BTranslationUtils::GetBitmap(&cacheFile);
if (bitmap != NULL && bitmap->IsValid() == true)
return bitmap;
return NULL;
}
void
User::_SetCachedAvatar(BBitmap* bitmap)
{
_EnsureCachePath();
BFile cacheFile(fCachePath.Path(), B_WRITE_ONLY | B_CREATE_FILE);
BBitmapStream* stream = new BBitmapStream(bitmap);
BTranslatorRoster* roster = BTranslatorRoster::Default();
int32 format_count;
translator_info info;
const translation_format* formats = NULL;
roster->Identify(stream, new BMessage(), &info, 0, "image");
roster->GetOutputFormats(info.translator, &formats, &format_count);
roster->Translate(info.translator, stream, new BMessage(), &cacheFile,
formats[0].type);
}

View File

@ -1,6 +1,7 @@
/*
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2012, Dario Casalinuovo. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef USER_H
@ -10,6 +11,7 @@
#include <Message.h>
#include <Messenger.h>
#include <ObjectList.h>
#include <Path.h>
#include <libsupport/KeyMap.h>
@ -66,6 +68,11 @@ public:
rgb_color fItemColor;
protected:
virtual void _EnsureCachePath();
BBitmap* _GetCachedAvatar();
void _SetCachedAvatar(BBitmap* avatar);
BMessenger fMessenger;
ProtocolLooper* fLooper;
@ -76,6 +83,7 @@ protected:
BString fName;
BString fPersonalStatus;
BBitmap* fAvatarBitmap;
BPath fCachePath;
CayaStatus fStatus;
UserPopUp* fPopUp;
ChatMap fConversations;